@hienlh/ppm 0.23.5 → 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 (714) hide show
  1. package/CHANGELOG.md +89 -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 +30 -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-DKcsVDle.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-qMGJH0Bx.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-D2I742dl.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-Bz4LjgIa.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-CapP1yXq.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-CdXi7cZN.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-B2nZzJ2b.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-BGoDxkdF.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-DC3OzzOl.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-i41W43ER.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-DHzPIkJg.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-Dj4vrDvj.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-BJ9edGEP.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-CxdGSNGr.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-ok96IgnS.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-Drkjb_LI.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-C8PFlvaq.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-CFYO0Ro3.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-BcHIEANE.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-BGsp0edA.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-CsZCCRJI.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-Ci0O2Ng6.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-4iCGE4h2.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-CK6DulYk.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-CWBaWKjA.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-Br6mrxrw.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-CwCy7ZWf.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-BW14RpCb.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-CgOBEUnb.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-rH6epJYA.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-QwURkjpV.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/codex-app-server/codex-reset-credit.ts +49 -0
  316. package/src/providers/provider-probe.ts +63 -0
  317. package/src/providers/registry.ts +109 -29
  318. package/src/server/index.ts +9 -0
  319. package/src/server/middleware/auth.ts +5 -1
  320. package/src/server/routes/codex-accounts.ts +14 -0
  321. package/src/server/routes/cross-origin-guard.ts +20 -0
  322. package/src/server/routes/git.ts +40 -4
  323. package/src/server/routes/lsp.ts +97 -4
  324. package/src/server/routes/resources.ts +72 -9
  325. package/src/server/routes/settings.ts +19 -1
  326. package/src/server/routes/speech.ts +66 -0
  327. package/src/server/routes/system-services.ts +76 -0
  328. package/src/server/routes/tunnel.ts +33 -1
  329. package/src/server/ws/chat.ts +74 -3
  330. package/src/services/codex-account-login.ts +26 -2
  331. package/src/services/codex-reset-credit.service.ts +83 -0
  332. package/src/services/compaction-savings.ts +127 -0
  333. package/src/services/db.service.ts +123 -8
  334. package/src/services/edge-forwarder.ts +191 -191
  335. package/src/services/fs-ops/fs-ops-trash.service.ts +22 -9
  336. package/src/services/git-refs/for-each-ref.ts +118 -0
  337. package/src/services/git.service.ts +25 -2
  338. package/src/services/host-info/spawn-runner.ts +48 -4
  339. package/src/services/jsonl-transcript-parser.ts +7 -42
  340. package/src/services/lsp/lsp-install.ts +289 -0
  341. package/src/services/lsp/lsp-manager.ts +160 -29
  342. package/src/services/lsp/server-registry.ts +120 -4
  343. package/src/services/named-tunnel/named-tunnel-config.ts +8 -2
  344. package/src/services/named-tunnel/named-tunnel-setup.service.ts +4 -0
  345. package/src/services/read-lines.ts +54 -0
  346. package/src/services/speech-to-text/whisper-catalog.ts +142 -0
  347. package/src/services/speech-to-text/whisper-download.ts +113 -0
  348. package/src/services/speech-to-text/whisper-hallucinations.ts +51 -0
  349. package/src/services/speech-to-text/whisper-install.service.ts +247 -0
  350. package/src/services/speech-to-text/whisper-paths.ts +62 -0
  351. package/src/services/speech-to-text/whisper-transcribe.service.ts +117 -0
  352. package/src/services/supervisor.ts +94 -11
  353. package/src/services/system-metrics/cpu-details-linux.ts +252 -0
  354. package/src/services/system-metrics/cpu-memory-collector.ts +140 -18
  355. package/src/services/system-metrics/device-collector-linux.ts +31 -0
  356. package/src/services/system-metrics/device-collector-types.ts +40 -0
  357. package/src/services/system-metrics/disk-devices-linux.ts +156 -0
  358. package/src/services/system-metrics/disk-inventory-linux.ts +150 -0
  359. package/src/services/system-metrics/fans-linux.ts +51 -0
  360. package/src/services/system-metrics/gpu-api-versions.ts +120 -0
  361. package/src/services/system-metrics/gpu-devices-linux.ts +370 -0
  362. package/src/services/system-metrics/gpu-fdinfo-linux.ts +253 -0
  363. package/src/services/system-metrics/hardware-inventory.ts +50 -0
  364. package/src/services/system-metrics/linux-fs.ts +43 -0
  365. package/src/services/system-metrics/memory-darwin.ts +91 -0
  366. package/src/services/system-metrics/memory-linux.ts +156 -0
  367. package/src/services/system-metrics/net-devices-linux.ts +114 -0
  368. package/src/services/system-metrics/net-inventory-linux.ts +100 -0
  369. package/src/services/system-metrics/partitions-linux.ts +158 -0
  370. package/src/services/system-metrics/process-collector-linux.ts +58 -6
  371. package/src/services/system-metrics/process-collector-types.ts +8 -1
  372. package/src/services/system-metrics/process-details-darwin.ts +166 -0
  373. package/src/services/system-metrics/process-details-linux.ts +150 -0
  374. package/src/services/system-metrics/process-grouping.ts +2 -1
  375. package/src/services/system-metrics/process-rows-builder.ts +2 -0
  376. package/src/services/system-metrics/process-swap-linux.ts +37 -0
  377. package/src/services/system-metrics/signal-executor.ts +84 -0
  378. package/src/services/system-metrics/signal-request-handler.ts +92 -0
  379. package/src/services/system-metrics/system-metrics-platform.ts +30 -4
  380. package/src/services/system-metrics/system-metrics-tick.ts +73 -4
  381. package/src/services/system-metrics/system-metrics.service.ts +87 -2
  382. package/src/services/system-metrics/udev-db.ts +40 -0
  383. package/src/services/system-services/app-cgroup-linux.ts +115 -0
  384. package/src/services/system-services/app-icon-service.ts +31 -0
  385. package/src/services/system-services/app-icons-linux.ts +124 -0
  386. package/src/services/system-services/apps-linux.ts +174 -0
  387. package/src/services/system-services/desktop-entry.ts +103 -0
  388. package/src/services/system-services/service-guard.ts +124 -0
  389. package/src/services/system-services/systemd-collector.ts +203 -0
  390. package/src/services/system-services/systemd-parse.ts +162 -0
  391. package/src/services/windows-process-tree.ts +351 -351
  392. package/src/shared/prompt-cache-idle.ts +197 -0
  393. package/src/shared/turn-usage.ts +85 -1
  394. package/src/shared/usage-extra.ts +19 -0
  395. package/src/types/chat.ts +29 -0
  396. package/src/types/config.ts +14 -0
  397. package/src/types/git.ts +41 -0
  398. package/src/types/system-hardware.ts +137 -0
  399. package/src/types/system-metrics.ts +231 -2
  400. package/src/types/system-services.ts +73 -0
  401. package/src/web/components/branch-review/branch-review-tab.tsx +20 -20
  402. package/src/web/components/branch-review/branch-review-tree-row.tsx +1 -13
  403. package/src/web/components/chat/chat-tab.tsx +3 -0
  404. package/src/web/components/chat/codex-usage-panel.tsx +4 -0
  405. package/src/web/components/chat/compaction-divider.tsx +48 -0
  406. package/src/web/components/chat/idle-cache-notice.tsx +67 -0
  407. package/src/web/components/chat/message-input.tsx +48 -13
  408. package/src/web/components/chat/message-list.tsx +15 -0
  409. package/src/web/components/chat/prompt-cache-chip.tsx +74 -0
  410. package/src/web/components/editor/code-editor.tsx +1 -0
  411. package/src/web/components/editor/editor-language-service.tsx +11 -3
  412. package/src/web/components/editor/lsp-status.tsx +115 -13
  413. package/src/web/components/git/branch-picker.tsx +419 -0
  414. package/src/web/components/git/branch-select.tsx +34 -0
  415. package/src/web/components/git/create-worktree-dialog.tsx +17 -16
  416. package/src/web/components/git/git-repo-picker.tsx +28 -40
  417. package/src/web/components/layout/status-bar.tsx +42 -19
  418. package/src/web/components/settings/accounts/account-card.tsx +10 -2
  419. package/src/web/components/settings/accounts/account-usage-extras.tsx +3 -2
  420. package/src/web/components/settings/accounts/codex-accounts-section.tsx +3 -1
  421. package/src/web/components/settings/accounts/codex-reset-credit-button.tsx +120 -0
  422. package/src/web/components/settings/ai-settings-section.tsx +67 -3
  423. package/src/web/components/settings/appearance-settings-section.tsx +2 -28
  424. package/src/web/components/settings/language-servers-section.tsx +362 -0
  425. package/src/web/components/settings/settings-categories.ts +8 -3
  426. package/src/web/components/settings/settings-section-content.tsx +2 -0
  427. package/src/web/components/settings/voice-settings-section.tsx +283 -0
  428. package/src/web/components/system/apps/app-row.tsx +110 -0
  429. package/src/web/components/system/apps/app-rows.ts +140 -0
  430. package/src/web/components/system/apps/apps-panel.tsx +129 -0
  431. package/src/web/components/system/metric-chart-canvas.tsx +79 -3
  432. package/src/web/components/system/overview-cards/card-shell.tsx +54 -0
  433. package/src/web/components/system/overview-cards/cpu-card.tsx +11 -6
  434. package/src/web/components/system/overview-cards/disk-card.tsx +11 -6
  435. package/src/web/components/system/overview-cards/gpu-card.tsx +16 -6
  436. package/src/web/components/system/overview-cards/mem-card.tsx +11 -6
  437. package/src/web/components/system/overview-cards/net-card.tsx +11 -6
  438. package/src/web/components/system/overview-device-target.ts +69 -0
  439. package/src/web/components/system/overview-panel.tsx +15 -1
  440. package/src/web/components/system/performance/cpu-core-grid.tsx +74 -0
  441. package/src/web/components/system/performance/cpu-detail.tsx +220 -0
  442. package/src/web/components/system/performance/detail-parts.tsx +149 -0
  443. package/src/web/components/system/performance/device-list.ts +139 -0
  444. package/src/web/components/system/performance/disk-detail.tsx +64 -0
  445. package/src/web/components/system/performance/fans-detail.tsx +35 -0
  446. package/src/web/components/system/performance/gpu-detail.tsx +116 -0
  447. package/src/web/components/system/performance/memory-detail.tsx +109 -0
  448. package/src/web/components/system/performance/nic-detail.tsx +55 -0
  449. package/src/web/components/system/performance/partition-list.tsx +79 -0
  450. package/src/web/components/system/performance/performance-panel.tsx +206 -0
  451. package/src/web/components/system/performance/use-hardware-inventory.ts +48 -0
  452. package/src/web/components/system/process-columns-grid.ts +5 -3
  453. package/src/web/components/system/process-details-dialog.tsx +116 -0
  454. package/src/web/components/system/process-group-row.tsx +6 -1
  455. package/src/web/components/system/process-row-format.ts +6 -0
  456. package/src/web/components/system/process-row-menu.tsx +72 -0
  457. package/src/web/components/system/process-row.tsx +7 -1
  458. package/src/web/components/system/process-table-model.ts +1 -1
  459. package/src/web/components/system/process-table-sort.ts +8 -4
  460. package/src/web/components/system/process-table-toolbar.tsx +10 -2
  461. package/src/web/components/system/process-table-totals.ts +3 -0
  462. package/src/web/components/system/process-table.tsx +25 -2
  463. package/src/web/components/system/services/service-action-confirm.tsx +100 -0
  464. package/src/web/components/system/services/service-columns.ts +103 -0
  465. package/src/web/components/system/services/service-details-sheet.tsx +97 -0
  466. package/src/web/components/system/services/service-resources.ts +105 -0
  467. package/src/web/components/system/services/service-row.tsx +146 -0
  468. package/src/web/components/system/services/service-rows.ts +92 -0
  469. package/src/web/components/system/services/service-sort.ts +90 -0
  470. package/src/web/components/system/services/services-header.tsx +51 -0
  471. package/src/web/components/system/services/services-panel.tsx +207 -0
  472. package/src/web/components/system/services/use-services.ts +92 -0
  473. package/src/web/components/system/sortable-header.tsx +13 -8
  474. package/src/web/components/system/sysmon-preferences.tsx +85 -0
  475. package/src/web/components/system/system-monitor-body.tsx +101 -43
  476. package/src/web/components/system/system-monitor-window-content.tsx +2 -3
  477. package/src/web/components/system/use-process-signal.ts +87 -0
  478. package/src/web/components/tunnels/public-tunnel-switch.tsx +82 -0
  479. package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
  480. package/src/web/components/ui/dialog.tsx +14 -1
  481. package/src/web/components/ui/search-select.tsx +279 -0
  482. package/src/web/components/ui/start-ellipsis.tsx +18 -0
  483. package/src/web/hooks/use-chat.ts +28 -0
  484. package/src/web/hooks/use-global-keybindings.ts +7 -5
  485. package/src/web/hooks/use-lsp.ts +23 -2
  486. package/src/web/hooks/use-minute-clock.ts +20 -0
  487. package/src/web/hooks/use-whisper-voice-input.ts +113 -0
  488. package/src/web/lib/api-tunnels.ts +19 -0
  489. package/src/web/lib/branch-select-items.ts +29 -0
  490. package/src/web/lib/cpu-graph-mode.ts +90 -0
  491. package/src/web/lib/format-bytes.ts +14 -0
  492. package/src/web/lib/git-ref-picker.ts +120 -0
  493. package/src/web/lib/lsp/lsp-client.ts +32 -0
  494. package/src/web/lib/search-select-rows.ts +55 -0
  495. package/src/web/lib/temperature.ts +27 -0
  496. package/src/web/lib/voice-wav.ts +69 -0
  497. package/src/web/stores/git-status-store.ts +31 -17
  498. package/src/web/stores/keybindings-store.ts +14 -1
  499. package/src/web/stores/settings-store.ts +65 -0
  500. package/src/web/styles/globals.css +11 -0
  501. package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js +0 -1
  502. package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js.br +0 -0
  503. package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js.gz +0 -0
  504. package/dist/web/assets/ai-resource-editor-DKcsVDle.js.br +0 -0
  505. package/dist/web/assets/ai-resource-editor-DKcsVDle.js.gz +0 -0
  506. package/dist/web/assets/ai-settings-section-D7zJ-hCO.js +0 -1
  507. package/dist/web/assets/ai-settings-section-D7zJ-hCO.js.br +0 -0
  508. package/dist/web/assets/ai-settings-section-D7zJ-hCO.js.gz +0 -0
  509. package/dist/web/assets/ai-settings-section-OPqC2bYG.js +0 -1
  510. package/dist/web/assets/api-client-BgedDTvo.js +0 -1
  511. package/dist/web/assets/api-client-c8YOpTlT.js.br +0 -0
  512. package/dist/web/assets/api-client-c8YOpTlT.js.gz +0 -0
  513. package/dist/web/assets/api-settings-BmvNoCbn.js.br +0 -0
  514. package/dist/web/assets/api-settings-BmvNoCbn.js.gz +0 -0
  515. package/dist/web/assets/api-settings-Bti1-Zn3.js +0 -1
  516. package/dist/web/assets/appearance-settings-section-DL466x83.js +0 -1
  517. package/dist/web/assets/appearance-settings-section-DL466x83.js.br +0 -0
  518. package/dist/web/assets/appearance-settings-section-DL466x83.js.gz +0 -0
  519. package/dist/web/assets/audio-preview-vaG2cB-k.js.br +0 -0
  520. package/dist/web/assets/audio-preview-vaG2cB-k.js.gz +0 -0
  521. package/dist/web/assets/branch-review-tab-Dag86n_R.js +0 -1
  522. package/dist/web/assets/branch-review-tab-Dag86n_R.js.br +0 -0
  523. package/dist/web/assets/branch-review-tab-Dag86n_R.js.gz +0 -0
  524. package/dist/web/assets/button-Ci9EUgqd.js.br +0 -0
  525. package/dist/web/assets/button-Ci9EUgqd.js.gz +0 -0
  526. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.br +0 -0
  527. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.gz +0 -0
  528. package/dist/web/assets/chat-tab-CcYZLXls.js +0 -15
  529. package/dist/web/assets/chat-tab-CcYZLXls.js.br +0 -0
  530. package/dist/web/assets/chat-tab-CcYZLXls.js.gz +0 -0
  531. package/dist/web/assets/chat-tab-QFDhzzBZ.js +0 -1
  532. package/dist/web/assets/chat-tab-QFDhzzBZ.js.br +0 -0
  533. package/dist/web/assets/chat-tab-QFDhzzBZ.js.gz +0 -0
  534. package/dist/web/assets/code-editor-K-IN8VwJ.js +0 -7
  535. package/dist/web/assets/code-editor-K-IN8VwJ.js.br +0 -0
  536. package/dist/web/assets/code-editor-K-IN8VwJ.js.gz +0 -0
  537. package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js +0 -1
  538. package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js.br +0 -0
  539. package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js.gz +0 -0
  540. package/dist/web/assets/conflict-editor-qMGJH0Bx.js.br +0 -0
  541. package/dist/web/assets/conflict-editor-qMGJH0Bx.js.gz +0 -0
  542. package/dist/web/assets/context-menu-CjYTq8DI.js +0 -1
  543. package/dist/web/assets/context-menu-CjYTq8DI.js.br +0 -0
  544. package/dist/web/assets/context-menu-CjYTq8DI.js.gz +0 -0
  545. package/dist/web/assets/csv-preview-D2I742dl.js.br +0 -0
  546. package/dist/web/assets/csv-preview-D2I742dl.js.gz +0 -0
  547. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.br +0 -0
  548. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.gz +0 -0
  549. package/dist/web/assets/database-viewer-Bz4LjgIa.js.br +0 -0
  550. package/dist/web/assets/database-viewer-Bz4LjgIa.js.gz +0 -0
  551. package/dist/web/assets/design-export-client-ChMcMoqW.js.br +0 -0
  552. package/dist/web/assets/design-export-client-ChMcMoqW.js.gz +0 -0
  553. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.br +0 -0
  554. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.gz +0 -0
  555. package/dist/web/assets/design-tab-C987MtMR.js +0 -33
  556. package/dist/web/assets/design-tab-C987MtMR.js.br +0 -0
  557. package/dist/web/assets/design-tab-C987MtMR.js.gz +0 -0
  558. package/dist/web/assets/designs-sidebar-panel-CapP1yXq.js.br +0 -0
  559. package/dist/web/assets/designs-sidebar-panel-CapP1yXq.js.gz +0 -0
  560. package/dist/web/assets/dialog-B8clVkyi.js +0 -1
  561. package/dist/web/assets/dialog-B8clVkyi.js.br +0 -0
  562. package/dist/web/assets/dialog-B8clVkyi.js.gz +0 -0
  563. package/dist/web/assets/diff-viewer-CdXi7cZN.js.br +0 -0
  564. package/dist/web/assets/diff-viewer-CdXi7cZN.js.gz +0 -0
  565. package/dist/web/assets/docx-preview-C9XdKEj1.js.br +0 -0
  566. package/dist/web/assets/docx-preview-C9XdKEj1.js.gz +0 -0
  567. package/dist/web/assets/editor-language-service-Zle_PZV8.js +0 -1
  568. package/dist/web/assets/editor-language-service-Zle_PZV8.js.br +0 -0
  569. package/dist/web/assets/editor-language-service-Zle_PZV8.js.gz +0 -0
  570. package/dist/web/assets/explorer-body-DHMQR1Rk.js +0 -2
  571. package/dist/web/assets/explorer-body-DHMQR1Rk.js.br +0 -0
  572. package/dist/web/assets/explorer-body-DHMQR1Rk.js.gz +0 -0
  573. package/dist/web/assets/explorer-window-content-Df40nQBk.js +0 -1
  574. package/dist/web/assets/explorer-window-content-Df40nQBk.js.br +0 -0
  575. package/dist/web/assets/explorer-window-content-Df40nQBk.js.gz +0 -0
  576. package/dist/web/assets/extension-manager-section-B2nZzJ2b.js.br +0 -0
  577. package/dist/web/assets/extension-manager-section-B2nZzJ2b.js.gz +0 -0
  578. package/dist/web/assets/extension-webview-BGoDxkdF.js.br +0 -0
  579. package/dist/web/assets/extension-webview-BGoDxkdF.js.gz +0 -0
  580. package/dist/web/assets/file-icons-gx_FBOXY.js.br +0 -0
  581. package/dist/web/assets/file-icons-gx_FBOXY.js.gz +0 -0
  582. package/dist/web/assets/file-store-D9KE0kQC.js.br +0 -0
  583. package/dist/web/assets/file-store-D9KE0kQC.js.gz +0 -0
  584. package/dist/web/assets/files-settings-section-DC3OzzOl.js.br +0 -0
  585. package/dist/web/assets/files-settings-section-DC3OzzOl.js.gz +0 -0
  586. package/dist/web/assets/format-bytes-DmSHAKFe.js +0 -1
  587. package/dist/web/assets/format-file-meta-mQwA6SuY.js.br +0 -0
  588. package/dist/web/assets/format-file-meta-mQwA6SuY.js.gz +0 -0
  589. package/dist/web/assets/fs-api-DL36slbd.js.br +0 -0
  590. package/dist/web/assets/fs-api-DL36slbd.js.gz +0 -0
  591. package/dist/web/assets/general-settings-section-i41W43ER.js.br +0 -0
  592. package/dist/web/assets/general-settings-section-i41W43ER.js.gz +0 -0
  593. package/dist/web/assets/git-log-panel-DHzPIkJg.js.br +0 -0
  594. package/dist/web/assets/git-log-panel-DHzPIkJg.js.gz +0 -0
  595. package/dist/web/assets/git-repo-store-DSypNj19.js.br +0 -0
  596. package/dist/web/assets/git-repo-store-DSypNj19.js.gz +0 -0
  597. package/dist/web/assets/glide-data-grid-Dj4vrDvj.js.br +0 -0
  598. package/dist/web/assets/glide-data-grid-Dj4vrDvj.js.gz +0 -0
  599. package/dist/web/assets/group-chat-tab-DfwZb-fI.js +0 -1
  600. package/dist/web/assets/group-chat-tab-DfwZb-fI.js.br +0 -0
  601. package/dist/web/assets/group-chat-tab-DfwZb-fI.js.gz +0 -0
  602. package/dist/web/assets/index-DMA-So69.css +0 -1
  603. package/dist/web/assets/index-DMA-So69.css.br +0 -0
  604. package/dist/web/assets/index-DMA-So69.css.gz +0 -0
  605. package/dist/web/assets/index-jG9mLs-J.js +0 -52
  606. package/dist/web/assets/index-jG9mLs-J.js.br +0 -0
  607. package/dist/web/assets/index-jG9mLs-J.js.gz +0 -0
  608. package/dist/web/assets/keybindings-store-BlapkC6O.js +0 -1
  609. package/dist/web/assets/keyboard-shortcuts-section-CxdGSNGr.js.br +0 -0
  610. package/dist/web/assets/keyboard-shortcuts-section-CxdGSNGr.js.gz +0 -0
  611. package/dist/web/assets/markdown-renderer-DJ9EVU1B.js +0 -1
  612. package/dist/web/assets/markdown-renderer-ok96IgnS.js.br +0 -0
  613. package/dist/web/assets/markdown-renderer-ok96IgnS.js.gz +0 -0
  614. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.br +0 -0
  615. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.gz +0 -0
  616. package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js +0 -1
  617. package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js.br +0 -0
  618. package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js.gz +0 -0
  619. package/dist/web/assets/new-design-dialog-Drkjb_LI.js.br +0 -0
  620. package/dist/web/assets/new-design-dialog-Drkjb_LI.js.gz +0 -0
  621. package/dist/web/assets/notification-store-DCyxho0O.js +0 -1
  622. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.br +0 -0
  623. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.gz +0 -0
  624. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.br +0 -0
  625. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.gz +0 -0
  626. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.br +0 -0
  627. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.gz +0 -0
  628. package/dist/web/assets/overview-panel-BZAW_nag.js +0 -1
  629. package/dist/web/assets/overview-panel-BZAW_nag.js.br +0 -0
  630. package/dist/web/assets/overview-panel-BZAW_nag.js.gz +0 -0
  631. package/dist/web/assets/pdf-preview-qdXmMkOR.js.br +0 -0
  632. package/dist/web/assets/pdf-preview-qdXmMkOR.js.gz +0 -0
  633. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.br +0 -0
  634. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.gz +0 -0
  635. package/dist/web/assets/ppmbot-settings-section-C8PFlvaq.js.br +0 -0
  636. package/dist/web/assets/ppmbot-settings-section-C8PFlvaq.js.gz +0 -0
  637. package/dist/web/assets/pptx-export-CG6MRNok.js.br +0 -0
  638. package/dist/web/assets/pptx-export-CG6MRNok.js.gz +0 -0
  639. package/dist/web/assets/problems-panel-CFYO0Ro3.js.br +0 -0
  640. package/dist/web/assets/problems-panel-CFYO0Ro3.js.gz +0 -0
  641. package/dist/web/assets/process-table-BVeRguFg.js +0 -1
  642. package/dist/web/assets/process-table-BVeRguFg.js.br +0 -0
  643. package/dist/web/assets/process-table-BVeRguFg.js.gz +0 -0
  644. package/dist/web/assets/project-store-C5gJXkvb.js.br +0 -0
  645. package/dist/web/assets/project-store-C5gJXkvb.js.gz +0 -0
  646. package/dist/web/assets/proxy-settings-section-BcHIEANE.js.br +0 -0
  647. package/dist/web/assets/proxy-settings-section-BcHIEANE.js.gz +0 -0
  648. package/dist/web/assets/query-audit-section-UKG_smyt.js.br +0 -0
  649. package/dist/web/assets/query-audit-section-UKG_smyt.js.gz +0 -0
  650. package/dist/web/assets/remote-desktop-clipboard-notice-BGsp0edA.js.br +0 -0
  651. package/dist/web/assets/remote-desktop-clipboard-notice-BGsp0edA.js.gz +0 -0
  652. package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js +0 -2
  653. package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js.br +0 -0
  654. package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js.gz +0 -0
  655. package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js +0 -1
  656. package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js.br +0 -0
  657. package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js.gz +0 -0
  658. package/dist/web/assets/remote-desktop-readiness-gate-CsZCCRJI.js.br +0 -0
  659. package/dist/web/assets/remote-desktop-readiness-gate-CsZCCRJI.js.gz +0 -0
  660. package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js +0 -1
  661. package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js.br +0 -0
  662. package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js.gz +0 -0
  663. package/dist/web/assets/schedules-settings-section-Ci0O2Ng6.js.br +0 -0
  664. package/dist/web/assets/schedules-settings-section-Ci0O2Ng6.js.gz +0 -0
  665. package/dist/web/assets/scroll-area-XonvWYn_.js.br +0 -0
  666. package/dist/web/assets/scroll-area-XonvWYn_.js.gz +0 -0
  667. package/dist/web/assets/settings-body-B6JGOIYb.js +0 -2
  668. package/dist/web/assets/settings-body-B6JGOIYb.js.br +0 -0
  669. package/dist/web/assets/settings-body-B6JGOIYb.js.gz +0 -0
  670. package/dist/web/assets/settings-store-Br5c1efC.js +0 -2
  671. package/dist/web/assets/settings-store-Br5c1efC.js.br +0 -0
  672. package/dist/web/assets/settings-store-Br5c1efC.js.gz +0 -0
  673. package/dist/web/assets/settings-tab-CIQM4fNE.js +0 -1
  674. package/dist/web/assets/settings-window-content-BGNNz-E5.js +0 -1
  675. package/dist/web/assets/sql-query-editor-4iCGE4h2.js.br +0 -3
  676. package/dist/web/assets/sql-query-editor-4iCGE4h2.js.gz +0 -0
  677. package/dist/web/assets/sqlite-viewer-CK6DulYk.js.br +0 -0
  678. package/dist/web/assets/sqlite-viewer-CK6DulYk.js.gz +0 -0
  679. package/dist/web/assets/system-monitor-body-J9JtvAWV.js +0 -2
  680. package/dist/web/assets/system-monitor-body-J9JtvAWV.js.br +0 -0
  681. package/dist/web/assets/system-monitor-body-J9JtvAWV.js.gz +0 -0
  682. package/dist/web/assets/system-monitor-tab-DjBeRE81.js +0 -1
  683. package/dist/web/assets/system-monitor-window-content-BT7-ugFx.js +0 -1
  684. package/dist/web/assets/tab-host-window-content-CWBaWKjA.js.br +0 -0
  685. package/dist/web/assets/tab-host-window-content-CWBaWKjA.js.gz +0 -0
  686. package/dist/web/assets/team-member-sheet-Br6mrxrw.js.br +0 -0
  687. package/dist/web/assets/team-member-sheet-Br6mrxrw.js.gz +0 -0
  688. package/dist/web/assets/team-member-window-content-CwCy7ZWf.js.br +0 -0
  689. package/dist/web/assets/team-member-window-content-CwCy7ZWf.js.gz +0 -0
  690. package/dist/web/assets/terminal-tab-BW14RpCb.js.br +0 -0
  691. package/dist/web/assets/terminal-tab-BW14RpCb.js.gz +0 -0
  692. package/dist/web/assets/tool-cards-CgOBEUnb.js.br +0 -0
  693. package/dist/web/assets/tool-cards-CgOBEUnb.js.gz +0 -0
  694. package/dist/web/assets/use-inline-blame-Bzjfru4n.js +0 -16
  695. package/dist/web/assets/use-inline-blame-Bzjfru4n.js.br +0 -0
  696. package/dist/web/assets/use-inline-blame-Bzjfru4n.js.gz +0 -0
  697. package/dist/web/assets/use-lsp-hGdjL2hV.js +0 -6
  698. package/dist/web/assets/use-lsp-hGdjL2hV.js.br +0 -0
  699. package/dist/web/assets/use-lsp-hGdjL2hV.js.gz +0 -0
  700. package/dist/web/assets/vendor-ui-BHh12_0v.js.br +0 -0
  701. package/dist/web/assets/vendor-ui-BHh12_0v.js.gz +0 -0
  702. package/dist/web/assets/video-preview-P9T-ZVdN.js +0 -1
  703. package/dist/web/assets/video-preview-P9T-ZVdN.js.br +0 -0
  704. package/dist/web/assets/video-preview-P9T-ZVdN.js.gz +0 -0
  705. package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
  706. package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
  707. package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
  708. package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
  709. package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
  710. /package/dist/web/assets/{__vite-browser-external-BpSQWxcq.js → __vite-browser-external-BILfYaAs.js} +0 -0
  711. /package/dist/web/assets/{run-in-terminal-HIdNgYim.js → run-in-terminal-2pSiup8e.js} +0 -0
  712. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js → vendor-xterm-DF1JTfsy.js} +0 -0
  713. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.br → vendor-xterm-DF1JTfsy.js.br} +0 -0
  714. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.gz → vendor-xterm-DF1JTfsy.js.gz} +0 -0
@@ -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
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * The signal decision chain, transport-free like the kill one and deliberately
3
+ * built from the SAME parts: parse → live re-query → identity check → guard on
4
+ * the FRESH name → execute.
5
+ *
6
+ * The guard is `checkKillAllowed` unchanged. A SIGSTOP on systemd wedges the
7
+ * machine as thoroughly as a SIGKILL would, and SIGSTOP on PPM's own supervisor
8
+ * hangs every session — "can this process be signalled" and "can this process be
9
+ * ended" are the same question, so they must not be two lists that can drift.
10
+ */
11
+ import type {
12
+ MetricsPlatform, ProcessSignal, SignalProcessRequest, SignalProcessResult,
13
+ } from "../../types/system-metrics.ts";
14
+ import { PROCESS_SIGNALS } from "../../types/system-metrics.ts";
15
+ import { ok, err, type ApiResponse } from "../../types/api.ts";
16
+ import type { ProcessCollector } from "./process-collector-types.ts";
17
+ import { identityMatches, resolveLiveProcess } from "./kill-identity-resolver.ts";
18
+ import { checkKillAllowed } from "./kill-guard.ts";
19
+ import type { ProtectedPids } from "./ppm-protected-pids.ts";
20
+
21
+ export interface SignalHandlerDeps {
22
+ platform: MetricsPlatform;
23
+ collector: ProcessCollector;
24
+ resolveProtected: (isAlive: (pid: number) => boolean, nameOf: (pid: number) => string | undefined) => ProtectedPids;
25
+ execute: (pid: number, signal: ProcessSignal, tree: boolean) => Promise<SignalProcessResult>;
26
+ /** Signals this host can deliver; anything else is a 400 before any re-query. */
27
+ supported: readonly ProcessSignal[];
28
+ /** Audit line: pid + name + signal + result ONLY. `~/.ppm/ppm.log`'s tail is
29
+ * served unauthenticated by `/api/logs/recent`, so no command line here. */
30
+ log: (line: string) => void;
31
+ }
32
+
33
+ export type SignalStatus = 200 | 400 | 403 | 404 | 409 | 500;
34
+
35
+ export interface SignalOutcome {
36
+ status: SignalStatus;
37
+ body: ApiResponse<SignalProcessResult>;
38
+ }
39
+
40
+ export function parseSignalRequest(body: unknown): SignalProcessRequest | null {
41
+ if (!body || typeof body !== "object") return null;
42
+ const b = body as Record<string, unknown>;
43
+ if (typeof b.pid !== "number" || !Number.isInteger(b.pid) || b.pid <= 0) return null;
44
+ if (typeof b.startedAt !== "number" || !Number.isFinite(b.startedAt) || b.startedAt < 0) return null;
45
+ if (b.tree !== undefined && typeof b.tree !== "boolean") return null;
46
+ if (typeof b.signal !== "string" || !PROCESS_SIGNALS.includes(b.signal as ProcessSignal)) return null;
47
+ return { pid: b.pid, startedAt: b.startedAt, signal: b.signal as ProcessSignal, tree: b.tree === true };
48
+ }
49
+
50
+ export async function handleSignalRequest(body: unknown, deps: SignalHandlerDeps): Promise<SignalOutcome> {
51
+ const req = parseSignalRequest(body);
52
+ if (!req) {
53
+ return { status: 400, body: err(`Body must be {pid, startedAt, signal: one of ${PROCESS_SIGNALS.join("|")}, tree?}`) };
54
+ }
55
+ if (!deps.supported.includes(req.signal)) {
56
+ return { status: 400, body: err(`This host cannot deliver SIG${req.signal}`) };
57
+ }
58
+ const tree = req.tree === true;
59
+
60
+ const { live, maps } = await resolveLiveProcess(req.pid, deps.collector);
61
+ if (!live) return { status: 404, body: err(`PID ${req.pid} is no longer running`) };
62
+ if (!identityMatches(req.startedAt, live.startedAt)) {
63
+ return { status: 409, body: err(`PID ${req.pid} was recycled — refresh and try again`) };
64
+ }
65
+
66
+ const protectedPids = deps.resolveProtected(
67
+ (pid) => maps.byPid.has(pid),
68
+ (pid) => maps.byPid.get(pid)?.name.toLowerCase(),
69
+ );
70
+ const verdict = checkKillAllowed({ pid: live.pid, name: live.name }, tree, {
71
+ platform: deps.platform,
72
+ protectedPids: protectedPids.pids,
73
+ ppidOf: maps.ppidOf,
74
+ startedAtOf: maps.startedAtOf,
75
+ });
76
+ const prefix = `[SystemMetrics] signal=${req.signal} pid=${live.pid} name=${live.name} tree=${tree}`;
77
+ if (!verdict.allowed) {
78
+ deps.log(`${prefix} → refused: ${verdict.reason}`);
79
+ return { status: 403, body: err(verdict.reason ?? "Refused") };
80
+ }
81
+
82
+ deps.log(`${prefix} → allowed`);
83
+ try {
84
+ const result = await deps.execute(live.pid, req.signal, tree);
85
+ deps.log(`${prefix} → done (${result.signalled.length} signalled)`);
86
+ return { status: 200, body: ok(result) };
87
+ } catch (e) {
88
+ const message = (e as Error)?.message ?? String(e);
89
+ deps.log(`${prefix} → failed: ${message}`);
90
+ return { status: 500, body: err(`Failed to signal PID ${live.pid}: ${message}`) };
91
+ }
92
+ }
@@ -1,9 +1,14 @@
1
1
  /** Per-OS collector wiring for the snapshot service. Nothing here spawns until
2
2
  * a full-tier tick actually calls a collector. */
3
3
  import type { MetricsPlatform } from "../../types/system-metrics.ts";
4
+ import type { AppCollector } from "../system-services/apps-linux.ts";
5
+ import { createLinuxAppCollector } from "../system-services/apps-linux.ts";
4
6
  import type { ProcessCollector } from "./process-collector-types.ts";
5
7
  import { EMPTY_PROCESS_COLLECTOR } from "./process-collector-types.ts";
6
8
  import type { DiskNetCounters } from "./disk-net-collector-linux.ts";
9
+ import type { DeviceCollector } from "./device-collector-types.ts";
10
+ import { collectLinuxDevices } from "./device-collector-linux.ts";
11
+ import { createDrmGpuCollector } from "./gpu-fdinfo-linux.ts";
7
12
  import { collectLinuxDiskNet } from "./disk-net-collector-linux.ts";
8
13
  import { collectDarwinDiskNet } from "./disk-net-collector-darwin.ts";
9
14
  import { createNvidiaGpuCollector, type GpuCollector } from "./gpu-collector-nvidia.ts";
@@ -20,6 +25,12 @@ export interface PlatformCollectors {
20
25
  /** Null on win32: the counters ride along in the process round trip. */
21
26
  diskNet: (() => Promise<DiskNetCounters>) | null;
22
27
  gpus: GpuCollector;
28
+ /** Per-drive and per-interface figures. Null where the host has no source for
29
+ * them, which the client reads as "this machine lists no devices". */
30
+ devices: DeviceCollector | null;
31
+ /** Desktop applications with a live process. Null off Linux, which has neither
32
+ * .desktop entries in the XDG sense nor app cgroups to read them from. */
33
+ apps: AppCollector | null;
23
34
  }
24
35
 
25
36
  export function toMetricsPlatform(p: NodeJS.Platform = process.platform): MetricsPlatform {
@@ -30,22 +41,37 @@ export function createPlatformCollectors(platform: MetricsPlatform = toMetricsPl
30
41
  const gpus = createNvidiaGpuCollector();
31
42
  switch (platform) {
32
43
  case "win32":
33
- return { platform, processes: createWindowsProcessCollector(), diskNet: null, gpus };
44
+ return { platform, processes: createWindowsProcessCollector(), diskNet: null, gpus, devices: null, apps: null };
34
45
  case "darwin":
35
46
  return {
36
47
  platform,
37
48
  processes: createDarwinProcessCollector(undefined, undefined, { net: createDarwinProcessNetCollector() }),
38
49
  diskNet: () => collectDarwinDiskNet(),
39
50
  gpus,
51
+ devices: null,
52
+ apps: null,
40
53
  };
41
- case "linux":
54
+ case "linux": {
55
+ // ONE collector for both: the whole-GPU figures and the process rows are
56
+ // built from the same `/proc` walk, so they can never disagree, and the
57
+ // walk is paid for once per tick rather than twice.
58
+ const drm = createDrmGpuCollector();
59
+ // Its desktop-entry scan is lazy, so a host where nobody opens the Apps
60
+ // page never pays for it.
61
+ const apps = createLinuxAppCollector();
42
62
  return {
43
63
  platform,
44
- processes: createLinuxProcessCollector(readProcTable, { gpuMemory: createNvidiaProcessMemoryCollector() }),
64
+ processes: createLinuxProcessCollector(readProcTable, {
65
+ gpuMemory: createNvidiaProcessMemoryCollector(),
66
+ drm,
67
+ }),
45
68
  diskNet: async () => collectLinuxDiskNet(),
46
69
  gpus,
70
+ devices: (prev) => collectLinuxDevices(prev, drm),
71
+ apps: (processes) => apps.collect(processes),
47
72
  };
73
+ }
48
74
  default:
49
- return { platform, processes: EMPTY_PROCESS_COLLECTOR, diskNet: null, gpus };
75
+ return { platform, processes: EMPTY_PROCESS_COLLECTOR, diskNet: null, gpus, devices: null, apps: null };
50
76
  }
51
77
  }