@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
@@ -4,14 +4,20 @@
4
4
  * already anchors the `/proc/<pid>/stat` parse on the last `)` so a process
5
5
  * name containing spaces cannot shift the fields.
6
6
  *
7
- * Per-process VRAM needs the one `nvidia-smi` call; per-process GPU busy % has
8
- * no unprivileged source at all, so `gpuPct` stays undefined here.
7
+ * Per-process VRAM needs the one `nvidia-smi` call. Per-process GPU busy % comes
8
+ * from DRM fdinfo where the driver publishes it (Intel, AMD) — the proprietary
9
+ * NVIDIA driver publishes neither, so an NVIDIA-only host still fills memory
10
+ * alone.
9
11
  */
10
12
  import { readProcTable, type ProcEntry } from "../proc-table-linux.ts";
11
13
  import type { ProcessCollection, ProcessCollector, RawProcessRow } from "./process-collector-types.ts";
12
14
  import { createStickyColumns } from "./process-collector-types.ts";
13
15
  import { readProcIoBytes, type ProcIoBytes } from "./process-io-linux.ts";
16
+ import { readProcSwapMB } from "./process-swap-linux.ts";
17
+ import { realLinuxFs } from "./linux-fs.ts";
18
+ import { serviceKeyFromCgroup } from "../system-services/app-cgroup-linux.ts";
14
19
  import type { ProcessGpuMemoryCollector } from "./gpu-process-memory-nvidia.ts";
20
+ import type { DrmGpuCollector } from "./gpu-fdinfo-linux.ts";
15
21
 
16
22
  const KB_PER_MB = 1024;
17
23
 
@@ -36,10 +42,20 @@ export function procEntriesToRows(entries: readonly ProcEntry[]): RawProcessRow[
36
42
  export interface LinuxProcessCollectorOptions {
37
43
  /** Injected so unit tests never touch a real `/proc`. */
38
44
  readIo?: (pid: number) => ProcIoBytes | null;
45
+ /** `VmSwap` for one pid, MB. Null = gone or unreadable. */
46
+ readSwap?: (pid: number) => number | null;
47
+ /** `/proc/<pid>/cgroup` for one pid, used only to name its systemd unit. */
48
+ readCgroup?: (pid: number) => string | null;
49
+ /** Whose `systemctl --user` the Services page is reading. Defaults to this
50
+ * process's own uid. */
51
+ selfUid?: number;
39
52
  /** Omitted or null → no per-process VRAM query at all. The production wiring
40
53
  * in `system-metrics-platform.ts` injects it; defaulting to a real collector
41
54
  * here would make an innocent unit test spawn `nvidia-smi`. */
42
55
  gpuMemory?: ProcessGpuMemoryCollector | null;
56
+ /** Shared with the whole-GPU collector: it memoises one `/proc` walk per tick,
57
+ * so whichever of the two asks first pays for it and both see the same numbers. */
58
+ drm?: DrmGpuCollector | null;
43
59
  }
44
60
 
45
61
  export function createLinuxProcessCollector(
@@ -47,7 +63,17 @@ export function createLinuxProcessCollector(
47
63
  opts: LinuxProcessCollectorOptions = {},
48
64
  ): ProcessCollector {
49
65
  const readIo = opts.readIo ?? readProcIoBytes;
66
+ const readSwap = opts.readSwap ?? readProcSwapMB;
67
+ // The Apps page reads the same file under a DIFFERENT rule (it wants the
68
+ // outermost app unit, this wants the innermost unit of any kind), so the two
69
+ // cannot share one read without one of them getting the wrong answer. 1.3 ms
70
+ // for 561 pids, measured on this host.
71
+ const readCgroup = opts.readCgroup ?? ((pid: number) => realLinuxFs.read(`/proc/${pid}/cgroup`));
72
+ // Which user manager is "ours" — a unit of another uid is not on the Services
73
+ // page at all, so its processes must not land on our same-named row.
74
+ const selfUid = opts.selfUid ?? process.getuid?.() ?? 0;
50
75
  const gpuMemory = opts.gpuMemory ?? null;
76
+ const drm = opts.drm ?? null;
51
77
  const observeColumns = createStickyColumns();
52
78
 
53
79
  return {
@@ -58,28 +84,54 @@ export function createLinuxProcessCollector(
58
84
  return { rows: [], columns: observeColumns({}), warnings: ["Process list unavailable: /proc is not readable"] };
59
85
  }
60
86
  const gpuMemByPid = (await gpuMemory?.collect()) ?? null;
87
+ const drmByPid = drm?.usage().perProcess ?? null;
61
88
 
62
89
  let anyIo = false;
90
+ let anySwap = false;
63
91
  const rows = procEntriesToRows(table).map((r) => {
64
92
  // EACCES for another user's process is expected, not an error: that row
65
93
  // simply has no disk figures.
66
94
  const io = readIo(r.pid);
67
95
  if (io) anyIo = true;
96
+ // Both sources list only the processes actually using the GPU, so a
97
+ // missing pid means "measured, holding none" — not "unknown".
98
+ const drmRow = drmByPid?.get(r.pid);
99
+ const nvidiaMem = gpuMemByPid ? gpuMemByPid.get(r.pid) ?? 0 : undefined;
100
+ const drmMem = drmByPid ? (drmRow ? drmRow.vramMB + drmRow.sharedMB : 0) : undefined;
101
+ // A process that exited between the table read and now has neither; both
102
+ // stay absent for that row rather than being reported as zero.
103
+ const swapMB = readSwap(r.pid);
104
+ if (swapMB !== null) anySwap = true;
105
+ const unitKey = serviceKeyFromCgroup(readCgroup(r.pid) ?? "", selfUid);
68
106
  return {
69
107
  ...r,
108
+ ...(swapMB === null ? {} : { swapMB }),
109
+ ...(unitKey === null ? {} : { unitKey }),
70
110
  diskReadBytes: io?.readBytes,
71
111
  diskWriteBytes: io?.writeBytes,
72
- // The query lists only processes holding VRAM, so a missing pid means
73
- // "measured, holding none".
74
- gpuMemMB: gpuMemByPid ? gpuMemByPid.get(r.pid) ?? 0 : undefined,
112
+ ...(drmByPid ? { gpuPct: drmRow?.gpuPct ?? 0 } : {}),
113
+ gpuMemMB: sumDefined(nvidiaMem, drmMem),
75
114
  };
76
115
  });
77
116
 
78
117
  return {
79
118
  rows,
80
- columns: observeColumns({ disk: anyIo, gpu: gpuMemByPid !== null }),
119
+ columns: observeColumns({
120
+ disk: anyIo,
121
+ gpu: gpuMemByPid !== null || drmByPid !== null,
122
+ swap: anySwap,
123
+ }),
81
124
  warnings: [],
82
125
  };
83
126
  },
84
127
  };
85
128
  }
129
+
130
+ /** Undefined only when NEITHER source measured anything — a host with one of the
131
+ * two must not report "unknown" for a figure it really does have. */
132
+ function sumDefined(a: number | undefined, b: number | undefined): number | undefined {
133
+ if (a === undefined && b === undefined) return undefined;
134
+ return round1((a ?? 0) + (b ?? 0));
135
+ }
136
+
137
+ const round1 = (n: number) => Math.round(n * 10) / 10;
@@ -13,6 +13,12 @@ export interface RawProcessRow {
13
13
  /** Cumulative CPU time (user + kernel), milliseconds. */
14
14
  cpuMs: number;
15
15
  ramMB: number;
16
+ /** Swapped-out anonymous memory, MB. `undefined` = this OS has no per-process
17
+ * source; 0 is a real reading (a kernel thread has no address space). */
18
+ swapMB?: number;
19
+ /** `"<scope>:<unit>"` — which Services row owns this pid. Absent off systemd,
20
+ * for a pid in no unit, and for another user's units. */
21
+ unitKey?: string;
16
22
  /** Epoch ms UTC; 0 when unknown. */
17
23
  startedAt: number;
18
24
  /** CUMULATIVE per-process byte counters. The rows builder turns them into
@@ -49,7 +55,7 @@ export interface ProcessCollector {
49
55
 
50
56
  /** Frozen: it is shared by every light-tier snapshot, so an accidental mutation
51
57
  * would rewrite history for all of them. */
52
- export const NO_PROCESS_COLUMNS: ProcessColumnAvailability = Object.freeze({ disk: false, gpu: false, net: false });
58
+ export const NO_PROCESS_COLUMNS: ProcessColumnAvailability = Object.freeze({ disk: false, gpu: false, net: false, swap: false });
53
59
 
54
60
  /**
55
61
  * Sticky column availability. A capability is advertised as soon as it has
@@ -64,6 +70,7 @@ export function createStickyColumns(): (seen: Partial<ProcessColumnAvailability>
64
70
  state.disk ||= seen.disk === true;
65
71
  state.gpu ||= seen.gpu === true;
66
72
  state.net ||= seen.net === true;
73
+ state.swap ||= seen.swap === true;
67
74
  return { ...state };
68
75
  };
69
76
  }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * The same Details dialog as `process-details-linux.ts`, for macOS.
3
+ *
4
+ * It exists because the dialog was *lying* there: the service answered `null`
5
+ * for every non-Linux platform and the route turned that into a 404 reading
6
+ * "PID <n> is no longer running" — a sentence that is correct on Linux, where a
7
+ * vanished `/proc/<pid>` really does mean the process exited, and simply untrue
8
+ * anywhere else. A process sitting in the table at 4.2% CPU was reported dead.
9
+ *
10
+ * macOS has no `/proc`, but `ps` answers ten of the eleven fields, and two of
11
+ * them more directly than Linux does: `lstart` is a real timestamp rather than
12
+ * jiffies to be added to `btime`, and `user` is the login name already, so no
13
+ * `/etc/passwd` lookup is needed and it works across users. Only `cgroup` has no
14
+ * equivalent — macOS has no such concept — and it stays null, which the page
15
+ * draws as an em dash: the honest answer rather than an invented one.
16
+ *
17
+ * Measured on an M1 Max: `ps` for one pid 29.7 ms, `ps -M` 32.5 ms, `lsof` 37.5
18
+ * ms. The last three run concurrently, so a dialog costs about two spawns' wall
19
+ * time. That is affordable only because this is on-demand — it must never be
20
+ * moved onto the tick, which is the same rule the Linux module states.
21
+ */
22
+ import type { ProcessDetails } from "../../types/system-metrics.ts";
23
+ import { redactSecrets } from "../redact-secrets.ts";
24
+ import { defaultRunner, type Runner } from "../host-info/spawn-runner.ts";
25
+
26
+ /**
27
+ * BSD's state letters, which are NOT Linux's. The one that catches people is
28
+ * **U**: uninterruptible wait, spelled `D` on Linux. `I` is also real here —
29
+ * macOS marks a process idle once it has slept more than 20 seconds — and `Z`
30
+ * is far from rare: this host had 126 zombies against 645 sleepers.
31
+ */
32
+ export const DARWIN_PROCESS_STATES: Record<string, string> = {
33
+ R: "Running", S: "Sleeping", I: "Idle", T: "Stopped",
34
+ U: "Uninterruptible sleep", Z: "Zombie",
35
+ };
36
+
37
+ export interface PsFields {
38
+ ppid: number;
39
+ state: string | null;
40
+ nice: number | null;
41
+ /** Epoch ms, or 0 when `lstart` did not parse — the UI draws 0 as an em dash. */
42
+ startedAt: number;
43
+ user: string | null;
44
+ exe: string | null;
45
+ }
46
+
47
+ /**
48
+ * One line of `ps -o ppid=,stat=,nice=,lstart=,user=,comm=`, e.g.
49
+ * ` 1 S 0 Tue Sep 8 10:05:03 2026 thawng /System/…/Finder`
50
+ *
51
+ * Split by position, not by a delimiter, because `ps` on macOS offers none —
52
+ * and two fields contain spaces. `lstart` is **always five tokens** (verified
53
+ * across all 740 processes on a live host: a single-digit day pads with two
54
+ * spaces, which collapses on a `\s+` split rather than dropping a token), so
55
+ * every field up to `user` is at a fixed index and `comm` is whatever is left.
56
+ * It has to be last for that reason: a path like
57
+ * `/Applications/Google Chrome.app/…/Google Chrome Helper (Renderer)` holds six
58
+ * spaces, so anything after it could not be found again.
59
+ */
60
+ export function parsePsLine(text: string | null | undefined): PsFields | null {
61
+ const line = (text ?? "").trim();
62
+ if (!line) return null;
63
+ const t = line.split(/\s+/);
64
+ // ppid, stat, nice, five for lstart, user — comm may legitimately be empty.
65
+ if (t.length < 9) return null;
66
+
67
+ const ppid = Number(t[0]);
68
+ if (!Number.isInteger(ppid) || ppid < 0) return null;
69
+
70
+ const nice = Number(t[2]);
71
+ const started = Date.parse(t.slice(3, 8).join(" "));
72
+ const exe = t.slice(9).join(" ");
73
+
74
+ return {
75
+ ppid,
76
+ state: DARWIN_PROCESS_STATES[t[1]![0] ?? ""] ?? null,
77
+ nice: Number.isFinite(nice) ? nice : null,
78
+ startedAt: Number.isFinite(started) ? started : 0,
79
+ user: t[8] || null,
80
+ exe: exe || null,
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Thread count from a bare `ps -M -p <pid>` dump: one header line, then one line
86
+ * per thread.
87
+ *
88
+ * `-M` may not be combined with `-o` — asking for both prints the chosen columns
89
+ * AND leftovers of the thread layout on the same line, which parses as nonsense
90
+ * rather than failing, so this is deliberately a second call against the default
91
+ * format rather than a column added to the first.
92
+ */
93
+ export function parseThreadCount(text: string | null | undefined): number | null {
94
+ const lines = (text ?? "").split("\n").filter((l) => l.trim().length > 0);
95
+ return lines.length > 1 ? lines.length - 1 : null;
96
+ }
97
+
98
+ /**
99
+ * `lsof -a -p <pid> -d cwd -Fn` in its machine-readable form: one field per
100
+ * line, prefixed by its type, `n` being the name.
101
+ *
102
+ * Another user's working directory comes back as exit 0 with **no output at
103
+ * all** rather than an error, which is the normal case on any machine with
104
+ * daemons on it — the same "absent, not failed" reading the Linux module gives
105
+ * an EACCES on `/proc/<pid>/cwd`.
106
+ */
107
+ export function parseLsofCwd(text: string | null | undefined): string | null {
108
+ for (const line of (text ?? "").split("\n")) {
109
+ if (line.startsWith("n")) return line.slice(1).trim() || null;
110
+ }
111
+ return null;
112
+ }
113
+
114
+ /** The last path segment, for the `name` field — macOS has no `comm` truncated
115
+ * to 15 characters to take it from, only the executable's full path. */
116
+ function baseName(exe: string | null): string | null {
117
+ if (!exe) return null;
118
+ const cut = exe.lastIndexOf("/");
119
+ return (cut >= 0 ? exe.slice(cut + 1) : exe) || null;
120
+ }
121
+
122
+ /**
123
+ * Null when the pid is gone, which `ps` reports as a non-zero exit with nothing
124
+ * on stdout — so the route's "no longer running" is finally true when it is said.
125
+ */
126
+ export async function readProcessDetailsDarwin(
127
+ pid: number,
128
+ run: Runner = defaultRunner,
129
+ ): Promise<ProcessDetails | null> {
130
+ if (!Number.isInteger(pid) || pid <= 0) return null;
131
+ const arg = String(pid);
132
+
133
+ const ps = await run(["ps", "-o", "ppid=,stat=,nice=,lstart=,user=,comm=", "-p", arg]);
134
+ if (ps.code !== 0) return null;
135
+ const fields = parsePsLine(ps.stdout);
136
+ if (!fields) return null;
137
+
138
+ // Concurrently: three independent spawns, and every one of them is allowed to
139
+ // fail on its own. A process whose command line or thread count cannot be read
140
+ // is still a process whose parent, user and state were just read successfully.
141
+ const [cmd, threads, cwd] = await Promise.all([
142
+ run(["ps", "-o", "command=", "-p", arg]),
143
+ run(["ps", "-M", "-p", arg]),
144
+ run(["lsof", "-a", "-p", arg, "-d", "cwd", "-Fn"]),
145
+ ]);
146
+
147
+ const command = cmd.code === 0 ? cmd.stdout.trim() : "";
148
+ return {
149
+ pid,
150
+ ppid: fields.ppid,
151
+ name: baseName(fields.exe) ?? arg,
152
+ startedAt: fields.startedAt,
153
+ // Redacted but NOT truncated, exactly as on Linux: showing the whole line is
154
+ // what this dialog is for.
155
+ command: command ? redactSecrets(command) : null,
156
+ exe: fields.exe,
157
+ cwd: cwd.code === 0 ? parseLsofCwd(cwd.stdout) : null,
158
+ user: fields.user,
159
+ state: fields.state,
160
+ threads: threads.code === 0 ? parseThreadCount(threads.stdout) : null,
161
+ nice: fields.nice,
162
+ // macOS has no cgroups. Null is the honest answer and renders as an em dash;
163
+ // inventing a value here would be the same mistake this file exists to undo.
164
+ cgroup: null,
165
+ };
166
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * On-demand facts for the process Details dialog — Mission Center's process
3
+ * properties. Fetched when the dialog opens, never per tick: it is a handful of
4
+ * reads per process and nobody needs `cwd` at 0.5 Hz.
5
+ *
6
+ * Every field is null when this pid's permissions do not expose it. Another
7
+ * user's `exe` and `cwd` are EACCES for an unprivileged PPM, which is the normal
8
+ * case on a shared machine and not an error.
9
+ */
10
+ import type { ProcessDetails } from "../../types/system-metrics.ts";
11
+ import { redactSecrets } from "../redact-secrets.ts";
12
+ import { readAttr, realLinuxFs, type LinuxFs } from "./linux-fs.ts";
13
+
14
+ const PROC = "/proc";
15
+ /** Same assumption `proc-table-linux.ts` documents: 100 on every mainstream Linux. */
16
+ const CLOCK_TICKS_PER_SEC = 100;
17
+
18
+ /** The kernel's one-letter state, spelled out the way `ps` and Mission Center do. */
19
+ export const PROCESS_STATES: Record<string, string> = {
20
+ R: "Running", S: "Sleeping", D: "Uninterruptible sleep", Z: "Zombie",
21
+ T: "Stopped", t: "Tracing stop", X: "Dead", I: "Idle", W: "Paging", K: "Wakekill",
22
+ };
23
+
24
+ export interface StatFields {
25
+ state: string;
26
+ ppid: number;
27
+ nice: number;
28
+ threads: number;
29
+ /** Ticks since boot. */
30
+ startTicks: number;
31
+ comm: string;
32
+ }
33
+
34
+ /**
35
+ * `/proc/<pid>/stat`, anchored on the LAST `)`.
36
+ *
37
+ * The second field is the executable name in parentheses and it is not escaped,
38
+ * so a process called `foo) 0 (bar` shifts every field after it for any parser
39
+ * that splits on whitespace. Anchoring on the last `)` is the only correct
40
+ * reading, and it is what `readProcTable` does too.
41
+ */
42
+ export function parseStatFields(text: string): StatFields | null {
43
+ const close = text.lastIndexOf(")");
44
+ const open = text.indexOf("(");
45
+ if (close < 0 || open < 0 || close < open) return null;
46
+ const rest = text.slice(close + 1).trim().split(/\s+/);
47
+ // `rest[0]` is field 3 (state), so field N is at rest[N - 3].
48
+ const at = (field: number) => Number(rest[field - 3]);
49
+ const ppid = at(4);
50
+ if (!Number.isFinite(ppid)) return null;
51
+ return {
52
+ comm: text.slice(open + 1, close),
53
+ state: rest[0] ?? "",
54
+ ppid,
55
+ nice: at(19),
56
+ threads: at(20),
57
+ startTicks: at(22),
58
+ };
59
+ }
60
+
61
+ /** `/proc/stat`'s `btime` line: boot time as epoch SECONDS. */
62
+ export function parseBootTimeSec(procStat: string | null): number | null {
63
+ const m = /^btime\s+(\d+)/m.exec(procStat ?? "");
64
+ const n = m ? Number(m[1]) : NaN;
65
+ return Number.isFinite(n) ? n : null;
66
+ }
67
+
68
+ /** The real uid from `/proc/<pid>/status`'s `Uid: real effective saved fs`. */
69
+ export function parseUid(status: string | null): number | null {
70
+ const m = /^Uid:\s+(\d+)/m.exec(status ?? "");
71
+ const n = m ? Number(m[1]) : NaN;
72
+ return Number.isFinite(n) ? n : null;
73
+ }
74
+
75
+ /** uid → login name from `/etc/passwd`, which is world-readable by design. */
76
+ export function lookupUser(uid: number, passwd: string | null): string | null {
77
+ for (const line of (passwd ?? "").split("\n")) {
78
+ const f = line.split(":");
79
+ if (f.length > 2 && Number(f[2]) === uid) return f[0] ?? null;
80
+ }
81
+ return null;
82
+ }
83
+
84
+ /** cgroup v2 writes one `0::<path>` line; v1 writes several, and the systemd
85
+ * hierarchy is the one that names the unit. */
86
+ export function parseCgroup(text: string | null): string | null {
87
+ const lines = (text ?? "").split("\n").filter(Boolean);
88
+ const v2 = lines.find((l) => l.startsWith("0::"));
89
+ if (v2) return v2.slice(3) || null;
90
+ const systemd = lines.find((l) => l.includes(":name=systemd:"));
91
+ const chosen = systemd ?? lines[0];
92
+ if (!chosen) return null;
93
+ const idx = chosen.indexOf(":", chosen.indexOf(":") + 1);
94
+ return idx >= 0 ? chosen.slice(idx + 1) || null : null;
95
+ }
96
+
97
+ export interface ProcessDetailsOptions {
98
+ fs?: LinuxFs;
99
+ /** Injected so the lookup is testable and read once per request, not per line. */
100
+ passwd?: () => string | null;
101
+ }
102
+
103
+ /** Null when the pid is gone (or /proc is unreadable) — the dialog then says so. */
104
+ export function readProcessDetails(pid: number, opts: ProcessDetailsOptions = {}): ProcessDetails | null {
105
+ const fs = opts.fs ?? realLinuxFs;
106
+ if (!Number.isInteger(pid) || pid <= 0) return null;
107
+ const stat = fs.read(`${PROC}/${pid}/stat`);
108
+ const fields = stat ? parseStatFields(stat) : null;
109
+ if (!fields) return null;
110
+
111
+ const status = fs.read(`${PROC}/${pid}/status`);
112
+ const uid = parseUid(status);
113
+ const bootSec = parseBootTimeSec(fs.read(`${PROC}/stat`));
114
+ const rawCmdline = fs.read(`${PROC}/${pid}/cmdline`) ?? "";
115
+ // NUL-separated argv. A kernel thread has an empty cmdline, which is not a
116
+ // command line of "" — it has none at all.
117
+ const argv = rawCmdline.split("\0").filter(Boolean).join(" ");
118
+
119
+ return {
120
+ pid,
121
+ ppid: fields.ppid,
122
+ name: nameOf(status) ?? fields.comm,
123
+ startedAt: bootSec !== null && Number.isFinite(fields.startTicks)
124
+ ? Math.round((bootSec + fields.startTicks / CLOCK_TICKS_PER_SEC) * 1000)
125
+ : 0,
126
+ // Redacted but NOT truncated: the dialog exists to show the whole line, and
127
+ // the 160-char cut on a table row is a bandwidth decision, not a privacy one.
128
+ command: argv ? redactSecrets(argv) : null,
129
+ exe: fs.readlink(`${PROC}/${pid}/exe`),
130
+ cwd: fs.readlink(`${PROC}/${pid}/cwd`),
131
+ user: uid === null ? null : lookupUser(uid, (opts.passwd ?? (() => fs.read("/etc/passwd")))()),
132
+ state: describeState(fields.state),
133
+ threads: Number.isFinite(fields.threads) ? fields.threads : null,
134
+ nice: Number.isFinite(fields.nice) ? fields.nice : null,
135
+ cgroup: parseCgroup(fs.read(`${PROC}/${pid}/cgroup`)),
136
+ };
137
+ }
138
+
139
+ /** `/proc/<pid>/status`'s `Name:` is the same truncated comm, but without the
140
+ * parenthesis quoting — preferred when present because it needs no unwrapping. */
141
+ function nameOf(status: string | null): string | null {
142
+ const m = /^Name:\s*(.+)$/m.exec(status ?? "");
143
+ return m?.[1]?.trim() || null;
144
+ }
145
+
146
+ export function describeState(code: string): string | null {
147
+ if (!code) return null;
148
+ const word = PROCESS_STATES[code];
149
+ return word ? `${code} (${word})` : code;
150
+ }
@@ -16,7 +16,7 @@ const POSIX_BOUNDARY_NAMES: ReadonlySet<string> = new Set(["launchd", "systemd",
16
16
  const round1 = (n: number): number => Math.round(n * 10) / 10;
17
17
 
18
18
  /** The optional per-process columns, which roll up by summation. */
19
- type OptionalMetric = "diskReadBps" | "diskWriteBps" | "gpuPct" | "gpuMemMB" | "netInBps" | "netOutBps";
19
+ type OptionalMetric = "swapMB" | "diskReadBps" | "diskWriteBps" | "gpuPct" | "gpuMemMB" | "netInBps" | "netOutBps";
20
20
 
21
21
  /**
22
22
  * Sum over the members that HAVE a value; `undefined` when none does, so a
@@ -129,6 +129,7 @@ export function groupProcesses(
129
129
  count: g.procs.length,
130
130
  ppm: g.procs.some((p) => p.ppm),
131
131
  pids: g.procs.map((p) => p.pid),
132
+ swapMB: sumOptional(g.procs, "swapMB"),
132
133
  diskReadBps: sumOptional(g.procs, "diskReadBps"),
133
134
  diskWriteBps: sumOptional(g.procs, "diskWriteBps"),
134
135
  gpuPct: sumOptional(g.procs, "gpuPct"),
@@ -93,6 +93,8 @@ export function buildProcessRows(input: BuildRowsInput): BuiltRows {
93
93
  command: sanitizeCommand(r.command, r.name),
94
94
  cpu: percentByKey.get(key) ?? 0,
95
95
  ramMB: Math.round(r.ramMB * 10) / 10,
96
+ ...(r.swapMB === undefined ? {} : { swapMB: Math.round(r.swapMB * 10) / 10 }),
97
+ ...(r.unitKey === undefined ? {} : { unitKey: r.unitKey }),
96
98
  startedAt: r.startedAt,
97
99
  ppm: ppmPids.has(r.pid),
98
100
  protected: !checkKillAllowed({ pid: r.pid, name: r.name }, false, guardCtx).allowed,
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Per-process swap — Mission Center's Swap column, on the process table and on
3
+ * every Services row.
4
+ *
5
+ * `VmSwap` in `/proc/<pid>/status` is the only cheap source: `smaps_rollup` also
6
+ * carries it but walks every mapping, and on a 560-process desktop that is the
7
+ * difference between a few milliseconds and a tick that misses its deadline.
8
+ * Measured here: the whole table costs 3.2 ms, beside the 1.7 ms `/proc/<pid>/io`
9
+ * already pays every tick.
10
+ *
11
+ * A kernel thread has no address space and so no `VmSwap` line at all. That is
12
+ * 0 swapped bytes, not an unmeasurable one — the distinction matters because the
13
+ * table renders `undefined` as an em dash, and 335 of this host's 561 rows would
14
+ * otherwise be dashes on a column that really does read zero for them.
15
+ */
16
+ import { readFileSync } from "node:fs";
17
+
18
+ const KB_PER_MB = 1024;
19
+
20
+ /** `VmSwap` in kB from a `/proc/<pid>/status` dump. A process with an address
21
+ * space always has the line; one without is a kernel thread, i.e. 0. */
22
+ export function parseVmSwapKB(status: string): number {
23
+ const m = /^VmSwap:\s+(\d+)\s*kB/m.exec(status);
24
+ if (!m) return 0;
25
+ const kb = Number(m[1]);
26
+ return Number.isFinite(kb) ? kb : 0;
27
+ }
28
+
29
+ /** Swapped MB for one pid, or null when the process is gone or unreadable —
30
+ * another user's process is expected to refuse, and that row simply has none. */
31
+ export function readProcSwapMB(pid: number): number | null {
32
+ try {
33
+ return parseVmSwapKB(readFileSync(`/proc/${pid}/status`, "utf-8")) / KB_PER_MB;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Delivers ONE signal to a process, or to its whole collected tree — Mission
3
+ * Center's "Send Signal" submenu. Separate from `executeKill` on purpose: a kill
4
+ * escalates SIGTERM to SIGKILL after a grace period, which is right for "end this
5
+ * process" and wrong for every other signal. Asking for SIGSTOP must send SIGSTOP
6
+ * and nothing else.
7
+ *
8
+ * Pids are validated integers passed to `process.kill` or as argv elements —
9
+ * never interpolated into a shell string.
10
+ */
11
+ import type { ProcessSignal, SignalProcessResult } from "../../types/system-metrics.ts";
12
+ import type { Runner } from "../host-info/spawn-runner.ts";
13
+ import { defaultRunner } from "../host-info/spawn-runner.ts";
14
+ import { collectProcessTree } from "../windows-process-tree.ts";
15
+
16
+ /** Windows has no signals. `taskkill` is the only delivery there and it can only
17
+ * mean "end it", so those two map and the rest are refused with a reason. */
18
+ export const WINDOWS_SUPPORTED_SIGNALS: ReadonlySet<ProcessSignal> = new Set<ProcessSignal>(["TERM", "KILL"]);
19
+
20
+ export interface SignalExecutorDeps {
21
+ platform: NodeJS.Platform;
22
+ run: Runner;
23
+ signal: (pid: number, sig: NodeJS.Signals) => void;
24
+ collectTree: (pid: number) => number[];
25
+ }
26
+
27
+ export const defaultSignalExecutorDeps: SignalExecutorDeps = {
28
+ platform: process.platform,
29
+ run: defaultRunner,
30
+ signal: (pid, sig) => { process.kill(pid, sig); },
31
+ collectTree: collectProcessTree,
32
+ };
33
+
34
+ /** Which signals this host can actually deliver, for the client to build its menu. */
35
+ export function supportedSignals(platform: NodeJS.Platform = process.platform): ProcessSignal[] {
36
+ return platform === "win32"
37
+ ? [...WINDOWS_SUPPORTED_SIGNALS]
38
+ : ["TERM", "KILL", "STOP", "CONT", "HUP", "INT", "USR1", "USR2"];
39
+ }
40
+
41
+ /** Throws on executor failure; the handler maps that to 500. */
42
+ export async function executeSignal(
43
+ pid: number,
44
+ signal: ProcessSignal,
45
+ tree: boolean,
46
+ deps: SignalExecutorDeps = defaultSignalExecutorDeps,
47
+ ): Promise<SignalProcessResult> {
48
+ if (!Number.isInteger(pid) || pid <= 0) throw new Error(`Invalid PID ${pid}`);
49
+
50
+ if (deps.platform === "win32") {
51
+ if (!WINDOWS_SUPPORTED_SIGNALS.has(signal)) {
52
+ throw new Error(`Windows cannot deliver SIG${signal}`);
53
+ }
54
+ const argv = tree
55
+ ? ["taskkill", "/PID", String(pid), "/T", "/F"]
56
+ : ["taskkill", "/PID", String(pid), "/F"];
57
+ const r = await deps.run(argv, 5000);
58
+ if (r.code !== 0 || r.timedOut) {
59
+ throw new Error((r.stderr || r.stdout || `taskkill exited ${r.timedOut ? "on timeout" : r.code}`).trim());
60
+ }
61
+ return { pid, signal, tree, method: "taskkill", signalled: [pid] };
62
+ }
63
+
64
+ const posix = `SIG${signal}` as NodeJS.Signals;
65
+ if (!tree) {
66
+ deps.signal(pid, posix);
67
+ return { pid, signal, tree: false, method: "signal", signalled: [pid] };
68
+ }
69
+
70
+ // Enumerate BEFORE signalling: SIGKILL on the root reparents its children to
71
+ // init, and the tree can no longer be recovered afterwards. Children are
72
+ // signalled first so a parent cannot fork a replacement mid-sweep.
73
+ const pids = deps.collectTree(pid);
74
+ const signalled: number[] = [];
75
+ for (const target of pids) {
76
+ // A process exiting between the walk and the signal is the normal case here,
77
+ // not a failure of the request — it is simply not in the result.
78
+ try {
79
+ deps.signal(target, posix);
80
+ signalled.push(target);
81
+ } catch { /* already gone */ }
82
+ }
83
+ return { pid, signal, tree: true, method: "signal", signalled };
84
+ }