@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,120 @@
1
+ /**
2
+ * OpenGL and Vulkan versions for the GPU page. Both come from a one-shot tool
3
+ * and neither ever changes while the machine is up, so the result is cached for
4
+ * the process lifetime and the tools are never spawned from a tick.
5
+ *
6
+ * `eglinfo` is asked with `EGL_PLATFORM=surfaceless`, which is what lets this
7
+ * answer at all on a headless host or from a systemd unit with no display —
8
+ * `glxinfo` needs an X connection and would simply fail there.
9
+ */
10
+ import type { Runner } from "../host-info/spawn-runner.ts";
11
+ import { defaultRunner } from "../host-info/spawn-runner.ts";
12
+
13
+ /** `env` carries the platform override because the shared `Runner` takes an argv
14
+ * and no environment — and without it `eglinfo` needs a display, which a PPM
15
+ * started from a systemd unit does not have. */
16
+ export const EGLINFO_ARGV = ["env", "EGL_PLATFORM=surfaceless", "eglinfo"];
17
+ export const VULKANINFO_ARGV = ["vulkaninfo", "--summary"];
18
+ const SPAWN_TIMEOUT_MS = 8000;
19
+
20
+ export interface GpuApiVersions {
21
+ /** Highest context the driver offers: "4.6", or "ES 3.2" when that is all. */
22
+ opengl?: string;
23
+ /** Vulkan API version, e.g. "1.4.354". */
24
+ vulkan?: string;
25
+ /** Mesa's own version, which is the meaningful "driver version" for i915,
26
+ * xe and amdgpu — none of those modules publish one in sysfs. */
27
+ mesa?: string;
28
+ }
29
+
30
+ /** "OpenGL core profile version string: 4.6 (Core Profile) Mesa 26.2.2" → "4.6".
31
+ * A driver with no desktop GL at all reports its ES version instead, which is
32
+ * what Mission Center shows for those. */
33
+ export function parseOpenglVersion(text: string): string | undefined {
34
+ const core = /^OpenGL core profile version(?: string)?:\s*(\d+\.\d+)/m.exec(text);
35
+ if (core) return core[1];
36
+ const compat = /^OpenGL version(?: string)?:\s*(\d+\.\d+)/m.exec(text);
37
+ if (compat) return compat[1];
38
+ const es = /^OpenGL ES profile version(?: string)?:\s*OpenGL ES (\d+\.\d+)/m.exec(text);
39
+ return es ? `ES ${es[1]}` : undefined;
40
+ }
41
+
42
+ /** `vulkaninfo --summary` prints one `apiVersion = 1.4.354` per device; the
43
+ * highest is what the machine supports. */
44
+ export function parseVulkanVersion(text: string): string | undefined {
45
+ const versions = [...text.matchAll(/apiVersion\s*[=:]\s*(?:0x[0-9a-f]+\s*\()?(\d+\.\d+\.\d+)/gi)]
46
+ .map((m) => m[1]!)
47
+ .sort(compareVersions);
48
+ return versions.at(-1);
49
+ }
50
+
51
+ function compareVersions(a: string, b: string): number {
52
+ const pa = a.split(".").map(Number);
53
+ const pb = b.split(".").map(Number);
54
+ for (let i = 0; i < 3; i++) {
55
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
56
+ if (d !== 0) return d;
57
+ }
58
+ return 0;
59
+ }
60
+
61
+ /** The Mesa build out of an OpenGL version line: "OpenGL core profile version:
62
+ * 4.6 (Core Profile) Mesa 26.2.2-arch3.2" -> "Mesa 26.2.2-arch3.2".
63
+ *
64
+ * Anchored to that line on purpose. eglinfo also prints "EGL vendor string: Mesa
65
+ * Project" much earlier, so an unanchored search reports the version as
66
+ * "Mesa Project" — well-formed, plausible, and wrong. */
67
+ export function parseMesaVersion(text: string): string | undefined {
68
+ const m = /^OpenGL [^\n]*version(?: string)?:[^\n]*\bMesa ([\w.+-]+)/m.exec(text);
69
+ return m ? `Mesa ${m[1]}` : undefined;
70
+ }
71
+
72
+ export interface GpuApiVersionReader {
73
+ read(): Promise<GpuApiVersions>;
74
+ }
75
+
76
+ export function createGpuApiVersionReader(run: Runner = defaultRunner): GpuApiVersionReader {
77
+ let cached: Promise<GpuApiVersions> | null = null;
78
+ return {
79
+ read() {
80
+ // One in-flight promise, reused forever: two windows opening at once must
81
+ // not spawn `vulkaninfo` twice, and the answer cannot change afterwards.
82
+ cached ??= probe(run);
83
+ return cached;
84
+ },
85
+ };
86
+ }
87
+
88
+ async function probe(run: Runner): Promise<GpuApiVersions> {
89
+ const [gl, vk] = await Promise.all([
90
+ tryRun(run, EGLINFO_ARGV),
91
+ tryRun(run, VULKANINFO_ARGV),
92
+ ]);
93
+ return {
94
+ ...(gl ? optional("opengl", parseOpenglVersion(gl)) : {}),
95
+ ...(gl ? optional("mesa", parseMesaVersion(gl)) : {}),
96
+ ...(vk ? optional("vulkan", parseVulkanVersion(vk)) : {}),
97
+ };
98
+ }
99
+
100
+ /**
101
+ * A missing tool is not an error worth surfacing — the page hides the row.
102
+ *
103
+ * The exit code is deliberately NOT a gate. `eglinfo` sweeps every EGL platform
104
+ * it knows and exits 1 when any of them fails, which on a headless host means
105
+ * every run — while still printing a complete, correct surfaceless report to
106
+ * stdout. Gating on the code threw away 2784 good lines and left the OpenGL row
107
+ * permanently blank. Output is the signal; the parsers reject anything else.
108
+ */
109
+ async function tryRun(run: Runner, argv: readonly string[]): Promise<string | null> {
110
+ try {
111
+ const r = await run([...argv], SPAWN_TIMEOUT_MS);
112
+ return !r.timedOut && r.stdout.trim() ? r.stdout : null;
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+
118
+ function optional<K extends string>(key: K, value: string | undefined): Partial<Record<K, string>> {
119
+ return value === undefined ? {} : ({ [key]: value } as Record<K, string>);
120
+ }
@@ -0,0 +1,370 @@
1
+ /**
2
+ * Whole-GPU figures for Mission Center's GPU page, from `/sys/class/drm/card*`.
3
+ *
4
+ * There is no one source: utilisation comes from the DRM fdinfo engine counters
5
+ * where the driver publishes them (Intel, AMD, and the only unprivileged option
6
+ * on Intel at all), from amdgpu's own `gpu_busy_percent` where it exists, and
7
+ * from i915's rc6 idle residency as a last resort. Anything a given driver does
8
+ * not expose stays ABSENT rather than 0, so the page hides the row.
9
+ *
10
+ * NVIDIA keeps its existing `nvidia-smi` collector: the proprietary driver
11
+ * publishes neither fdinfo engine counters nor the sysfs attributes below.
12
+ */
13
+ import os from "node:os";
14
+ import type { GpuInfo, GpuMetrics } from "../../types/system-metrics.ts";
15
+ import { readAttr, readNumber, realLinuxFs, type LinuxFs } from "./linux-fs.ts";
16
+ import { readUdevProperties, udevValue } from "./udev-db.ts";
17
+ import type { DrmUsage } from "./gpu-fdinfo-linux.ts";
18
+
19
+ export const DRM_DIR = "/sys/class/drm";
20
+ const RAPL_DIR = "/sys/class/powercap";
21
+
22
+ const VENDORS: Record<string, string> = {
23
+ "0x8086": "Intel",
24
+ "0x1002": "AMD",
25
+ "0x1022": "AMD",
26
+ "0x10de": "NVIDIA",
27
+ };
28
+
29
+ /** `current_link_speed` reads "8.0 GT/s PCIe"; the rate identifies the generation. */
30
+ const PCIE_GEN_BY_RATE: Record<string, number> = {
31
+ "2.5": 1, "5.0": 2, "8.0": 3, "16.0": 4, "32.0": 5, "64.0": 6,
32
+ };
33
+
34
+ export interface GpuCard {
35
+ /** "card1". */
36
+ card: string;
37
+ /** PCI address — the id both `GpuMetrics` and `GpuInfo` are keyed by. */
38
+ pdev: string;
39
+ driver: string;
40
+ vendor?: string;
41
+ }
42
+
43
+ /** Real render nodes only: `card1-DP-1` is a connector, not a device, and a
44
+ * driver with no PCI parent (vkms, a virtio display) has nothing to report. */
45
+ export function listGpuCards(fs: Pick<LinuxFs, "list" | "read" | "readlink" | "realpath">): GpuCard[] {
46
+ const cards: GpuCard[] = [];
47
+ for (const entry of (fs.list(DRM_DIR) ?? []).sort()) {
48
+ if (!/^card\d+$/.test(entry)) continue;
49
+ const real = fs.realpath(`${DRM_DIR}/${entry}/device`);
50
+ const pdev = real ? real.slice(real.lastIndexOf("/") + 1) : "";
51
+ if (!/^[0-9a-f]{4}:/i.test(pdev)) continue;
52
+ const driver = basename(fs.readlink(`${DRM_DIR}/${entry}/device/driver`) ?? "");
53
+ const vendorId = readAttr(fs, `${DRM_DIR}/${entry}/device/vendor`);
54
+ cards.push({
55
+ card: entry,
56
+ pdev,
57
+ driver,
58
+ ...(vendorId && VENDORS[vendorId] ? { vendor: VENDORS[vendorId] } : {}),
59
+ });
60
+ }
61
+ return cards;
62
+ }
63
+
64
+ export interface GpuSample {
65
+ atSec: number;
66
+ /** i915 cumulative idle residency, ms. */
67
+ rc6Ms?: number;
68
+ /** RAPL uncore energy, µJ — the integrated GPU's share of package power. */
69
+ uncoreUj?: number;
70
+ }
71
+
72
+ export type GpuSampleState = Map<string, GpuSample>;
73
+
74
+ export interface GpuDeviceCollection {
75
+ gpus: GpuMetrics[];
76
+ next: GpuSampleState;
77
+ }
78
+
79
+ export function collectLinuxGpus(
80
+ prev: GpuSampleState,
81
+ usage: DrmUsage,
82
+ fs: Pick<LinuxFs, "list" | "read" | "readlink" | "realpath"> = realLinuxFs,
83
+ now: () => number = Date.now,
84
+ totalRamBytes: number = os.totalmem(),
85
+ ): GpuDeviceCollection {
86
+ const atSec = now() / 1000;
87
+ const uncoreUj = readUncoreEnergy(fs);
88
+ const next: GpuSampleState = new Map();
89
+ const gpus: GpuMetrics[] = [];
90
+
91
+ for (const card of listGpuCards(fs)) {
92
+ // NVIDIA is covered by the nvidia-smi collector; listing it here too would
93
+ // publish the same GPU twice with half the figures missing.
94
+ if (card.driver === "nvidia" || card.driver === "nouveau") continue;
95
+ const dir = `${DRM_DIR}/${card.card}`;
96
+ const sample: GpuSample = {
97
+ atSec,
98
+ ...defined("rc6Ms", readNumber(fs, `${dir}/power/rc6_residency_ms`)),
99
+ ...defined("uncoreUj", uncoreUj),
100
+ };
101
+ next.set(card.card, sample);
102
+ gpus.push(buildGpuMetrics(card, dir, prev.get(card.card) ?? null, sample, usage, fs, totalRamBytes));
103
+ }
104
+ return { gpus, next };
105
+ }
106
+
107
+ function buildGpuMetrics(
108
+ card: GpuCard,
109
+ dir: string,
110
+ prev: GpuSample | null,
111
+ next: GpuSample,
112
+ usage: DrmUsage,
113
+ fs: Pick<LinuxFs, "list" | "read">,
114
+ totalRamBytes: number,
115
+ ): GpuMetrics {
116
+ const engines = usage.perDevice.get(card.pdev);
117
+ const integrated = card.driver === "i915" || card.driver === "xe";
118
+ const vram = readVram(dir, fs);
119
+ const hwmon = findHwmon(dir, fs);
120
+
121
+ return {
122
+ id: card.pdev,
123
+ name: gpuName(card, fs),
124
+ utilPercent: utilisation(card, dir, engines, prev, next, fs),
125
+ vramUsedMB: vram.usedMB,
126
+ vramTotalMB: vram.totalMB,
127
+ ...sharedMemory(card, dir, usage, fs, totalRamBytes),
128
+ ...videoEngines(card, engines),
129
+ ...defined("clockMHz", currentClockMHz(card, dir, fs)),
130
+ ...defined("clockMaxMHz", maxClockMHz(card, dir, fs)),
131
+ ...defined("memClockMHz", pickDpmCurrent(readAttr(fs, `${dir}/device/pp_dpm_mclk`))),
132
+ ...defined("powerW", integrated ? uncoreWatts(prev, next) : hwmonPowerW(hwmon, fs)),
133
+ ...defined("tempC", hwmonTempC(hwmon, fs)),
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Engine busy first: it is the only unprivileged per-engine figure Intel has and
139
+ * it matches what the process rows are built from, so the page and the table
140
+ * agree. amdgpu's own counter is preferred over rc6 where fdinfo said nothing,
141
+ * and rc6 is the last resort — it measures IDLE, so busy is its complement.
142
+ */
143
+ export function utilisation(
144
+ card: GpuCard,
145
+ dir: string,
146
+ engines: ReadonlyMap<string, number> | undefined,
147
+ prev: GpuSample | null,
148
+ next: GpuSample,
149
+ fs: Pick<LinuxFs, "read">,
150
+ ): number {
151
+ const render = (engines?.get("render") ?? 0) + (engines?.get("compute") ?? 0);
152
+ if (render > 0) return round1(Math.min(100, render));
153
+
154
+ const amdBusy = readNumber(fs, `${dir}/device/gpu_busy_percent`);
155
+ if (amdBusy !== undefined) return round1(Math.min(100, Math.max(0, amdBusy)));
156
+
157
+ const rc6 = rc6BusyPercent(prev, next);
158
+ return rc6 ?? 0;
159
+ }
160
+
161
+ /** i915's rc6 counter is cumulative time spent in the deepest idle state. */
162
+ export function rc6BusyPercent(prev: GpuSample | null, next: GpuSample): number | undefined {
163
+ if (!prev || prev.rc6Ms === undefined || next.rc6Ms === undefined) return undefined;
164
+ const dtMs = (next.atSec - prev.atSec) * 1000;
165
+ const idle = next.rc6Ms - prev.rc6Ms;
166
+ if (!(dtMs > 0) || idle < 0) return undefined;
167
+ return round1(Math.min(100, Math.max(0, 100 - idle / dtMs * 100)));
168
+ }
169
+
170
+ /** Intel exposes ONE video engine doing both encode and decode, so the page
171
+ * labels it "Video encode/decode" rather than inventing a second figure. */
172
+ function videoEngines(card: GpuCard, engines: ReadonlyMap<string, number> | undefined): Partial<GpuMetrics> {
173
+ if (!engines) return {};
174
+ const video = engines.get("video");
175
+ const enhance = engines.get("video-enhance");
176
+ if (video === undefined && enhance === undefined) return {};
177
+ if (card.driver === "i915" || card.driver === "xe") {
178
+ return { encodePercent: round1(Math.min(100, (video ?? 0) + (enhance ?? 0))) };
179
+ }
180
+ return {
181
+ ...defined("encodePercent", video === undefined ? undefined : round1(video)),
182
+ ...defined("decodePercent", enhance === undefined ? undefined : round1(enhance)),
183
+ };
184
+ }
185
+
186
+ /**
187
+ * System memory the GPU is using — Mission Center's "Memory Usage" on a card
188
+ * with no VRAM of its own, where it is the page's only memory figure.
189
+ *
190
+ * amdgpu's own GTT counters win where they exist: they are the driver's view of
191
+ * its aperture, and the aperture — not system RAM — is that card's ceiling. An
192
+ * integrated GPU publishes neither, so the figure is summed out of its clients'
193
+ * DRM fdinfo against the machine's RAM, which is what Mission Center shows (it
194
+ * read 2.52 GiB / 62.5 GiB here while this summed 2.54 GiB).
195
+ *
196
+ * Both halves must be present or neither is reported: a used figure over an
197
+ * unknown ceiling is not a reading.
198
+ */
199
+ export function sharedMemory(
200
+ card: GpuCard,
201
+ dir: string,
202
+ usage: DrmUsage,
203
+ fs: Pick<LinuxFs, "read">,
204
+ totalRamBytes: number,
205
+ ): Partial<GpuMetrics> {
206
+ const gttUsed = bytesToMB(readNumber(fs, `${dir}/device/mem_info_gtt_used`));
207
+ const gttTotal = bytesToMB(readNumber(fs, `${dir}/device/mem_info_gtt_total`));
208
+ if (gttUsed !== undefined && gttTotal !== undefined) {
209
+ return { sharedUsedMB: gttUsed, sharedTotalMB: gttTotal };
210
+ }
211
+ const fromClients = usage.sharedByDevice.get(card.pdev);
212
+ const ram = bytesToMB(totalRamBytes > 0 ? totalRamBytes : undefined);
213
+ if (fromClients === undefined || ram === undefined) return {};
214
+ return { sharedUsedMB: Math.round(fromClients), sharedTotalMB: ram };
215
+ }
216
+
217
+ /** amdgpu is the only driver here with dedicated memory counters; an integrated
218
+ * GPU reports a 0 total, which the contract defines as "has none to report". */
219
+ function readVram(dir: string, fs: Pick<LinuxFs, "read">): { usedMB: number; totalMB: number } {
220
+ const used = readNumber(fs, `${dir}/device/mem_info_vram_used`);
221
+ const total = readNumber(fs, `${dir}/device/mem_info_vram_total`);
222
+ return { usedMB: bytesToMB(used) ?? 0, totalMB: bytesToMB(total) ?? 0 };
223
+ }
224
+
225
+ /**
226
+ * i915's REQUESTED clock, not its actual one.
227
+ *
228
+ * `gt_act_freq_mhz` is sampled the instant the file is read, and an idle GPU is
229
+ * parked in RC6 for most of any 2 s tick — so it returns 0 far more often than
230
+ * not and the figure flickers between 0 and 1400 MHz beside a fixed maximum,
231
+ * which reads as a broken number rather than as an idle GPU. `gt_cur_freq_mhz`
232
+ * is the frequency the driver is holding the card at and moves with load.
233
+ */
234
+ function currentClockMHz(card: GpuCard, dir: string, fs: Pick<LinuxFs, "read">): number | undefined {
235
+ return readNumber(fs, `${dir}/gt_cur_freq_mhz`)
236
+ ?? readNumber(fs, `${dir}/gt_act_freq_mhz`)
237
+ ?? pickDpmCurrent(readAttr(fs, `${dir}/device/pp_dpm_sclk`));
238
+ }
239
+
240
+ function maxClockMHz(card: GpuCard, dir: string, fs: Pick<LinuxFs, "read">): number | undefined {
241
+ return readNumber(fs, `${dir}/gt_RP0_freq_mhz`)
242
+ ?? readNumber(fs, `${dir}/gt_max_freq_mhz`)
243
+ ?? pickDpmMax(readAttr(fs, `${dir}/device/pp_dpm_sclk`));
244
+ }
245
+
246
+ /** amdgpu's DPM tables list one state per line and mark the live one with `*`:
247
+ * `1: 500Mhz *`. */
248
+ export function pickDpmCurrent(table: string | undefined): number | undefined {
249
+ if (!table) return undefined;
250
+ for (const line of table.split("\n")) {
251
+ if (!line.includes("*")) continue;
252
+ const m = /(\d+)\s*Mhz/i.exec(line);
253
+ if (m) return Number(m[1]);
254
+ }
255
+ return undefined;
256
+ }
257
+
258
+ export function pickDpmMax(table: string | undefined): number | undefined {
259
+ if (!table) return undefined;
260
+ let max: number | undefined;
261
+ for (const line of table.split("\n")) {
262
+ const m = /(\d+)\s*Mhz/i.exec(line);
263
+ if (m) max = Math.max(max ?? 0, Number(m[1]));
264
+ }
265
+ return max;
266
+ }
267
+
268
+ /** The card's own hwmon directory, e.g. `.../card0/device/hwmon/hwmon4`. */
269
+ function findHwmon(dir: string, fs: Pick<LinuxFs, "list">): string | undefined {
270
+ const base = `${dir}/device/hwmon`;
271
+ const entry = fs.list(base)?.find((n) => n.startsWith("hwmon"));
272
+ return entry ? `${base}/${entry}` : undefined;
273
+ }
274
+
275
+ function hwmonTempC(hwmon: string | undefined, fs: Pick<LinuxFs, "read">): number | undefined {
276
+ if (!hwmon) return undefined;
277
+ const milli = readNumber(fs, `${hwmon}/temp1_input`);
278
+ return milli === undefined ? undefined : Math.round(milli / 100) / 10;
279
+ }
280
+
281
+ /** amdgpu publishes microwatts. */
282
+ function hwmonPowerW(hwmon: string | undefined, fs: Pick<LinuxFs, "read">): number | undefined {
283
+ if (!hwmon) return undefined;
284
+ const uw = readNumber(fs, `${hwmon}/power1_average`) ?? readNumber(fs, `${hwmon}/power1_input`);
285
+ return uw === undefined ? undefined : Math.round(uw / 1000) / 1000;
286
+ }
287
+
288
+ /** RAPL's uncore domain is the integrated GPU's slice of the package budget —
289
+ * the only power figure an Intel iGPU has without root. */
290
+ export function readUncoreEnergy(fs: Pick<LinuxFs, "list" | "read">): number | undefined {
291
+ for (const pkg of fs.list(RAPL_DIR) ?? []) {
292
+ if (!/^intel-rapl:\d+$/.test(pkg)) continue;
293
+ for (const sub of fs.list(`${RAPL_DIR}/${pkg}`) ?? []) {
294
+ if (!sub.startsWith("intel-rapl:")) continue;
295
+ if (readAttr(fs, `${RAPL_DIR}/${pkg}/${sub}/name`) !== "uncore") continue;
296
+ const uj = readNumber(fs, `${RAPL_DIR}/${pkg}/${sub}/energy_uj`);
297
+ if (uj !== undefined) return uj;
298
+ }
299
+ }
300
+ return undefined;
301
+ }
302
+
303
+ function uncoreWatts(prev: GpuSample | null, next: GpuSample): number | undefined {
304
+ if (!prev || prev.uncoreUj === undefined || next.uncoreUj === undefined) return undefined;
305
+ const dt = next.atSec - prev.atSec;
306
+ const dj = next.uncoreUj - prev.uncoreUj;
307
+ if (!(dt > 0) || dj < 0) return undefined;
308
+ return Math.round(dj / dt / 1000) / 1000;
309
+ }
310
+
311
+ // ---------------------------------------------------------------- static
312
+
313
+ export function readGpuInfo(
314
+ card: GpuCard,
315
+ api: { opengl?: string; vulkan?: string; mesa?: string },
316
+ fs: Pick<LinuxFs, "list" | "read">,
317
+ ): GpuInfo {
318
+ const dir = `${DRM_DIR}/${card.card}`;
319
+ const link = pcieLink(dir, fs);
320
+ return {
321
+ id: card.pdev,
322
+ name: gpuName(card, fs),
323
+ ...defined("vendor", card.vendor),
324
+ ...defined("driver", card.driver || undefined),
325
+ ...defined("driverVersion", readAttr(fs, `/sys/module/${card.driver}/version`) ?? api.mesa),
326
+ ...defined("openglVersion", api.opengl),
327
+ ...defined("vulkanVersion", api.vulkan),
328
+ ...link,
329
+ ...(card.driver === "i915" || card.driver === "xe" ? { encodeDecodeShared: true } : {}),
330
+ };
331
+ }
332
+
333
+ /** The PCI database name udev already resolved, e.g. "Alder Lake-S GT1 [UHD
334
+ * Graphics 770]". Falls back to the driver, never to an empty string. */
335
+ export function gpuName(card: GpuCard, fs: Pick<LinuxFs, "read">): string {
336
+ const props = readUdevProperties(`+pci:${card.pdev}`, fs.read);
337
+ const fallback = [card.vendor, card.driver].filter(Boolean).join(" ");
338
+ return udevValue(props, "ID_MODEL_FROM_DATABASE") ?? (fallback || card.pdev);
339
+ }
340
+
341
+ /** Current and maximum link, with the maximum reported only when it DIFFERS —
342
+ * Mission Center hides an equal one, and an integrated GPU has no real link at
343
+ * all (its `current_link_speed` reads "Unknown" and its width 0). */
344
+ export function pcieLink(dir: string, fs: Pick<LinuxFs, "read">): Partial<GpuInfo> {
345
+ const gen = pcieGen(readAttr(fs, `${dir}/device/current_link_speed`));
346
+ const lanes = positive(readNumber(fs, `${dir}/device/current_link_width`));
347
+ const maxGen = pcieGen(readAttr(fs, `${dir}/device/max_link_speed`));
348
+ const maxLanes = positive(readNumber(fs, `${dir}/device/max_link_width`));
349
+ if (gen === undefined && lanes === undefined) return {};
350
+ return {
351
+ ...defined("pcieGen", gen),
352
+ ...defined("pcieLanes", lanes),
353
+ ...(maxGen !== undefined && maxGen !== gen ? { pcieMaxGen: maxGen } : {}),
354
+ ...(maxLanes !== undefined && maxLanes !== lanes ? { pcieMaxLanes: maxLanes } : {}),
355
+ };
356
+ }
357
+
358
+ export function pcieGen(speed: string | undefined): number | undefined {
359
+ const m = /^([\d.]+)\s*GT\/s/i.exec(speed?.trim() ?? "");
360
+ return m ? PCIE_GEN_BY_RATE[m[1]!] : undefined;
361
+ }
362
+
363
+ const basename = (p: string) => p.slice(p.lastIndexOf("/") + 1);
364
+ const round1 = (n: number) => Math.round(n * 10) / 10;
365
+ const positive = (n: number | undefined) => (n !== undefined && n > 0 ? n : undefined);
366
+ const bytesToMB = (n: number | undefined) => (n === undefined ? undefined : Math.round(n / 1024 ** 2));
367
+
368
+ function defined<K extends string, V>(key: K, value: V | undefined): Partial<Record<K, V>> {
369
+ return value === undefined ? {} : ({ [key]: value } as Record<K, V>);
370
+ }