@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.
- package/CHANGELOG.md +89 -0
- package/CLAUDE.md +21 -1
- package/Dockerfile.test +8 -1
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +30 -1
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js +1 -0
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.gz +0 -0
- package/dist/web/assets/{ai-resource-editor-DKcsVDle.js → ai-resource-editor-CY4n_Ccv.js} +1 -1
- package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js +1 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.br +0 -0
- package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-DDs11XV4.js +1 -0
- package/dist/web/assets/api-client-CJPnCOG-.js +1 -0
- package/dist/web/assets/{api-client-c8YOpTlT.js → api-client-D-SMbdiH.js} +1 -1
- package/dist/web/assets/api-client-D-SMbdiH.js.br +0 -0
- package/dist/web/assets/api-client-D-SMbdiH.js.gz +0 -0
- package/dist/web/assets/api-settings-BDkkhFMq.js +1 -0
- package/dist/web/assets/{api-settings-BmvNoCbn.js → api-settings-Bv9mLCty.js} +1 -1
- package/dist/web/assets/api-settings-Bv9mLCty.js.br +0 -0
- package/dist/web/assets/api-settings-Bv9mLCty.js.gz +0 -0
- package/dist/web/assets/{api-themes-6fOQJgM9.js → api-themes-3wW-zLzU.js} +1 -1
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js +1 -0
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.gz +0 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js +1 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js.br +0 -0
- package/dist/web/assets/apps-panel-DXAFsveZ.js.gz +0 -0
- package/dist/web/assets/{audio-preview-vaG2cB-k.js → audio-preview-BfES4Cx5.js} +1 -1
- package/dist/web/assets/audio-preview-BfES4Cx5.js.br +0 -0
- package/dist/web/assets/audio-preview-BfES4Cx5.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js +1 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js.br +0 -0
- package/dist/web/assets/branch-review-tab-CA8hPSX9.js.gz +0 -0
- package/dist/web/assets/{button-Ci9EUgqd.js → button-DeAyLH9U.js} +1 -1
- package/dist/web/assets/button-DeAyLH9U.js.br +0 -0
- package/dist/web/assets/button-DeAyLH9U.js.gz +0 -0
- package/dist/web/assets/{chat-preparation-cache-BSIQGiWx.js → chat-preparation-cache-CcCd2g7A.js} +1 -1
- package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.br +0 -0
- package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.gz +0 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js +1 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js.br +0 -0
- package/dist/web/assets/chat-tab-BWi_bUzA.js.gz +0 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js +15 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js.br +0 -0
- package/dist/web/assets/chat-tab-BvJhIaVE.js.gz +0 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js +7 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js.br +0 -0
- package/dist/web/assets/code-editor-OJUdLVnn.js.gz +0 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js +1 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.gz +0 -0
- package/dist/web/assets/{conflict-editor-qMGJH0Bx.js → conflict-editor-BpKW_vbL.js} +1 -1
- package/dist/web/assets/conflict-editor-BpKW_vbL.js.br +0 -0
- package/dist/web/assets/conflict-editor-BpKW_vbL.js.gz +0 -0
- package/dist/web/assets/context-menu-7OX80HDB.js +1 -0
- package/dist/web/assets/context-menu-7OX80HDB.js.br +0 -0
- package/dist/web/assets/context-menu-7OX80HDB.js.gz +0 -0
- package/dist/web/assets/{csv-preview-D2I742dl.js → csv-preview-COYdTABa.js} +1 -1
- package/dist/web/assets/csv-preview-COYdTABa.js.br +0 -0
- package/dist/web/assets/csv-preview-COYdTABa.js.gz +0 -0
- package/dist/web/assets/{data-grid-overlay-editor-CQRVKr7y.js → data-grid-overlay-editor-CeZoduke.js} +1 -1
- package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.br +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.gz +0 -0
- package/dist/web/assets/{database-viewer-Bz4LjgIa.js → database-viewer-BQcBqCKm.js} +1 -1
- package/dist/web/assets/database-viewer-BQcBqCKm.js.br +0 -0
- package/dist/web/assets/database-viewer-BQcBqCKm.js.gz +0 -0
- package/dist/web/assets/{design-export-client-ChMcMoqW.js → design-export-client-OrnGCSwu.js} +1 -1
- package/dist/web/assets/design-export-client-OrnGCSwu.js.br +0 -0
- package/dist/web/assets/design-export-client-OrnGCSwu.js.gz +0 -0
- package/dist/web/assets/{design-responsive-dialog-DNBhJJLf.js → design-responsive-dialog-vJjQrC4n.js} +1 -1
- package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.br +0 -0
- package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.gz +0 -0
- package/dist/web/assets/design-tab-BbmFk38H.js +33 -0
- package/dist/web/assets/design-tab-BbmFk38H.js.br +0 -0
- package/dist/web/assets/design-tab-BbmFk38H.js.gz +0 -0
- package/dist/web/assets/{designs-sidebar-panel-CapP1yXq.js → designs-sidebar-panel-D2kXwB8B.js} +1 -1
- package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.gz +0 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js +1 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js.br +0 -0
- package/dist/web/assets/dialog-Bocc0Fgb.js.gz +0 -0
- package/dist/web/assets/{diff-viewer-CdXi7cZN.js → diff-viewer-Bj4DT6Mj.js} +1 -1
- package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.br +0 -0
- package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.gz +0 -0
- package/dist/web/assets/{docx-preview-C9XdKEj1.js → docx-preview-C2QqNGRE.js} +1 -1
- package/dist/web/assets/docx-preview-C2QqNGRE.js.br +0 -0
- package/dist/web/assets/docx-preview-C2QqNGRE.js.gz +0 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js +1 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js.br +3 -0
- package/dist/web/assets/editor-language-service-COqB2tuv.js.gz +0 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js +2 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js.br +0 -0
- package/dist/web/assets/explorer-body-DGrYajDN.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js +1 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js.br +0 -0
- package/dist/web/assets/explorer-window-content-DLzkODTP.js.gz +0 -0
- package/dist/web/assets/{extension-manager-section-B2nZzJ2b.js → extension-manager-section-Bu0qcB2i.js} +1 -1
- package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.br +0 -0
- package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.gz +0 -0
- package/dist/web/assets/{extension-webview-BGoDxkdF.js → extension-webview-G_WJ0N52.js} +1 -1
- package/dist/web/assets/extension-webview-G_WJ0N52.js.br +0 -0
- package/dist/web/assets/extension-webview-G_WJ0N52.js.gz +0 -0
- package/dist/web/assets/{file-icons-gx_FBOXY.js → file-icons-l7fNOmdS.js} +1 -1
- package/dist/web/assets/file-icons-l7fNOmdS.js.br +0 -0
- package/dist/web/assets/file-icons-l7fNOmdS.js.gz +0 -0
- package/dist/web/assets/{file-store-D9KE0kQC.js → file-store-B0e7sLag.js} +1 -1
- package/dist/web/assets/file-store-B0e7sLag.js.br +0 -0
- package/dist/web/assets/file-store-B0e7sLag.js.gz +0 -0
- package/dist/web/assets/{files-settings-section-DC3OzzOl.js → files-settings-section-ChZ_CynX.js} +1 -1
- package/dist/web/assets/files-settings-section-ChZ_CynX.js.br +0 -0
- package/dist/web/assets/files-settings-section-ChZ_CynX.js.gz +0 -0
- package/dist/web/assets/format-bytes-__396eCN.js +1 -0
- package/dist/web/assets/{format-file-meta-mQwA6SuY.js → format-file-meta-o1XBuoKS.js} +1 -1
- package/dist/web/assets/format-file-meta-o1XBuoKS.js.br +0 -0
- package/dist/web/assets/format-file-meta-o1XBuoKS.js.gz +0 -0
- package/dist/web/assets/{fs-api-DL36slbd.js → fs-api-CeHKwx95.js} +1 -1
- package/dist/web/assets/fs-api-CeHKwx95.js.br +0 -0
- package/dist/web/assets/fs-api-CeHKwx95.js.gz +0 -0
- package/dist/web/assets/{general-settings-section-i41W43ER.js → general-settings-section-MSvDEbFa.js} +1 -1
- package/dist/web/assets/general-settings-section-MSvDEbFa.js.br +0 -0
- package/dist/web/assets/general-settings-section-MSvDEbFa.js.gz +0 -0
- package/dist/web/assets/{git-log-panel-DHzPIkJg.js → git-log-panel-gw5_a6j3.js} +1 -1
- package/dist/web/assets/git-log-panel-gw5_a6j3.js.br +0 -0
- package/dist/web/assets/git-log-panel-gw5_a6j3.js.gz +0 -0
- package/dist/web/assets/{git-repo-store-DSypNj19.js → git-repo-store-BpPnah5l.js} +1 -1
- package/dist/web/assets/git-repo-store-BpPnah5l.js.br +0 -0
- package/dist/web/assets/git-repo-store-BpPnah5l.js.gz +0 -0
- package/dist/web/assets/{glide-data-grid-Dj4vrDvj.js → glide-data-grid-Db2Cl26B.js} +5 -5
- package/dist/web/assets/glide-data-grid-Db2Cl26B.js.br +0 -0
- package/dist/web/assets/glide-data-grid-Db2Cl26B.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js +1 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js.br +0 -0
- package/dist/web/assets/group-chat-tab-B4etmYTR.js.gz +0 -0
- package/dist/web/assets/{image-preview-CGdZrmLo.js → image-preview-CjNhpfWw.js} +1 -1
- package/dist/web/assets/index-CtAvmybi.js +52 -0
- package/dist/web/assets/index-CtAvmybi.js.br +0 -0
- package/dist/web/assets/index-CtAvmybi.js.gz +0 -0
- package/dist/web/assets/index-DeCJasyy.css +1 -0
- package/dist/web/assets/index-DeCJasyy.css.br +0 -0
- package/dist/web/assets/index-DeCJasyy.css.gz +0 -0
- package/dist/web/assets/{jira-watcher-section-BJ9edGEP.js → jira-watcher-section-CKSI1Alo.js} +1 -1
- package/dist/web/assets/keybindings-store-C4_yyU4u.js +1 -0
- package/dist/web/assets/{keyboard-shortcuts-section-CxdGSNGr.js → keyboard-shortcuts-section-CEaVUc9a.js} +1 -1
- package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.gz +0 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js +2 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js.br +0 -0
- package/dist/web/assets/language-servers-section-ePtEpnDc.js.gz +0 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js +1 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js.br +0 -0
- package/dist/web/assets/lsp-client-XzmR3Brr.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-CTtDap-l.js +1 -0
- package/dist/web/assets/{markdown-renderer-ok96IgnS.js → markdown-renderer-D05fAr57.js} +2 -2
- package/dist/web/assets/markdown-renderer-D05fAr57.js.br +0 -0
- package/dist/web/assets/markdown-renderer-D05fAr57.js.gz +0 -0
- package/dist/web/assets/{media-url-CzUJrREv.js → media-url-C6NumuN5.js} +1 -1
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js +1 -0
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.br +0 -0
- package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.gz +0 -0
- package/dist/web/assets/{mobile-bottom-sheet-CuNi2FRv.js → mobile-bottom-sheet-D4UyOatB.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.br +0 -0
- package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.gz +0 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.gz +0 -0
- package/dist/web/assets/{new-design-dialog-Drkjb_LI.js → new-design-dialog-BgmQopJM.js} +1 -1
- package/dist/web/assets/new-design-dialog-BgmQopJM.js.br +0 -0
- package/dist/web/assets/new-design-dialog-BgmQopJM.js.gz +0 -0
- package/dist/web/assets/notification-store-q5QBklKA.js +1 -0
- package/dist/web/assets/{notifications-settings-section-C05WYqcE.js → notifications-settings-section-BBJ0r9OS.js} +1 -1
- package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.br +0 -0
- package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.gz +0 -0
- package/dist/web/assets/{onboarding-entry-CmUqv1kl.js → onboarding-entry-BYOYswsi.js} +1 -1
- package/dist/web/assets/onboarding-entry-BYOYswsi.js.br +0 -0
- package/dist/web/assets/onboarding-entry-BYOYswsi.js.gz +0 -0
- package/dist/web/assets/{onboarding-quick-orientation-DIhWv1CN.js → onboarding-quick-orientation-DPHYFMbA.js} +1 -1
- package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.br +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.gz +0 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js +1 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js.br +0 -0
- package/dist/web/assets/overview-panel-pkPs44Tv.js.gz +0 -0
- package/dist/web/assets/{pdf-preview-qdXmMkOR.js → pdf-preview-c-L_kDAs.js} +1 -1
- package/dist/web/assets/pdf-preview-c-L_kDAs.js.br +0 -0
- package/dist/web/assets/pdf-preview-c-L_kDAs.js.gz +0 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js +3 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js.br +0 -0
- package/dist/web/assets/performance-panel-yPrq0DJV.js.gz +0 -0
- package/dist/web/assets/{postgres-viewer-Xvlun_n5.js → postgres-viewer-CnwDCMNd.js} +1 -1
- package/dist/web/assets/postgres-viewer-CnwDCMNd.js.br +0 -0
- package/dist/web/assets/postgres-viewer-CnwDCMNd.js.gz +0 -0
- package/dist/web/assets/{ppmbot-settings-section-C8PFlvaq.js → ppmbot-settings-section-BDXoSIDp.js} +1 -1
- package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.gz +0 -0
- package/dist/web/assets/{pptx-export-CG6MRNok.js → pptx-export-D0RDY48h.js} +4 -4
- package/dist/web/assets/pptx-export-D0RDY48h.js.br +0 -0
- package/dist/web/assets/pptx-export-D0RDY48h.js.gz +0 -0
- package/dist/web/assets/{problems-panel-CFYO0Ro3.js → problems-panel-BgY8oyo9.js} +1 -1
- package/dist/web/assets/problems-panel-BgY8oyo9.js.br +0 -0
- package/dist/web/assets/problems-panel-BgY8oyo9.js.gz +0 -0
- package/dist/web/assets/process-row-format-CaaMcHzn.js +1 -0
- package/dist/web/assets/process-table-BOwDtXuG.js +1 -0
- package/dist/web/assets/process-table-BOwDtXuG.js.br +0 -0
- package/dist/web/assets/process-table-BOwDtXuG.js.gz +0 -0
- package/dist/web/assets/{project-framework-store-XxFXcUpb.js → project-framework-store-UDEMu28U.js} +1 -1
- package/dist/web/assets/{project-store-C5gJXkvb.js → project-store-DGa31y5B.js} +1 -1
- package/dist/web/assets/project-store-DGa31y5B.js.br +0 -0
- package/dist/web/assets/project-store-DGa31y5B.js.gz +0 -0
- package/dist/web/assets/{proxy-settings-section-BcHIEANE.js → proxy-settings-section-Db6Kc6xG.js} +1 -1
- package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.gz +0 -0
- package/dist/web/assets/{query-audit-section-UKG_smyt.js → query-audit-section-C0PAXhfT.js} +1 -1
- package/dist/web/assets/query-audit-section-C0PAXhfT.js.br +0 -0
- package/dist/web/assets/query-audit-section-C0PAXhfT.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-clipboard-notice-BGsp0edA.js → remote-desktop-clipboard-notice-DOVtobj_.js} +1 -1
- package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js +1 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-readiness-gate-CsZCCRJI.js → remote-desktop-readiness-gate-BsfoJzdc.js} +1 -1
- package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.gz +0 -0
- package/dist/web/assets/{schedules-settings-section-Ci0O2Ng6.js → schedules-settings-section-CvbjQM8z.js} +1 -1
- package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.gz +0 -0
- package/dist/web/assets/{scroll-area-XonvWYn_.js → scroll-area-sjOeAfoD.js} +1 -1
- package/dist/web/assets/scroll-area-sjOeAfoD.js.br +0 -0
- package/dist/web/assets/scroll-area-sjOeAfoD.js.gz +0 -0
- package/dist/web/assets/{separator-sQj04Ari.js → separator-9A3PCG1t.js} +1 -1
- package/dist/web/assets/services-panel-CimW47P8.js +1 -0
- package/dist/web/assets/services-panel-CimW47P8.js.br +0 -0
- package/dist/web/assets/services-panel-CimW47P8.js.gz +0 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js +2 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js.br +0 -0
- package/dist/web/assets/settings-body-BTXNtpWL.js.gz +0 -0
- package/dist/web/assets/settings-store-DvftLqzy.js +2 -0
- package/dist/web/assets/settings-store-DvftLqzy.js.br +0 -0
- package/dist/web/assets/settings-store-DvftLqzy.js.gz +0 -0
- package/dist/web/assets/settings-tab-CGhaRXjs.js +1 -0
- package/dist/web/assets/settings-window-content--Uyg_Psr.js +1 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js +1 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js.br +0 -0
- package/dist/web/assets/sortable-header-DUW9T1Hz.js.gz +0 -0
- package/dist/web/assets/{sql-query-editor-4iCGE4h2.js → sql-query-editor-Dn-cgDrW.js} +1 -1
- package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.br +0 -0
- package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.gz +0 -0
- package/dist/web/assets/{sqlite-viewer-CK6DulYk.js → sqlite-viewer-B0NfaMjq.js} +1 -1
- package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js +2 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js.br +0 -0
- package/dist/web/assets/system-monitor-body-CxCfRQFb.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-Cb3EZUdp.js +1 -0
- package/dist/web/assets/system-monitor-window-content-51CA-2PH.js +1 -0
- package/dist/web/assets/{tab-host-window-content-CWBaWKjA.js → tab-host-window-content-CSrcmKNG.js} +1 -1
- package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.gz +0 -0
- package/dist/web/assets/{team-member-sheet-Br6mrxrw.js → team-member-sheet-D4X6nh-x.js} +2 -2
- package/dist/web/assets/team-member-sheet-D4X6nh-x.js.br +0 -0
- package/dist/web/assets/team-member-sheet-D4X6nh-x.js.gz +0 -0
- package/dist/web/assets/{team-member-window-content-CwCy7ZWf.js → team-member-window-content-BxkbGVIL.js} +1 -1
- package/dist/web/assets/team-member-window-content-BxkbGVIL.js.br +0 -0
- package/dist/web/assets/team-member-window-content-BxkbGVIL.js.gz +0 -0
- package/dist/web/assets/{terminal-tab-BW14RpCb.js → terminal-tab-BYo34IqU.js} +3 -3
- package/dist/web/assets/terminal-tab-BYo34IqU.js.br +0 -0
- package/dist/web/assets/terminal-tab-BYo34IqU.js.gz +0 -0
- package/dist/web/assets/{tool-cards-CgOBEUnb.js → tool-cards-DvXjOped.js} +4 -4
- package/dist/web/assets/tool-cards-DvXjOped.js.br +0 -0
- package/dist/web/assets/tool-cards-DvXjOped.js.gz +0 -0
- package/dist/web/assets/{use-blob-url-CmavyEP8.js → use-blob-url-CISBWKG5.js} +1 -1
- package/dist/web/assets/use-inline-blame-Br6mheS4.js +16 -0
- package/dist/web/assets/use-inline-blame-Br6mheS4.js.br +0 -0
- package/dist/web/assets/use-inline-blame-Br6mheS4.js.gz +0 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js +6 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js.br +0 -0
- package/dist/web/assets/use-lsp-BpJmvQ0n.js.gz +0 -0
- package/dist/web/assets/{use-monaco-theme-rH6epJYA.js → use-monaco-theme-UGOzyIhv.js} +1 -1
- package/dist/web/assets/use-process-kill-CyiiUD1E.js +1 -0
- package/dist/web/assets/use-process-kill-CyiiUD1E.js.br +0 -0
- package/dist/web/assets/use-process-kill-CyiiUD1E.js.gz +0 -0
- package/dist/web/assets/{use-websocket-QwURkjpV.js → use-websocket-Dpl21cHG.js} +1 -1
- package/dist/web/assets/{vendor-ui-BHh12_0v.js → vendor-ui-P9Ym7hCv.js} +1 -1
- package/dist/web/assets/vendor-ui-P9Ym7hCv.js.br +0 -0
- package/dist/web/assets/vendor-ui-P9Ym7hCv.js.gz +0 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js +1 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js.br +0 -0
- package/dist/web/assets/video-preview-D6Jw-IZK.js.gz +0 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js +1 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js.br +0 -0
- package/dist/web/assets/voice-settings-section-CcHQDYzN.js.gz +0 -0
- package/dist/web/assets/ws-auth-CqI8-aoA.js +1 -0
- package/dist/web/index.html +20 -20
- package/dist/web/index.html.br +0 -0
- package/dist/web/index.html.gz +0 -0
- package/dist/web/sw.js +1 -1
- package/dist/web/sw.js.br +0 -0
- package/dist/web/sw.js.gz +0 -0
- package/docs/deployment-guide.md +23 -0
- package/package.json +1 -1
- package/release-from-worktree.sh +224 -0
- package/src/cli/commands/config-cmd.ts +12 -0
- package/src/providers/claude-agent-sdk.ts +65 -2
- package/src/providers/codex-app-server/codex-jsonrpc-client.ts +16 -1
- package/src/providers/codex-app-server/codex-provider.ts +39 -7
- package/src/providers/codex-app-server/codex-reset-credit.ts +49 -0
- package/src/providers/provider-probe.ts +63 -0
- package/src/providers/registry.ts +109 -29
- package/src/server/index.ts +9 -0
- package/src/server/middleware/auth.ts +5 -1
- package/src/server/routes/codex-accounts.ts +14 -0
- package/src/server/routes/cross-origin-guard.ts +20 -0
- package/src/server/routes/git.ts +40 -4
- package/src/server/routes/lsp.ts +97 -4
- package/src/server/routes/resources.ts +72 -9
- package/src/server/routes/settings.ts +19 -1
- package/src/server/routes/speech.ts +66 -0
- package/src/server/routes/system-services.ts +76 -0
- package/src/server/routes/tunnel.ts +33 -1
- package/src/server/ws/chat.ts +74 -3
- package/src/services/codex-account-login.ts +26 -2
- package/src/services/codex-reset-credit.service.ts +83 -0
- package/src/services/compaction-savings.ts +127 -0
- package/src/services/db.service.ts +123 -8
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/fs-ops/fs-ops-trash.service.ts +22 -9
- package/src/services/git-refs/for-each-ref.ts +118 -0
- package/src/services/git.service.ts +25 -2
- package/src/services/host-info/spawn-runner.ts +48 -4
- package/src/services/jsonl-transcript-parser.ts +7 -42
- package/src/services/lsp/lsp-install.ts +289 -0
- package/src/services/lsp/lsp-manager.ts +160 -29
- package/src/services/lsp/server-registry.ts +120 -4
- package/src/services/named-tunnel/named-tunnel-config.ts +8 -2
- package/src/services/named-tunnel/named-tunnel-setup.service.ts +4 -0
- package/src/services/read-lines.ts +54 -0
- package/src/services/speech-to-text/whisper-catalog.ts +142 -0
- package/src/services/speech-to-text/whisper-download.ts +113 -0
- package/src/services/speech-to-text/whisper-hallucinations.ts +51 -0
- package/src/services/speech-to-text/whisper-install.service.ts +247 -0
- package/src/services/speech-to-text/whisper-paths.ts +62 -0
- package/src/services/speech-to-text/whisper-transcribe.service.ts +117 -0
- package/src/services/supervisor.ts +94 -11
- package/src/services/system-metrics/cpu-details-linux.ts +252 -0
- package/src/services/system-metrics/cpu-memory-collector.ts +140 -18
- package/src/services/system-metrics/device-collector-linux.ts +31 -0
- package/src/services/system-metrics/device-collector-types.ts +40 -0
- package/src/services/system-metrics/disk-devices-linux.ts +156 -0
- package/src/services/system-metrics/disk-inventory-linux.ts +150 -0
- package/src/services/system-metrics/fans-linux.ts +51 -0
- package/src/services/system-metrics/gpu-api-versions.ts +120 -0
- package/src/services/system-metrics/gpu-devices-linux.ts +370 -0
- package/src/services/system-metrics/gpu-fdinfo-linux.ts +253 -0
- package/src/services/system-metrics/hardware-inventory.ts +50 -0
- package/src/services/system-metrics/linux-fs.ts +43 -0
- package/src/services/system-metrics/memory-darwin.ts +91 -0
- package/src/services/system-metrics/memory-linux.ts +156 -0
- package/src/services/system-metrics/net-devices-linux.ts +114 -0
- package/src/services/system-metrics/net-inventory-linux.ts +100 -0
- package/src/services/system-metrics/partitions-linux.ts +158 -0
- package/src/services/system-metrics/process-collector-linux.ts +58 -6
- package/src/services/system-metrics/process-collector-types.ts +8 -1
- package/src/services/system-metrics/process-details-darwin.ts +166 -0
- package/src/services/system-metrics/process-details-linux.ts +150 -0
- package/src/services/system-metrics/process-grouping.ts +2 -1
- package/src/services/system-metrics/process-rows-builder.ts +2 -0
- package/src/services/system-metrics/process-swap-linux.ts +37 -0
- package/src/services/system-metrics/signal-executor.ts +84 -0
- package/src/services/system-metrics/signal-request-handler.ts +92 -0
- package/src/services/system-metrics/system-metrics-platform.ts +30 -4
- package/src/services/system-metrics/system-metrics-tick.ts +73 -4
- package/src/services/system-metrics/system-metrics.service.ts +87 -2
- package/src/services/system-metrics/udev-db.ts +40 -0
- package/src/services/system-services/app-cgroup-linux.ts +115 -0
- package/src/services/system-services/app-icon-service.ts +31 -0
- package/src/services/system-services/app-icons-linux.ts +124 -0
- package/src/services/system-services/apps-linux.ts +174 -0
- package/src/services/system-services/desktop-entry.ts +103 -0
- package/src/services/system-services/service-guard.ts +124 -0
- package/src/services/system-services/systemd-collector.ts +203 -0
- package/src/services/system-services/systemd-parse.ts +162 -0
- package/src/services/windows-process-tree.ts +351 -351
- package/src/shared/prompt-cache-idle.ts +197 -0
- package/src/shared/turn-usage.ts +85 -1
- package/src/shared/usage-extra.ts +19 -0
- package/src/types/chat.ts +29 -0
- package/src/types/config.ts +14 -0
- package/src/types/git.ts +41 -0
- package/src/types/system-hardware.ts +137 -0
- package/src/types/system-metrics.ts +231 -2
- package/src/types/system-services.ts +73 -0
- package/src/web/components/branch-review/branch-review-tab.tsx +20 -20
- package/src/web/components/branch-review/branch-review-tree-row.tsx +1 -13
- package/src/web/components/chat/chat-tab.tsx +3 -0
- package/src/web/components/chat/codex-usage-panel.tsx +4 -0
- package/src/web/components/chat/compaction-divider.tsx +48 -0
- package/src/web/components/chat/idle-cache-notice.tsx +67 -0
- package/src/web/components/chat/message-input.tsx +48 -13
- package/src/web/components/chat/message-list.tsx +15 -0
- package/src/web/components/chat/prompt-cache-chip.tsx +74 -0
- package/src/web/components/editor/code-editor.tsx +1 -0
- package/src/web/components/editor/editor-language-service.tsx +11 -3
- package/src/web/components/editor/lsp-status.tsx +115 -13
- package/src/web/components/git/branch-picker.tsx +419 -0
- package/src/web/components/git/branch-select.tsx +34 -0
- package/src/web/components/git/create-worktree-dialog.tsx +17 -16
- package/src/web/components/git/git-repo-picker.tsx +28 -40
- package/src/web/components/layout/status-bar.tsx +42 -19
- package/src/web/components/settings/accounts/account-card.tsx +10 -2
- package/src/web/components/settings/accounts/account-usage-extras.tsx +3 -2
- package/src/web/components/settings/accounts/codex-accounts-section.tsx +3 -1
- package/src/web/components/settings/accounts/codex-reset-credit-button.tsx +120 -0
- package/src/web/components/settings/ai-settings-section.tsx +67 -3
- package/src/web/components/settings/appearance-settings-section.tsx +2 -28
- package/src/web/components/settings/language-servers-section.tsx +362 -0
- package/src/web/components/settings/settings-categories.ts +8 -3
- package/src/web/components/settings/settings-section-content.tsx +2 -0
- package/src/web/components/settings/voice-settings-section.tsx +283 -0
- package/src/web/components/system/apps/app-row.tsx +110 -0
- package/src/web/components/system/apps/app-rows.ts +140 -0
- package/src/web/components/system/apps/apps-panel.tsx +129 -0
- package/src/web/components/system/metric-chart-canvas.tsx +79 -3
- package/src/web/components/system/overview-cards/card-shell.tsx +54 -0
- package/src/web/components/system/overview-cards/cpu-card.tsx +11 -6
- package/src/web/components/system/overview-cards/disk-card.tsx +11 -6
- package/src/web/components/system/overview-cards/gpu-card.tsx +16 -6
- package/src/web/components/system/overview-cards/mem-card.tsx +11 -6
- package/src/web/components/system/overview-cards/net-card.tsx +11 -6
- package/src/web/components/system/overview-device-target.ts +69 -0
- package/src/web/components/system/overview-panel.tsx +15 -1
- package/src/web/components/system/performance/cpu-core-grid.tsx +74 -0
- package/src/web/components/system/performance/cpu-detail.tsx +220 -0
- package/src/web/components/system/performance/detail-parts.tsx +149 -0
- package/src/web/components/system/performance/device-list.ts +139 -0
- package/src/web/components/system/performance/disk-detail.tsx +64 -0
- package/src/web/components/system/performance/fans-detail.tsx +35 -0
- package/src/web/components/system/performance/gpu-detail.tsx +116 -0
- package/src/web/components/system/performance/memory-detail.tsx +109 -0
- package/src/web/components/system/performance/nic-detail.tsx +55 -0
- package/src/web/components/system/performance/partition-list.tsx +79 -0
- package/src/web/components/system/performance/performance-panel.tsx +206 -0
- package/src/web/components/system/performance/use-hardware-inventory.ts +48 -0
- package/src/web/components/system/process-columns-grid.ts +5 -3
- package/src/web/components/system/process-details-dialog.tsx +116 -0
- package/src/web/components/system/process-group-row.tsx +6 -1
- package/src/web/components/system/process-row-format.ts +6 -0
- package/src/web/components/system/process-row-menu.tsx +72 -0
- package/src/web/components/system/process-row.tsx +7 -1
- package/src/web/components/system/process-table-model.ts +1 -1
- package/src/web/components/system/process-table-sort.ts +8 -4
- package/src/web/components/system/process-table-toolbar.tsx +10 -2
- package/src/web/components/system/process-table-totals.ts +3 -0
- package/src/web/components/system/process-table.tsx +25 -2
- package/src/web/components/system/services/service-action-confirm.tsx +100 -0
- package/src/web/components/system/services/service-columns.ts +103 -0
- package/src/web/components/system/services/service-details-sheet.tsx +97 -0
- package/src/web/components/system/services/service-resources.ts +105 -0
- package/src/web/components/system/services/service-row.tsx +146 -0
- package/src/web/components/system/services/service-rows.ts +92 -0
- package/src/web/components/system/services/service-sort.ts +90 -0
- package/src/web/components/system/services/services-header.tsx +51 -0
- package/src/web/components/system/services/services-panel.tsx +207 -0
- package/src/web/components/system/services/use-services.ts +92 -0
- package/src/web/components/system/sortable-header.tsx +13 -8
- package/src/web/components/system/sysmon-preferences.tsx +85 -0
- package/src/web/components/system/system-monitor-body.tsx +101 -43
- package/src/web/components/system/system-monitor-window-content.tsx +2 -3
- package/src/web/components/system/use-process-signal.ts +87 -0
- package/src/web/components/tunnels/public-tunnel-switch.tsx +82 -0
- package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
- package/src/web/components/ui/dialog.tsx +14 -1
- package/src/web/components/ui/search-select.tsx +279 -0
- package/src/web/components/ui/start-ellipsis.tsx +18 -0
- package/src/web/hooks/use-chat.ts +28 -0
- package/src/web/hooks/use-global-keybindings.ts +7 -5
- package/src/web/hooks/use-lsp.ts +23 -2
- package/src/web/hooks/use-minute-clock.ts +20 -0
- package/src/web/hooks/use-whisper-voice-input.ts +113 -0
- package/src/web/lib/api-tunnels.ts +19 -0
- package/src/web/lib/branch-select-items.ts +29 -0
- package/src/web/lib/cpu-graph-mode.ts +90 -0
- package/src/web/lib/format-bytes.ts +14 -0
- package/src/web/lib/git-ref-picker.ts +120 -0
- package/src/web/lib/lsp/lsp-client.ts +32 -0
- package/src/web/lib/search-select-rows.ts +55 -0
- package/src/web/lib/temperature.ts +27 -0
- package/src/web/lib/voice-wav.ts +69 -0
- package/src/web/stores/git-status-store.ts +31 -17
- package/src/web/stores/keybindings-store.ts +14 -1
- package/src/web/stores/settings-store.ts +65 -0
- package/src/web/styles/globals.css +11 -0
- package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js +0 -1
- package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-CgG5P3Jm.js.gz +0 -0
- package/dist/web/assets/ai-resource-editor-DKcsVDle.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-DKcsVDle.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-D7zJ-hCO.js +0 -1
- package/dist/web/assets/ai-settings-section-D7zJ-hCO.js.br +0 -0
- package/dist/web/assets/ai-settings-section-D7zJ-hCO.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-OPqC2bYG.js +0 -1
- package/dist/web/assets/api-client-BgedDTvo.js +0 -1
- package/dist/web/assets/api-client-c8YOpTlT.js.br +0 -0
- package/dist/web/assets/api-client-c8YOpTlT.js.gz +0 -0
- package/dist/web/assets/api-settings-BmvNoCbn.js.br +0 -0
- package/dist/web/assets/api-settings-BmvNoCbn.js.gz +0 -0
- package/dist/web/assets/api-settings-Bti1-Zn3.js +0 -1
- package/dist/web/assets/appearance-settings-section-DL466x83.js +0 -1
- package/dist/web/assets/appearance-settings-section-DL466x83.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-DL466x83.js.gz +0 -0
- package/dist/web/assets/audio-preview-vaG2cB-k.js.br +0 -0
- package/dist/web/assets/audio-preview-vaG2cB-k.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-Dag86n_R.js +0 -1
- package/dist/web/assets/branch-review-tab-Dag86n_R.js.br +0 -0
- package/dist/web/assets/branch-review-tab-Dag86n_R.js.gz +0 -0
- package/dist/web/assets/button-Ci9EUgqd.js.br +0 -0
- package/dist/web/assets/button-Ci9EUgqd.js.gz +0 -0
- package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.br +0 -0
- package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.gz +0 -0
- package/dist/web/assets/chat-tab-CcYZLXls.js +0 -15
- package/dist/web/assets/chat-tab-CcYZLXls.js.br +0 -0
- package/dist/web/assets/chat-tab-CcYZLXls.js.gz +0 -0
- package/dist/web/assets/chat-tab-QFDhzzBZ.js +0 -1
- package/dist/web/assets/chat-tab-QFDhzzBZ.js.br +0 -0
- package/dist/web/assets/chat-tab-QFDhzzBZ.js.gz +0 -0
- package/dist/web/assets/code-editor-K-IN8VwJ.js +0 -7
- package/dist/web/assets/code-editor-K-IN8VwJ.js.br +0 -0
- package/dist/web/assets/code-editor-K-IN8VwJ.js.gz +0 -0
- package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js +0 -1
- package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js.br +0 -0
- package/dist/web/assets/codex-sign-in-again-dialog-C8JvblLG.js.gz +0 -0
- package/dist/web/assets/conflict-editor-qMGJH0Bx.js.br +0 -0
- package/dist/web/assets/conflict-editor-qMGJH0Bx.js.gz +0 -0
- package/dist/web/assets/context-menu-CjYTq8DI.js +0 -1
- package/dist/web/assets/context-menu-CjYTq8DI.js.br +0 -0
- package/dist/web/assets/context-menu-CjYTq8DI.js.gz +0 -0
- package/dist/web/assets/csv-preview-D2I742dl.js.br +0 -0
- package/dist/web/assets/csv-preview-D2I742dl.js.gz +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.br +0 -0
- package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.gz +0 -0
- package/dist/web/assets/database-viewer-Bz4LjgIa.js.br +0 -0
- package/dist/web/assets/database-viewer-Bz4LjgIa.js.gz +0 -0
- package/dist/web/assets/design-export-client-ChMcMoqW.js.br +0 -0
- package/dist/web/assets/design-export-client-ChMcMoqW.js.gz +0 -0
- package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.br +0 -0
- package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.gz +0 -0
- package/dist/web/assets/design-tab-C987MtMR.js +0 -33
- package/dist/web/assets/design-tab-C987MtMR.js.br +0 -0
- package/dist/web/assets/design-tab-C987MtMR.js.gz +0 -0
- package/dist/web/assets/designs-sidebar-panel-CapP1yXq.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-CapP1yXq.js.gz +0 -0
- package/dist/web/assets/dialog-B8clVkyi.js +0 -1
- package/dist/web/assets/dialog-B8clVkyi.js.br +0 -0
- package/dist/web/assets/dialog-B8clVkyi.js.gz +0 -0
- package/dist/web/assets/diff-viewer-CdXi7cZN.js.br +0 -0
- package/dist/web/assets/diff-viewer-CdXi7cZN.js.gz +0 -0
- package/dist/web/assets/docx-preview-C9XdKEj1.js.br +0 -0
- package/dist/web/assets/docx-preview-C9XdKEj1.js.gz +0 -0
- package/dist/web/assets/editor-language-service-Zle_PZV8.js +0 -1
- package/dist/web/assets/editor-language-service-Zle_PZV8.js.br +0 -0
- package/dist/web/assets/editor-language-service-Zle_PZV8.js.gz +0 -0
- package/dist/web/assets/explorer-body-DHMQR1Rk.js +0 -2
- package/dist/web/assets/explorer-body-DHMQR1Rk.js.br +0 -0
- package/dist/web/assets/explorer-body-DHMQR1Rk.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-Df40nQBk.js +0 -1
- package/dist/web/assets/explorer-window-content-Df40nQBk.js.br +0 -0
- package/dist/web/assets/explorer-window-content-Df40nQBk.js.gz +0 -0
- package/dist/web/assets/extension-manager-section-B2nZzJ2b.js.br +0 -0
- package/dist/web/assets/extension-manager-section-B2nZzJ2b.js.gz +0 -0
- package/dist/web/assets/extension-webview-BGoDxkdF.js.br +0 -0
- package/dist/web/assets/extension-webview-BGoDxkdF.js.gz +0 -0
- package/dist/web/assets/file-icons-gx_FBOXY.js.br +0 -0
- package/dist/web/assets/file-icons-gx_FBOXY.js.gz +0 -0
- package/dist/web/assets/file-store-D9KE0kQC.js.br +0 -0
- package/dist/web/assets/file-store-D9KE0kQC.js.gz +0 -0
- package/dist/web/assets/files-settings-section-DC3OzzOl.js.br +0 -0
- package/dist/web/assets/files-settings-section-DC3OzzOl.js.gz +0 -0
- package/dist/web/assets/format-bytes-DmSHAKFe.js +0 -1
- package/dist/web/assets/format-file-meta-mQwA6SuY.js.br +0 -0
- package/dist/web/assets/format-file-meta-mQwA6SuY.js.gz +0 -0
- package/dist/web/assets/fs-api-DL36slbd.js.br +0 -0
- package/dist/web/assets/fs-api-DL36slbd.js.gz +0 -0
- package/dist/web/assets/general-settings-section-i41W43ER.js.br +0 -0
- package/dist/web/assets/general-settings-section-i41W43ER.js.gz +0 -0
- package/dist/web/assets/git-log-panel-DHzPIkJg.js.br +0 -0
- package/dist/web/assets/git-log-panel-DHzPIkJg.js.gz +0 -0
- package/dist/web/assets/git-repo-store-DSypNj19.js.br +0 -0
- package/dist/web/assets/git-repo-store-DSypNj19.js.gz +0 -0
- package/dist/web/assets/glide-data-grid-Dj4vrDvj.js.br +0 -0
- package/dist/web/assets/glide-data-grid-Dj4vrDvj.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-DfwZb-fI.js +0 -1
- package/dist/web/assets/group-chat-tab-DfwZb-fI.js.br +0 -0
- package/dist/web/assets/group-chat-tab-DfwZb-fI.js.gz +0 -0
- package/dist/web/assets/index-DMA-So69.css +0 -1
- package/dist/web/assets/index-DMA-So69.css.br +0 -0
- package/dist/web/assets/index-DMA-So69.css.gz +0 -0
- package/dist/web/assets/index-jG9mLs-J.js +0 -52
- package/dist/web/assets/index-jG9mLs-J.js.br +0 -0
- package/dist/web/assets/index-jG9mLs-J.js.gz +0 -0
- package/dist/web/assets/keybindings-store-BlapkC6O.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-CxdGSNGr.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-CxdGSNGr.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-DJ9EVU1B.js +0 -1
- package/dist/web/assets/markdown-renderer-ok96IgnS.js.br +0 -0
- package/dist/web/assets/markdown-renderer-ok96IgnS.js.gz +0 -0
- package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.br +0 -0
- package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.gz +0 -0
- package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-Cc03LUKy.js.gz +0 -0
- package/dist/web/assets/new-design-dialog-Drkjb_LI.js.br +0 -0
- package/dist/web/assets/new-design-dialog-Drkjb_LI.js.gz +0 -0
- package/dist/web/assets/notification-store-DCyxho0O.js +0 -1
- package/dist/web/assets/notifications-settings-section-C05WYqcE.js.br +0 -0
- package/dist/web/assets/notifications-settings-section-C05WYqcE.js.gz +0 -0
- package/dist/web/assets/onboarding-entry-CmUqv1kl.js.br +0 -0
- package/dist/web/assets/onboarding-entry-CmUqv1kl.js.gz +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.br +0 -0
- package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.gz +0 -0
- package/dist/web/assets/overview-panel-BZAW_nag.js +0 -1
- package/dist/web/assets/overview-panel-BZAW_nag.js.br +0 -0
- package/dist/web/assets/overview-panel-BZAW_nag.js.gz +0 -0
- package/dist/web/assets/pdf-preview-qdXmMkOR.js.br +0 -0
- package/dist/web/assets/pdf-preview-qdXmMkOR.js.gz +0 -0
- package/dist/web/assets/postgres-viewer-Xvlun_n5.js.br +0 -0
- package/dist/web/assets/postgres-viewer-Xvlun_n5.js.gz +0 -0
- package/dist/web/assets/ppmbot-settings-section-C8PFlvaq.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-C8PFlvaq.js.gz +0 -0
- package/dist/web/assets/pptx-export-CG6MRNok.js.br +0 -0
- package/dist/web/assets/pptx-export-CG6MRNok.js.gz +0 -0
- package/dist/web/assets/problems-panel-CFYO0Ro3.js.br +0 -0
- package/dist/web/assets/problems-panel-CFYO0Ro3.js.gz +0 -0
- package/dist/web/assets/process-table-BVeRguFg.js +0 -1
- package/dist/web/assets/process-table-BVeRguFg.js.br +0 -0
- package/dist/web/assets/process-table-BVeRguFg.js.gz +0 -0
- package/dist/web/assets/project-store-C5gJXkvb.js.br +0 -0
- package/dist/web/assets/project-store-C5gJXkvb.js.gz +0 -0
- package/dist/web/assets/proxy-settings-section-BcHIEANE.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-BcHIEANE.js.gz +0 -0
- package/dist/web/assets/query-audit-section-UKG_smyt.js.br +0 -0
- package/dist/web/assets/query-audit-section-UKG_smyt.js.gz +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-BGsp0edA.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-BGsp0edA.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DxkmF8qb.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DMD0M9Jh.js.gz +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-CsZCCRJI.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-CsZCCRJI.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-DrHw_vwY.js.gz +0 -0
- package/dist/web/assets/schedules-settings-section-Ci0O2Ng6.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-Ci0O2Ng6.js.gz +0 -0
- package/dist/web/assets/scroll-area-XonvWYn_.js.br +0 -0
- package/dist/web/assets/scroll-area-XonvWYn_.js.gz +0 -0
- package/dist/web/assets/settings-body-B6JGOIYb.js +0 -2
- package/dist/web/assets/settings-body-B6JGOIYb.js.br +0 -0
- package/dist/web/assets/settings-body-B6JGOIYb.js.gz +0 -0
- package/dist/web/assets/settings-store-Br5c1efC.js +0 -2
- package/dist/web/assets/settings-store-Br5c1efC.js.br +0 -0
- package/dist/web/assets/settings-store-Br5c1efC.js.gz +0 -0
- package/dist/web/assets/settings-tab-CIQM4fNE.js +0 -1
- package/dist/web/assets/settings-window-content-BGNNz-E5.js +0 -1
- package/dist/web/assets/sql-query-editor-4iCGE4h2.js.br +0 -3
- package/dist/web/assets/sql-query-editor-4iCGE4h2.js.gz +0 -0
- package/dist/web/assets/sqlite-viewer-CK6DulYk.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-CK6DulYk.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-J9JtvAWV.js +0 -2
- package/dist/web/assets/system-monitor-body-J9JtvAWV.js.br +0 -0
- package/dist/web/assets/system-monitor-body-J9JtvAWV.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-DjBeRE81.js +0 -1
- package/dist/web/assets/system-monitor-window-content-BT7-ugFx.js +0 -1
- package/dist/web/assets/tab-host-window-content-CWBaWKjA.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-CWBaWKjA.js.gz +0 -0
- package/dist/web/assets/team-member-sheet-Br6mrxrw.js.br +0 -0
- package/dist/web/assets/team-member-sheet-Br6mrxrw.js.gz +0 -0
- package/dist/web/assets/team-member-window-content-CwCy7ZWf.js.br +0 -0
- package/dist/web/assets/team-member-window-content-CwCy7ZWf.js.gz +0 -0
- package/dist/web/assets/terminal-tab-BW14RpCb.js.br +0 -0
- package/dist/web/assets/terminal-tab-BW14RpCb.js.gz +0 -0
- package/dist/web/assets/tool-cards-CgOBEUnb.js.br +0 -0
- package/dist/web/assets/tool-cards-CgOBEUnb.js.gz +0 -0
- package/dist/web/assets/use-inline-blame-Bzjfru4n.js +0 -16
- package/dist/web/assets/use-inline-blame-Bzjfru4n.js.br +0 -0
- package/dist/web/assets/use-inline-blame-Bzjfru4n.js.gz +0 -0
- package/dist/web/assets/use-lsp-hGdjL2hV.js +0 -6
- package/dist/web/assets/use-lsp-hGdjL2hV.js.br +0 -0
- package/dist/web/assets/use-lsp-hGdjL2hV.js.gz +0 -0
- package/dist/web/assets/vendor-ui-BHh12_0v.js.br +0 -0
- package/dist/web/assets/vendor-ui-BHh12_0v.js.gz +0 -0
- package/dist/web/assets/video-preview-P9T-ZVdN.js +0 -1
- package/dist/web/assets/video-preview-P9T-ZVdN.js.br +0 -0
- package/dist/web/assets/video-preview-P9T-ZVdN.js.gz +0 -0
- package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
- /package/dist/web/assets/{__vite-browser-external-BpSQWxcq.js → __vite-browser-external-BILfYaAs.js} +0 -0
- /package/dist/web/assets/{run-in-terminal-HIdNgYim.js → run-in-terminal-2pSiup8e.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js → vendor-xterm-DF1JTfsy.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.br → vendor-xterm-DF1JTfsy.js.br} +0 -0
- /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.gz → vendor-xterm-DF1JTfsy.js.gz} +0 -0
|
@@ -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
|
+
}
|
|
@@ -4,14 +4,20 @@
|
|
|
4
4
|
* already anchors the `/proc/<pid>/stat` parse on the last `)` so a process
|
|
5
5
|
* name containing spaces cannot shift the fields.
|
|
6
6
|
*
|
|
7
|
-
* Per-process VRAM needs the one `nvidia-smi` call
|
|
8
|
-
*
|
|
7
|
+
* Per-process VRAM needs the one `nvidia-smi` call. Per-process GPU busy % comes
|
|
8
|
+
* from DRM fdinfo where the driver publishes it (Intel, AMD) — the proprietary
|
|
9
|
+
* NVIDIA driver publishes neither, so an NVIDIA-only host still fills memory
|
|
10
|
+
* alone.
|
|
9
11
|
*/
|
|
10
12
|
import { readProcTable, type ProcEntry } from "../proc-table-linux.ts";
|
|
11
13
|
import type { ProcessCollection, ProcessCollector, RawProcessRow } from "./process-collector-types.ts";
|
|
12
14
|
import { createStickyColumns } from "./process-collector-types.ts";
|
|
13
15
|
import { readProcIoBytes, type ProcIoBytes } from "./process-io-linux.ts";
|
|
16
|
+
import { readProcSwapMB } from "./process-swap-linux.ts";
|
|
17
|
+
import { realLinuxFs } from "./linux-fs.ts";
|
|
18
|
+
import { serviceKeyFromCgroup } from "../system-services/app-cgroup-linux.ts";
|
|
14
19
|
import type { ProcessGpuMemoryCollector } from "./gpu-process-memory-nvidia.ts";
|
|
20
|
+
import type { DrmGpuCollector } from "./gpu-fdinfo-linux.ts";
|
|
15
21
|
|
|
16
22
|
const KB_PER_MB = 1024;
|
|
17
23
|
|
|
@@ -36,10 +42,20 @@ export function procEntriesToRows(entries: readonly ProcEntry[]): RawProcessRow[
|
|
|
36
42
|
export interface LinuxProcessCollectorOptions {
|
|
37
43
|
/** Injected so unit tests never touch a real `/proc`. */
|
|
38
44
|
readIo?: (pid: number) => ProcIoBytes | null;
|
|
45
|
+
/** `VmSwap` for one pid, MB. Null = gone or unreadable. */
|
|
46
|
+
readSwap?: (pid: number) => number | null;
|
|
47
|
+
/** `/proc/<pid>/cgroup` for one pid, used only to name its systemd unit. */
|
|
48
|
+
readCgroup?: (pid: number) => string | null;
|
|
49
|
+
/** Whose `systemctl --user` the Services page is reading. Defaults to this
|
|
50
|
+
* process's own uid. */
|
|
51
|
+
selfUid?: number;
|
|
39
52
|
/** Omitted or null → no per-process VRAM query at all. The production wiring
|
|
40
53
|
* in `system-metrics-platform.ts` injects it; defaulting to a real collector
|
|
41
54
|
* here would make an innocent unit test spawn `nvidia-smi`. */
|
|
42
55
|
gpuMemory?: ProcessGpuMemoryCollector | null;
|
|
56
|
+
/** Shared with the whole-GPU collector: it memoises one `/proc` walk per tick,
|
|
57
|
+
* so whichever of the two asks first pays for it and both see the same numbers. */
|
|
58
|
+
drm?: DrmGpuCollector | null;
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
export function createLinuxProcessCollector(
|
|
@@ -47,7 +63,17 @@ export function createLinuxProcessCollector(
|
|
|
47
63
|
opts: LinuxProcessCollectorOptions = {},
|
|
48
64
|
): ProcessCollector {
|
|
49
65
|
const readIo = opts.readIo ?? readProcIoBytes;
|
|
66
|
+
const readSwap = opts.readSwap ?? readProcSwapMB;
|
|
67
|
+
// The Apps page reads the same file under a DIFFERENT rule (it wants the
|
|
68
|
+
// outermost app unit, this wants the innermost unit of any kind), so the two
|
|
69
|
+
// cannot share one read without one of them getting the wrong answer. 1.3 ms
|
|
70
|
+
// for 561 pids, measured on this host.
|
|
71
|
+
const readCgroup = opts.readCgroup ?? ((pid: number) => realLinuxFs.read(`/proc/${pid}/cgroup`));
|
|
72
|
+
// Which user manager is "ours" — a unit of another uid is not on the Services
|
|
73
|
+
// page at all, so its processes must not land on our same-named row.
|
|
74
|
+
const selfUid = opts.selfUid ?? process.getuid?.() ?? 0;
|
|
50
75
|
const gpuMemory = opts.gpuMemory ?? null;
|
|
76
|
+
const drm = opts.drm ?? null;
|
|
51
77
|
const observeColumns = createStickyColumns();
|
|
52
78
|
|
|
53
79
|
return {
|
|
@@ -58,28 +84,54 @@ export function createLinuxProcessCollector(
|
|
|
58
84
|
return { rows: [], columns: observeColumns({}), warnings: ["Process list unavailable: /proc is not readable"] };
|
|
59
85
|
}
|
|
60
86
|
const gpuMemByPid = (await gpuMemory?.collect()) ?? null;
|
|
87
|
+
const drmByPid = drm?.usage().perProcess ?? null;
|
|
61
88
|
|
|
62
89
|
let anyIo = false;
|
|
90
|
+
let anySwap = false;
|
|
63
91
|
const rows = procEntriesToRows(table).map((r) => {
|
|
64
92
|
// EACCES for another user's process is expected, not an error: that row
|
|
65
93
|
// simply has no disk figures.
|
|
66
94
|
const io = readIo(r.pid);
|
|
67
95
|
if (io) anyIo = true;
|
|
96
|
+
// Both sources list only the processes actually using the GPU, so a
|
|
97
|
+
// missing pid means "measured, holding none" — not "unknown".
|
|
98
|
+
const drmRow = drmByPid?.get(r.pid);
|
|
99
|
+
const nvidiaMem = gpuMemByPid ? gpuMemByPid.get(r.pid) ?? 0 : undefined;
|
|
100
|
+
const drmMem = drmByPid ? (drmRow ? drmRow.vramMB + drmRow.sharedMB : 0) : undefined;
|
|
101
|
+
// A process that exited between the table read and now has neither; both
|
|
102
|
+
// stay absent for that row rather than being reported as zero.
|
|
103
|
+
const swapMB = readSwap(r.pid);
|
|
104
|
+
if (swapMB !== null) anySwap = true;
|
|
105
|
+
const unitKey = serviceKeyFromCgroup(readCgroup(r.pid) ?? "", selfUid);
|
|
68
106
|
return {
|
|
69
107
|
...r,
|
|
108
|
+
...(swapMB === null ? {} : { swapMB }),
|
|
109
|
+
...(unitKey === null ? {} : { unitKey }),
|
|
70
110
|
diskReadBytes: io?.readBytes,
|
|
71
111
|
diskWriteBytes: io?.writeBytes,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
gpuMemMB: gpuMemByPid ? gpuMemByPid.get(r.pid) ?? 0 : undefined,
|
|
112
|
+
...(drmByPid ? { gpuPct: drmRow?.gpuPct ?? 0 } : {}),
|
|
113
|
+
gpuMemMB: sumDefined(nvidiaMem, drmMem),
|
|
75
114
|
};
|
|
76
115
|
});
|
|
77
116
|
|
|
78
117
|
return {
|
|
79
118
|
rows,
|
|
80
|
-
columns: observeColumns({
|
|
119
|
+
columns: observeColumns({
|
|
120
|
+
disk: anyIo,
|
|
121
|
+
gpu: gpuMemByPid !== null || drmByPid !== null,
|
|
122
|
+
swap: anySwap,
|
|
123
|
+
}),
|
|
81
124
|
warnings: [],
|
|
82
125
|
};
|
|
83
126
|
},
|
|
84
127
|
};
|
|
85
128
|
}
|
|
129
|
+
|
|
130
|
+
/** Undefined only when NEITHER source measured anything — a host with one of the
|
|
131
|
+
* two must not report "unknown" for a figure it really does have. */
|
|
132
|
+
function sumDefined(a: number | undefined, b: number | undefined): number | undefined {
|
|
133
|
+
if (a === undefined && b === undefined) return undefined;
|
|
134
|
+
return round1((a ?? 0) + (b ?? 0));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const round1 = (n: number) => Math.round(n * 10) / 10;
|
|
@@ -13,6 +13,12 @@ export interface RawProcessRow {
|
|
|
13
13
|
/** Cumulative CPU time (user + kernel), milliseconds. */
|
|
14
14
|
cpuMs: number;
|
|
15
15
|
ramMB: number;
|
|
16
|
+
/** Swapped-out anonymous memory, MB. `undefined` = this OS has no per-process
|
|
17
|
+
* source; 0 is a real reading (a kernel thread has no address space). */
|
|
18
|
+
swapMB?: number;
|
|
19
|
+
/** `"<scope>:<unit>"` — which Services row owns this pid. Absent off systemd,
|
|
20
|
+
* for a pid in no unit, and for another user's units. */
|
|
21
|
+
unitKey?: string;
|
|
16
22
|
/** Epoch ms UTC; 0 when unknown. */
|
|
17
23
|
startedAt: number;
|
|
18
24
|
/** CUMULATIVE per-process byte counters. The rows builder turns them into
|
|
@@ -49,7 +55,7 @@ export interface ProcessCollector {
|
|
|
49
55
|
|
|
50
56
|
/** Frozen: it is shared by every light-tier snapshot, so an accidental mutation
|
|
51
57
|
* would rewrite history for all of them. */
|
|
52
|
-
export const NO_PROCESS_COLUMNS: ProcessColumnAvailability = Object.freeze({ disk: false, gpu: false, net: false });
|
|
58
|
+
export const NO_PROCESS_COLUMNS: ProcessColumnAvailability = Object.freeze({ disk: false, gpu: false, net: false, swap: false });
|
|
53
59
|
|
|
54
60
|
/**
|
|
55
61
|
* Sticky column availability. A capability is advertised as soon as it has
|
|
@@ -64,6 +70,7 @@ export function createStickyColumns(): (seen: Partial<ProcessColumnAvailability>
|
|
|
64
70
|
state.disk ||= seen.disk === true;
|
|
65
71
|
state.gpu ||= seen.gpu === true;
|
|
66
72
|
state.net ||= seen.net === true;
|
|
73
|
+
state.swap ||= seen.swap === true;
|
|
67
74
|
return { ...state };
|
|
68
75
|
};
|
|
69
76
|
}
|