@hienlh/ppm 0.23.6 → 0.23.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -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 +29 -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-Dn_wB-o5.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-BA3y-qSH.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-BioxkrQF.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-BSoJ0E6p.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-DHh5QsH9.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-lctWoSmG.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-rbkXsZVR.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-uPO0WgCq.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-CT7mDb0L.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-DANPfMRN.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-BJPkLiEw.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-R4PcAntf.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-DHRoyWcG.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-BKej4mUf.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-BHtYqkYZ.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-DS_XrpTG.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-D8AES1BA.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-DTBG4beI.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-CqtmbeRj.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-Djt6cpNL.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-DNJF8TcF.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-BKoPovy2.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-BjIMi9Wk.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-BNcA6Irq.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-CIRGNCvi.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-CwXpLi3X.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-4swiiDz7.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-BGcdtMMT.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-D0-krtA2.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-C88KphGx.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-Chk9guIU.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/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/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 +16 -3
- package/src/services/compaction-savings.ts +127 -0
- package/src/services/db.service.ts +123 -8
- 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/shared/prompt-cache-idle.ts +197 -0
- package/src/shared/turn-usage.ts +85 -1
- package/src/types/chat.ts +27 -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/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 +5 -1
- 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-DUVO32SQ.js +0 -1
- package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.gz +0 -0
- package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-CEbW8jRy.js +0 -1
- package/dist/web/assets/ai-settings-section-CEbW8jRy.js.br +0 -0
- package/dist/web/assets/ai-settings-section-CEbW8jRy.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-D-mwEYFZ.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-tw6TpFb6.js +0 -1
- package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-tw6TpFb6.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-MBuMWp_i.js +0 -1
- package/dist/web/assets/branch-review-tab-MBuMWp_i.js.br +0 -0
- package/dist/web/assets/branch-review-tab-MBuMWp_i.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-DVvnqhw6.js +0 -1
- package/dist/web/assets/chat-tab-DVvnqhw6.js.br +0 -0
- package/dist/web/assets/chat-tab-DVvnqhw6.js.gz +0 -0
- package/dist/web/assets/chat-tab-DaEHva22.js +0 -15
- package/dist/web/assets/chat-tab-DaEHva22.js.br +0 -0
- package/dist/web/assets/chat-tab-DaEHva22.js.gz +0 -0
- package/dist/web/assets/code-editor-Bu9lhTVp.js +0 -7
- package/dist/web/assets/code-editor-Bu9lhTVp.js.br +0 -0
- package/dist/web/assets/code-editor-Bu9lhTVp.js.gz +0 -0
- package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js +0 -1
- package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.gz +0 -0
- package/dist/web/assets/conflict-editor-BA3y-qSH.js.br +0 -0
- package/dist/web/assets/conflict-editor-BA3y-qSH.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-BioxkrQF.js.br +0 -0
- package/dist/web/assets/csv-preview-BioxkrQF.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-BSoJ0E6p.js.br +0 -0
- package/dist/web/assets/database-viewer-BSoJ0E6p.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-iU2CviE3.js +0 -33
- package/dist/web/assets/design-tab-iU2CviE3.js.br +0 -0
- package/dist/web/assets/design-tab-iU2CviE3.js.gz +0 -0
- package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.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-lctWoSmG.js.br +0 -0
- package/dist/web/assets/diff-viewer-lctWoSmG.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-fPG56hQO.js +0 -1
- package/dist/web/assets/editor-language-service-fPG56hQO.js.br +0 -0
- package/dist/web/assets/editor-language-service-fPG56hQO.js.gz +0 -0
- package/dist/web/assets/explorer-body-BgF7FsxI.js +0 -2
- package/dist/web/assets/explorer-body-BgF7FsxI.js.br +0 -0
- package/dist/web/assets/explorer-body-BgF7FsxI.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-C21w_7lf.js +0 -1
- package/dist/web/assets/explorer-window-content-C21w_7lf.js.br +0 -0
- package/dist/web/assets/explorer-window-content-C21w_7lf.js.gz +0 -0
- package/dist/web/assets/extension-manager-section-rbkXsZVR.js.br +0 -0
- package/dist/web/assets/extension-manager-section-rbkXsZVR.js.gz +0 -0
- package/dist/web/assets/extension-webview-uPO0WgCq.js.br +0 -0
- package/dist/web/assets/extension-webview-uPO0WgCq.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-CT7mDb0L.js.br +0 -0
- package/dist/web/assets/files-settings-section-CT7mDb0L.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-DANPfMRN.js.br +0 -0
- package/dist/web/assets/general-settings-section-DANPfMRN.js.gz +0 -0
- package/dist/web/assets/git-log-panel-BJPkLiEw.js.br +0 -0
- package/dist/web/assets/git-log-panel-BJPkLiEw.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-R4PcAntf.js.br +0 -0
- package/dist/web/assets/glide-data-grid-R4PcAntf.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-BXMdo8w9.js +0 -1
- package/dist/web/assets/group-chat-tab-BXMdo8w9.js.br +0 -0
- package/dist/web/assets/group-chat-tab-BXMdo8w9.js.gz +0 -0
- package/dist/web/assets/index-C8nGqkKN.js +0 -52
- package/dist/web/assets/index-C8nGqkKN.js.br +0 -0
- package/dist/web/assets/index-C8nGqkKN.js.gz +0 -0
- package/dist/web/assets/index-DvClbTQx.css +0 -1
- package/dist/web/assets/index-DvClbTQx.css.br +0 -0
- package/dist/web/assets/index-DvClbTQx.css.gz +0 -0
- package/dist/web/assets/keybindings-store-BGKlQQAv.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.br +0 -0
- package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-vDNuKjel.js +0 -1
- 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-DtvxS7-r.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.gz +0 -0
- package/dist/web/assets/new-design-dialog-DS_XrpTG.js.br +0 -0
- package/dist/web/assets/new-design-dialog-DS_XrpTG.js.gz +0 -0
- package/dist/web/assets/notification-store-Dnnj20Ky.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-D8AES1BA.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-D8AES1BA.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-DTBG4beI.js.br +0 -0
- package/dist/web/assets/problems-panel-DTBG4beI.js.gz +0 -0
- package/dist/web/assets/process-table-D_gR2XA6.js +0 -1
- package/dist/web/assets/process-table-D_gR2XA6.js.br +0 -0
- package/dist/web/assets/process-table-D_gR2XA6.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-CqtmbeRj.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-CqtmbeRj.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-Djt6cpNL.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.gz +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.gz +0 -0
- package/dist/web/assets/schedules-settings-section-BKoPovy2.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-BKoPovy2.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-k2qPgRFe.js +0 -2
- package/dist/web/assets/settings-body-k2qPgRFe.js.br +0 -0
- package/dist/web/assets/settings-body-k2qPgRFe.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-Bb23VdBu.js +0 -1
- package/dist/web/assets/settings-window-content-ClarWusz.js +0 -1
- package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.br +0 -0
- package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.gz +0 -0
- package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-D0T3ggt2.js +0 -2
- package/dist/web/assets/system-monitor-body-D0T3ggt2.js.br +0 -0
- package/dist/web/assets/system-monitor-body-D0T3ggt2.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-I1Igmoey.js +0 -1
- package/dist/web/assets/system-monitor-window-content-C5SeUv1H.js +0 -1
- package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.gz +0 -0
- package/dist/web/assets/team-member-sheet-CwXpLi3X.js.br +0 -0
- package/dist/web/assets/team-member-sheet-CwXpLi3X.js.gz +0 -0
- package/dist/web/assets/team-member-window-content-4swiiDz7.js.br +0 -0
- package/dist/web/assets/team-member-window-content-4swiiDz7.js.gz +0 -0
- package/dist/web/assets/terminal-tab-BGcdtMMT.js.br +0 -0
- package/dist/web/assets/terminal-tab-BGcdtMMT.js.gz +0 -0
- package/dist/web/assets/tool-cards-D0-krtA2.js.br +0 -0
- package/dist/web/assets/tool-cards-D0-krtA2.js.gz +0 -0
- package/dist/web/assets/use-inline-blame-pKaXyGU-.js +0 -16
- package/dist/web/assets/use-inline-blame-pKaXyGU-.js.br +0 -0
- package/dist/web/assets/use-inline-blame-pKaXyGU-.js.gz +0 -0
- package/dist/web/assets/use-lsp-71azTXQz.js +0 -6
- package/dist/web/assets/use-lsp-71azTXQz.js.br +0 -0
- package/dist/web/assets/use-lsp-71azTXQz.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-DxEX-uGo.js +0 -1
- package/dist/web/assets/video-preview-DxEX-uGo.js.br +0 -0
- package/dist/web/assets/video-preview-DxEX-uGo.js.gz +0 -0
- package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
- /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,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Services page — Mission Center's Services tab.
|
|
3
|
+
*
|
|
4
|
+
* The two scopes are separate sections rather than one flat list: a user unit and
|
|
5
|
+
* a system unit of the same name are different units with very different
|
|
6
|
+
* consequences, and a flat list gives no way to tell them apart.
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback, useMemo, useState } from "react";
|
|
9
|
+
import { toast } from "sonner";
|
|
10
|
+
import { Search } from "@/lib/icons";
|
|
11
|
+
import { cn } from "@/lib/utils";
|
|
12
|
+
import { runServiceAction, useServices } from "./use-services";
|
|
13
|
+
import { SERVICE_FILTERS, serviceCounts, shapeServices, type ServiceFilter } from "./service-rows";
|
|
14
|
+
import { ServiceRow } from "./service-row";
|
|
15
|
+
import { ServicesHeader } from "./services-header";
|
|
16
|
+
import { serviceGridCssVars } from "./service-columns";
|
|
17
|
+
import { sortServiceRows, type ServiceSortKey } from "./service-sort";
|
|
18
|
+
import { toggleSort } from "../process-table-model";
|
|
19
|
+
import { resourcesFor, rollUpByUnit } from "./service-resources";
|
|
20
|
+
import { ServiceDetailsSheet } from "./service-details-sheet";
|
|
21
|
+
import {
|
|
22
|
+
ServiceActionConfirm, needsConfirm, type PendingServiceAction,
|
|
23
|
+
} from "./service-action-confirm";
|
|
24
|
+
import type { MetricsSnapshot, SortDir } from "../../../../types/system-metrics";
|
|
25
|
+
import type { ServiceAction, ServiceInfo, ServiceScope } from "../../../../types/system-services";
|
|
26
|
+
|
|
27
|
+
const SCOPES: readonly ServiceScope[] = ["system", "user"];
|
|
28
|
+
const SCOPE_LABELS: Record<ServiceScope, string> = { system: "System", user: "User" };
|
|
29
|
+
const FILTER_LABELS: Record<ServiceFilter, string> = {
|
|
30
|
+
all: "All", running: "Running", failed: "Failed", enabled: "Enabled",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** `metrics` is the live 2 s stream the Processes tab is already receiving. The
|
|
34
|
+
* unit list itself comes from `systemctl` on a separate 3 s poll, so the two
|
|
35
|
+
* arrive independently and a row simply shows dashes until the first full tick
|
|
36
|
+
* carrying process rows lands. */
|
|
37
|
+
export function ServicesPanel({ active, metrics }: { active: boolean; metrics?: MetricsSnapshot | null }) {
|
|
38
|
+
const { snapshot, error, loading, refresh } = useServices(active);
|
|
39
|
+
const [scope, setScope] = useState<ServiceScope>("system");
|
|
40
|
+
const [filter, setFilter] = useState<ServiceFilter>("all");
|
|
41
|
+
const [query, setQuery] = useState("");
|
|
42
|
+
// `null` = the page's own order (failed first, then running, then by name),
|
|
43
|
+
// which the third click of a header returns to.
|
|
44
|
+
const [sortKey, setSortKey] = useState<ServiceSortKey | null>(null);
|
|
45
|
+
const [sortDir, setSortDir] = useState<SortDir>("desc");
|
|
46
|
+
const [details, setDetails] = useState<ServiceInfo | null>(null);
|
|
47
|
+
const [pending, setPending] = useState<PendingServiceAction | null>(null);
|
|
48
|
+
|
|
49
|
+
const services = snapshot?.services ?? [];
|
|
50
|
+
const shaped = useMemo(() => shapeServices(services, scope, filter, query), [services, scope, filter, query]);
|
|
51
|
+
const counts = useMemo(() => serviceCounts(services, scope), [services, scope]);
|
|
52
|
+
// The light tier carries no process rows at all, so there is nothing to sum
|
|
53
|
+
// and every row must say so rather than reading as a machine at rest.
|
|
54
|
+
const byUnit = useMemo(
|
|
55
|
+
() => (metrics?.processes.length ? rollUpByUnit(metrics.processes) : null),
|
|
56
|
+
[metrics],
|
|
57
|
+
);
|
|
58
|
+
// The roll-up is attached BEFORE sorting: the columns sort on the figures the
|
|
59
|
+
// row is showing, and those live in the metrics stream rather than on the unit.
|
|
60
|
+
const rows = useMemo(
|
|
61
|
+
() => sortServiceRows(
|
|
62
|
+
shaped.map((service) => ({ service, resources: resourcesFor(service, byUnit) })),
|
|
63
|
+
sortKey,
|
|
64
|
+
sortDir,
|
|
65
|
+
),
|
|
66
|
+
[shaped, byUnit, sortKey, sortDir],
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const onSort = useCallback((key: ServiceSortKey) => {
|
|
70
|
+
const [nextKey, nextDir] = toggleSort(sortKey, sortDir, key);
|
|
71
|
+
setSortKey(nextKey);
|
|
72
|
+
setSortDir(nextDir);
|
|
73
|
+
}, [sortKey, sortDir]);
|
|
74
|
+
|
|
75
|
+
const perform = useCallback(async ({ service, action }: PendingServiceAction) => {
|
|
76
|
+
setPending(null);
|
|
77
|
+
try {
|
|
78
|
+
await runServiceAction(service.scope, service.unit, action);
|
|
79
|
+
toast.success(`${service.unit}: ${action} done`);
|
|
80
|
+
// systemd settles asynchronously, so the next poll is what shows the new
|
|
81
|
+
// state; refreshing now just shortens the wait.
|
|
82
|
+
await refresh();
|
|
83
|
+
} catch (e) {
|
|
84
|
+
toast.error(e instanceof Error ? e.message : `Could not ${action} ${service.unit}`);
|
|
85
|
+
}
|
|
86
|
+
}, [refresh]);
|
|
87
|
+
|
|
88
|
+
const onAction = useCallback((service: ServiceInfo, action: ServiceAction) => {
|
|
89
|
+
if (needsConfirm(action)) setPending({ service, action });
|
|
90
|
+
else void perform({ service, action });
|
|
91
|
+
}, [perform]);
|
|
92
|
+
|
|
93
|
+
if (snapshot && !snapshot.supported) {
|
|
94
|
+
return (
|
|
95
|
+
<div className="p-4 text-sm text-text-subtle" data-testid="sysmon-services">
|
|
96
|
+
This host has no service manager PPM can read.
|
|
97
|
+
{snapshot.warnings.map((w, i) => (
|
|
98
|
+
<p key={i} className="mt-1 text-xs">{w}</p>
|
|
99
|
+
))}
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
// `@container`: the resource columns are dropped on the PANEL's own width,
|
|
106
|
+
// not the viewport's — the System Monitor is a floating window on desktop
|
|
107
|
+
// and is routinely narrower than the screen it sits on.
|
|
108
|
+
<div
|
|
109
|
+
className="h-full flex flex-col min-h-0 @container"
|
|
110
|
+
// Set once here; every row and the header inherit the four templates.
|
|
111
|
+
style={serviceGridCssVars()}
|
|
112
|
+
data-testid="sysmon-services"
|
|
113
|
+
data-row-count={rows.length}
|
|
114
|
+
data-sort-key={sortKey ?? "default"}
|
|
115
|
+
data-sort-dir={sortDir}
|
|
116
|
+
>
|
|
117
|
+
<div className="shrink-0 border-b border-border">
|
|
118
|
+
<div className="flex items-center" role="tablist">
|
|
119
|
+
{SCOPES.map((s) => (
|
|
120
|
+
<button
|
|
121
|
+
key={s}
|
|
122
|
+
type="button"
|
|
123
|
+
role="tab"
|
|
124
|
+
aria-selected={scope === s}
|
|
125
|
+
onClick={() => setScope(s)}
|
|
126
|
+
data-testid={`sysmon-services-scope-${s}`}
|
|
127
|
+
className={cn(
|
|
128
|
+
"flex-1 md:flex-none min-h-11 px-4 text-sm font-medium transition-colors",
|
|
129
|
+
scope === s
|
|
130
|
+
? "text-text-primary border-b-2 border-primary -mb-px"
|
|
131
|
+
: "text-text-subtle hover:text-text-secondary",
|
|
132
|
+
)}
|
|
133
|
+
>
|
|
134
|
+
{SCOPE_LABELS[s]}
|
|
135
|
+
</button>
|
|
136
|
+
))}
|
|
137
|
+
</div>
|
|
138
|
+
<div className="flex flex-wrap items-center gap-2 p-2">
|
|
139
|
+
<div className="relative flex-1 min-w-[140px]">
|
|
140
|
+
<Search className="absolute left-2 top-1/2 -translate-y-1/2 size-3.5 text-text-subtle" />
|
|
141
|
+
<input
|
|
142
|
+
type="text"
|
|
143
|
+
value={query}
|
|
144
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
145
|
+
placeholder="Search services"
|
|
146
|
+
aria-label="Search services"
|
|
147
|
+
data-testid="sysmon-service-search"
|
|
148
|
+
className="w-full min-h-11 md:min-h-8 pl-7 pr-2 text-sm rounded-md border border-border bg-transparent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
149
|
+
/>
|
|
150
|
+
</div>
|
|
151
|
+
{SERVICE_FILTERS.map((f) => (
|
|
152
|
+
<button
|
|
153
|
+
key={f}
|
|
154
|
+
type="button"
|
|
155
|
+
onClick={() => setFilter(f)}
|
|
156
|
+
aria-pressed={filter === f}
|
|
157
|
+
data-testid={`sysmon-service-filter-${f}`}
|
|
158
|
+
className={cn(
|
|
159
|
+
"min-h-11 md:min-h-8 px-3 text-xs rounded-md border transition-colors",
|
|
160
|
+
filter === f ? "border-primary bg-primary/10 text-primary" : "border-border hover:bg-surface-hover",
|
|
161
|
+
)}
|
|
162
|
+
>
|
|
163
|
+
{FILTER_LABELS[f]}
|
|
164
|
+
</button>
|
|
165
|
+
))}
|
|
166
|
+
</div>
|
|
167
|
+
<p className="px-3 pb-2 text-[11px] text-text-subtle">
|
|
168
|
+
{counts.total} units · {counts.running} running
|
|
169
|
+
{counts.failed > 0 && <span className="text-error"> · {counts.failed} failed</span>}
|
|
170
|
+
</p>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
{snapshot && snapshot.warnings.length > 0 && (
|
|
174
|
+
<div className="px-3 py-1.5 text-[11px] text-warning bg-warning/10 border-b border-border shrink-0">
|
|
175
|
+
{snapshot.warnings.map((w, i) => <div key={i}>{w}</div>)}
|
|
176
|
+
</div>
|
|
177
|
+
)}
|
|
178
|
+
|
|
179
|
+
<div className="flex-1 min-h-0 overflow-y-auto">
|
|
180
|
+
<ServicesHeader sortKey={sortKey} sortDir={sortDir} onSort={onSort} />
|
|
181
|
+
<div className="divide-y divide-border">
|
|
182
|
+
{loading && <p className="p-4 text-sm text-text-subtle">Listing units…</p>}
|
|
183
|
+
{error && <p className="p-4 text-sm text-error">{error}</p>}
|
|
184
|
+
{!loading && !error && rows.length === 0 && (
|
|
185
|
+
<p className="p-4 text-sm text-text-subtle">No units match.</p>
|
|
186
|
+
)}
|
|
187
|
+
{rows.map(({ service, resources }) => (
|
|
188
|
+
<ServiceRow
|
|
189
|
+
key={`${service.scope}:${service.unit}`}
|
|
190
|
+
service={service}
|
|
191
|
+
resources={resources}
|
|
192
|
+
onOpen={setDetails}
|
|
193
|
+
onAction={onAction}
|
|
194
|
+
/>
|
|
195
|
+
))}
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<ServiceDetailsSheet target={details} onClose={() => setDetails(null)} />
|
|
200
|
+
<ServiceActionConfirm
|
|
201
|
+
pending={pending}
|
|
202
|
+
onConfirm={(p) => void perform(p)}
|
|
203
|
+
onCancel={() => setPending(null)}
|
|
204
|
+
/>
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Services page's data: a poll, not a stream.
|
|
3
|
+
*
|
|
4
|
+
* The list costs two `systemctl` spawns per scope, so it rides its own timer at
|
|
5
|
+
* SERVICES_POLL_INTERVAL_MS while the page is visible rather than being folded
|
|
6
|
+
* into the 2 s metrics tick — a status bar on every page must not spawn anything.
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
9
|
+
import { api, getAuthToken } from "@/lib/api-client";
|
|
10
|
+
import type {
|
|
11
|
+
ServiceAction, ServiceActionResult, ServiceDetails, ServicesSnapshot, ServiceScope,
|
|
12
|
+
} from "../../../../types/system-services";
|
|
13
|
+
import { SERVICES_POLL_INTERVAL_MS } from "../../../../types/system-services";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `api.post` cannot add the `X-PPM-Request` header the mutating routes require
|
|
17
|
+
* (CSRF hardening for the auth-disabled configuration), so this mirrors
|
|
18
|
+
* `killProcess`: a raw fetch with the same single-Error-on-any-failure contract.
|
|
19
|
+
*/
|
|
20
|
+
export async function runServiceAction(
|
|
21
|
+
scope: ServiceScope,
|
|
22
|
+
unit: string,
|
|
23
|
+
action: ServiceAction,
|
|
24
|
+
): Promise<ServiceActionResult> {
|
|
25
|
+
const token = getAuthToken();
|
|
26
|
+
const headers: Record<string, string> = {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
"X-PPM-Request": "1",
|
|
29
|
+
};
|
|
30
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
31
|
+
|
|
32
|
+
const res = await fetch(
|
|
33
|
+
`/api/system/services/${scope}/${encodeURIComponent(unit)}/${action}`,
|
|
34
|
+
{ method: "POST", headers, body: "{}" },
|
|
35
|
+
);
|
|
36
|
+
let json: { ok: boolean; data?: ServiceActionResult; error?: string };
|
|
37
|
+
try {
|
|
38
|
+
json = await res.json();
|
|
39
|
+
} catch {
|
|
40
|
+
throw new Error(res.ok ? "Empty response from server" : `Server error (HTTP ${res.status})`);
|
|
41
|
+
}
|
|
42
|
+
if (json.ok === false) throw new Error(json.error ?? `HTTP ${res.status}`);
|
|
43
|
+
return json.data as ServiceActionResult;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function fetchServiceDetails(scope: ServiceScope, unit: string): Promise<ServiceDetails> {
|
|
47
|
+
return api.get<ServiceDetails>(`/api/system/services/${scope}/${encodeURIComponent(unit)}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface UseServicesResult {
|
|
51
|
+
snapshot: ServicesSnapshot | null;
|
|
52
|
+
error: string | null;
|
|
53
|
+
/** True only before the FIRST answer — a refresh must not blank the list. */
|
|
54
|
+
loading: boolean;
|
|
55
|
+
refresh: () => Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function useServices(active: boolean): UseServicesResult {
|
|
59
|
+
const [snapshot, setSnapshot] = useState<ServicesSnapshot | null>(null);
|
|
60
|
+
const [error, setError] = useState<string | null>(null);
|
|
61
|
+
const inFlight = useRef(false);
|
|
62
|
+
const mounted = useRef(true);
|
|
63
|
+
|
|
64
|
+
const refresh = useCallback(async () => {
|
|
65
|
+
if (inFlight.current) return;
|
|
66
|
+
inFlight.current = true;
|
|
67
|
+
try {
|
|
68
|
+
const next = await api.get<ServicesSnapshot>("/api/system/services");
|
|
69
|
+
if (!mounted.current) return;
|
|
70
|
+
setSnapshot(next);
|
|
71
|
+
setError(null);
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (mounted.current) setError(e instanceof Error ? e.message : "Could not list services");
|
|
74
|
+
} finally {
|
|
75
|
+
inFlight.current = false;
|
|
76
|
+
}
|
|
77
|
+
}, []);
|
|
78
|
+
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
mounted.current = true;
|
|
81
|
+
return () => { mounted.current = false; };
|
|
82
|
+
}, []);
|
|
83
|
+
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (!active) return;
|
|
86
|
+
void refresh();
|
|
87
|
+
const timer = setInterval(() => void refresh(), SERVICES_POLL_INTERVAL_MS);
|
|
88
|
+
return () => clearInterval(timer);
|
|
89
|
+
}, [active, refresh]);
|
|
90
|
+
|
|
91
|
+
return { snapshot, error, loading: snapshot === null && error === null, refresh };
|
|
92
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ArrowUp, ArrowDown } from "@/lib/icons";
|
|
2
2
|
import { cn } from "@/lib/utils";
|
|
3
|
-
import type { SortDir
|
|
3
|
+
import type { SortDir } from "../../../types/system-metrics";
|
|
4
4
|
import type { ResizableColumnKey } from "./process-columns-grid";
|
|
5
5
|
|
|
6
6
|
export interface ColumnResizeHandlers {
|
|
@@ -8,12 +8,16 @@ export interface ColumnResizeHandlers {
|
|
|
8
8
|
onResizeReset: (key: ResizableColumnKey) => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
/** Sortable column header shared by the process table
|
|
12
|
-
* `columnheader` `<div>`, not a `<th>` — the parent row is a CSS-grid
|
|
11
|
+
/** Sortable column header shared by the process table and the services table.
|
|
12
|
+
* Renders as a `columnheader` `<div>`, not a `<th>` — the parent row is a CSS-grid
|
|
13
13
|
* `<div role="row">`, and a `<th>` inside a non-table ancestor both triggers React's
|
|
14
14
|
* DOM-nesting warning and makes `aria-sort` meaningless to assistive tech outside
|
|
15
|
-
* an actual table.
|
|
16
|
-
|
|
15
|
+
* an actual table.
|
|
16
|
+
*
|
|
17
|
+
* Generic over the field name because the two tables do not sort on the same
|
|
18
|
+
* set: the services table has a `pid` column, which is a systemd property and
|
|
19
|
+
* not one of `SortKey`'s metrics. */
|
|
20
|
+
export function SortableHeader<F extends string>({
|
|
17
21
|
label,
|
|
18
22
|
field,
|
|
19
23
|
activeKey,
|
|
@@ -26,10 +30,11 @@ export function SortableHeader({
|
|
|
26
30
|
resize,
|
|
27
31
|
}: {
|
|
28
32
|
label: string;
|
|
29
|
-
field:
|
|
30
|
-
|
|
33
|
+
field: F;
|
|
34
|
+
/** `null` = nothing is sorted by, i.e. the table's own default order. */
|
|
35
|
+
activeKey: F | null;
|
|
31
36
|
activeDir: SortDir;
|
|
32
|
-
onClick: (field:
|
|
37
|
+
onClick: (field: F) => void;
|
|
33
38
|
/** Text/justify alignment — the "Process" column is left-aligned over the name
|
|
34
39
|
* cell, every numeric column stays right-aligned. */
|
|
35
40
|
align?: "left" | "right";
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System Monitor preferences — Mission Center's Preferences dialog, reduced to
|
|
3
|
+
* the settings PPM can actually honour.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately NOT here: Mission Center's update interval and graph data-point
|
|
6
|
+
* count. PPM's tick rate is the server's (2 s full, 5 s light) and is shared by
|
|
7
|
+
* every subscriber, so a per-client control over it would either do nothing or
|
|
8
|
+
* change the rate for somebody else's window.
|
|
9
|
+
*
|
|
10
|
+
* Rendered inline under the tab strip rather than in a popover: it is two rows,
|
|
11
|
+
* it has to work identically on a phone, and an inline panel needs no portal, no
|
|
12
|
+
* placement and no separate mobile sheet.
|
|
13
|
+
*/
|
|
14
|
+
import { useSettingsStore } from "@/stores/settings-store";
|
|
15
|
+
import { cn } from "@/lib/utils";
|
|
16
|
+
import type { TempUnit } from "@/lib/temperature";
|
|
17
|
+
|
|
18
|
+
const UNITS: { id: TempUnit; label: string }[] = [
|
|
19
|
+
{ id: "c", label: "°C" },
|
|
20
|
+
{ id: "f", label: "°F" },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
export function SysMonPreferences() {
|
|
24
|
+
const tempUnit = useSettingsStore((s) => s.sysmonTempUnit);
|
|
25
|
+
const setTempUnit = useSettingsStore((s) => s.setSysmonTempUnit);
|
|
26
|
+
const kernelTimes = useSettingsStore((s) => s.sysmonKernelTimes);
|
|
27
|
+
const setKernelTimes = useSettingsStore((s) => s.setSysmonKernelTimes);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
className="shrink-0 border-b border-border bg-surface-hover/30 px-3 py-2 space-y-2"
|
|
32
|
+
data-testid="sysmon-preferences"
|
|
33
|
+
>
|
|
34
|
+
<div className="flex items-center justify-between gap-3">
|
|
35
|
+
<span className="text-xs text-text-secondary">Temperature unit</span>
|
|
36
|
+
<div className="flex items-center gap-1" role="radiogroup" aria-label="Temperature unit">
|
|
37
|
+
{UNITS.map((u) => (
|
|
38
|
+
<button
|
|
39
|
+
key={u.id}
|
|
40
|
+
type="button"
|
|
41
|
+
role="radio"
|
|
42
|
+
aria-checked={tempUnit === u.id}
|
|
43
|
+
onClick={() => setTempUnit(u.id)}
|
|
44
|
+
data-testid={`sysmon-pref-temp-${u.id}`}
|
|
45
|
+
className={cn(
|
|
46
|
+
"min-h-11 md:min-h-8 px-3 text-xs rounded-md border transition-colors",
|
|
47
|
+
tempUnit === u.id
|
|
48
|
+
? "border-primary bg-primary/10 text-primary"
|
|
49
|
+
: "border-border hover:bg-surface-hover",
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
{u.label}
|
|
53
|
+
</button>
|
|
54
|
+
))}
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div className="flex items-center justify-between gap-3">
|
|
59
|
+
<label htmlFor="sysmon-pref-kernel" className="text-xs text-text-secondary">
|
|
60
|
+
Show kernel times on the CPU graph
|
|
61
|
+
</label>
|
|
62
|
+
<button
|
|
63
|
+
id="sysmon-pref-kernel"
|
|
64
|
+
type="button"
|
|
65
|
+
role="switch"
|
|
66
|
+
aria-checked={kernelTimes}
|
|
67
|
+
onClick={() => setKernelTimes(!kernelTimes)}
|
|
68
|
+
data-testid="sysmon-pref-kernel"
|
|
69
|
+
className={cn(
|
|
70
|
+
"min-h-11 md:min-h-8 px-3 text-xs rounded-md border transition-colors",
|
|
71
|
+
kernelTimes
|
|
72
|
+
? "border-primary bg-primary/10 text-primary"
|
|
73
|
+
: "border-border hover:bg-surface-hover",
|
|
74
|
+
)}
|
|
75
|
+
>
|
|
76
|
+
{kernelTimes ? "On" : "Off"}
|
|
77
|
+
</button>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<p className="text-[11px] text-text-subtle">
|
|
81
|
+
These apply to this device only — the machine being watched is the same for everyone.
|
|
82
|
+
</p>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
@@ -1,21 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared shell for the System Monitor: connection indicator, warning strip, and the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* sub-tabs. Rendered identically by the desktop window and the mobile tab, so this
|
|
4
|
+
* file and the panels beneath it are written once for both hosts.
|
|
5
|
+
*
|
|
6
|
+
* The five tabs follow Mission Center's own division — Performance, Apps,
|
|
7
|
+
* Processes, Services — with PPM's existing Overview kept as the default, because
|
|
8
|
+
* a one-screen summary is what most opens of this window are for.
|
|
5
9
|
*/
|
|
6
10
|
import { lazy, memo, Suspense, useState } from "react";
|
|
7
|
-
import { Wifi, WifiOff } from "@/lib/icons";
|
|
11
|
+
import { Settings, Wifi, WifiOff } from "@/lib/icons";
|
|
8
12
|
import { cn } from "@/lib/utils";
|
|
9
13
|
import { useResourceMonitor } from "@/hooks/use-resource-monitor";
|
|
14
|
+
import { SysMonPreferences } from "./sysmon-preferences";
|
|
10
15
|
|
|
11
16
|
const OverviewPanel = lazy(() =>
|
|
12
17
|
import("./overview-panel").then((m) => ({ default: m.OverviewPanel })),
|
|
13
18
|
);
|
|
19
|
+
const PerformancePanel = lazy(() =>
|
|
20
|
+
import("./performance/performance-panel").then((m) => ({ default: m.PerformancePanel })),
|
|
21
|
+
);
|
|
22
|
+
const AppsPanel = lazy(() =>
|
|
23
|
+
import("./apps/apps-panel").then((m) => ({ default: m.AppsPanel })),
|
|
24
|
+
);
|
|
14
25
|
const ProcessTable = lazy(() =>
|
|
15
26
|
import("./process-table").then((m) => ({ default: m.ProcessTable })),
|
|
16
27
|
);
|
|
28
|
+
const ServicesPanel = lazy(() =>
|
|
29
|
+
import("./services/services-panel").then((m) => ({ default: m.ServicesPanel })),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export const SYSMON_TABS = ["overview", "performance", "apps", "processes", "services"] as const;
|
|
33
|
+
export type SysMonTab = (typeof SYSMON_TABS)[number];
|
|
17
34
|
|
|
18
|
-
|
|
35
|
+
const TAB_LABELS: Record<SysMonTab, string> = {
|
|
36
|
+
overview: "Overview",
|
|
37
|
+
performance: "Performance",
|
|
38
|
+
apps: "Apps",
|
|
39
|
+
processes: "Processes",
|
|
40
|
+
services: "Services",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** A tab id off a persisted window payload is untrusted the same way one off the
|
|
44
|
+
* wire is — an unknown value falls back rather than rendering nothing. */
|
|
45
|
+
export function parseSysMonTab(value: unknown): SysMonTab {
|
|
46
|
+
return SYSMON_TABS.includes(value as SysMonTab) ? (value as SysMonTab) : "overview";
|
|
47
|
+
}
|
|
19
48
|
|
|
20
49
|
export interface SystemMonitorBodyProps {
|
|
21
50
|
initialTab?: SysMonTab;
|
|
@@ -59,12 +88,24 @@ export const SystemMonitorBody = memo(function SystemMonitorBody({
|
|
|
59
88
|
}: SystemMonitorBodyProps) {
|
|
60
89
|
const { latest, history, isConnected, tickCount } = useResourceMonitor({ processes: true });
|
|
61
90
|
const [tab, setTab] = useState<SysMonTab>(initialTab);
|
|
91
|
+
const [prefsOpen, setPrefsOpen] = useState(false);
|
|
92
|
+
// The Performance page's selected device lives here rather than in that panel,
|
|
93
|
+
// because an Overview card has to be able to set it on the way in. `null` is
|
|
94
|
+
// "nothing chosen" — the desktop sidebar falls back to its first entry and the
|
|
95
|
+
// phone shows the device list, which is what both did before.
|
|
96
|
+
const [device, setDevice] = useState<string | null>(null);
|
|
62
97
|
|
|
63
98
|
const selectTab = (next: SysMonTab) => {
|
|
64
99
|
setTab(next);
|
|
65
100
|
onTabChange?.(next);
|
|
66
101
|
};
|
|
67
102
|
|
|
103
|
+
/** An Overview card was clicked: select its device, then show Performance. */
|
|
104
|
+
const openDevice = (key: string) => {
|
|
105
|
+
setDevice(key);
|
|
106
|
+
selectTab("performance");
|
|
107
|
+
};
|
|
108
|
+
|
|
68
109
|
const elapsed = latest ? Math.round((Date.now() - latest.ts) / 1000) : 0;
|
|
69
110
|
const warnings = latest?.warnings ?? [];
|
|
70
111
|
|
|
@@ -88,54 +129,71 @@ export const SystemMonitorBody = memo(function SystemMonitorBody({
|
|
|
88
129
|
</div>
|
|
89
130
|
)}
|
|
90
131
|
|
|
91
|
-
{/* Sub-tab switcher
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
className={cn(
|
|
115
|
-
"flex-1 md:flex-none min-h-11 px-4 text-sm font-medium transition-colors",
|
|
116
|
-
tab === "processes"
|
|
117
|
-
? "text-text-primary border-b-2 border-primary -mb-px"
|
|
118
|
-
: "text-text-subtle hover:text-text-secondary",
|
|
119
|
-
)}
|
|
120
|
-
>
|
|
121
|
-
Processes
|
|
122
|
-
</button>
|
|
123
|
-
{variant === "window" && (
|
|
124
|
-
<div className="ml-auto pr-3">
|
|
132
|
+
{/* Sub-tab switcher. Five tabs no longer fit a phone, so the strip scrolls
|
|
133
|
+
sideways rather than wrapping to a second row that would eat the list. */}
|
|
134
|
+
<div className="flex items-center border-b border-border shrink-0 overflow-x-auto" role="tablist">
|
|
135
|
+
{SYSMON_TABS.map((id) => (
|
|
136
|
+
<button
|
|
137
|
+
key={id}
|
|
138
|
+
type="button"
|
|
139
|
+
role="tab"
|
|
140
|
+
aria-selected={tab === id}
|
|
141
|
+
data-testid={`sysmon-tab-${id}`}
|
|
142
|
+
onClick={() => selectTab(id)}
|
|
143
|
+
className={cn(
|
|
144
|
+
"shrink-0 min-h-11 px-4 text-sm font-medium transition-colors",
|
|
145
|
+
tab === id
|
|
146
|
+
? "text-text-primary border-b-2 border-primary -mb-px"
|
|
147
|
+
: "text-text-subtle hover:text-text-secondary",
|
|
148
|
+
)}
|
|
149
|
+
>
|
|
150
|
+
{TAB_LABELS[id]}
|
|
151
|
+
</button>
|
|
152
|
+
))}
|
|
153
|
+
<div className="ml-auto flex items-center gap-2 pl-3 pr-1 shrink-0">
|
|
154
|
+
{variant === "window" && (
|
|
125
155
|
<ConnectionIndicator isConnected={isConnected} elapsed={elapsed} tickCount={tickCount} />
|
|
126
|
-
|
|
127
|
-
|
|
156
|
+
)}
|
|
157
|
+
<button
|
|
158
|
+
type="button"
|
|
159
|
+
aria-label="System Monitor preferences"
|
|
160
|
+
aria-expanded={prefsOpen}
|
|
161
|
+
onClick={() => setPrefsOpen((open) => !open)}
|
|
162
|
+
data-testid="sysmon-prefs-toggle"
|
|
163
|
+
className={cn(
|
|
164
|
+
"flex items-center justify-center size-11 md:size-8 rounded transition-colors",
|
|
165
|
+
prefsOpen ? "text-primary bg-primary/10" : "text-text-subtle hover:text-text-secondary hover:bg-surface-hover",
|
|
166
|
+
)}
|
|
167
|
+
>
|
|
168
|
+
<Settings className="size-4" />
|
|
169
|
+
</button>
|
|
170
|
+
</div>
|
|
128
171
|
</div>
|
|
129
172
|
|
|
130
|
-
{
|
|
173
|
+
{prefsOpen && <SysMonPreferences />}
|
|
174
|
+
|
|
175
|
+
{/* Body — scrolls internally, never the page. Services is the one tab that
|
|
176
|
+
does not wait on `latest`: it has its own endpoint and would otherwise be
|
|
177
|
+
blank on a host where the metrics stream is the thing that is broken. */}
|
|
131
178
|
<div className="flex-1 min-h-0 overflow-y-auto">
|
|
132
179
|
<Suspense fallback={<div className="p-4 text-xs text-text-subtle">Loading…</div>}>
|
|
133
|
-
{
|
|
180
|
+
{tab === "services" ? (
|
|
181
|
+
<ServicesPanel active metrics={latest} />
|
|
182
|
+
) : !latest ? (
|
|
134
183
|
<div className="flex items-center justify-center h-full text-text-subtle text-sm p-4">
|
|
135
184
|
{isConnected ? "Waiting for data…" : "Connecting to resource monitor…"}
|
|
136
185
|
</div>
|
|
137
186
|
) : tab === "overview" ? (
|
|
138
|
-
<OverviewPanel system={latest.system} history={history} />
|
|
187
|
+
<OverviewPanel system={latest.system} history={history} onOpenDevice={openDevice} />
|
|
188
|
+
) : tab === "performance" ? (
|
|
189
|
+
<PerformancePanel
|
|
190
|
+
system={latest.system}
|
|
191
|
+
history={history}
|
|
192
|
+
device={device}
|
|
193
|
+
onDeviceChange={setDevice}
|
|
194
|
+
/>
|
|
195
|
+
) : tab === "apps" ? (
|
|
196
|
+
<AppsPanel snapshot={latest} />
|
|
139
197
|
) : (
|
|
140
198
|
<ProcessTable snapshot={latest} />
|
|
141
199
|
)}
|
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
* window's payload so a reload restores it. */
|
|
3
3
|
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
4
4
|
import type { WindowContentProps } from "@/components/floating-window/window-content-registry";
|
|
5
|
-
import { SystemMonitorBody } from "./system-monitor-body";
|
|
5
|
+
import { SystemMonitorBody, parseSysMonTab } from "./system-monitor-body";
|
|
6
6
|
|
|
7
7
|
export default function SystemMonitorWindowContent({ id, payload }: WindowContentProps) {
|
|
8
8
|
const setPayload = useWindowStore((s) => s.setPayload);
|
|
9
|
-
const initialTab = payload?.tab === "processes" ? "processes" : "overview";
|
|
10
9
|
|
|
11
10
|
return (
|
|
12
11
|
<SystemMonitorBody
|
|
13
|
-
initialTab={
|
|
12
|
+
initialTab={parseSysMonTab(payload?.tab)}
|
|
14
13
|
onTabChange={(tab) => setPayload(id, { tab })}
|
|
15
14
|
variant="window"
|
|
16
15
|
/>
|