@hienlh/ppm 0.23.6 → 0.23.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (701) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/CLAUDE.md +21 -1
  3. package/Dockerfile.test +8 -1
  4. package/assets/skills/ppm/SKILL.md +1 -1
  5. package/assets/skills/ppm/references/cli-reference.md +4 -4
  6. package/assets/skills/ppm/references/http-api.md +29 -1
  7. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js +1 -0
  8. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.br +0 -0
  9. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.gz +0 -0
  10. package/dist/web/assets/{ai-resource-editor-Dn_wB-o5.js → ai-resource-editor-CY4n_Ccv.js} +1 -1
  11. package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.br +0 -0
  12. package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.gz +0 -0
  13. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js +1 -0
  14. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.br +0 -0
  15. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.gz +0 -0
  16. package/dist/web/assets/ai-settings-section-DDs11XV4.js +1 -0
  17. package/dist/web/assets/api-client-CJPnCOG-.js +1 -0
  18. package/dist/web/assets/{api-client-c8YOpTlT.js → api-client-D-SMbdiH.js} +1 -1
  19. package/dist/web/assets/api-client-D-SMbdiH.js.br +0 -0
  20. package/dist/web/assets/api-client-D-SMbdiH.js.gz +0 -0
  21. package/dist/web/assets/api-settings-BDkkhFMq.js +1 -0
  22. package/dist/web/assets/{api-settings-BmvNoCbn.js → api-settings-Bv9mLCty.js} +1 -1
  23. package/dist/web/assets/api-settings-Bv9mLCty.js.br +0 -0
  24. package/dist/web/assets/api-settings-Bv9mLCty.js.gz +0 -0
  25. package/dist/web/assets/{api-themes-6fOQJgM9.js → api-themes-3wW-zLzU.js} +1 -1
  26. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js +1 -0
  27. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.br +0 -0
  28. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.gz +0 -0
  29. package/dist/web/assets/apps-panel-DXAFsveZ.js +1 -0
  30. package/dist/web/assets/apps-panel-DXAFsveZ.js.br +0 -0
  31. package/dist/web/assets/apps-panel-DXAFsveZ.js.gz +0 -0
  32. package/dist/web/assets/{audio-preview-vaG2cB-k.js → audio-preview-BfES4Cx5.js} +1 -1
  33. package/dist/web/assets/audio-preview-BfES4Cx5.js.br +0 -0
  34. package/dist/web/assets/audio-preview-BfES4Cx5.js.gz +0 -0
  35. package/dist/web/assets/branch-review-tab-CA8hPSX9.js +1 -0
  36. package/dist/web/assets/branch-review-tab-CA8hPSX9.js.br +0 -0
  37. package/dist/web/assets/branch-review-tab-CA8hPSX9.js.gz +0 -0
  38. package/dist/web/assets/{button-Ci9EUgqd.js → button-DeAyLH9U.js} +1 -1
  39. package/dist/web/assets/button-DeAyLH9U.js.br +0 -0
  40. package/dist/web/assets/button-DeAyLH9U.js.gz +0 -0
  41. package/dist/web/assets/{chat-preparation-cache-BSIQGiWx.js → chat-preparation-cache-CcCd2g7A.js} +1 -1
  42. package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.br +0 -0
  43. package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.gz +0 -0
  44. package/dist/web/assets/chat-tab-BWi_bUzA.js +1 -0
  45. package/dist/web/assets/chat-tab-BWi_bUzA.js.br +0 -0
  46. package/dist/web/assets/chat-tab-BWi_bUzA.js.gz +0 -0
  47. package/dist/web/assets/chat-tab-BvJhIaVE.js +15 -0
  48. package/dist/web/assets/chat-tab-BvJhIaVE.js.br +0 -0
  49. package/dist/web/assets/chat-tab-BvJhIaVE.js.gz +0 -0
  50. package/dist/web/assets/code-editor-OJUdLVnn.js +7 -0
  51. package/dist/web/assets/code-editor-OJUdLVnn.js.br +0 -0
  52. package/dist/web/assets/code-editor-OJUdLVnn.js.gz +0 -0
  53. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js +1 -0
  54. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.br +0 -0
  55. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.gz +0 -0
  56. package/dist/web/assets/{conflict-editor-BA3y-qSH.js → conflict-editor-BpKW_vbL.js} +1 -1
  57. package/dist/web/assets/conflict-editor-BpKW_vbL.js.br +0 -0
  58. package/dist/web/assets/conflict-editor-BpKW_vbL.js.gz +0 -0
  59. package/dist/web/assets/context-menu-7OX80HDB.js +1 -0
  60. package/dist/web/assets/context-menu-7OX80HDB.js.br +0 -0
  61. package/dist/web/assets/context-menu-7OX80HDB.js.gz +0 -0
  62. package/dist/web/assets/{csv-preview-BioxkrQF.js → csv-preview-COYdTABa.js} +1 -1
  63. package/dist/web/assets/csv-preview-COYdTABa.js.br +0 -0
  64. package/dist/web/assets/csv-preview-COYdTABa.js.gz +0 -0
  65. package/dist/web/assets/{data-grid-overlay-editor-CQRVKr7y.js → data-grid-overlay-editor-CeZoduke.js} +1 -1
  66. package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.br +0 -0
  67. package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.gz +0 -0
  68. package/dist/web/assets/{database-viewer-BSoJ0E6p.js → database-viewer-BQcBqCKm.js} +1 -1
  69. package/dist/web/assets/database-viewer-BQcBqCKm.js.br +0 -0
  70. package/dist/web/assets/database-viewer-BQcBqCKm.js.gz +0 -0
  71. package/dist/web/assets/{design-export-client-ChMcMoqW.js → design-export-client-OrnGCSwu.js} +1 -1
  72. package/dist/web/assets/design-export-client-OrnGCSwu.js.br +0 -0
  73. package/dist/web/assets/design-export-client-OrnGCSwu.js.gz +0 -0
  74. package/dist/web/assets/{design-responsive-dialog-DNBhJJLf.js → design-responsive-dialog-vJjQrC4n.js} +1 -1
  75. package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.br +0 -0
  76. package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.gz +0 -0
  77. package/dist/web/assets/design-tab-BbmFk38H.js +33 -0
  78. package/dist/web/assets/design-tab-BbmFk38H.js.br +0 -0
  79. package/dist/web/assets/design-tab-BbmFk38H.js.gz +0 -0
  80. package/dist/web/assets/{designs-sidebar-panel-DHh5QsH9.js → designs-sidebar-panel-D2kXwB8B.js} +1 -1
  81. package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.br +0 -0
  82. package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.gz +0 -0
  83. package/dist/web/assets/dialog-Bocc0Fgb.js +1 -0
  84. package/dist/web/assets/dialog-Bocc0Fgb.js.br +0 -0
  85. package/dist/web/assets/dialog-Bocc0Fgb.js.gz +0 -0
  86. package/dist/web/assets/{diff-viewer-lctWoSmG.js → diff-viewer-Bj4DT6Mj.js} +1 -1
  87. package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.br +0 -0
  88. package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.gz +0 -0
  89. package/dist/web/assets/{docx-preview-C9XdKEj1.js → docx-preview-C2QqNGRE.js} +1 -1
  90. package/dist/web/assets/docx-preview-C2QqNGRE.js.br +0 -0
  91. package/dist/web/assets/docx-preview-C2QqNGRE.js.gz +0 -0
  92. package/dist/web/assets/editor-language-service-COqB2tuv.js +1 -0
  93. package/dist/web/assets/editor-language-service-COqB2tuv.js.br +3 -0
  94. package/dist/web/assets/editor-language-service-COqB2tuv.js.gz +0 -0
  95. package/dist/web/assets/explorer-body-DGrYajDN.js +2 -0
  96. package/dist/web/assets/explorer-body-DGrYajDN.js.br +0 -0
  97. package/dist/web/assets/explorer-body-DGrYajDN.js.gz +0 -0
  98. package/dist/web/assets/explorer-window-content-DLzkODTP.js +1 -0
  99. package/dist/web/assets/explorer-window-content-DLzkODTP.js.br +0 -0
  100. package/dist/web/assets/explorer-window-content-DLzkODTP.js.gz +0 -0
  101. package/dist/web/assets/{extension-manager-section-rbkXsZVR.js → extension-manager-section-Bu0qcB2i.js} +1 -1
  102. package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.br +0 -0
  103. package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.gz +0 -0
  104. package/dist/web/assets/{extension-webview-uPO0WgCq.js → extension-webview-G_WJ0N52.js} +1 -1
  105. package/dist/web/assets/extension-webview-G_WJ0N52.js.br +0 -0
  106. package/dist/web/assets/extension-webview-G_WJ0N52.js.gz +0 -0
  107. package/dist/web/assets/{file-icons-gx_FBOXY.js → file-icons-l7fNOmdS.js} +1 -1
  108. package/dist/web/assets/file-icons-l7fNOmdS.js.br +0 -0
  109. package/dist/web/assets/file-icons-l7fNOmdS.js.gz +0 -0
  110. package/dist/web/assets/{file-store-D9KE0kQC.js → file-store-B0e7sLag.js} +1 -1
  111. package/dist/web/assets/file-store-B0e7sLag.js.br +0 -0
  112. package/dist/web/assets/file-store-B0e7sLag.js.gz +0 -0
  113. package/dist/web/assets/{files-settings-section-CT7mDb0L.js → files-settings-section-ChZ_CynX.js} +1 -1
  114. package/dist/web/assets/files-settings-section-ChZ_CynX.js.br +0 -0
  115. package/dist/web/assets/files-settings-section-ChZ_CynX.js.gz +0 -0
  116. package/dist/web/assets/format-bytes-__396eCN.js +1 -0
  117. package/dist/web/assets/{format-file-meta-mQwA6SuY.js → format-file-meta-o1XBuoKS.js} +1 -1
  118. package/dist/web/assets/format-file-meta-o1XBuoKS.js.br +0 -0
  119. package/dist/web/assets/format-file-meta-o1XBuoKS.js.gz +0 -0
  120. package/dist/web/assets/{fs-api-DL36slbd.js → fs-api-CeHKwx95.js} +1 -1
  121. package/dist/web/assets/fs-api-CeHKwx95.js.br +0 -0
  122. package/dist/web/assets/fs-api-CeHKwx95.js.gz +0 -0
  123. package/dist/web/assets/{general-settings-section-DANPfMRN.js → general-settings-section-MSvDEbFa.js} +1 -1
  124. package/dist/web/assets/general-settings-section-MSvDEbFa.js.br +0 -0
  125. package/dist/web/assets/general-settings-section-MSvDEbFa.js.gz +0 -0
  126. package/dist/web/assets/{git-log-panel-BJPkLiEw.js → git-log-panel-gw5_a6j3.js} +1 -1
  127. package/dist/web/assets/git-log-panel-gw5_a6j3.js.br +0 -0
  128. package/dist/web/assets/git-log-panel-gw5_a6j3.js.gz +0 -0
  129. package/dist/web/assets/{git-repo-store-DSypNj19.js → git-repo-store-BpPnah5l.js} +1 -1
  130. package/dist/web/assets/git-repo-store-BpPnah5l.js.br +0 -0
  131. package/dist/web/assets/git-repo-store-BpPnah5l.js.gz +0 -0
  132. package/dist/web/assets/{glide-data-grid-R4PcAntf.js → glide-data-grid-Db2Cl26B.js} +5 -5
  133. package/dist/web/assets/glide-data-grid-Db2Cl26B.js.br +0 -0
  134. package/dist/web/assets/glide-data-grid-Db2Cl26B.js.gz +0 -0
  135. package/dist/web/assets/group-chat-tab-B4etmYTR.js +1 -0
  136. package/dist/web/assets/group-chat-tab-B4etmYTR.js.br +0 -0
  137. package/dist/web/assets/group-chat-tab-B4etmYTR.js.gz +0 -0
  138. package/dist/web/assets/{image-preview-CGdZrmLo.js → image-preview-CjNhpfWw.js} +1 -1
  139. package/dist/web/assets/index-CtAvmybi.js +52 -0
  140. package/dist/web/assets/index-CtAvmybi.js.br +0 -0
  141. package/dist/web/assets/index-CtAvmybi.js.gz +0 -0
  142. package/dist/web/assets/index-DeCJasyy.css +1 -0
  143. package/dist/web/assets/index-DeCJasyy.css.br +0 -0
  144. package/dist/web/assets/index-DeCJasyy.css.gz +0 -0
  145. package/dist/web/assets/{jira-watcher-section-DHRoyWcG.js → jira-watcher-section-CKSI1Alo.js} +1 -1
  146. package/dist/web/assets/keybindings-store-C4_yyU4u.js +1 -0
  147. package/dist/web/assets/{keyboard-shortcuts-section-BKej4mUf.js → keyboard-shortcuts-section-CEaVUc9a.js} +1 -1
  148. package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.br +0 -0
  149. package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.gz +0 -0
  150. package/dist/web/assets/language-servers-section-ePtEpnDc.js +2 -0
  151. package/dist/web/assets/language-servers-section-ePtEpnDc.js.br +0 -0
  152. package/dist/web/assets/language-servers-section-ePtEpnDc.js.gz +0 -0
  153. package/dist/web/assets/lsp-client-XzmR3Brr.js +1 -0
  154. package/dist/web/assets/lsp-client-XzmR3Brr.js.br +0 -0
  155. package/dist/web/assets/lsp-client-XzmR3Brr.js.gz +0 -0
  156. package/dist/web/assets/markdown-renderer-CTtDap-l.js +1 -0
  157. package/dist/web/assets/{markdown-renderer-BHtYqkYZ.js → markdown-renderer-D05fAr57.js} +2 -2
  158. package/dist/web/assets/markdown-renderer-D05fAr57.js.br +0 -0
  159. package/dist/web/assets/markdown-renderer-D05fAr57.js.gz +0 -0
  160. package/dist/web/assets/{media-url-CzUJrREv.js → media-url-C6NumuN5.js} +1 -1
  161. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js +1 -0
  162. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.br +0 -0
  163. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.gz +0 -0
  164. package/dist/web/assets/{mobile-bottom-sheet-CuNi2FRv.js → mobile-bottom-sheet-D4UyOatB.js} +1 -1
  165. package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.br +0 -0
  166. package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.gz +0 -0
  167. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js +1 -0
  168. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.br +0 -0
  169. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.gz +0 -0
  170. package/dist/web/assets/{new-design-dialog-DS_XrpTG.js → new-design-dialog-BgmQopJM.js} +1 -1
  171. package/dist/web/assets/new-design-dialog-BgmQopJM.js.br +0 -0
  172. package/dist/web/assets/new-design-dialog-BgmQopJM.js.gz +0 -0
  173. package/dist/web/assets/notification-store-q5QBklKA.js +1 -0
  174. package/dist/web/assets/{notifications-settings-section-C05WYqcE.js → notifications-settings-section-BBJ0r9OS.js} +1 -1
  175. package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.br +0 -0
  176. package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.gz +0 -0
  177. package/dist/web/assets/{onboarding-entry-CmUqv1kl.js → onboarding-entry-BYOYswsi.js} +1 -1
  178. package/dist/web/assets/onboarding-entry-BYOYswsi.js.br +0 -0
  179. package/dist/web/assets/onboarding-entry-BYOYswsi.js.gz +0 -0
  180. package/dist/web/assets/{onboarding-quick-orientation-DIhWv1CN.js → onboarding-quick-orientation-DPHYFMbA.js} +1 -1
  181. package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.br +0 -0
  182. package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.gz +0 -0
  183. package/dist/web/assets/overview-panel-pkPs44Tv.js +1 -0
  184. package/dist/web/assets/overview-panel-pkPs44Tv.js.br +0 -0
  185. package/dist/web/assets/overview-panel-pkPs44Tv.js.gz +0 -0
  186. package/dist/web/assets/{pdf-preview-qdXmMkOR.js → pdf-preview-c-L_kDAs.js} +1 -1
  187. package/dist/web/assets/pdf-preview-c-L_kDAs.js.br +0 -0
  188. package/dist/web/assets/pdf-preview-c-L_kDAs.js.gz +0 -0
  189. package/dist/web/assets/performance-panel-yPrq0DJV.js +3 -0
  190. package/dist/web/assets/performance-panel-yPrq0DJV.js.br +0 -0
  191. package/dist/web/assets/performance-panel-yPrq0DJV.js.gz +0 -0
  192. package/dist/web/assets/{postgres-viewer-Xvlun_n5.js → postgres-viewer-CnwDCMNd.js} +1 -1
  193. package/dist/web/assets/postgres-viewer-CnwDCMNd.js.br +0 -0
  194. package/dist/web/assets/postgres-viewer-CnwDCMNd.js.gz +0 -0
  195. package/dist/web/assets/{ppmbot-settings-section-D8AES1BA.js → ppmbot-settings-section-BDXoSIDp.js} +1 -1
  196. package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.br +0 -0
  197. package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.gz +0 -0
  198. package/dist/web/assets/{pptx-export-CG6MRNok.js → pptx-export-D0RDY48h.js} +4 -4
  199. package/dist/web/assets/pptx-export-D0RDY48h.js.br +0 -0
  200. package/dist/web/assets/pptx-export-D0RDY48h.js.gz +0 -0
  201. package/dist/web/assets/{problems-panel-DTBG4beI.js → problems-panel-BgY8oyo9.js} +1 -1
  202. package/dist/web/assets/problems-panel-BgY8oyo9.js.br +0 -0
  203. package/dist/web/assets/problems-panel-BgY8oyo9.js.gz +0 -0
  204. package/dist/web/assets/process-row-format-CaaMcHzn.js +1 -0
  205. package/dist/web/assets/process-table-BOwDtXuG.js +1 -0
  206. package/dist/web/assets/process-table-BOwDtXuG.js.br +0 -0
  207. package/dist/web/assets/process-table-BOwDtXuG.js.gz +0 -0
  208. package/dist/web/assets/{project-framework-store-XxFXcUpb.js → project-framework-store-UDEMu28U.js} +1 -1
  209. package/dist/web/assets/{project-store-C5gJXkvb.js → project-store-DGa31y5B.js} +1 -1
  210. package/dist/web/assets/project-store-DGa31y5B.js.br +0 -0
  211. package/dist/web/assets/project-store-DGa31y5B.js.gz +0 -0
  212. package/dist/web/assets/{proxy-settings-section-CqtmbeRj.js → proxy-settings-section-Db6Kc6xG.js} +1 -1
  213. package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.br +0 -0
  214. package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.gz +0 -0
  215. package/dist/web/assets/{query-audit-section-UKG_smyt.js → query-audit-section-C0PAXhfT.js} +1 -1
  216. package/dist/web/assets/query-audit-section-C0PAXhfT.js.br +0 -0
  217. package/dist/web/assets/query-audit-section-C0PAXhfT.js.gz +0 -0
  218. package/dist/web/assets/{remote-desktop-clipboard-notice-Djt6cpNL.js → remote-desktop-clipboard-notice-DOVtobj_.js} +1 -1
  219. package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.br +0 -0
  220. package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.gz +0 -0
  221. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js +2 -0
  222. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.br +0 -0
  223. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.gz +0 -0
  224. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js +1 -0
  225. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.br +0 -0
  226. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.gz +0 -0
  227. package/dist/web/assets/{remote-desktop-readiness-gate-DNJF8TcF.js → remote-desktop-readiness-gate-BsfoJzdc.js} +1 -1
  228. package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.br +0 -0
  229. package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.gz +0 -0
  230. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js +1 -0
  231. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.br +0 -0
  232. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.gz +0 -0
  233. package/dist/web/assets/{schedules-settings-section-BKoPovy2.js → schedules-settings-section-CvbjQM8z.js} +1 -1
  234. package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.br +0 -0
  235. package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.gz +0 -0
  236. package/dist/web/assets/{scroll-area-XonvWYn_.js → scroll-area-sjOeAfoD.js} +1 -1
  237. package/dist/web/assets/scroll-area-sjOeAfoD.js.br +0 -0
  238. package/dist/web/assets/scroll-area-sjOeAfoD.js.gz +0 -0
  239. package/dist/web/assets/{separator-sQj04Ari.js → separator-9A3PCG1t.js} +1 -1
  240. package/dist/web/assets/services-panel-CimW47P8.js +1 -0
  241. package/dist/web/assets/services-panel-CimW47P8.js.br +0 -0
  242. package/dist/web/assets/services-panel-CimW47P8.js.gz +0 -0
  243. package/dist/web/assets/settings-body-BTXNtpWL.js +2 -0
  244. package/dist/web/assets/settings-body-BTXNtpWL.js.br +0 -0
  245. package/dist/web/assets/settings-body-BTXNtpWL.js.gz +0 -0
  246. package/dist/web/assets/settings-store-DvftLqzy.js +2 -0
  247. package/dist/web/assets/settings-store-DvftLqzy.js.br +0 -0
  248. package/dist/web/assets/settings-store-DvftLqzy.js.gz +0 -0
  249. package/dist/web/assets/settings-tab-CGhaRXjs.js +1 -0
  250. package/dist/web/assets/settings-window-content--Uyg_Psr.js +1 -0
  251. package/dist/web/assets/sortable-header-DUW9T1Hz.js +1 -0
  252. package/dist/web/assets/sortable-header-DUW9T1Hz.js.br +0 -0
  253. package/dist/web/assets/sortable-header-DUW9T1Hz.js.gz +0 -0
  254. package/dist/web/assets/{sql-query-editor-BjIMi9Wk.js → sql-query-editor-Dn-cgDrW.js} +1 -1
  255. package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.br +0 -0
  256. package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.gz +0 -0
  257. package/dist/web/assets/{sqlite-viewer-BNcA6Irq.js → sqlite-viewer-B0NfaMjq.js} +1 -1
  258. package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.br +0 -0
  259. package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.gz +0 -0
  260. package/dist/web/assets/system-monitor-body-CxCfRQFb.js +2 -0
  261. package/dist/web/assets/system-monitor-body-CxCfRQFb.js.br +0 -0
  262. package/dist/web/assets/system-monitor-body-CxCfRQFb.js.gz +0 -0
  263. package/dist/web/assets/system-monitor-tab-Cb3EZUdp.js +1 -0
  264. package/dist/web/assets/system-monitor-window-content-51CA-2PH.js +1 -0
  265. package/dist/web/assets/{tab-host-window-content-CIRGNCvi.js → tab-host-window-content-CSrcmKNG.js} +1 -1
  266. package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.br +0 -0
  267. package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.gz +0 -0
  268. package/dist/web/assets/{team-member-sheet-CwXpLi3X.js → team-member-sheet-D4X6nh-x.js} +2 -2
  269. package/dist/web/assets/team-member-sheet-D4X6nh-x.js.br +0 -0
  270. package/dist/web/assets/team-member-sheet-D4X6nh-x.js.gz +0 -0
  271. package/dist/web/assets/{team-member-window-content-4swiiDz7.js → team-member-window-content-BxkbGVIL.js} +1 -1
  272. package/dist/web/assets/team-member-window-content-BxkbGVIL.js.br +0 -0
  273. package/dist/web/assets/team-member-window-content-BxkbGVIL.js.gz +0 -0
  274. package/dist/web/assets/{terminal-tab-BGcdtMMT.js → terminal-tab-BYo34IqU.js} +3 -3
  275. package/dist/web/assets/terminal-tab-BYo34IqU.js.br +0 -0
  276. package/dist/web/assets/terminal-tab-BYo34IqU.js.gz +0 -0
  277. package/dist/web/assets/{tool-cards-D0-krtA2.js → tool-cards-DvXjOped.js} +4 -4
  278. package/dist/web/assets/tool-cards-DvXjOped.js.br +0 -0
  279. package/dist/web/assets/tool-cards-DvXjOped.js.gz +0 -0
  280. package/dist/web/assets/{use-blob-url-CmavyEP8.js → use-blob-url-CISBWKG5.js} +1 -1
  281. package/dist/web/assets/use-inline-blame-Br6mheS4.js +16 -0
  282. package/dist/web/assets/use-inline-blame-Br6mheS4.js.br +0 -0
  283. package/dist/web/assets/use-inline-blame-Br6mheS4.js.gz +0 -0
  284. package/dist/web/assets/use-lsp-BpJmvQ0n.js +6 -0
  285. package/dist/web/assets/use-lsp-BpJmvQ0n.js.br +0 -0
  286. package/dist/web/assets/use-lsp-BpJmvQ0n.js.gz +0 -0
  287. package/dist/web/assets/{use-monaco-theme-C88KphGx.js → use-monaco-theme-UGOzyIhv.js} +1 -1
  288. package/dist/web/assets/use-process-kill-CyiiUD1E.js +1 -0
  289. package/dist/web/assets/use-process-kill-CyiiUD1E.js.br +0 -0
  290. package/dist/web/assets/use-process-kill-CyiiUD1E.js.gz +0 -0
  291. package/dist/web/assets/{use-websocket-Chk9guIU.js → use-websocket-Dpl21cHG.js} +1 -1
  292. package/dist/web/assets/{vendor-ui-BHh12_0v.js → vendor-ui-P9Ym7hCv.js} +1 -1
  293. package/dist/web/assets/vendor-ui-P9Ym7hCv.js.br +0 -0
  294. package/dist/web/assets/vendor-ui-P9Ym7hCv.js.gz +0 -0
  295. package/dist/web/assets/video-preview-D6Jw-IZK.js +1 -0
  296. package/dist/web/assets/video-preview-D6Jw-IZK.js.br +0 -0
  297. package/dist/web/assets/video-preview-D6Jw-IZK.js.gz +0 -0
  298. package/dist/web/assets/voice-settings-section-CcHQDYzN.js +1 -0
  299. package/dist/web/assets/voice-settings-section-CcHQDYzN.js.br +0 -0
  300. package/dist/web/assets/voice-settings-section-CcHQDYzN.js.gz +0 -0
  301. package/dist/web/assets/ws-auth-CqI8-aoA.js +1 -0
  302. package/dist/web/index.html +20 -20
  303. package/dist/web/index.html.br +0 -0
  304. package/dist/web/index.html.gz +0 -0
  305. package/dist/web/sw.js +1 -1
  306. package/dist/web/sw.js.br +0 -0
  307. package/dist/web/sw.js.gz +0 -0
  308. package/docs/deployment-guide.md +23 -0
  309. package/package.json +1 -1
  310. package/release-from-worktree.sh +224 -0
  311. package/src/cli/commands/config-cmd.ts +12 -0
  312. package/src/providers/claude-agent-sdk.ts +65 -2
  313. package/src/providers/codex-app-server/codex-jsonrpc-client.ts +16 -1
  314. package/src/providers/codex-app-server/codex-provider.ts +39 -7
  315. package/src/providers/provider-probe.ts +63 -0
  316. package/src/providers/registry.ts +109 -29
  317. package/src/server/index.ts +9 -0
  318. package/src/server/middleware/auth.ts +5 -1
  319. package/src/server/routes/cross-origin-guard.ts +20 -0
  320. package/src/server/routes/git.ts +40 -4
  321. package/src/server/routes/lsp.ts +97 -4
  322. package/src/server/routes/resources.ts +72 -9
  323. package/src/server/routes/settings.ts +19 -1
  324. package/src/server/routes/speech.ts +66 -0
  325. package/src/server/routes/system-services.ts +76 -0
  326. package/src/server/routes/tunnel.ts +33 -1
  327. package/src/server/ws/chat.ts +74 -3
  328. package/src/services/codex-account-login.ts +26 -2
  329. package/src/services/codex-reset-credit.service.ts +16 -3
  330. package/src/services/compaction-savings.ts +127 -0
  331. package/src/services/db.service.ts +123 -8
  332. package/src/services/fs-ops/fs-ops-trash.service.ts +22 -9
  333. package/src/services/git-refs/for-each-ref.ts +118 -0
  334. package/src/services/git.service.ts +25 -2
  335. package/src/services/host-info/spawn-runner.ts +48 -4
  336. package/src/services/jsonl-transcript-parser.ts +7 -42
  337. package/src/services/lsp/lsp-install.ts +289 -0
  338. package/src/services/lsp/lsp-manager.ts +160 -29
  339. package/src/services/lsp/server-registry.ts +120 -4
  340. package/src/services/named-tunnel/named-tunnel-config.ts +8 -2
  341. package/src/services/named-tunnel/named-tunnel-setup.service.ts +4 -0
  342. package/src/services/read-lines.ts +54 -0
  343. package/src/services/speech-to-text/whisper-catalog.ts +142 -0
  344. package/src/services/speech-to-text/whisper-download.ts +113 -0
  345. package/src/services/speech-to-text/whisper-hallucinations.ts +51 -0
  346. package/src/services/speech-to-text/whisper-install.service.ts +247 -0
  347. package/src/services/speech-to-text/whisper-paths.ts +62 -0
  348. package/src/services/speech-to-text/whisper-transcribe.service.ts +117 -0
  349. package/src/services/supervisor.ts +94 -11
  350. package/src/services/system-metrics/cpu-details-linux.ts +252 -0
  351. package/src/services/system-metrics/cpu-memory-collector.ts +140 -18
  352. package/src/services/system-metrics/device-collector-linux.ts +31 -0
  353. package/src/services/system-metrics/device-collector-types.ts +40 -0
  354. package/src/services/system-metrics/disk-devices-linux.ts +156 -0
  355. package/src/services/system-metrics/disk-inventory-linux.ts +150 -0
  356. package/src/services/system-metrics/fans-linux.ts +51 -0
  357. package/src/services/system-metrics/gpu-api-versions.ts +120 -0
  358. package/src/services/system-metrics/gpu-devices-linux.ts +370 -0
  359. package/src/services/system-metrics/gpu-fdinfo-linux.ts +253 -0
  360. package/src/services/system-metrics/hardware-inventory.ts +50 -0
  361. package/src/services/system-metrics/linux-fs.ts +43 -0
  362. package/src/services/system-metrics/memory-darwin.ts +91 -0
  363. package/src/services/system-metrics/memory-linux.ts +156 -0
  364. package/src/services/system-metrics/net-devices-linux.ts +114 -0
  365. package/src/services/system-metrics/net-inventory-linux.ts +100 -0
  366. package/src/services/system-metrics/partitions-linux.ts +158 -0
  367. package/src/services/system-metrics/process-collector-linux.ts +58 -6
  368. package/src/services/system-metrics/process-collector-types.ts +8 -1
  369. package/src/services/system-metrics/process-details-darwin.ts +166 -0
  370. package/src/services/system-metrics/process-details-linux.ts +150 -0
  371. package/src/services/system-metrics/process-grouping.ts +2 -1
  372. package/src/services/system-metrics/process-rows-builder.ts +2 -0
  373. package/src/services/system-metrics/process-swap-linux.ts +37 -0
  374. package/src/services/system-metrics/signal-executor.ts +84 -0
  375. package/src/services/system-metrics/signal-request-handler.ts +92 -0
  376. package/src/services/system-metrics/system-metrics-platform.ts +30 -4
  377. package/src/services/system-metrics/system-metrics-tick.ts +73 -4
  378. package/src/services/system-metrics/system-metrics.service.ts +87 -2
  379. package/src/services/system-metrics/udev-db.ts +40 -0
  380. package/src/services/system-services/app-cgroup-linux.ts +115 -0
  381. package/src/services/system-services/app-icon-service.ts +31 -0
  382. package/src/services/system-services/app-icons-linux.ts +124 -0
  383. package/src/services/system-services/apps-linux.ts +174 -0
  384. package/src/services/system-services/desktop-entry.ts +103 -0
  385. package/src/services/system-services/service-guard.ts +124 -0
  386. package/src/services/system-services/systemd-collector.ts +203 -0
  387. package/src/services/system-services/systemd-parse.ts +162 -0
  388. package/src/shared/prompt-cache-idle.ts +197 -0
  389. package/src/shared/turn-usage.ts +85 -1
  390. package/src/types/chat.ts +27 -0
  391. package/src/types/config.ts +14 -0
  392. package/src/types/git.ts +41 -0
  393. package/src/types/system-hardware.ts +137 -0
  394. package/src/types/system-metrics.ts +231 -2
  395. package/src/types/system-services.ts +73 -0
  396. package/src/web/components/branch-review/branch-review-tab.tsx +20 -20
  397. package/src/web/components/branch-review/branch-review-tree-row.tsx +1 -13
  398. package/src/web/components/chat/chat-tab.tsx +3 -0
  399. package/src/web/components/chat/compaction-divider.tsx +48 -0
  400. package/src/web/components/chat/idle-cache-notice.tsx +67 -0
  401. package/src/web/components/chat/message-input.tsx +48 -13
  402. package/src/web/components/chat/message-list.tsx +15 -0
  403. package/src/web/components/chat/prompt-cache-chip.tsx +74 -0
  404. package/src/web/components/editor/code-editor.tsx +1 -0
  405. package/src/web/components/editor/editor-language-service.tsx +11 -3
  406. package/src/web/components/editor/lsp-status.tsx +115 -13
  407. package/src/web/components/git/branch-picker.tsx +419 -0
  408. package/src/web/components/git/branch-select.tsx +34 -0
  409. package/src/web/components/git/create-worktree-dialog.tsx +17 -16
  410. package/src/web/components/git/git-repo-picker.tsx +28 -40
  411. package/src/web/components/layout/status-bar.tsx +42 -19
  412. package/src/web/components/settings/accounts/account-card.tsx +5 -1
  413. package/src/web/components/settings/ai-settings-section.tsx +67 -3
  414. package/src/web/components/settings/appearance-settings-section.tsx +2 -28
  415. package/src/web/components/settings/language-servers-section.tsx +362 -0
  416. package/src/web/components/settings/settings-categories.ts +8 -3
  417. package/src/web/components/settings/settings-section-content.tsx +2 -0
  418. package/src/web/components/settings/voice-settings-section.tsx +283 -0
  419. package/src/web/components/system/apps/app-row.tsx +110 -0
  420. package/src/web/components/system/apps/app-rows.ts +140 -0
  421. package/src/web/components/system/apps/apps-panel.tsx +129 -0
  422. package/src/web/components/system/metric-chart-canvas.tsx +79 -3
  423. package/src/web/components/system/overview-cards/card-shell.tsx +54 -0
  424. package/src/web/components/system/overview-cards/cpu-card.tsx +11 -6
  425. package/src/web/components/system/overview-cards/disk-card.tsx +11 -6
  426. package/src/web/components/system/overview-cards/gpu-card.tsx +16 -6
  427. package/src/web/components/system/overview-cards/mem-card.tsx +11 -6
  428. package/src/web/components/system/overview-cards/net-card.tsx +11 -6
  429. package/src/web/components/system/overview-device-target.ts +69 -0
  430. package/src/web/components/system/overview-panel.tsx +15 -1
  431. package/src/web/components/system/performance/cpu-core-grid.tsx +74 -0
  432. package/src/web/components/system/performance/cpu-detail.tsx +220 -0
  433. package/src/web/components/system/performance/detail-parts.tsx +149 -0
  434. package/src/web/components/system/performance/device-list.ts +139 -0
  435. package/src/web/components/system/performance/disk-detail.tsx +64 -0
  436. package/src/web/components/system/performance/fans-detail.tsx +35 -0
  437. package/src/web/components/system/performance/gpu-detail.tsx +116 -0
  438. package/src/web/components/system/performance/memory-detail.tsx +109 -0
  439. package/src/web/components/system/performance/nic-detail.tsx +55 -0
  440. package/src/web/components/system/performance/partition-list.tsx +79 -0
  441. package/src/web/components/system/performance/performance-panel.tsx +206 -0
  442. package/src/web/components/system/performance/use-hardware-inventory.ts +48 -0
  443. package/src/web/components/system/process-columns-grid.ts +5 -3
  444. package/src/web/components/system/process-details-dialog.tsx +116 -0
  445. package/src/web/components/system/process-group-row.tsx +6 -1
  446. package/src/web/components/system/process-row-format.ts +6 -0
  447. package/src/web/components/system/process-row-menu.tsx +72 -0
  448. package/src/web/components/system/process-row.tsx +7 -1
  449. package/src/web/components/system/process-table-model.ts +1 -1
  450. package/src/web/components/system/process-table-sort.ts +8 -4
  451. package/src/web/components/system/process-table-toolbar.tsx +10 -2
  452. package/src/web/components/system/process-table-totals.ts +3 -0
  453. package/src/web/components/system/process-table.tsx +25 -2
  454. package/src/web/components/system/services/service-action-confirm.tsx +100 -0
  455. package/src/web/components/system/services/service-columns.ts +103 -0
  456. package/src/web/components/system/services/service-details-sheet.tsx +97 -0
  457. package/src/web/components/system/services/service-resources.ts +105 -0
  458. package/src/web/components/system/services/service-row.tsx +146 -0
  459. package/src/web/components/system/services/service-rows.ts +92 -0
  460. package/src/web/components/system/services/service-sort.ts +90 -0
  461. package/src/web/components/system/services/services-header.tsx +51 -0
  462. package/src/web/components/system/services/services-panel.tsx +207 -0
  463. package/src/web/components/system/services/use-services.ts +92 -0
  464. package/src/web/components/system/sortable-header.tsx +13 -8
  465. package/src/web/components/system/sysmon-preferences.tsx +85 -0
  466. package/src/web/components/system/system-monitor-body.tsx +101 -43
  467. package/src/web/components/system/system-monitor-window-content.tsx +2 -3
  468. package/src/web/components/system/use-process-signal.ts +87 -0
  469. package/src/web/components/tunnels/public-tunnel-switch.tsx +82 -0
  470. package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
  471. package/src/web/components/ui/dialog.tsx +14 -1
  472. package/src/web/components/ui/search-select.tsx +279 -0
  473. package/src/web/components/ui/start-ellipsis.tsx +18 -0
  474. package/src/web/hooks/use-chat.ts +28 -0
  475. package/src/web/hooks/use-global-keybindings.ts +7 -5
  476. package/src/web/hooks/use-lsp.ts +23 -2
  477. package/src/web/hooks/use-minute-clock.ts +20 -0
  478. package/src/web/hooks/use-whisper-voice-input.ts +113 -0
  479. package/src/web/lib/api-tunnels.ts +19 -0
  480. package/src/web/lib/branch-select-items.ts +29 -0
  481. package/src/web/lib/cpu-graph-mode.ts +90 -0
  482. package/src/web/lib/format-bytes.ts +14 -0
  483. package/src/web/lib/git-ref-picker.ts +120 -0
  484. package/src/web/lib/lsp/lsp-client.ts +32 -0
  485. package/src/web/lib/search-select-rows.ts +55 -0
  486. package/src/web/lib/temperature.ts +27 -0
  487. package/src/web/lib/voice-wav.ts +69 -0
  488. package/src/web/stores/git-status-store.ts +31 -17
  489. package/src/web/stores/keybindings-store.ts +14 -1
  490. package/src/web/stores/settings-store.ts +65 -0
  491. package/src/web/styles/globals.css +11 -0
  492. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js +0 -1
  493. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.br +0 -0
  494. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.gz +0 -0
  495. package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.br +0 -0
  496. package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.gz +0 -0
  497. package/dist/web/assets/ai-settings-section-CEbW8jRy.js +0 -1
  498. package/dist/web/assets/ai-settings-section-CEbW8jRy.js.br +0 -0
  499. package/dist/web/assets/ai-settings-section-CEbW8jRy.js.gz +0 -0
  500. package/dist/web/assets/ai-settings-section-D-mwEYFZ.js +0 -1
  501. package/dist/web/assets/api-client-BgedDTvo.js +0 -1
  502. package/dist/web/assets/api-client-c8YOpTlT.js.br +0 -0
  503. package/dist/web/assets/api-client-c8YOpTlT.js.gz +0 -0
  504. package/dist/web/assets/api-settings-BmvNoCbn.js.br +0 -0
  505. package/dist/web/assets/api-settings-BmvNoCbn.js.gz +0 -0
  506. package/dist/web/assets/api-settings-Bti1-Zn3.js +0 -1
  507. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js +0 -1
  508. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.br +0 -0
  509. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.gz +0 -0
  510. package/dist/web/assets/audio-preview-vaG2cB-k.js.br +0 -0
  511. package/dist/web/assets/audio-preview-vaG2cB-k.js.gz +0 -0
  512. package/dist/web/assets/branch-review-tab-MBuMWp_i.js +0 -1
  513. package/dist/web/assets/branch-review-tab-MBuMWp_i.js.br +0 -0
  514. package/dist/web/assets/branch-review-tab-MBuMWp_i.js.gz +0 -0
  515. package/dist/web/assets/button-Ci9EUgqd.js.br +0 -0
  516. package/dist/web/assets/button-Ci9EUgqd.js.gz +0 -0
  517. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.br +0 -0
  518. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.gz +0 -0
  519. package/dist/web/assets/chat-tab-DVvnqhw6.js +0 -1
  520. package/dist/web/assets/chat-tab-DVvnqhw6.js.br +0 -0
  521. package/dist/web/assets/chat-tab-DVvnqhw6.js.gz +0 -0
  522. package/dist/web/assets/chat-tab-DaEHva22.js +0 -15
  523. package/dist/web/assets/chat-tab-DaEHva22.js.br +0 -0
  524. package/dist/web/assets/chat-tab-DaEHva22.js.gz +0 -0
  525. package/dist/web/assets/code-editor-Bu9lhTVp.js +0 -7
  526. package/dist/web/assets/code-editor-Bu9lhTVp.js.br +0 -0
  527. package/dist/web/assets/code-editor-Bu9lhTVp.js.gz +0 -0
  528. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js +0 -1
  529. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.br +0 -0
  530. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.gz +0 -0
  531. package/dist/web/assets/conflict-editor-BA3y-qSH.js.br +0 -0
  532. package/dist/web/assets/conflict-editor-BA3y-qSH.js.gz +0 -0
  533. package/dist/web/assets/context-menu-CjYTq8DI.js +0 -1
  534. package/dist/web/assets/context-menu-CjYTq8DI.js.br +0 -0
  535. package/dist/web/assets/context-menu-CjYTq8DI.js.gz +0 -0
  536. package/dist/web/assets/csv-preview-BioxkrQF.js.br +0 -0
  537. package/dist/web/assets/csv-preview-BioxkrQF.js.gz +0 -0
  538. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.br +0 -0
  539. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.gz +0 -0
  540. package/dist/web/assets/database-viewer-BSoJ0E6p.js.br +0 -0
  541. package/dist/web/assets/database-viewer-BSoJ0E6p.js.gz +0 -0
  542. package/dist/web/assets/design-export-client-ChMcMoqW.js.br +0 -0
  543. package/dist/web/assets/design-export-client-ChMcMoqW.js.gz +0 -0
  544. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.br +0 -0
  545. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.gz +0 -0
  546. package/dist/web/assets/design-tab-iU2CviE3.js +0 -33
  547. package/dist/web/assets/design-tab-iU2CviE3.js.br +0 -0
  548. package/dist/web/assets/design-tab-iU2CviE3.js.gz +0 -0
  549. package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.br +0 -0
  550. package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.gz +0 -0
  551. package/dist/web/assets/dialog-B8clVkyi.js +0 -1
  552. package/dist/web/assets/dialog-B8clVkyi.js.br +0 -0
  553. package/dist/web/assets/dialog-B8clVkyi.js.gz +0 -0
  554. package/dist/web/assets/diff-viewer-lctWoSmG.js.br +0 -0
  555. package/dist/web/assets/diff-viewer-lctWoSmG.js.gz +0 -0
  556. package/dist/web/assets/docx-preview-C9XdKEj1.js.br +0 -0
  557. package/dist/web/assets/docx-preview-C9XdKEj1.js.gz +0 -0
  558. package/dist/web/assets/editor-language-service-fPG56hQO.js +0 -1
  559. package/dist/web/assets/editor-language-service-fPG56hQO.js.br +0 -0
  560. package/dist/web/assets/editor-language-service-fPG56hQO.js.gz +0 -0
  561. package/dist/web/assets/explorer-body-BgF7FsxI.js +0 -2
  562. package/dist/web/assets/explorer-body-BgF7FsxI.js.br +0 -0
  563. package/dist/web/assets/explorer-body-BgF7FsxI.js.gz +0 -0
  564. package/dist/web/assets/explorer-window-content-C21w_7lf.js +0 -1
  565. package/dist/web/assets/explorer-window-content-C21w_7lf.js.br +0 -0
  566. package/dist/web/assets/explorer-window-content-C21w_7lf.js.gz +0 -0
  567. package/dist/web/assets/extension-manager-section-rbkXsZVR.js.br +0 -0
  568. package/dist/web/assets/extension-manager-section-rbkXsZVR.js.gz +0 -0
  569. package/dist/web/assets/extension-webview-uPO0WgCq.js.br +0 -0
  570. package/dist/web/assets/extension-webview-uPO0WgCq.js.gz +0 -0
  571. package/dist/web/assets/file-icons-gx_FBOXY.js.br +0 -0
  572. package/dist/web/assets/file-icons-gx_FBOXY.js.gz +0 -0
  573. package/dist/web/assets/file-store-D9KE0kQC.js.br +0 -0
  574. package/dist/web/assets/file-store-D9KE0kQC.js.gz +0 -0
  575. package/dist/web/assets/files-settings-section-CT7mDb0L.js.br +0 -0
  576. package/dist/web/assets/files-settings-section-CT7mDb0L.js.gz +0 -0
  577. package/dist/web/assets/format-bytes-DmSHAKFe.js +0 -1
  578. package/dist/web/assets/format-file-meta-mQwA6SuY.js.br +0 -0
  579. package/dist/web/assets/format-file-meta-mQwA6SuY.js.gz +0 -0
  580. package/dist/web/assets/fs-api-DL36slbd.js.br +0 -0
  581. package/dist/web/assets/fs-api-DL36slbd.js.gz +0 -0
  582. package/dist/web/assets/general-settings-section-DANPfMRN.js.br +0 -0
  583. package/dist/web/assets/general-settings-section-DANPfMRN.js.gz +0 -0
  584. package/dist/web/assets/git-log-panel-BJPkLiEw.js.br +0 -0
  585. package/dist/web/assets/git-log-panel-BJPkLiEw.js.gz +0 -0
  586. package/dist/web/assets/git-repo-store-DSypNj19.js.br +0 -0
  587. package/dist/web/assets/git-repo-store-DSypNj19.js.gz +0 -0
  588. package/dist/web/assets/glide-data-grid-R4PcAntf.js.br +0 -0
  589. package/dist/web/assets/glide-data-grid-R4PcAntf.js.gz +0 -0
  590. package/dist/web/assets/group-chat-tab-BXMdo8w9.js +0 -1
  591. package/dist/web/assets/group-chat-tab-BXMdo8w9.js.br +0 -0
  592. package/dist/web/assets/group-chat-tab-BXMdo8w9.js.gz +0 -0
  593. package/dist/web/assets/index-C8nGqkKN.js +0 -52
  594. package/dist/web/assets/index-C8nGqkKN.js.br +0 -0
  595. package/dist/web/assets/index-C8nGqkKN.js.gz +0 -0
  596. package/dist/web/assets/index-DvClbTQx.css +0 -1
  597. package/dist/web/assets/index-DvClbTQx.css.br +0 -0
  598. package/dist/web/assets/index-DvClbTQx.css.gz +0 -0
  599. package/dist/web/assets/keybindings-store-BGKlQQAv.js +0 -1
  600. package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.br +0 -0
  601. package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.gz +0 -0
  602. package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.br +0 -0
  603. package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.gz +0 -0
  604. package/dist/web/assets/markdown-renderer-vDNuKjel.js +0 -1
  605. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.br +0 -0
  606. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.gz +0 -0
  607. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js +0 -1
  608. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.br +0 -0
  609. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.gz +0 -0
  610. package/dist/web/assets/new-design-dialog-DS_XrpTG.js.br +0 -0
  611. package/dist/web/assets/new-design-dialog-DS_XrpTG.js.gz +0 -0
  612. package/dist/web/assets/notification-store-Dnnj20Ky.js +0 -1
  613. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.br +0 -0
  614. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.gz +0 -0
  615. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.br +0 -0
  616. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.gz +0 -0
  617. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.br +0 -0
  618. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.gz +0 -0
  619. package/dist/web/assets/overview-panel-BZAW_nag.js +0 -1
  620. package/dist/web/assets/overview-panel-BZAW_nag.js.br +0 -0
  621. package/dist/web/assets/overview-panel-BZAW_nag.js.gz +0 -0
  622. package/dist/web/assets/pdf-preview-qdXmMkOR.js.br +0 -0
  623. package/dist/web/assets/pdf-preview-qdXmMkOR.js.gz +0 -0
  624. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.br +0 -0
  625. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.gz +0 -0
  626. package/dist/web/assets/ppmbot-settings-section-D8AES1BA.js.br +0 -0
  627. package/dist/web/assets/ppmbot-settings-section-D8AES1BA.js.gz +0 -0
  628. package/dist/web/assets/pptx-export-CG6MRNok.js.br +0 -0
  629. package/dist/web/assets/pptx-export-CG6MRNok.js.gz +0 -0
  630. package/dist/web/assets/problems-panel-DTBG4beI.js.br +0 -0
  631. package/dist/web/assets/problems-panel-DTBG4beI.js.gz +0 -0
  632. package/dist/web/assets/process-table-D_gR2XA6.js +0 -1
  633. package/dist/web/assets/process-table-D_gR2XA6.js.br +0 -0
  634. package/dist/web/assets/process-table-D_gR2XA6.js.gz +0 -0
  635. package/dist/web/assets/project-store-C5gJXkvb.js.br +0 -0
  636. package/dist/web/assets/project-store-C5gJXkvb.js.gz +0 -0
  637. package/dist/web/assets/proxy-settings-section-CqtmbeRj.js.br +0 -0
  638. package/dist/web/assets/proxy-settings-section-CqtmbeRj.js.gz +0 -0
  639. package/dist/web/assets/query-audit-section-UKG_smyt.js.br +0 -0
  640. package/dist/web/assets/query-audit-section-UKG_smyt.js.gz +0 -0
  641. package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.br +0 -0
  642. package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.gz +0 -0
  643. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js +0 -2
  644. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.br +0 -0
  645. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.gz +0 -0
  646. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js +0 -1
  647. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.br +0 -0
  648. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.gz +0 -0
  649. package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.br +0 -0
  650. package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.gz +0 -0
  651. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js +0 -1
  652. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.br +0 -0
  653. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.gz +0 -0
  654. package/dist/web/assets/schedules-settings-section-BKoPovy2.js.br +0 -0
  655. package/dist/web/assets/schedules-settings-section-BKoPovy2.js.gz +0 -0
  656. package/dist/web/assets/scroll-area-XonvWYn_.js.br +0 -0
  657. package/dist/web/assets/scroll-area-XonvWYn_.js.gz +0 -0
  658. package/dist/web/assets/settings-body-k2qPgRFe.js +0 -2
  659. package/dist/web/assets/settings-body-k2qPgRFe.js.br +0 -0
  660. package/dist/web/assets/settings-body-k2qPgRFe.js.gz +0 -0
  661. package/dist/web/assets/settings-store-Br5c1efC.js +0 -2
  662. package/dist/web/assets/settings-store-Br5c1efC.js.br +0 -0
  663. package/dist/web/assets/settings-store-Br5c1efC.js.gz +0 -0
  664. package/dist/web/assets/settings-tab-Bb23VdBu.js +0 -1
  665. package/dist/web/assets/settings-window-content-ClarWusz.js +0 -1
  666. package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.br +0 -0
  667. package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.gz +0 -0
  668. package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.br +0 -0
  669. package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.gz +0 -0
  670. package/dist/web/assets/system-monitor-body-D0T3ggt2.js +0 -2
  671. package/dist/web/assets/system-monitor-body-D0T3ggt2.js.br +0 -0
  672. package/dist/web/assets/system-monitor-body-D0T3ggt2.js.gz +0 -0
  673. package/dist/web/assets/system-monitor-tab-I1Igmoey.js +0 -1
  674. package/dist/web/assets/system-monitor-window-content-C5SeUv1H.js +0 -1
  675. package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.br +0 -0
  676. package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.gz +0 -0
  677. package/dist/web/assets/team-member-sheet-CwXpLi3X.js.br +0 -0
  678. package/dist/web/assets/team-member-sheet-CwXpLi3X.js.gz +0 -0
  679. package/dist/web/assets/team-member-window-content-4swiiDz7.js.br +0 -0
  680. package/dist/web/assets/team-member-window-content-4swiiDz7.js.gz +0 -0
  681. package/dist/web/assets/terminal-tab-BGcdtMMT.js.br +0 -0
  682. package/dist/web/assets/terminal-tab-BGcdtMMT.js.gz +0 -0
  683. package/dist/web/assets/tool-cards-D0-krtA2.js.br +0 -0
  684. package/dist/web/assets/tool-cards-D0-krtA2.js.gz +0 -0
  685. package/dist/web/assets/use-inline-blame-pKaXyGU-.js +0 -16
  686. package/dist/web/assets/use-inline-blame-pKaXyGU-.js.br +0 -0
  687. package/dist/web/assets/use-inline-blame-pKaXyGU-.js.gz +0 -0
  688. package/dist/web/assets/use-lsp-71azTXQz.js +0 -6
  689. package/dist/web/assets/use-lsp-71azTXQz.js.br +0 -0
  690. package/dist/web/assets/use-lsp-71azTXQz.js.gz +0 -0
  691. package/dist/web/assets/vendor-ui-BHh12_0v.js.br +0 -0
  692. package/dist/web/assets/vendor-ui-BHh12_0v.js.gz +0 -0
  693. package/dist/web/assets/video-preview-DxEX-uGo.js +0 -1
  694. package/dist/web/assets/video-preview-DxEX-uGo.js.br +0 -0
  695. package/dist/web/assets/video-preview-DxEX-uGo.js.gz +0 -0
  696. package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
  697. /package/dist/web/assets/{__vite-browser-external-BpSQWxcq.js → __vite-browser-external-BILfYaAs.js} +0 -0
  698. /package/dist/web/assets/{run-in-terminal-HIdNgYim.js → run-in-terminal-2pSiup8e.js} +0 -0
  699. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js → vendor-xterm-DF1JTfsy.js} +0 -0
  700. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.br → vendor-xterm-DF1JTfsy.js.br} +0 -0
  701. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.gz → vendor-xterm-DF1JTfsy.js.gz} +0 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Injectable filesystem access for the /proc and /sys collectors, so every parser
3
+ * is fixture-tested without a real host. Each call returns null instead of
4
+ * throwing: a device or a process vanishing between a directory listing and the
5
+ * read is the normal case here, not an error worth a stack trace per tick.
6
+ */
7
+ import { existsSync, readdirSync, readFileSync, readlinkSync, realpathSync } from "node:fs";
8
+
9
+ export type FileReader = (path: string) => string | null;
10
+ export type DirLister = (path: string) => string[] | null;
11
+ export type LinkReader = (path: string) => string | null;
12
+
13
+ export interface LinuxFs {
14
+ read: FileReader;
15
+ list: DirLister;
16
+ /** The link's own target, as written (often relative: `../../devices/...`). */
17
+ readlink: LinkReader;
18
+ /** Fully resolved absolute path, or null when it does not resolve. */
19
+ realpath: LinkReader;
20
+ exists: (path: string) => boolean;
21
+ }
22
+
23
+ export const realLinuxFs: LinuxFs = {
24
+ read: (path) => { try { return readFileSync(path, "utf-8"); } catch { return null; } },
25
+ list: (path) => { try { return readdirSync(path); } catch { return null; } },
26
+ readlink: (path) => { try { return readlinkSync(path); } catch { return null; } },
27
+ realpath: (path) => { try { return realpathSync(path); } catch { return null; } },
28
+ exists: (path) => existsSync(path),
29
+ };
30
+
31
+ /** A sysfs attribute as a trimmed string, or undefined when absent or blank. */
32
+ export function readAttr(fs: Pick<LinuxFs, "read">, path: string): string | undefined {
33
+ const v = fs.read(path)?.trim();
34
+ return v ? v : undefined;
35
+ }
36
+
37
+ /** A sysfs attribute as a finite number, or undefined. */
38
+ export function readNumber(fs: Pick<LinuxFs, "read">, path: string): number | undefined {
39
+ const v = readAttr(fs, path);
40
+ if (v === undefined) return undefined;
41
+ const n = Number(v);
42
+ return Number.isFinite(n) ? n : undefined;
43
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * macOS swap, which is the one memory figure the platform publishes and `node:os`
3
+ * does not.
4
+ *
5
+ * Off Linux every swap field was absent, and the memory page renders an absent
6
+ * field as an em dash — i.e. as the claim "this host's swap cannot be measured".
7
+ * On a Mac it can: `vm.swapusage` is a single sysctl. On the host this was found
8
+ * on it read **8047 MB of 9216 MB in use**, which is the most consequential thing
9
+ * that page could have been saying about the machine and was saying nothing about.
10
+ *
11
+ * `vm_stat` is deliberately not used here. It carries page counts but no swap at
12
+ * all, and the page counts are not needed: `os.freemem()` on darwin agrees with
13
+ * what `top` calls unused (75 MB against PPM's 124 MB on the same host, sampled
14
+ * seconds apart), so the cross-platform figure is already the one Activity
15
+ * Monitor shows. Do not "fix" it against `memory_pressure`, whose free
16
+ * percentage measures what could be reclaimed under duress and read 56% on a
17
+ * machine `top` called 31G used.
18
+ *
19
+ * The per-tick cost was measured rather than assumed, because this runs on every
20
+ * tick: **1.33 ms/call**, against the 1.7 ms `/proc/<pid>/io` already costs per
21
+ * tick on Linux. It stays `spawnSync` because `collectMemory` is synchronous and
22
+ * making the whole memory step async for one number is the larger change.
23
+ */
24
+ import type { MemoryMetrics } from "../../types/system-metrics.ts";
25
+
26
+ type SwapFields = Pick<MemoryMetrics, "swapTotalMB" | "swapUsedMB">;
27
+
28
+ /** `total = 9216.00M used = 8047.00M free = 1169.00M (encrypted)` */
29
+ const SWAP_RE = /total\s*=\s*([\d.]+)([KMGT])?\b[\s\S]*?used\s*=\s*([\d.]+)([KMGT])?\b/i;
30
+
31
+ const MB_PER_UNIT: Record<string, number> = { K: 1 / 1024, M: 1, G: 1024, T: 1024 * 1024 };
32
+
33
+ const round1 = (n: number): number => Math.round(n * 10) / 10;
34
+
35
+ /**
36
+ * Pure half, so the format can be tested without a Mac.
37
+ *
38
+ * `undefined` rather than zeroes when the text does not parse: a shape this code
39
+ * does not recognise is a host it did not measure, and 0 would be a claim that
40
+ * the machine has no swap.
41
+ */
42
+ export function parseSwapUsage(text: string | null | undefined): SwapFields | undefined {
43
+ if (!text) return undefined;
44
+ const m = SWAP_RE.exec(text);
45
+ if (!m) return undefined;
46
+
47
+ const toMB = (value: string, unit: string | undefined): number | null => {
48
+ const n = Number(value);
49
+ if (!Number.isFinite(n) || n < 0) return null;
50
+ // A bare number is bytes. The format normally carries a suffix, but a swap
51
+ // file of zero prints as `0.00M` on some releases and `0` on others, and
52
+ // reading that second form as megabytes would invent 0 MB either way — it
53
+ // is only correct here because the value is zero.
54
+ return unit ? n * (MB_PER_UNIT[unit.toUpperCase()] ?? 1) : n / (1024 * 1024);
55
+ };
56
+
57
+ const total = toMB(m[1]!, m[2]);
58
+ const used = toMB(m[3]!, m[4]);
59
+ if (total === null || used === null) return undefined;
60
+
61
+ return {
62
+ swapTotalMB: round1(total),
63
+ // Clamped, because a used figure above the total is not a bigger swap, it is
64
+ // a sample taken while the file was being resized.
65
+ swapUsedMB: round1(Math.min(Math.max(used, 0), total)),
66
+ };
67
+ }
68
+
69
+ /**
70
+ * `null` on every platform but darwin, so nothing is spawned where the figure
71
+ * already comes from `/proc/meminfo` or from CIM.
72
+ */
73
+ export function readSwapUsage(): string | null {
74
+ if (process.platform !== "darwin") return null;
75
+ try {
76
+ const result = Bun.spawnSync(["sysctl", "-n", "vm.swapusage"], {
77
+ stdout: "pipe",
78
+ stderr: "ignore",
79
+ stdin: "ignore",
80
+ });
81
+ if (result.exitCode !== 0) return null;
82
+ return new TextDecoder().decode(result.stdout);
83
+ } catch {
84
+ // `Bun.spawn` raises `Executable not found in $PATH` *synchronously* for a
85
+ // missing binary rather than reporting it through an exit code, and
86
+ // `spawnSync` is no different — the same trap `spawn-runner.ts` carries a
87
+ // comment about. A stripped-down host without `sysctl` gets an em dash, not
88
+ // a collector that throws mid-tick.
89
+ return null;
90
+ }
91
+ }
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Mission Center's memory page: the composition bar and the figures under it,
3
+ * all from `/proc/meminfo`, plus the populated slots from the SMBIOS table udev
4
+ * already decoded into its database (the raw table needs root; this does not).
5
+ */
6
+ import type { MemoryMetrics } from "../../types/system-metrics.ts";
7
+ import type { MemoryDeviceInfo, MemoryInfo } from "../../types/system-hardware.ts";
8
+ import { realLinuxFs, type LinuxFs } from "./linux-fs.ts";
9
+ import { readUdevProperties, udevValue } from "./udev-db.ts";
10
+
11
+ /** udev's own name for the SMBIOS record. */
12
+ export const DMI_UDEV_DEVICE = "+dmi:id";
13
+ const MB = 1024 * 1024;
14
+
15
+ /** Every `Key: N kB` line as BYTES. Values without a unit (the HugePages counts)
16
+ * are kept verbatim, which is what they mean. */
17
+ export function parseMeminfo(text: string): Map<string, number> {
18
+ const out = new Map<string, number>();
19
+ for (const line of text.split("\n")) {
20
+ const sep = line.indexOf(":");
21
+ if (sep < 0) continue;
22
+ const rest = line.slice(sep + 1).trim();
23
+ const [rawValue, unit] = rest.split(/\s+/);
24
+ const n = Number(rawValue);
25
+ if (!Number.isFinite(n)) continue;
26
+ out.set(line.slice(0, sep), unit === "kB" ? n * 1024 : n);
27
+ }
28
+ return out;
29
+ }
30
+
31
+ /**
32
+ * Adds the composition and the swap/commit figures to the cross-platform base.
33
+ *
34
+ * The four parts add up to the total EXACTLY and "in use" is exactly the headline
35
+ * `usedMB` (total - MemAvailable), so the bar and the figure beside it can never
36
+ * disagree. Standby is the rest of what the kernel would hand back on demand
37
+ * (MemAvailable - MemFree), and modified is carved out of it rather than added —
38
+ * a dirty page is also a cached page, so adding the two would overflow the bar.
39
+ */
40
+ export function enrichMemory(
41
+ base: MemoryMetrics,
42
+ text: string | null,
43
+ zram: ZramTotals | undefined = undefined,
44
+ ): MemoryMetrics {
45
+ if (!text) return base;
46
+ const m = parseMeminfo(text);
47
+ const total = m.get("MemTotal");
48
+ if (total === undefined || total <= 0) return base;
49
+
50
+ const get = (k: string) => m.get(k) ?? 0;
51
+ const free = clamp(get("MemFree"), 0, total);
52
+ const available = clamp(m.get("MemAvailable") ?? free, free, total);
53
+ const reclaimable = available - free;
54
+ const modified = clamp(get("Dirty") + get("Writeback"), 0, reclaimable);
55
+ const swapTotal = get("SwapTotal");
56
+
57
+ return {
58
+ ...base,
59
+ inUseBytes: total - available,
60
+ modifiedBytes: modified,
61
+ standbyBytes: reclaimable - modified,
62
+ freeBytes: free,
63
+ cachedMB: round1(get("Cached") / MB),
64
+ committedMB: round1(get("Committed_AS") / MB),
65
+ commitLimitMB: round1(get("CommitLimit") / MB),
66
+ swapTotalMB: round1(swapTotal / MB),
67
+ swapUsedMB: round1(Math.max(swapTotal - get("SwapFree"), 0) / MB),
68
+ ...(zram
69
+ ? {
70
+ zramCompressedMB: round1(zram.compressedBytes / MB),
71
+ zramSavingsMB: round1(zram.savingsBytes / MB),
72
+ }
73
+ : {}),
74
+ };
75
+ }
76
+
77
+ export interface ZramTotals {
78
+ compressedBytes: number;
79
+ savingsBytes: number;
80
+ }
81
+
82
+ /**
83
+ * `/sys/block/zram<N>/mm_stat`, summed over every device — a host can have one
84
+ * per CPU. Undefined when there is no zram at all, which is a different answer
85
+ * from a zram holding nothing: the Memory page hides the rows in the first case
86
+ * and shows zeroes in the second.
87
+ *
88
+ * Field order (Documentation/admin-guide/blockdev/zram.rst): orig_data_size,
89
+ * compr_data_size, mem_used_total, mem_limit, mem_used_max, same_pages,
90
+ * pages_compacted, huge_pages. Savings is orig minus compr, which is what
91
+ * Mission Center shows — NOT orig minus mem_used_total, which also subtracts
92
+ * zram's own allocator overhead and reads several percent low.
93
+ */
94
+ export function readZramTotals(fs: LinuxFs = realLinuxFs): ZramTotals | undefined {
95
+ const devices = (fs.list("/sys/block") ?? []).filter((n) => /^zram\d+$/.test(n));
96
+ if (devices.length === 0) return undefined;
97
+ let compressedBytes = 0;
98
+ let savingsBytes = 0;
99
+ let any = false;
100
+ for (const dev of devices) {
101
+ const stat = fs.read(`/sys/block/${dev}/mm_stat`)?.trim().split(/\s+/);
102
+ if (!stat || stat.length < 2) continue;
103
+ const orig = Number(stat[0]);
104
+ const compr = Number(stat[1]);
105
+ if (!Number.isFinite(orig) || !Number.isFinite(compr)) continue;
106
+ any = true;
107
+ compressedBytes += compr;
108
+ savingsBytes += Math.max(0, orig - compr);
109
+ }
110
+ return any ? { compressedBytes, savingsBytes } : undefined;
111
+ }
112
+
113
+ const clamp = (v: number, lo: number, hi: number) => Math.min(Math.max(v, lo), hi);
114
+
115
+ /** The populated slots, in board order. `MEMORY_DEVICE_<n>_*` is udev's decode of
116
+ * SMBIOS type 17; an empty slot has no `SIZE`, so it simply does not appear. */
117
+ export function readMemoryInfo(fs: Pick<LinuxFs, "read"> = realLinuxFs): MemoryInfo {
118
+ const props = readUdevProperties(DMI_UDEV_DEVICE, fs.read);
119
+ const devices: MemoryDeviceInfo[] = [];
120
+
121
+ for (let i = 0; ; i++) {
122
+ const prefix = `MEMORY_DEVICE_${i}_`;
123
+ const locator = udevValue(props, `${prefix}LOCATOR`);
124
+ const size = Number(udevValue(props, `${prefix}SIZE`));
125
+ // udev numbers the slots contiguously, so the first gap is the end of the list.
126
+ if (!locator && !Number.isFinite(size)) break;
127
+ if (i > 64) break;
128
+ if (!locator || !Number.isFinite(size) || size <= 0) continue;
129
+ devices.push({
130
+ locator,
131
+ sizeBytes: size,
132
+ ...defined("bankLocator", udevValue(props, `${prefix}BANK_LOCATOR`)),
133
+ ...defined("formFactor", udevValue(props, `${prefix}FORM_FACTOR`)),
134
+ ...defined("ramType", udevValue(props, `${prefix}TYPE`)),
135
+ ...defined("speedMts", positive(udevValue(props, `${prefix}SPEED_MTS`))),
136
+ ...defined("manufacturer", udevValue(props, `${prefix}MANUFACTURER`)),
137
+ ...defined("rank", positive(udevValue(props, `${prefix}RANK`))),
138
+ });
139
+ }
140
+
141
+ return {
142
+ devices,
143
+ ...defined("maxCapacityBytes", positive(udevValue(props, "MEMORY_ARRAY_MAX_CAPACITY"))),
144
+ };
145
+ }
146
+
147
+ const round1 = (n: number) => Math.round(n * 10) / 10;
148
+
149
+ function positive(raw: string | undefined): number | undefined {
150
+ const n = Number(raw);
151
+ return Number.isFinite(n) && n > 0 ? n : undefined;
152
+ }
153
+
154
+ function defined<K extends string, V>(key: K, value: V | undefined): Partial<Record<K, V>> {
155
+ return value === undefined ? {} : ({ [key]: value } as Record<K, V>);
156
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Per-interface figures for the Performance page's network entries, from
3
+ * `/sys/class/net/<if>/`. Throughput is the same counter Mission Center reads
4
+ * (`statistics/rx_bytes`, `tx_bytes`); the link state comes from the kernel's
5
+ * own `operstate`/`carrier` rather than from NetworkManager, so it is right on a
6
+ * host that does not run NetworkManager at all.
7
+ */
8
+ import type { NicMetrics, NicState } from "../../types/system-metrics.ts";
9
+ import { readAttr, readNumber, realLinuxFs, type LinuxFs } from "./linux-fs.ts";
10
+
11
+ export const SYS_NET = "/sys/class/net";
12
+ /** ARPHRD_LOOPBACK. Mission Center drops interfaces named `lo*`; the type is exact. */
13
+ const ARPHRD_LOOPBACK = 772;
14
+ const IFF_UP = 0x1;
15
+
16
+ export interface NicSample {
17
+ atSec: number;
18
+ rx: number;
19
+ tx: number;
20
+ }
21
+
22
+ /** Previous sample per interface name. */
23
+ export type NicSampleState = Map<string, NicSample>;
24
+
25
+ /** Live wireless facts for one interface; the collector takes them as data so it
26
+ * never spawns anything itself. */
27
+ export interface WirelessStatus {
28
+ ssid?: string;
29
+ signalPercent?: number;
30
+ frequencyMHz?: number;
31
+ }
32
+
33
+ export function listNetInterfaces(fs: Pick<LinuxFs, "list" | "read"> = realLinuxFs): string[] {
34
+ const names = fs.list(SYS_NET);
35
+ if (!names) return [];
36
+ return names.filter((n) => readNumber(fs, `${SYS_NET}/${n}/type`) !== ARPHRD_LOOPBACK).sort();
37
+ }
38
+
39
+ /** `operstate` is RFC 2863's, verbatim. `unknown` is what tun, wireguard and
40
+ * other virtual interfaces report for their whole life, so those are decided by
41
+ * carrier plus the admin flag instead. */
42
+ export function nicState(
43
+ operstate: string | undefined,
44
+ carrier: string | undefined,
45
+ flags: string | undefined,
46
+ ): NicState {
47
+ switch (operstate) {
48
+ case "up": return "connected";
49
+ case "dormant":
50
+ case "testing": return "connecting";
51
+ case "down": return "disconnected";
52
+ case "notpresent":
53
+ case "lowerlayerdown": return "unavailable";
54
+ case "unknown": {
55
+ const up = (Number.parseInt(flags ?? "0", 16) & IFF_UP) !== 0;
56
+ return carrier === "1" && up ? "connected" : "unknown";
57
+ }
58
+ default: return "unknown";
59
+ }
60
+ }
61
+
62
+ export interface NicDeviceCollection {
63
+ nics: NicMetrics[];
64
+ next: NicSampleState;
65
+ }
66
+
67
+ export function collectLinuxNicDevices(
68
+ prev: NicSampleState,
69
+ fs: Pick<LinuxFs, "list" | "read"> = realLinuxFs,
70
+ now: () => number = Date.now,
71
+ wireless: ReadonlyMap<string, WirelessStatus> = new Map(),
72
+ ): NicDeviceCollection {
73
+ const atSec = now() / 1000;
74
+ const next: NicSampleState = new Map();
75
+ const nics: NicMetrics[] = [];
76
+
77
+ for (const id of listNetInterfaces(fs)) {
78
+ const rx = readNumber(fs, `${SYS_NET}/${id}/statistics/rx_bytes`);
79
+ const tx = readNumber(fs, `${SYS_NET}/${id}/statistics/tx_bytes`);
80
+ if (rx === undefined || tx === undefined) continue;
81
+ const sample: NicSample = { atSec, rx, tx };
82
+ next.set(id, sample);
83
+
84
+ // `speed` is -1 with no link, and reading it EINVALs on a virtual interface.
85
+ const speed = readNumber(fs, `${SYS_NET}/${id}/speed`);
86
+ nics.push({
87
+ ...toNicMetrics(id, prev.get(id) ?? null, sample),
88
+ state: nicState(
89
+ readAttr(fs, `${SYS_NET}/${id}/operstate`),
90
+ readAttr(fs, `${SYS_NET}/${id}/carrier`),
91
+ readAttr(fs, `${SYS_NET}/${id}/flags`),
92
+ ),
93
+ ...(speed !== undefined && speed > 0 ? { linkMbps: speed } : {}),
94
+ ...(wireless.get(id) ?? {}),
95
+ });
96
+ }
97
+ return { nics, next };
98
+ }
99
+
100
+ /** Rates only — the caller adds state and link facts. */
101
+ export function toNicMetrics(id: string, prev: NicSample | null, next: NicSample): NicMetrics {
102
+ const base: NicMetrics = {
103
+ id, available: false, rxBps: 0, txBps: 0, rxTotal: next.rx, txTotal: next.tx, state: "unknown",
104
+ };
105
+ const dt = prev ? next.atSec - prev.atSec : 0;
106
+ // The kernel zeroes these when an interface is recreated under the same name.
107
+ if (!prev || !Number.isFinite(dt) || dt <= 0 || next.rx < prev.rx || next.tx < prev.tx) return base;
108
+ return {
109
+ ...base,
110
+ available: true,
111
+ rxBps: Math.round((next.rx - prev.rx) / dt),
112
+ txBps: Math.round((next.tx - prev.tx) / dt),
113
+ };
114
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Static facts about each network interface: what kind it is, the adapter's
3
+ * marketing name, its driver, MAC and addresses.
4
+ *
5
+ * Mission Center classifies by NetworkManager's device type and falls back to a
6
+ * table of name prefixes — and its type read always fails (it asks for a u64
7
+ * where NM publishes a u32), so in practice the prefix table is all that ever
8
+ * runs. PPM asks sysfs and udev first, which are exact, and keeps that same
9
+ * prefix table only as the last resort.
10
+ */
11
+ import { networkInterfaces } from "node:os";
12
+ import type { NicInfo, NicKind } from "../../types/system-hardware.ts";
13
+ import { readAttr, readNumber, realLinuxFs, type LinuxFs } from "./linux-fs.ts";
14
+ import { readUdevProperties, udevValue } from "./udev-db.ts";
15
+ import { listNetInterfaces, SYS_NET } from "./net-devices-linux.ts";
16
+
17
+ const ARPHRD_INFINIBAND = 32;
18
+ /** `tun_flags` bit 0: a TUN (layer 3) device, i.e. a tunnel rather than a tap. */
19
+ const IFF_TUN = 0x1;
20
+
21
+ export function readNicInventory(
22
+ fs: LinuxFs = realLinuxFs,
23
+ addresses: () => AddressMap = readAddresses,
24
+ ): NicInfo[] {
25
+ const addrs = addresses();
26
+ return listNetInterfaces(fs).map((id) => readNicInfo(id, fs, addrs[id]));
27
+ }
28
+
29
+ export function readNicInfo(id: string, fs: LinuxFs, addr: Addresses | undefined): NicInfo {
30
+ const udev = readUdevProperties(`n${readAttr(fs, `${SYS_NET}/${id}/ifindex`) ?? ""}`, fs.read);
31
+ const driver = udevValue(udev, "ID_NET_DRIVER")
32
+ ?? basename(fs.readlink(`${SYS_NET}/${id}/device/driver`) ?? "");
33
+
34
+ return {
35
+ id,
36
+ kind: nicKind(id, fs),
37
+ ...optional("deviceName", udevValue(udev, "ID_MODEL_FROM_DATABASE")),
38
+ ...optional("driver", driver || undefined),
39
+ ...optional("mac", readAttr(fs, `${SYS_NET}/${id}/address`)),
40
+ ipv4: addr?.ipv4 ?? [],
41
+ ipv6: addr?.ipv6 ?? [],
42
+ };
43
+ }
44
+
45
+ /** sysfs facts first, Mission Center's prefix table only when none of them apply. */
46
+ export function nicKind(id: string, fs: Pick<LinuxFs, "read" | "exists">): NicKind {
47
+ const devtype = uevent(fs, id).get("DEVTYPE");
48
+ if (devtype === "wireguard") return "vpn";
49
+ if (devtype === "wlan" || fs.exists(`${SYS_NET}/${id}/wireless`)) return "wireless";
50
+ if (readNumber(fs, `${SYS_NET}/${id}/type`) === ARPHRD_INFINIBAND) return "infiniband";
51
+ if (devtype === "bridge") return id.startsWith("docker") ? "docker" : "bridge";
52
+ // A TUN device is a tunnel by construction — Mission Center has no rule for
53
+ // these and files every one of them (tailscale0, tun0, nordlynx) under "other".
54
+ const tunFlags = readAttr(fs, `${SYS_NET}/${id}/tun_flags`);
55
+ if (tunFlags && (Number.parseInt(tunFlags, 16) & IFF_TUN) !== 0) return "vpn";
56
+ return kindFromName(id);
57
+ }
58
+
59
+ /** Mission Center's `connection_kind_from_name`, order included. */
60
+ export function kindFromName(id: string): NicKind {
61
+ if (id.startsWith("bn")) return "bluetooth";
62
+ if (id.startsWith("br") || id.startsWith("virbr")) return "bridge";
63
+ if (id.startsWith("docker")) return "docker";
64
+ if (id.startsWith("eth") || id.startsWith("en")) return "wired";
65
+ if (id.startsWith("ib")) return "infiniband";
66
+ if (id.startsWith("mp")) return "multipass";
67
+ if (id.startsWith("veth")) return "virtual";
68
+ if (id.startsWith("vpn") || id.startsWith("wg")) return "vpn";
69
+ if (id.startsWith("wl") || id.startsWith("ww")) return "wireless";
70
+ return "other";
71
+ }
72
+
73
+ function uevent(fs: Pick<LinuxFs, "read">, id: string): Map<string, string> {
74
+ const props = new Map<string, string>();
75
+ for (const line of (fs.read(`${SYS_NET}/${id}/uevent`) ?? "").split("\n")) {
76
+ const eq = line.indexOf("=");
77
+ if (eq > 0) props.set(line.slice(0, eq), line.slice(eq + 1).trim());
78
+ }
79
+ return props;
80
+ }
81
+
82
+ export interface Addresses { ipv4: string[]; ipv6: string[] }
83
+ export type AddressMap = Record<string, Addresses>;
84
+
85
+ export function readAddresses(): AddressMap {
86
+ const map: AddressMap = {};
87
+ for (const [name, addrs] of Object.entries(networkInterfaces())) {
88
+ for (const a of addrs ?? []) {
89
+ const entry = (map[name] ??= { ipv4: [], ipv6: [] });
90
+ (a.family === "IPv4" ? entry.ipv4 : entry.ipv6).push(a.address);
91
+ }
92
+ }
93
+ return map;
94
+ }
95
+
96
+ const basename = (p: string) => p.slice(p.lastIndexOf("/") + 1);
97
+
98
+ function optional<K extends string>(key: K, value: string | undefined): Partial<Record<K, string>> {
99
+ return value === undefined ? {} : ({ [key]: value } as Record<K, string>);
100
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Partitions of a whole disk, with what is mounted on them and how full it is —
3
+ * Mission Center's Partitions section on the drive page.
4
+ *
5
+ * Mission Center asks udisks2 over D-Bus. This reads sysfs for the partition
6
+ * list, `/proc/self/mountinfo` for the mounts and `statfs` for the usage, so it
7
+ * needs neither a system bus nor root.
8
+ *
9
+ * The usage figures are read with the ASYNC `statfs`, deliberately: PPM serves
10
+ * every request and every chat session from one event loop, and `statfsSync` on
11
+ * a mount whose device is spinning up (or an autofs mount that is cold) blocks
12
+ * that loop for as long as the kernel takes. It is also why this is not on the
13
+ * 2 s tick — it belongs to the inventory, which is fetched on demand.
14
+ */
15
+ import type { DiskInfo, PartitionInfo, PartitionMount } from "../../types/system-hardware.ts";
16
+ import { readAttr, readNumber, realLinuxFs, type LinuxFs } from "./linux-fs.ts";
17
+ import { readUdevProperties, udevValue } from "./udev-db.ts";
18
+ import { SYS_BLOCK } from "./disk-devices-linux.ts";
19
+
20
+ const SECTOR_BYTES = 512;
21
+ const MOUNTINFO = "/proc/self/mountinfo";
22
+
23
+ /** One mount as `/proc/self/mountinfo` describes it. */
24
+ export interface MountEntry {
25
+ /** mountinfo's major:minor. For ext4 this is the block device's own, but a
26
+ * filesystem that can span devices registers an ANONYMOUS one instead — every
27
+ * btrfs mount on this host reports `0:35` rather than `259:2` — so this alone
28
+ * finds no mount at all on a btrfs root, which is most Arch installs. */
29
+ deviceId: string;
30
+ /** The device as the kernel records it, "/dev/nvme0n1p2". This is what matches
31
+ * a btrfs partition; `deviceId` is what still matches when the source is a
32
+ * label or a stacked device. Both are needed. */
33
+ source: string;
34
+ /** Which part of the filesystem is mounted: "/" for the whole thing, "/@home"
35
+ * for a btrfs subvolume, a directory for a bind mount. */
36
+ root: string;
37
+ mountPoint: string;
38
+ filesystem: string;
39
+ }
40
+
41
+ /**
42
+ * mountinfo's variable-length optional-fields group ends at a literal `-`, so the
43
+ * tail cannot be indexed from the start of the line. Splitting on the separator
44
+ * first is what makes `fstype` findable at all.
45
+ *
46
+ * Paths are escaped by the kernel — a mount under `/mnt/my drive` arrives as
47
+ * `/mnt/my\040drive`, and leaving it that way means the statfs below fails on
48
+ * exactly the mounts whose names have spaces.
49
+ */
50
+ export function parseMountInfo(text: string): MountEntry[] {
51
+ const out: MountEntry[] = [];
52
+ for (const line of text.split("\n")) {
53
+ const sep = line.indexOf(" - ");
54
+ if (sep < 0) continue;
55
+ const head = line.slice(0, sep).split(" ");
56
+ const tail = line.slice(sep + 3).split(" ");
57
+ const deviceId = head[2];
58
+ const root = head[3];
59
+ const mountPoint = head[4];
60
+ const filesystem = tail[0];
61
+ if (!deviceId || !root || !mountPoint || !filesystem) continue;
62
+ out.push({
63
+ deviceId,
64
+ source: unescapeMountPath(tail[1] ?? ""),
65
+ root: unescapeMountPath(root),
66
+ mountPoint: unescapeMountPath(mountPoint),
67
+ filesystem,
68
+ });
69
+ }
70
+ return out;
71
+ }
72
+
73
+ /** The four sequences the kernel escapes: space, tab, newline, backslash. */
74
+ export function unescapeMountPath(path: string): string {
75
+ return path.replace(/\\(040|011|012|134)/g, (_, code) =>
76
+ ({ "040": " ", "011": "\t", "012": "\n", "134": "\\" })[code as string] ?? _);
77
+ }
78
+
79
+ /** Partition directories of a whole disk: sysfs nests them under the disk and
80
+ * marks each with a `partition` attribute, which is what tells `sda1` apart from
81
+ * `queue` or `holders`. */
82
+ export function listPartitions(diskId: string, fs: LinuxFs = realLinuxFs): string[] {
83
+ return (fs.list(`${SYS_BLOCK}/${diskId}`) ?? [])
84
+ .filter((name) => fs.exists(`${SYS_BLOCK}/${diskId}/${name}/partition`))
85
+ .sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
86
+ }
87
+
88
+ /** The static half: everything but the usage, which needs a syscall per mount. */
89
+ export function readPartitions(
90
+ diskId: string,
91
+ fs: LinuxFs = realLinuxFs,
92
+ mounts: MountEntry[] = parseMountInfo(fs.read(MOUNTINFO) ?? ""),
93
+ ): PartitionInfo[] {
94
+ return listPartitions(diskId, fs).map((id) => {
95
+ const base = `${SYS_BLOCK}/${diskId}/${id}`;
96
+ const deviceId = readAttr(fs, `${base}/dev`);
97
+ const udev = readUdevProperties(deviceId ? `b${deviceId}` : "", fs.read);
98
+ const sectors = readNumber(fs, `${base}/size`) ?? 0;
99
+ const devicePath = `/dev/${id}`;
100
+ const mine = mounts.filter((m) => (deviceId && m.deviceId === deviceId) || m.source === devicePath);
101
+ // udev knows the type even for a partition nothing has mounted, which is the
102
+ // case the mountinfo scan cannot answer at all.
103
+ const filesystem = udevValue(udev, "ID_FS_TYPE") ?? mine[0]?.filesystem;
104
+ return {
105
+ id,
106
+ devicePath,
107
+ sizeBytes: sectors * SECTOR_BYTES,
108
+ ...(filesystem ? { filesystem } : {}),
109
+ mounts: mine.map((m) => ({ mountPoint: m.mountPoint, filesystem: m.filesystem })),
110
+ };
111
+ });
112
+ }
113
+
114
+ export type StatfsReader = (path: string) => Promise<{ blocks: number; bavail: number; bfree: number; bsize: number }>;
115
+
116
+ const realStatfs: StatfsReader = async (path) => {
117
+ const { statfs } = await import("node:fs/promises");
118
+ return statfs(path) as unknown as ReturnType<StatfsReader> extends Promise<infer T> ? T : never;
119
+ };
120
+
121
+ /**
122
+ * `used` is computed against the blocks a non-root user may actually have, not
123
+ * against the total: ext4 reserves 5% for root, so `blocks - bfree` reports a
124
+ * fresh filesystem as several percent full while `df` says 1%. This is `df`'s own
125
+ * arithmetic — total is what you can use plus what is used.
126
+ */
127
+ export function usageFromStatfs(s: { blocks: number; bavail: number; bfree: number; bsize: number }): PartitionMount {
128
+ const used = (s.blocks - s.bfree) * s.bsize;
129
+ const total = used + s.bavail * s.bsize;
130
+ return { mountPoint: "", filesystem: "", usedBytes: used, totalBytes: total };
131
+ }
132
+
133
+ /**
134
+ * Fills in every mount's usage, in parallel. A mount that refuses is left with no
135
+ * figures rather than zeroes — an unreadable filesystem is not an empty one.
136
+ */
137
+ export async function attachPartitionUsage(
138
+ disks: DiskInfo[],
139
+ statfs: StatfsReader = realStatfs,
140
+ ): Promise<void> {
141
+ const jobs: Promise<void>[] = [];
142
+ for (const disk of disks) {
143
+ for (const part of disk.partitions ?? []) {
144
+ for (const mount of part.mounts) {
145
+ jobs.push(
146
+ statfs(mount.mountPoint)
147
+ .then((s) => {
148
+ const { usedBytes, totalBytes } = usageFromStatfs(s);
149
+ mount.usedBytes = usedBytes;
150
+ mount.totalBytes = totalBytes;
151
+ })
152
+ .catch(() => {}),
153
+ );
154
+ }
155
+ }
156
+ }
157
+ await Promise.all(jobs);
158
+ }