@hienlh/ppm 0.18.8 → 0.18.9
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/.spike/s.err +63 -0
- package/.spike/tunnel.err +42 -0
- package/.spike/w.err +96 -0
- package/CHANGELOG.md +9 -0
- package/CLAUDE.md +1 -0
- 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 +4 -3
- package/dist/web/assets/{ai-resource-editor-BydGrxjb.js → ai-resource-editor-DFCuNe-P.js} +1 -1
- package/dist/web/assets/{angular-html-jfMqUuRd.js → angular-html-Ctz0zN01.js} +1 -1
- package/dist/web/assets/{angular-ts-wytn9PMm.js → angular-ts-QXHpgB1C.js} +1 -1
- package/dist/web/assets/{api-settings-DlcoR5QT.js → api-settings-nblja3Rk.js} +1 -1
- package/dist/web/assets/{apl-i-ahKx6O.js → apl-b9KVk-O4.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-C7ra20CE.js +1 -0
- package/dist/web/assets/{astro-DVBCJfG6.js → astro-BlFEeGYr.js} +1 -1
- package/dist/web/assets/{audio-preview-DzBGq9Lk.js → audio-preview-CZLmhf__.js} +1 -1
- package/dist/web/assets/{blade-BHlL8SqU.js → blade-CGkj2MUI.js} +1 -1
- package/dist/web/assets/{bsl-D-UOfR1F.js → bsl-CVsbb6ap.js} +1 -1
- package/dist/web/assets/button-BA_fJOtX.js +1 -0
- package/dist/web/assets/{cairo-Bn6rucli.js → cairo-BbIHl2iE.js} +1 -1
- package/dist/web/assets/chat-tab-flMPLoKb.js +15 -0
- package/dist/web/assets/circle-hjUGru6R.js +1 -0
- package/dist/web/assets/circle-question-mark-CzR7YRc-.js +1 -0
- package/dist/web/assets/{cobol-Byn9FYKu.js → cobol-BWSGjmWb.js} +1 -1
- package/dist/web/assets/code-editor-C2VQbXzw.js +10 -0
- package/dist/web/assets/{coffee-DjBl4gm-.js → coffee-CWGNOxds.js} +1 -1
- package/dist/web/assets/{conflict-editor-CRConSGG.js → conflict-editor-CdH_h0vD.js} +3 -3
- package/dist/web/assets/{context-menu-DkQdt6YA.js → context-menu-Cq0u3SK9.js} +1 -1
- package/dist/web/assets/{cpp-CKzic-3E.js → cpp-DHGV24J2.js} +1 -1
- package/dist/web/assets/{crystal-Bkg-Ly_g.js → crystal-Vlwf2UMP.js} +1 -1
- package/dist/web/assets/{csv-preview-BtCGfmrq.js → csv-preview-CY_454vd.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-B1mTl3KS.js → data-grid-overlay-editor-D9il5DZS.js} +1 -1
- package/dist/web/assets/{database-viewer-2M5sKRqb.js → database-viewer-BCZOTrPT.js} +1 -1
- package/dist/web/assets/{diff-viewer-BMr7vOvZ.js → diff-viewer-BwfMN-nW.js} +1 -1
- package/dist/web/assets/{docx-preview-BpG2kr_-.js → docx-preview-D3Sdh_aT.js} +1 -1
- package/dist/web/assets/{edge-DVbZnd3Y.js → edge-Bhqk64zS.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-BivQwZMD.js → edit-diff-preview-gq6ALf2B.js} +1 -1
- package/dist/web/assets/{elixir-Dwi8Wu7W.js → elixir-D466WCFm.js} +1 -1
- package/dist/web/assets/{elm-DtIv-HXJ.js → elm-Bfs2qNPR.js} +1 -1
- package/dist/web/assets/{erb-D3HEDz1x.js → erb-WI7jUaB6.js} +1 -1
- package/dist/web/assets/{erlang-2MjTCzGz.js → erlang-BCBe8nCc.js} +1 -1
- package/dist/web/assets/{esm-CZ8B8Ba2.js → esm-CZs9WVDO.js} +1 -1
- package/dist/web/assets/{explorer-body-DXufyj-9.js → explorer-body-BKOMM566.js} +2 -2
- package/dist/web/assets/{explorer-window-content-B3krk4G1.js → explorer-window-content-Bbzijk8t.js} +1 -1
- package/dist/web/assets/{extension-webview-12M45CGq.js → extension-webview-CuOQrHIS.js} +1 -1
- package/dist/web/assets/format-bytes-Dk7B73B7.js +1 -0
- package/dist/web/assets/{fortran-fixed-form-BLyAtyPM.js → fortran-fixed-form-CXLIv8Ox.js} +1 -1
- package/dist/web/assets/{fsharp-Bxbn_gbr.js → fsharp-CZsYmiw9.js} +1 -1
- package/dist/web/assets/{gdresource-sFMY4D2Q.js → gdresource-BGRvoWfC.js} +1 -1
- package/dist/web/assets/{git-commit-BzB9Lio5.js → git-commit-DH6mY3Km.js} +1 -1
- package/dist/web/assets/{git-log-panel-Cp4k3tX_.js → git-log-panel-DcV7PhqW.js} +1 -1
- package/dist/web/assets/{git-rebase-CKSVd848.js → git-rebase-C5Gql6Ma.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +1 -0
- package/dist/web/assets/{glide-data-grid-B0BB0VDl.js → glide-data-grid-Cehfgrzc.js} +7 -7
- package/dist/web/assets/{glimmer-js-BY8aExAJ.js → glimmer-js-1-6JMJlj.js} +1 -1
- package/dist/web/assets/{glimmer-ts-Bak54dBX.js → glimmer-ts-C_Njj0nK.js} +1 -1
- package/dist/web/assets/{glsl-nR2eaJQe.js → glsl-DbkxE1TN.js} +1 -1
- package/dist/web/assets/{graphql-CGPPFAU6.js → graphql-BK75fiXl.js} +1 -1
- package/dist/web/assets/group-chat-tab-BVPYxjz-.js +1 -0
- package/dist/web/assets/{hack-CXIMX-Ol.js → hack-DG151vit.js} +1 -1
- package/dist/web/assets/{haml-tPY-9Pfm.js → haml-DKeIPQWM.js} +1 -1
- package/dist/web/assets/{handlebars-BuW1LT7T.js → handlebars-398uCI13.js} +1 -1
- package/dist/web/assets/{html-bgVcwZ-t.js → html-NLWdst5q.js} +1 -1
- package/dist/web/assets/{html-derivative-D6-IxTgn.js → html-derivative-CJf_Le2z.js} +1 -1
- package/dist/web/assets/{http-CJ1zyB-h.js → http-G1K2FozA.js} +1 -1
- package/dist/web/assets/{hurl-CmoT7l3T.js → hurl-WDC6sSBz.js} +1 -1
- package/dist/web/assets/{hxml-CztOsL8o.js → hxml-Dc3jBXuf.js} +1 -1
- package/dist/web/assets/{image-preview-3HfuxA0N.js → image-preview-D-Ok10eZ.js} +1 -1
- package/dist/web/assets/index-CerSxGdf.js +52 -0
- package/dist/web/assets/index-DRA_OpWY.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +1 -0
- package/dist/web/assets/{jinja-B1pq3jJq.js → jinja-CWsQj2y0.js} +1 -1
- package/dist/web/assets/{jison-D8B5pCwA.js → jison-CciJg2NW.js} +1 -1
- package/dist/web/assets/{julia-D0K3bwpU.js → julia-IOQNJAB7.js} +1 -1
- package/dist/web/assets/{just-B9Jlddu-.js → just-BGdHchwS.js} +1 -1
- package/dist/web/assets/{keybindings-store-oMJmtpH4.js → keybindings-store-aIY40k2o.js} +1 -1
- package/dist/web/assets/{latex-BPJSSE6j.js → latex-D6TOl-L2.js} +1 -1
- package/dist/web/assets/{liquid-lv10fo4U.js → liquid-CVSvu_Wn.js} +1 -1
- package/dist/web/assets/{lua-PNuaIBEF.js → lua-CcKiU6HW.js} +1 -1
- package/dist/web/assets/markdown-renderer-I89kyQhe.js +1 -0
- package/dist/web/assets/{markdown-renderer-DPcoPjmO.js → markdown-renderer-pVzBdkpl.js} +3 -3
- package/dist/web/assets/{marko-Du3frD6X.js → marko--UOicMGo.js} +1 -1
- package/dist/web/assets/{mdc-BeDVcFRl.js → mdc-D690aU2C.js} +1 -1
- package/dist/web/assets/{mobile-explorer-sheet-CEVcU964.js → mobile-explorer-sheet-5Uj9ZMM9.js} +1 -1
- package/dist/web/assets/{nextflow-DkcXP71s.js → nextflow-DR8PhpF8.js} +1 -1
- package/dist/web/assets/{nginx-C5n8N_bt.js → nginx-Qb9pUk1g.js} +1 -1
- package/dist/web/assets/{nim-CIhyfs-A.js → nim-DLa8R3NS.js} +1 -1
- package/dist/web/assets/{notification-store-B8AqxwRT.js → notification-store-DJ-OtAG3.js} +1 -1
- package/dist/web/assets/{number-overlay-editor-NgOsWJ7x.js → number-overlay-editor-D9SkFg1Y.js} +1 -1
- package/dist/web/assets/overview-panel-Cgi3UPY1.js +1 -0
- package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +1 -0
- package/dist/web/assets/{pdf-preview-BslNoDFw.js → pdf-preview-Di5xHFyT.js} +1 -1
- package/dist/web/assets/{perl-Cf31sZYE.js → perl-AMNGIneF.js} +1 -1
- package/dist/web/assets/{php-Dzl_MDIW.js → php-CDsOOxXn.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +1 -0
- package/dist/web/assets/{postgres-viewer-BtSXQ3S4.js → postgres-viewer-CR6VpTrX.js} +3 -3
- package/dist/web/assets/process-table-DL6shbzt.js +1 -0
- package/dist/web/assets/{pug-CxSYHrB3.js → pug-C2kdkhQ6.js} +1 -1
- package/dist/web/assets/{qml-DlEjGhwN.js → qml-DRDkUp75.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +1 -0
- package/dist/web/assets/{razor-KVt5uW14.js → razor-wY_6wUeC.js} +1 -1
- package/dist/web/assets/{rst-D5BwNTnw.js → rst-BRpofyNs.js} +1 -1
- package/dist/web/assets/{ruby-D5fejQwd.js → ruby-ieATBhWm.js} +1 -1
- package/dist/web/assets/{sas-Bj7B1CB2.js → sas-CoOOEbOO.js} +1 -1
- package/dist/web/assets/{scss-BB0CUoCL.js → scss-_nWV0bsb.js} +1 -1
- package/dist/web/assets/{settings-store-C9YT1Hir.js → settings-store-C20lqh0G.js} +2 -2
- package/dist/web/assets/settings-tab-jbiQwozX.js +1 -0
- package/dist/web/assets/{shaderlab-BdjEZUMc.js → shaderlab-XkqfIfO8.js} +1 -1
- package/dist/web/assets/{shellsession-Bp1OA1rR.js → shellsession-BKBIqTlM.js} +1 -1
- package/dist/web/assets/{soy-DlYz3wsC.js → soy-oVDnPzzh.js} +1 -1
- package/dist/web/assets/{sparql-CdfII5Jd.js → sparql-N2VclEsF.js} +1 -1
- package/dist/web/assets/{sql-query-editor-CkvpmXyA.js → sql-query-editor-BPYsJDsn.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-CJbP6ruh.js → sqlite-viewer-Bq9ZJA2y.js} +1 -1
- package/dist/web/assets/{stata-BvUA6GUW.js → stata-BuuClVDg.js} +1 -1
- package/dist/web/assets/{surrealql--DLNbTyI.js → surrealql-DE5_63MS.js} +1 -1
- package/dist/web/assets/{svelte-CBfSsG4n.js → svelte--YWjlOrK.js} +1 -1
- package/dist/web/assets/system-monitor-body-CKEYWyN9.js +2 -0
- package/dist/web/assets/system-monitor-tab-WjhFFHyM.js +1 -0
- package/dist/web/assets/system-monitor-window-content-CMiISeoC.js +1 -0
- package/dist/web/assets/team-member-sheet-oY5EkH53.js +2 -0
- package/dist/web/assets/{team-member-window-content-Cxh-HF2V.js → team-member-window-content-yCBeI_5X.js} +1 -1
- package/dist/web/assets/{templ-Dv8zpKZW.js → templ-MlpvJx4a.js} +1 -1
- package/dist/web/assets/{terminal-tab-gQCs_fyx.js → terminal-tab-BxHtMR7h.js} +3 -3
- package/dist/web/assets/{tex-CsrOiqh1.js → tex-0loAoXJG.js} +1 -1
- package/dist/web/assets/{tool-cards-BG2fz83z.js → tool-cards-BcGrk1zk.js} +5 -5
- package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +1 -0
- package/dist/web/assets/{ts-tags-3T98k4EJ.js → ts-tags-pt-Ug0hK.js} +1 -1
- package/dist/web/assets/{twig-u6QZ45FH.js → twig-DOePpLOL.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-DaqI7O-a.js → use-monaco-theme-CGucu3fb.js} +1 -1
- package/dist/web/assets/{use-open-team-member-DKpstvLS.js → use-open-team-member-DdrRXj-M.js} +1 -1
- package/dist/web/assets/{use-websocket-KVhDtbwK.js → use-websocket-C-Rxv8JN.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-Bg4vE8QA.js → vendor-mermaid-DrwG0NYt.js} +1 -1
- package/dist/web/assets/{video-preview-CVEUDZBj.js → video-preview-DYAbbmd0.js} +1 -1
- package/dist/web/assets/{vue-CxIsxtwn.js → vue-D6f-rprj.js} +1 -1
- package/dist/web/assets/{vue-html-BGL5qnuH.js → vue-html-DEYRkS1V.js} +1 -1
- package/dist/web/assets/{vue-vine-DHPh_gMr.js → vue-vine-CxSG2ojf.js} +1 -1
- package/dist/web/assets/{xml-C-vM2m7J.js → xml-DhrxbATj.js} +1 -1
- package/dist/web/assets/{xsl-DvTXNwuO.js → xsl-CU0ZndUO.js} +1 -1
- package/dist/web/index.html +18 -17
- package/dist/web/sw.js +1 -1
- package/docs/system-architecture.md +2 -2
- package/package.json +1 -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/src/server/index.ts +2 -8
- package/src/server/routes/resources.ts +119 -73
- package/src/services/autostart-generator.ts +79 -7
- package/src/services/autostart-register.ts +15 -2
- package/src/services/edge-forwarder.ts +191 -191
- package/src/services/proc-table-linux.ts +4 -0
- package/src/services/redact-secrets.ts +33 -0
- package/src/services/system-metrics/cpu-memory-collector.ts +101 -0
- package/src/services/system-metrics/disk-net-collector-darwin.ts +75 -0
- package/src/services/system-metrics/disk-net-collector-linux.ts +88 -0
- package/src/services/system-metrics/disk-net-collector-windows.ts +57 -0
- package/src/services/system-metrics/gpu-collector-nvidia.ts +78 -0
- package/src/services/system-metrics/gpu-process-memory-nvidia.ts +66 -0
- package/src/services/system-metrics/gpu-process-usage-windows.ts +138 -0
- package/src/services/system-metrics/kill-executor.ts +85 -0
- package/src/services/system-metrics/kill-guard.ts +124 -0
- package/src/services/system-metrics/kill-identity-resolver.ts +72 -0
- package/src/services/system-metrics/kill-request-handler.ts +79 -0
- package/src/services/system-metrics/metrics-collector-lock.ts +36 -0
- package/src/services/system-metrics/metrics-poll-scheduler.ts +83 -0
- package/src/services/system-metrics/metrics-subscriber-registry.ts +85 -0
- package/src/services/system-metrics/powershell-session-bootstrap.ts +48 -0
- package/src/services/system-metrics/powershell-session.ts +182 -0
- package/src/services/system-metrics/ppm-process-ownership.ts +34 -0
- package/src/services/system-metrics/ppm-protected-pids.ts +84 -0
- package/src/services/system-metrics/process-collector-darwin.ts +141 -0
- package/src/services/system-metrics/process-collector-linux.ts +85 -0
- package/src/services/system-metrics/process-collector-types.ts +80 -0
- package/src/services/system-metrics/process-collector-windows-parse.ts +153 -0
- package/src/services/system-metrics/process-collector-windows.ts +136 -0
- package/src/services/system-metrics/process-cpu-delta.ts +61 -0
- package/src/services/system-metrics/process-grouping.ts +142 -0
- package/src/services/system-metrics/process-io-delta.ts +84 -0
- package/src/services/system-metrics/process-io-linux.ts +46 -0
- package/src/services/system-metrics/process-net-collector-darwin.ts +103 -0
- package/src/services/system-metrics/process-rows-builder.ts +111 -0
- package/src/services/system-metrics/rate-delta.ts +47 -0
- package/src/services/system-metrics/system-metrics-platform.ts +51 -0
- package/src/services/system-metrics/system-metrics-tick.ts +178 -0
- package/src/services/system-metrics/system-metrics.service.ts +212 -0
- package/src/services/windows-process-tree.ts +351 -351
- package/src/types/system-metrics.ts +199 -0
- package/src/web/components/floating-window/window-content-registry.ts +2 -0
- package/src/web/components/floating-window/window-persistence.ts +1 -1
- package/src/web/components/floating-window/window-store-types.ts +1 -1
- package/src/web/components/system/build-kill-request.ts +9 -0
- package/src/web/components/system/chart-scale.ts +28 -0
- package/src/web/components/system/cpu-core-bars.tsx +33 -0
- package/src/web/components/system/kill-confirm-dialog.tsx +89 -0
- package/src/web/components/system/metric-chart-canvas.tsx +108 -0
- package/src/web/components/system/overview-cards/cpu-card.tsx +39 -0
- package/src/web/components/system/overview-cards/disk-card.tsx +41 -0
- package/src/web/components/system/overview-cards/gpu-card.tsx +33 -0
- package/src/web/components/system/overview-cards/mem-card.tsx +32 -0
- package/src/web/components/system/overview-cards/net-card.tsx +41 -0
- package/src/web/components/system/overview-panel.tsx +97 -0
- package/src/web/components/system/process-columns-grid.ts +93 -0
- package/src/web/components/system/process-group-row.tsx +71 -0
- package/src/web/components/system/process-row-format.ts +56 -0
- package/src/web/components/system/process-row.tsx +82 -0
- package/src/web/components/system/process-table-model.ts +127 -0
- package/src/web/components/system/process-table-sort.ts +90 -0
- package/src/web/components/system/process-table-toolbar.tsx +190 -0
- package/src/web/components/system/process-table-totals.ts +49 -0
- package/src/web/components/system/process-table.tsx +187 -0
- package/src/web/components/system/resolve-open-system-monitor-action.ts +29 -0
- package/src/web/components/system/resource-status-bar.tsx +17 -16
- package/src/web/components/system/sortable-header.tsx +65 -0
- package/src/web/components/system/sparkline-canvas.tsx +8 -9
- package/src/web/components/system/system-monitor-body.tsx +146 -0
- package/src/web/components/system/system-monitor-tab.tsx +2 -185
- package/src/web/components/system/system-monitor-window-content.tsx +18 -0
- package/src/web/components/system/use-open-system-monitor.ts +34 -0
- package/src/web/hooks/resource-monitor-lease.ts +55 -0
- package/src/web/hooks/use-element-width.ts +27 -0
- package/src/web/hooks/use-resource-monitor.ts +113 -35
- package/src/web/lib/format-bytes.ts +16 -0
- package/dist/web/assets/architecture-PBZL5I3N-Bs7wzj-W.js +0 -1
- package/dist/web/assets/arrow-right-DubGFkN8.js +0 -1
- package/dist/web/assets/button-B4MWPjWj.js +0 -1
- package/dist/web/assets/chat-tab-pBGQ9SCY.js +0 -15
- package/dist/web/assets/circle-question-mark-CENpx4oA.js +0 -1
- package/dist/web/assets/code-editor-XviNXdzi.js +0 -10
- package/dist/web/assets/gitGraph-HDMCJU4V-D7i54kbM.js +0 -1
- package/dist/web/assets/group-chat-tab-CcG_NXIS.js +0 -1
- package/dist/web/assets/index-BAVBuKmT.js +0 -52
- package/dist/web/assets/index-oxsyfDa0.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-BV41AzR9.js +0 -1
- package/dist/web/assets/markdown-renderer-Dg5HE9Zq.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-CaJoP44m.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-DSGZmNw2.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-Be4VUTs0.js +0 -1
- package/dist/web/assets/settings-tab-COSUzGl8.js +0 -1
- package/dist/web/assets/system-monitor-tab-DThAFSd_.js +0 -1
- package/dist/web/assets/team-member-sheet-M83B4znI.js +0 -2
- package/dist/web/assets/treemap-KZPCXAKY-Cu2zgbxU.js +0 -1
- package/src/services/resource-monitor-utils.ts +0 -141
- package/src/services/resource-monitor.service.ts +0 -147
- package/src/web/components/system/system-monitor-group-row.tsx +0 -153
- /package/dist/web/assets/{abap-C1K0-wzc.js → abap-MRbmsXOs.js} +0 -0
- /package/dist/web/assets/{actionscript-3-CJhQVjLA.js → actionscript-3-BDDHKqa4.js} +0 -0
- /package/dist/web/assets/{ada-Bt8r9fME.js → ada-DpuV9KwV.js} +0 -0
- /package/dist/web/assets/{andromeeda-DF1I8qi3.js → andromeeda-D6qUCKJo.js} +0 -0
- /package/dist/web/assets/{apache-CnlleE6P.js → apache-CX1NU_Tl.js} +0 -0
- /package/dist/web/assets/{apex-j0C6Xmk6.js → apex-B4-aoQ3K.js} +0 -0
- /package/dist/web/assets/{api-settings-DfNRPr1q.js → api-settings-kQHV6pYZ.js} +0 -0
- /package/dist/web/assets/{api-themes-8WTH6KpV.js → api-themes-CrK0tkW_.js} +0 -0
- /package/dist/web/assets/{applescript-DO7AnO8U.js → applescript-Dm9NI6KR.js} +0 -0
- /package/dist/web/assets/{apply-theme-CNj1iA-v.js → apply-theme-BH_d4amk.js} +0 -0
- /package/dist/web/assets/{ara-i83AydZj.js → ara-BGN8GAYn.js} +0 -0
- /package/dist/web/assets/{asciidoc-DbBA6-sF.js → asciidoc-s_yVuR3t.js} +0 -0
- /package/dist/web/assets/{asm-B5S47Rgr.js → asm-BzQdSvTe.js} +0 -0
- /package/dist/web/assets/{aurora-x-De_IaSKw.js → aurora-x-BJTLETG_.js} +0 -0
- /package/dist/web/assets/{awk-CfyLHXqS.js → awk-BQEGWxvX.js} +0 -0
- /package/dist/web/assets/{ayu-dark-DTLdZ1Si.js → ayu-dark-CpTORmLc.js} +0 -0
- /package/dist/web/assets/{ayu-light-DTOfkzhu.js → ayu-light-D8PVj-e6.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-DsAECCMv.js → ayu-mirage-DyElQHtm.js} +0 -0
- /package/dist/web/assets/{ballerina-CumGp9A7.js → ballerina-C82NkRtj.js} +0 -0
- /package/dist/web/assets/{bat-Ca2SBbYN.js → bat-0X7DtGI-.js} +0 -0
- /package/dist/web/assets/{beancount-CqyXBwwF.js → beancount-Xgvy6YRl.js} +0 -0
- /package/dist/web/assets/{berry-yl-kJr_H.js → berry-CCT2pZcQ.js} +0 -0
- /package/dist/web/assets/{bibtex-DoFFszjV.js → bibtex-CpXgZ9M_.js} +0 -0
- /package/dist/web/assets/{bicep-CWPi4nfK.js → bicep-fkeSA62l.js} +0 -0
- /package/dist/web/assets/{bird2-DXew-ut0.js → bird2-Co7SeAI8.js} +0 -0
- /package/dist/web/assets/{c-clbySDvd.js → c-BpmrTvJh.js} +0 -0
- /package/dist/web/assets/{c3-B65jvSM1.js → c3-BZ_Z0RrR.js} +0 -0
- /package/dist/web/assets/{cadence-Cm8tQTHN.js → cadence-B0GBC8OF.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-DXGOSUQc.js → can-open-in-ppm-omBzUBBq.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DLeGslh_.js → catppuccin-frappe-DIt_xR7m.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-CR5GeHws.js → catppuccin-latte-Dw40AcqA.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-p-XgjxhP.js → catppuccin-macchiato-BJ7DfVEF.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-B8QOAZLl.js → catppuccin-mocha-NI2lfXzU.js} +0 -0
- /package/dist/web/assets/{clarity-DPulbvKH.js → clarity-F39L0xMJ.js} +0 -0
- /package/dist/web/assets/{clock-D493FU_D.js → clock-CvhF4DJP.js} +0 -0
- /package/dist/web/assets/{clojure-DFuWS20u.js → clojure-DloMkd8K.js} +0 -0
- /package/dist/web/assets/{cmake-DejCqcu4.js → cmake-CwerJun_.js} +0 -0
- /package/dist/web/assets/{code-CLF5x7KK.js → code-DDPoqVri.js} +0 -0
- /package/dist/web/assets/{codeowners-BwAyqWIH.js → codeowners-CQyVz4Qf.js} +0 -0
- /package/dist/web/assets/{codeql-DgSwFjqI.js → codeql-Bb229zuY.js} +0 -0
- /package/dist/web/assets/{common-lisp-CxIVJCtf.js → common-lisp-KMlIwq5I.js} +0 -0
- /package/dist/web/assets/{copy-BApI9v7Z.js → copy-DKn11Pye.js} +0 -0
- /package/dist/web/assets/{coq-DLSjSnmf.js → coq-DHX_3IIo.js} +0 -0
- /package/dist/web/assets/{csharp-C1HHzXBp.js → csharp-CEmCZv9Q.js} +0 -0
- /package/dist/web/assets/{css-VXsMY--y.js → css-CqZqBD05.js} +0 -0
- /package/dist/web/assets/{csv-BEbcJdHz.js → csv-l1g_V5MV.js} +0 -0
- /package/dist/web/assets/{csv-parser-BRtnJCfv.js → csv-parser-CnS0wqr6.js} +0 -0
- /package/dist/web/assets/{cue-BkDnFqUD.js → cue-BrxRmilg.js} +0 -0
- /package/dist/web/assets/{cypher-1cMqojSQ.js → cypher-rZkKwqZc.js} +0 -0
- /package/dist/web/assets/{d-BnYjRXtH.js → d-BALR-QuP.js} +0 -0
- /package/dist/web/assets/{dark-plus-XfbaH7kZ.js → dark-plus-Cj7rVwh-.js} +0 -0
- /package/dist/web/assets/{dart-Ca7s-8hK.js → dart-CWQcdkXk.js} +0 -0
- /package/dist/web/assets/{data-grid-types-BXwlFMzs.js → data-grid-types-CYvF-xK5.js} +0 -0
- /package/dist/web/assets/{database-B9okYLx6.js → database-BH0urvbs.js} +0 -0
- /package/dist/web/assets/{dax-CmuOw-mY.js → dax-BNHD-QBA.js} +0 -0
- /package/dist/web/assets/{desktop-C2gJ6Ovb.js → desktop-CN0IXPrP.js} +0 -0
- /package/dist/web/assets/{diff-BCEo1Ej7.js → diff-BtOXapES.js} +0 -0
- /package/dist/web/assets/{dist-CUPbqNnL.js → dist-DB1Oaqcc.js} +0 -0
- /package/dist/web/assets/{dist-DOlBnxFX.js → dist-Di6G_5jU.js} +0 -0
- /package/dist/web/assets/{docker-DN2jlyAh.js → docker-DNsAo_qO.js} +0 -0
- /package/dist/web/assets/{dotenv-NExMY2kS.js → dotenv-D6Pl6aOU.js} +0 -0
- /package/dist/web/assets/{download-D9UYwY0-.js → download-zCATy4x4.js} +0 -0
- /package/dist/web/assets/{dracula-B9lbE01y.js → dracula-C3m-w12D.js} +0 -0
- /package/dist/web/assets/{dracula-soft-CMBBfKF_.js → dracula-soft-BYqvXm6Z.js} +0 -0
- /package/dist/web/assets/{dream-maker-DEyDwFsd.js → dream-maker-DZAPbPTi.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-D_qP2zS6.js → emacs-lisp-Ao5SW8ay.js} +0 -0
- /package/dist/web/assets/{everforest-dark-DbHa2U-p.js → everforest-dark-uC8QYotQ.js} +0 -0
- /package/dist/web/assets/{everforest-light-BISkJchP.js → everforest-light-CTgsVNMr.js} +0 -0
- /package/dist/web/assets/{fennel-6B22SfJR.js → fennel-WuBw6IR1.js} +0 -0
- /package/dist/web/assets/{file-exclamation-point-a8f3_w7a.js → file-exclamation-point-COAwgNGw.js} +0 -0
- /package/dist/web/assets/{fish-CubIIvJD.js → fish-Byy9dusu.js} +0 -0
- /package/dist/web/assets/{fluent-DF55zQ09.js → fluent-CDxb_sgw.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-DvOu8jAt.js → fortran-free-form-DKWSTamT.js} +0 -0
- /package/dist/web/assets/{gdscript-DCPxdLpq.js → gdscript-prYHMgtD.js} +0 -0
- /package/dist/web/assets/{gdshader-CTZ381FO.js → gdshader-D-RM-SQk.js} +0 -0
- /package/dist/web/assets/{genie-C_QDtvgU.js → genie-CowkJhej.js} +0 -0
- /package/dist/web/assets/{gherkin-BcvK42tF.js → gherkin-CLFpoVYJ.js} +0 -0
- /package/dist/web/assets/{github-dark-default-CKGVrl3Z.js → github-dark-default-BK_1Qgb8.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-C3dQZ_LC.js → github-dark-dimmed-Cv9lj6f-.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-DW78QukY.js → github-dark-high-contrast-CW5ZgIDh.js} +0 -0
- /package/dist/web/assets/{github-dark-C9afs_4w.js → github-dark-nW2F-RLd.js} +0 -0
- /package/dist/web/assets/{github-light-BnP2dznS.js → github-light-D4PqBHGZ.js} +0 -0
- /package/dist/web/assets/{github-light-default-C2fPZzPG.js → github-light-default-B-cHtJJV.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-BzIuUFR2.js → github-light-high-contrast-Dt0HJq50.js} +0 -0
- /package/dist/web/assets/{gleam-BpeKwEIO.js → gleam-DwSyXJWP.js} +0 -0
- /package/dist/web/assets/{gn-nUb_Mit0.js → gn-Cv5WEzHc.js} +0 -0
- /package/dist/web/assets/{gnuplot-D7I0v20p.js → gnuplot-D7bRdY_M.js} +0 -0
- /package/dist/web/assets/{go-D7Qqska7.js → go-DiRVJ22U.js} +0 -0
- /package/dist/web/assets/{groovy-DS-pne5-.js → groovy-BHAgLTeO.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-C0W01fsq.js → gruvbox-dark-hard-C8QZ3gzY.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-Bqo6fQbg.js → gruvbox-dark-medium-Dp1eeid2.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-D-XSM_fu.js → gruvbox-dark-soft-Cwq0dWVj.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-IVAwMJRl.js → gruvbox-light-hard-CLQCq2-w.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-38ATiG7i.js → gruvbox-light-medium-APHsh6Mo.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-DnZr3c_0.js → gruvbox-light-soft-CX-fYc64.js} +0 -0
- /package/dist/web/assets/{haskell-uQcywkDH.js → haskell-C4Tw-TDa.js} +0 -0
- /package/dist/web/assets/{haxe-c6bI4_GT.js → haxe-B7fSduTQ.js} +0 -0
- /package/dist/web/assets/{hcl-CQXTiEXq.js → hcl-Bi3ho6yC.js} +0 -0
- /package/dist/web/assets/{hjson-ChETf2bz.js → hjson-BXwae2M1.js} +0 -0
- /package/dist/web/assets/{hlsl-BMC4JGoE.js → hlsl-CRuQLBSa.js} +0 -0
- /package/dist/web/assets/{horizon-BusFlhLW.js → horizon-DtdQ6qjv.js} +0 -0
- /package/dist/web/assets/{horizon-bright-2oD0Mz7W.js → horizon-bright-BXSF_uKq.js} +0 -0
- /package/dist/web/assets/{houston-DdbbjqFg.js → houston-C6ASpUjT.js} +0 -0
- /package/dist/web/assets/{hy-D_SOuqw9.js → hy-BrWBHtHY.js} +0 -0
- /package/dist/web/assets/{image-gallery-CrM5fHKy.js → image-gallery-CGvlv8zR.js} +0 -0
- /package/dist/web/assets/{imba-BxLOHO5I.js → imba-C_JJXckG.js} +0 -0
- /package/dist/web/assets/{ini-ox-CFcg0.js → ini-DEE_vSHQ.js} +0 -0
- /package/dist/web/assets/{java-Bzo8yIal.js → java-CnmpcjcT.js} +0 -0
- /package/dist/web/assets/{javascript-DHuz9VXn.js → javascript-C-M7sa2e.js} +0 -0
- /package/dist/web/assets/{json-0_y80FD5.js → json-BjZ3dAk6.js} +0 -0
- /package/dist/web/assets/{json5-CEQ50pGM.js → json5-BQ2vpqjp.js} +0 -0
- /package/dist/web/assets/{jsonc-CfrLEAKA.js → jsonc-C5MjoWGx.js} +0 -0
- /package/dist/web/assets/{jsonl-fKbrANC2.js → jsonl-JvhrmQJI.js} +0 -0
- /package/dist/web/assets/{jsonnet-DKbkPaQ2.js → jsonnet-C5pdZVuo.js} +0 -0
- /package/dist/web/assets/{jssm-Dxxx1Hqu.js → jssm-Db17uybX.js} +0 -0
- /package/dist/web/assets/{jsx-DlJL-Oj3.js → jsx-tJp2Cyqu.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-CwN4SV1c.js → kanagawa-dragon-BculT_Y1.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-BHltayiE.js → kanagawa-lotus-yQgHUGwU.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-D-KXPjw6.js → kanagawa-wave-CyGoWN4d.js} +0 -0
- /package/dist/web/assets/{kdl-DvtoJdFo.js → kdl-Bn8R1REF.js} +0 -0
- /package/dist/web/assets/{kotlin-CTS4MLcx.js → kotlin-DWughK73.js} +0 -0
- /package/dist/web/assets/{kusto-HtSE_sKm.js → kusto--serPb0x.js} +0 -0
- /package/dist/web/assets/{laserwave-DaXZG9ge.js → laserwave-DfAPJ1tt.js} +0 -0
- /package/dist/web/assets/{lean-BYtGUfWx.js → lean-UAm1HOKl.js} +0 -0
- /package/dist/web/assets/{less-BoxmU_Mk.js → less-Xj6Ka0fF.js} +0 -0
- /package/dist/web/assets/{lib-B1clP4ai.js → lib-DgNcCtj3.js} +0 -0
- /package/dist/web/assets/{libesm-ah-mr-sh.js → libesm-CPh1Av0r.js} +0 -0
- /package/dist/web/assets/{light-plus-Bt5CyUuo.js → light-plus-BfS7gPcj.js} +0 -0
- /package/dist/web/assets/{llvm-CSdk9q9V.js → llvm-DvWiVwvU.js} +0 -0
- /package/dist/web/assets/{log-B-kp_3CL.js → log-Bo5z9bNz.js} +0 -0
- /package/dist/web/assets/{logo-DdIsXFDO.js → logo-CrIjcMZT.js} +0 -0
- /package/dist/web/assets/{luau-DUBpLlzQ.js → luau-C9TsYwNt.js} +0 -0
- /package/dist/web/assets/{make-B3JVjoW_.js → make-GYq4qVbx.js} +0 -0
- /package/dist/web/assets/{markdown-Seon0vHs.js → markdown-p5mNledS.js} +0 -0
- /package/dist/web/assets/{material-theme-Nq-ChX1P.js → material-theme-CWYOVxsP.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-CPV4ayXJ.js → material-theme-darker-BDGty7YH.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-0kyjYqEd.js → material-theme-lighter-JbgOgV3n.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-DGpAp5co.js → material-theme-ocean-EMOpLpa2.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-B0AUn0NG.js → material-theme-palenight-CY5hgm7h.js} +0 -0
- /package/dist/web/assets/{matlab-C2waytxs.js → matlab-C-He_NTH.js} +0 -0
- /package/dist/web/assets/{mdx-DAis6R6I.js → mdx-Cr2TR5fj.js} +0 -0
- /package/dist/web/assets/{media-url-DlYsHq0S.js → media-url-CylYQld1.js} +0 -0
- /package/dist/web/assets/{mermaid-_rnT2YGD.js → mermaid-BYc0-B0U.js} +0 -0
- /package/dist/web/assets/{min-dark-BSSjchUB.js → min-dark-CMJwqJqB.js} +0 -0
- /package/dist/web/assets/{min-light-DomAFQsa.js → min-light-Cx6vFiEX.js} +0 -0
- /package/dist/web/assets/{mipsasm-bBgtvPyG.js → mipsasm-Bjer5HwK.js} +0 -0
- /package/dist/web/assets/{mobile-bottom-sheet-CS3XMwFw.js → mobile-bottom-sheet-BUOJgiaZ.js} +0 -0
- /package/dist/web/assets/{mojo-Cp9BayW0.js → mojo-t90PR-Y2.js} +0 -0
- /package/dist/web/assets/{monokai-CL_9gbmn.js → monokai-dci_PdCm.js} +0 -0
- /package/dist/web/assets/{moonbit-BS_fcr-P.js → moonbit-AAzI-Hd-.js} +0 -0
- /package/dist/web/assets/{move-C79AH45U.js → move-kwBhnhrG.js} +0 -0
- /package/dist/web/assets/{narrat-CJ5s3BDf.js → narrat-CXww2YQL.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-ZHa4JrPJ.js → nextflow-groovy-CJXsuXGB.js} +0 -0
- /package/dist/web/assets/{night-owl-Jkf9zFQK.js → night-owl-_GD204Wr.js} +0 -0
- /package/dist/web/assets/{night-owl-light-DRPeaG5J.js → night-owl-light-DNgkw3kl.js} +0 -0
- /package/dist/web/assets/{nix-D2Jet9DN.js → nix-BgiorKFd.js} +0 -0
- /package/dist/web/assets/{nord-CREVs22j.js → nord-CaBmcxFC.js} +0 -0
- /package/dist/web/assets/{nushell-CAiDi_mR.js → nushell-DUh4UGx1.js} +0 -0
- /package/dist/web/assets/{objective-c-CVkmJkC1.js → objective-c-Cl9KU86S.js} +0 -0
- /package/dist/web/assets/{objective-cpp-DIKDO1Ly.js → objective-cpp-DVkIA8A0.js} +0 -0
- /package/dist/web/assets/{ocaml-R9qtGQhs.js → ocaml-vvoHTak0.js} +0 -0
- /package/dist/web/assets/{odin-DTYNQqVr.js → odin-Cyjw8woZ.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-BSLWUJn5.js → one-dark-pro-B1cviILi.js} +0 -0
- /package/dist/web/assets/{one-light-DbkRXG3t.js → one-light-BPGUJeYI.js} +0 -0
- /package/dist/web/assets/{openscad-BlPcSnmT.js → openscad-BLMdTUU8.js} +0 -0
- /package/dist/web/assets/{pascal-B1Y46ZZB.js → pascal-i5niy3e7.js} +0 -0
- /package/dist/web/assets/{pkl-BhJSJbFv.js → pkl-CuOV7SsU.js} +0 -0
- /package/dist/web/assets/{plastic-BzxsCTpi.js → plastic-Bf_zE5KL.js} +0 -0
- /package/dist/web/assets/{plsql-DBba7dyP.js → plsql-cfqEtMD3.js} +0 -0
- /package/dist/web/assets/{plus-DmjC2iRB.js → plus-BM-Ty0fp.js} +0 -0
- /package/dist/web/assets/{po-BvgLlnNo.js → po-CFJcWgjr.js} +0 -0
- /package/dist/web/assets/{poimandres-DUaI_1JP.js → poimandres-G5YoaIFf.js} +0 -0
- /package/dist/web/assets/{polar-C7uILwJn.js → polar-rcjs3i9R.js} +0 -0
- /package/dist/web/assets/{postcss-BgJlpFdw.js → postcss-CBKY1FTZ.js} +0 -0
- /package/dist/web/assets/{powerquery-Dn1MIpZu.js → powerquery-Db7SXLbO.js} +0 -0
- /package/dist/web/assets/{powershell-Bo-DYzOS.js → powershell-LFy3MUTP.js} +0 -0
- /package/dist/web/assets/{prisma-CTLs5IdT.js → prisma-BE8GR1lH.js} +0 -0
- /package/dist/web/assets/{prolog-QRGun3eG.js → prolog-DOn5lR1e.js} +0 -0
- /package/dist/web/assets/{proto-B7PI7apn.js → proto-wr-TpAK_.js} +0 -0
- /package/dist/web/assets/{puppet-CBq0tLrP.js → puppet-D2Dkv62u.js} +0 -0
- /package/dist/web/assets/{purescript-DFewOQb2.js → purescript-DvgJgPdy.js} +0 -0
- /package/dist/web/assets/{python-iWuxKXvT.js → python-C7TlkHhK.js} +0 -0
- /package/dist/web/assets/{qmldir-cXiW3AsF.js → qmldir-CtZMwhcW.js} +0 -0
- /package/dist/web/assets/{qss-DASwAbBL.js → qss-dNZ2btnl.js} +0 -0
- /package/dist/web/assets/{r-TU2eaIPw.js → r-BlqnNkHS.js} +0 -0
- /package/dist/web/assets/{racket-SkRKqrLY.js → racket-CzRQrGc4.js} +0 -0
- /package/dist/web/assets/{raku-D31lthkZ.js → raku-BwutWhBF.js} +0 -0
- /package/dist/web/assets/{red-CTcQZevb.js → red-BMXMywmL.js} +0 -0
- /package/dist/web/assets/{reg-D8YAsTGf.js → reg-BqOKrIOw.js} +0 -0
- /package/dist/web/assets/{regexp-CD2uvAWx.js → regexp-Bero1BN2.js} +0 -0
- /package/dist/web/assets/{rel-CAaI-1fg.js → rel-BXKWIElA.js} +0 -0
- /package/dist/web/assets/{resolve-theme-CJvkL8hU.js → resolve-theme-IdhSR-gx.js} +0 -0
- /package/dist/web/assets/{riscv-DR-hJVIj.js → riscv-BbbBYJBo.js} +0 -0
- /package/dist/web/assets/{ron-CuUCJ0n4.js → ron-BtVTWW4b.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-Bqz2sBRY.js → rose-pine-dawn-D7lwhUei.js} +0 -0
- /package/dist/web/assets/{rose-pine-aFHxW48i.js → rose-pine-hvkvQzvU.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-wqyh0an4.js → rose-pine-moon-CoHDmsIw.js} +0 -0
- /package/dist/web/assets/{rosmsg-CI1ywimO.js → rosmsg-CdaZFgI8.js} +0 -0
- /package/dist/web/assets/{run-in-terminal-CGW6o37_.js → run-in-terminal-CyS5Itj-.js} +0 -0
- /package/dist/web/assets/{rust-p7Imk4G_.js → rust-Dy2qsphD.js} +0 -0
- /package/dist/web/assets/{sass-C8JfaqCV.js → sass-Bz7NVxDb.js} +0 -0
- /package/dist/web/assets/{save-DRPrDfTt.js → save-C4z1p51e.js} +0 -0
- /package/dist/web/assets/{scala-DNxCW1By.js → scala-sXSwsNyq.js} +0 -0
- /package/dist/web/assets/{scheme-BYuUPJoL.js → scheme-DS7TUbN7.js} +0 -0
- /package/dist/web/assets/{sdbl-DbPeJPUr.js → sdbl-iISFvIep.js} +0 -0
- /package/dist/web/assets/{send-to-chat-YXHdAyLG.js → send-to-chat-BcO39BDR.js} +0 -0
- /package/dist/web/assets/{shellscript-DMiHlR3q.js → shellscript-BkIl4ApC.js} +0 -0
- /package/dist/web/assets/{shield-check-8GObuUAn.js → shield-check-C5laObJv.js} +0 -0
- /package/dist/web/assets/{shield-off-egKAZEwR.js → shield-off-DULFtyLS.js} +0 -0
- /package/dist/web/assets/{slack-dark-C4xGcQXI.js → slack-dark-B1eg0_m2.js} +0 -0
- /package/dist/web/assets/{slack-ochin-BzgRt_wm.js → slack-ochin-mdkc1ldu.js} +0 -0
- /package/dist/web/assets/{smalltalk-LDeL9PYH.js → smalltalk-CORtd03t.js} +0 -0
- /package/dist/web/assets/{snazzy-light-CXE7a5j_.js → snazzy-light-Bc6Q2G89.js} +0 -0
- /package/dist/web/assets/{solarized-dark-DgUhY74x.js → solarized-dark-CF83zRXM.js} +0 -0
- /package/dist/web/assets/{solarized-light-DD9C-H-9.js → solarized-light-BoKQZaYU.js} +0 -0
- /package/dist/web/assets/{solidity-CAbDB4D4.js → solidity-DOgi1N4w.js} +0 -0
- /package/dist/web/assets/{sparkles-n1hzh65o.js → sparkles-Dqsf3hq6.js} +0 -0
- /package/dist/web/assets/{splunk-kQREPfIc.js → splunk-BXfw5ZLy.js} +0 -0
- /package/dist/web/assets/{sql-CBzeNAD8.js → sql-BcVs-eX4.js} +0 -0
- /package/dist/web/assets/{ssh-config-L1euxrsM.js → ssh-config-CLCtNkkd.js} +0 -0
- /package/dist/web/assets/{stylus-DvBnYniP.js → stylus-DdP992aO.js} +0 -0
- /package/dist/web/assets/{swift-DF5NDQp6.js → swift-BnGb6Lgc.js} +0 -0
- /package/dist/web/assets/{synthwave-84-DbBhB_Hq.js → synthwave-84-cg9264l9.js} +0 -0
- /package/dist/web/assets/{system-verilog-D8s2ZW_k.js → system-verilog-GbHpszs3.js} +0 -0
- /package/dist/web/assets/{systemd-a5-XZJsG.js → systemd-Dz-bNsDQ.js} +0 -0
- /package/dist/web/assets/{table-BX2ZrJfM.js → table-CHmxuh6M.js} +0 -0
- /package/dist/web/assets/{talonscript-BLa0URTW.js → talonscript-CFIidoBA.js} +0 -0
- /package/dist/web/assets/{tasl-DIoV4XcC.js → tasl-Cu-TRTKx.js} +0 -0
- /package/dist/web/assets/{tcl-ztYAdXfQ.js → tcl-DwCHCB1K.js} +0 -0
- /package/dist/web/assets/{terraform-DvpCCiOZ.js → terraform-BzZw4T1z.js} +0 -0
- /package/dist/web/assets/{tokyo-night-BkHlYUv0.js → tokyo-night-RKsj2-tv.js} +0 -0
- /package/dist/web/assets/{toml-acIrxos6.js → toml-CirbOgDP.js} +0 -0
- /package/dist/web/assets/{tsv-BJB5EVCT.js → tsv-CraRcWdU.js} +0 -0
- /package/dist/web/assets/{tsx-B1MmXGT3.js → tsx-CjFg0lgw.js} +0 -0
- /package/dist/web/assets/{turtle-DFceTiqd.js → turtle-B-WBIOa6.js} +0 -0
- /package/dist/web/assets/{typescript-Dz9wU5Y1.js → typescript-MpLarYn1.js} +0 -0
- /package/dist/web/assets/{typespec-CPuYZijj.js → typespec-B7QlHMZ_.js} +0 -0
- /package/dist/web/assets/{typst-CfsCIYv8.js → typst-CcHSKFZj.js} +0 -0
- /package/dist/web/assets/{use-blob-url-BmlYYZ8L.js → use-blob-url-BKyVxOZw.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-B8FA4kQf.js → use-is-mobile-BXGVvczu.js} +0 -0
- /package/dist/web/assets/{v-CGo0jcXA.js → v-xTGhWZuD.js} +0 -0
- /package/dist/web/assets/{vala-AsSR0hrb.js → vala-DwebjH3H.js} +0 -0
- /package/dist/web/assets/{vb-C7tvbXv1.js → vb-BxJT2RAy.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-C1diXHJl.js → vendor-xterm-CU6zIYMB.js} +0 -0
- /package/dist/web/assets/{verilog--a33ND-p.js → verilog-CvV6RHPD.js} +0 -0
- /package/dist/web/assets/{vesper-B_Z0h4pn.js → vesper-CY3qd7E_.js} +0 -0
- /package/dist/web/assets/{vhdl-CWL5dZPN.js → vhdl-B9ZX-sUL.js} +0 -0
- /package/dist/web/assets/{viml-BglmT14Y.js → viml-Y42h_ExQ.js} +0 -0
- /package/dist/web/assets/{vitesse-black-RKFsSqQI.js → vitesse-black-DkXP6Sv-.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-D7zDWNmc.js → vitesse-dark-B9CkIB6r.js} +0 -0
- /package/dist/web/assets/{vitesse-light-MAp87W5b.js → vitesse-light-C7DHrJCK.js} +0 -0
- /package/dist/web/assets/{vyper-CgCBYg1G.js → vyper-Cnd9s5j-.js} +0 -0
- /package/dist/web/assets/{wasm-Bwl4txwp.js → wasm-DQE71XTB.js} +0 -0
- /package/dist/web/assets/{wasm-BOG7ZeTT.js → wasm-iWe7Fzjc.js} +0 -0
- /package/dist/web/assets/{wenyan-DpShPKXZ.js → wenyan-Bc5Pnm9l.js} +0 -0
- /package/dist/web/assets/{wgsl-BakcCblK.js → wgsl-D-YUAWkP.js} +0 -0
- /package/dist/web/assets/{wikitext-NroRWVAO.js → wikitext-DYQDUYf2.js} +0 -0
- /package/dist/web/assets/{wit-B5CM2pg6.js → wit-P6u7mfwy.js} +0 -0
- /package/dist/web/assets/{wolfram-7MTFBJpR.js → wolfram-6SXLUqao.js} +0 -0
- /package/dist/web/assets/{yaml-Bwr01G2K.js → yaml-CQiMLVcZ.js} +0 -0
- /package/dist/web/assets/{zenscript-Dj8GATvi.js → zenscript-DFMywo_P.js} +0 -0
- /package/dist/web/assets/{zig-LAE-fbS-.js → zig-CtAjaIiF.js} +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { formatBps } from "@/lib/format-bytes";
|
|
2
|
+
import { MetricChartCanvas } from "../metric-chart-canvas";
|
|
3
|
+
|
|
4
|
+
export interface NetCardProps {
|
|
5
|
+
available: boolean;
|
|
6
|
+
inBps: number;
|
|
7
|
+
outBps: number;
|
|
8
|
+
downSeries: number[];
|
|
9
|
+
upSeries: number[];
|
|
10
|
+
/** True while the stream has not yet delivered a second tick — a rate needs two
|
|
11
|
+
* samples, so `available:false` here is expected, not a missing collector. */
|
|
12
|
+
measuring?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function NetCard({ available, inBps, outBps, downSeries, upSeries, measuring }: NetCardProps) {
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
className="rounded-lg border border-border p-4 space-y-2"
|
|
19
|
+
data-testid="sysmon-card-net"
|
|
20
|
+
data-available={available}
|
|
21
|
+
>
|
|
22
|
+
<h3 className="text-sm font-medium">Network</h3>
|
|
23
|
+
{available ? (
|
|
24
|
+
<>
|
|
25
|
+
<MetricChartCanvas
|
|
26
|
+
series={[
|
|
27
|
+
{ data: downSeries, color: "var(--color-primary)" },
|
|
28
|
+
{ data: upSeries, color: "var(--color-warning)" },
|
|
29
|
+
]}
|
|
30
|
+
height={56}
|
|
31
|
+
/>
|
|
32
|
+
<p className="text-[11px] text-text-subtle">
|
|
33
|
+
Down {formatBps(inBps)} · Up {formatBps(outBps)}
|
|
34
|
+
</p>
|
|
35
|
+
</>
|
|
36
|
+
) : (
|
|
37
|
+
<p className="text-[11px] text-text-subtle">{measuring ? "measuring…" : "n/a"}</p>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import type { MetricsHistoryPoint, SystemMetrics } from "../../../types/system-metrics";
|
|
3
|
+
import { CpuCard } from "./overview-cards/cpu-card";
|
|
4
|
+
import { MemCard } from "./overview-cards/mem-card";
|
|
5
|
+
import { DiskCard } from "./overview-cards/disk-card";
|
|
6
|
+
import { NetCard } from "./overview-cards/net-card";
|
|
7
|
+
import { GpuCard } from "./overview-cards/gpu-card";
|
|
8
|
+
|
|
9
|
+
export interface OverviewPanelProps {
|
|
10
|
+
system: SystemMetrics;
|
|
11
|
+
history: MetricsHistoryPoint[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const SERIES_POINTS = 200;
|
|
15
|
+
|
|
16
|
+
/** One pass over the recent history window building every card's series together,
|
|
17
|
+
* rather than one `.slice(-200).map(...)` per card. */
|
|
18
|
+
function useOverviewSeries(history: MetricsHistoryPoint[]) {
|
|
19
|
+
return useMemo(() => {
|
|
20
|
+
const recent = history.slice(-SERIES_POINTS);
|
|
21
|
+
const cpu: number[] = [];
|
|
22
|
+
const mem: number[] = [];
|
|
23
|
+
const diskRead: number[] = [];
|
|
24
|
+
const diskWrite: number[] = [];
|
|
25
|
+
const netDown: number[] = [];
|
|
26
|
+
const netUp: number[] = [];
|
|
27
|
+
const gpuUtil: number[][] = [];
|
|
28
|
+
|
|
29
|
+
for (const point of recent) {
|
|
30
|
+
cpu.push(point.system.cpu.total);
|
|
31
|
+
mem.push(point.system.mem.percent);
|
|
32
|
+
diskRead.push(point.system.disk.available ? point.system.disk.inBps : 0);
|
|
33
|
+
diskWrite.push(point.system.disk.available ? point.system.disk.outBps : 0);
|
|
34
|
+
netDown.push(point.system.net.available ? point.system.net.inBps : 0);
|
|
35
|
+
netUp.push(point.system.net.available ? point.system.net.outBps : 0);
|
|
36
|
+
point.system.gpus.forEach((g, i) => {
|
|
37
|
+
(gpuUtil[i] ??= []).push(g.utilPercent);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return { cpu, mem, diskRead, diskWrite, netDown, netUp, gpuUtil };
|
|
42
|
+
}, [history]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function OverviewPanel({ system, history }: OverviewPanelProps) {
|
|
46
|
+
const series = useOverviewSeries(history);
|
|
47
|
+
// Disk/net rates need a delta between two samples — `available:false` on the very
|
|
48
|
+
// first frame(s) is the collector doing exactly what it should, not a missing
|
|
49
|
+
// source, so the card says so instead of the flat, indistinguishable "n/a".
|
|
50
|
+
const measuring = history.length <= 1;
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
className="p-4 grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4"
|
|
55
|
+
data-testid="sysmon-overview"
|
|
56
|
+
>
|
|
57
|
+
<CpuCard
|
|
58
|
+
total={system.cpu.total}
|
|
59
|
+
cores={system.cpu.cores}
|
|
60
|
+
model={system.cpu.model}
|
|
61
|
+
series={series.cpu}
|
|
62
|
+
/>
|
|
63
|
+
<MemCard
|
|
64
|
+
usedMB={system.mem.usedMB}
|
|
65
|
+
totalMB={system.mem.totalMB}
|
|
66
|
+
percent={system.mem.percent}
|
|
67
|
+
series={series.mem}
|
|
68
|
+
/>
|
|
69
|
+
<DiskCard
|
|
70
|
+
available={system.disk.available}
|
|
71
|
+
inBps={system.disk.inBps}
|
|
72
|
+
outBps={system.disk.outBps}
|
|
73
|
+
readSeries={series.diskRead}
|
|
74
|
+
writeSeries={series.diskWrite}
|
|
75
|
+
measuring={measuring}
|
|
76
|
+
/>
|
|
77
|
+
<NetCard
|
|
78
|
+
available={system.net.available}
|
|
79
|
+
inBps={system.net.inBps}
|
|
80
|
+
outBps={system.net.outBps}
|
|
81
|
+
downSeries={series.netDown}
|
|
82
|
+
upSeries={series.netUp}
|
|
83
|
+
measuring={measuring}
|
|
84
|
+
/>
|
|
85
|
+
{system.gpus.map((gpu, i) => (
|
|
86
|
+
<GpuCard
|
|
87
|
+
key={`${gpu.name}-${i}`}
|
|
88
|
+
name={gpu.name}
|
|
89
|
+
utilPercent={gpu.utilPercent}
|
|
90
|
+
vramUsedMB={gpu.vramUsedMB}
|
|
91
|
+
vramTotalMB={gpu.vramTotalMB}
|
|
92
|
+
series={series.gpuUtil[i] ?? []}
|
|
93
|
+
/>
|
|
94
|
+
))}
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** Pure grid-template builder for the process table. No React, so the visibility
|
|
2
|
+
* rules (which optional columns exist, which one survives below `@lg`) are
|
|
3
|
+
* unit-testable without mounting a component.
|
|
4
|
+
*
|
|
5
|
+
* Two responsive templates are computed up front and switched via CSS custom
|
|
6
|
+
* properties + a `@lg:` Tailwind class (see `PROCESS_ROW_GRID_CLASS` below) —
|
|
7
|
+
* Tailwind's arbitrary-value scan only needs the class NAME to be a static
|
|
8
|
+
* string; the var() value itself can vary at runtime. This mirrors the fixed
|
|
9
|
+
* two-template approach the process table already used for the trend/age
|
|
10
|
+
* track, just parameterised by which optional columns the host can measure. */
|
|
11
|
+
import type { CSSProperties } from "react";
|
|
12
|
+
import type { ProcessColumnAvailability, SortKey } from "../../../types/system-metrics";
|
|
13
|
+
|
|
14
|
+
export type OptionalColumnKey = "disk" | "gpu" | "net";
|
|
15
|
+
|
|
16
|
+
/** Alias kept local so call sites don't need to know the exact server-contract
|
|
17
|
+
* type name — this module only cares about the three boolean flags. */
|
|
18
|
+
export type ProcessColumnsFlags = ProcessColumnAvailability;
|
|
19
|
+
|
|
20
|
+
const OPTIONAL_COLUMN_ORDER: OptionalColumnKey[] = ["disk", "gpu", "net"];
|
|
21
|
+
|
|
22
|
+
/** Disk/Net cells show two values ("↓ read ↑ write"); GPU shows one composite
|
|
23
|
+
* ("12% · 1.1 GB") and fits narrower. */
|
|
24
|
+
const OPTIONAL_COLUMN_WIDTH: Record<OptionalColumnKey, string> = {
|
|
25
|
+
disk: "120px",
|
|
26
|
+
gpu: "90px",
|
|
27
|
+
net: "120px",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** Fixed tracks that exist regardless of optional columns: Process name (flexible),
|
|
31
|
+
* CPU, RAM at the start; the trend/age track (wide only) and the kill button at
|
|
32
|
+
* the end. */
|
|
33
|
+
const NAME_CPU_RAM = ["minmax(0,1fr)", "64px", "80px"];
|
|
34
|
+
const TREND_TRACK = "130px";
|
|
35
|
+
const KILL_TRACK = "44px";
|
|
36
|
+
|
|
37
|
+
export interface ProcessGridResult {
|
|
38
|
+
/** Grid template for `@lg` and up: Name/CPU/RAM + every enabled optional column
|
|
39
|
+
* in a fixed order + the trend/age track + kill button. */
|
|
40
|
+
wideTemplate: string;
|
|
41
|
+
/** Grid template below `@lg`: Name/CPU/RAM + AT MOST the one optional column
|
|
42
|
+
* currently sorted by (if enabled) + kill button. No trend/age track. */
|
|
43
|
+
narrowTemplate: string;
|
|
44
|
+
/** Which optional columns are enabled at all (host can measure them). */
|
|
45
|
+
columns: ProcessColumnsFlags;
|
|
46
|
+
/** The single optional column visible below `@lg`, or null when the current
|
|
47
|
+
* sort isn't on an optional column (or that column isn't enabled). */
|
|
48
|
+
narrowExtra: OptionalColumnKey | null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isOptionalColumnKey(key: SortKey): key is OptionalColumnKey {
|
|
52
|
+
return key === "disk" || key === "gpu" || key === "net";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function buildProcessGrid(columns: ProcessColumnsFlags, sortKey: SortKey): ProcessGridResult {
|
|
56
|
+
const enabled = OPTIONAL_COLUMN_ORDER.filter((k) => columns[k]);
|
|
57
|
+
const narrowExtra = isOptionalColumnKey(sortKey) && columns[sortKey] ? sortKey : null;
|
|
58
|
+
|
|
59
|
+
const wideTemplate = [
|
|
60
|
+
...NAME_CPU_RAM,
|
|
61
|
+
...enabled.map((k) => OPTIONAL_COLUMN_WIDTH[k]),
|
|
62
|
+
TREND_TRACK,
|
|
63
|
+
KILL_TRACK,
|
|
64
|
+
].join(" ");
|
|
65
|
+
|
|
66
|
+
const narrowTemplate = [
|
|
67
|
+
...NAME_CPU_RAM,
|
|
68
|
+
...(narrowExtra ? [OPTIONAL_COLUMN_WIDTH[narrowExtra]] : []),
|
|
69
|
+
KILL_TRACK,
|
|
70
|
+
].join(" ");
|
|
71
|
+
|
|
72
|
+
return { wideTemplate, narrowTemplate, columns, narrowExtra };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Static class names (Tailwind can see both arbitrary-value strings at build
|
|
76
|
+
* time); the actual template text is supplied per-render via the two CSS
|
|
77
|
+
* custom properties in `gridCssVars`. */
|
|
78
|
+
export const PROCESS_ROW_GRID_CLASS = "grid-cols-[var(--sysmon-grid-n)] @lg:grid-cols-[var(--sysmon-grid-w)]";
|
|
79
|
+
|
|
80
|
+
export function gridCssVars(grid: ProcessGridResult): CSSProperties {
|
|
81
|
+
return {
|
|
82
|
+
"--sysmon-grid-n": grid.narrowTemplate,
|
|
83
|
+
"--sysmon-grid-w": grid.wideTemplate,
|
|
84
|
+
} as CSSProperties;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Visibility className for an optional column's cell: always visible when it is
|
|
88
|
+
* the narrow-mode survivor, otherwise hidden below `@lg` and shown at `@lg`+.
|
|
89
|
+
* Caller must only render the cell at all when `columns[key]` is true — when
|
|
90
|
+
* disabled, the column has no track in either template. */
|
|
91
|
+
export function optionalCellClassName(grid: ProcessGridResult, key: OptionalColumnKey): string {
|
|
92
|
+
return grid.narrowExtra === key ? "block" : "hidden @lg:block";
|
|
93
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ChevronRight, ChevronDown } from "lucide-react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
import { formatRam } from "@/lib/format-bytes";
|
|
4
|
+
import { cpuColor, formatDiskCell, formatGpuCell, formatNetCell, sumOptionalBps } from "./process-row-format";
|
|
5
|
+
import { optionalCellClassName, type ProcessGridResult } from "./process-columns-grid";
|
|
6
|
+
import { SparklineCanvas } from "./sparkline-canvas";
|
|
7
|
+
import type { ProcessGroup } from "../../../types/system-metrics";
|
|
8
|
+
|
|
9
|
+
export interface ProcessGroupRowProps {
|
|
10
|
+
group: ProcessGroup;
|
|
11
|
+
expanded: boolean;
|
|
12
|
+
spark: number[];
|
|
13
|
+
grid: ProcessGridResult;
|
|
14
|
+
onToggle: (key: string) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function ProcessGroupRow({ group, expanded, spark, grid, onToggle }: ProcessGroupRowProps) {
|
|
18
|
+
const Chevron = expanded ? ChevronDown : ChevronRight;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
className="grid items-center gap-1 min-h-11 md:min-h-7 px-3 text-xs cursor-pointer hover:bg-surface-hover transition-colors grid-cols-[var(--sysmon-grid-n)] @lg:grid-cols-[var(--sysmon-grid-w)]"
|
|
23
|
+
onClick={() => onToggle(group.key)}
|
|
24
|
+
data-testid="sysmon-group-row"
|
|
25
|
+
data-group-key={group.key}
|
|
26
|
+
data-count={group.count}
|
|
27
|
+
data-disk-bps={sumOptionalBps(group.diskReadBps, group.diskWriteBps)}
|
|
28
|
+
data-gpu-pct={group.gpuPct}
|
|
29
|
+
data-net-bps={sumOptionalBps(group.netInBps, group.netOutBps)}
|
|
30
|
+
>
|
|
31
|
+
<div className="flex items-center gap-1.5 min-w-0">
|
|
32
|
+
<button
|
|
33
|
+
type="button"
|
|
34
|
+
onClick={(e) => {
|
|
35
|
+
e.stopPropagation();
|
|
36
|
+
onToggle(group.key);
|
|
37
|
+
}}
|
|
38
|
+
aria-expanded={expanded}
|
|
39
|
+
aria-label={`${expanded ? "Collapse" : "Expand"} ${group.label}`}
|
|
40
|
+
data-testid="sysmon-group-expand"
|
|
41
|
+
className="flex items-center justify-center size-11 md:size-7 -ml-2 shrink-0"
|
|
42
|
+
>
|
|
43
|
+
<Chevron className="size-3.5 text-text-subtle" />
|
|
44
|
+
</button>
|
|
45
|
+
<span className="truncate font-medium">{group.label}</span>
|
|
46
|
+
<span className="text-text-subtle shrink-0">({group.count})</span>
|
|
47
|
+
</div>
|
|
48
|
+
<span className={cn("text-right", cpuColor(group.cpu))}>{group.cpu.toFixed(1)}%</span>
|
|
49
|
+
<span className="text-right text-text-secondary">{formatRam(group.ramMB)}</span>
|
|
50
|
+
{grid.columns.disk && (
|
|
51
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "disk"))}>
|
|
52
|
+
{formatDiskCell(group.diskReadBps, group.diskWriteBps)}
|
|
53
|
+
</span>
|
|
54
|
+
)}
|
|
55
|
+
{grid.columns.gpu && (
|
|
56
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "gpu"))}>
|
|
57
|
+
{formatGpuCell(group.gpuPct, group.gpuMemMB)}
|
|
58
|
+
</span>
|
|
59
|
+
)}
|
|
60
|
+
{grid.columns.net && (
|
|
61
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "net"))}>
|
|
62
|
+
{formatNetCell(group.netInBps, group.netOutBps)}
|
|
63
|
+
</span>
|
|
64
|
+
)}
|
|
65
|
+
<div className="hidden @lg:flex items-center justify-end">
|
|
66
|
+
{spark.length > 1 && <SparklineCanvas data={spark} width={120} height={20} maxValue={100} />}
|
|
67
|
+
</div>
|
|
68
|
+
<div className="hidden @lg:block" />
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Formatting helpers for a single process row, salvaged from the deleted
|
|
2
|
+
* `system-monitor-group-row.tsx` byte-for-byte (same thresholds, same rounding).
|
|
3
|
+
* Grid template logic (which columns exist, the `@lg` trend/age track) now lives
|
|
4
|
+
* in `process-columns-grid.ts` since it grew a runtime dependency (enabled
|
|
5
|
+
* optional columns + active sort key) that no longer fits a static constant. */
|
|
6
|
+
import { formatBps, formatRam } from "@/lib/format-bytes";
|
|
7
|
+
|
|
8
|
+
export function cpuColor(cpu: number): string {
|
|
9
|
+
if (cpu > 80) return "text-error";
|
|
10
|
+
if (cpu > 50) return "text-warning";
|
|
11
|
+
return "text-success";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function formatAge(startedAt?: number): string {
|
|
15
|
+
if (!startedAt) return "";
|
|
16
|
+
const secs = Math.round((Date.now() - startedAt) / 1000);
|
|
17
|
+
if (secs < 60) return `${secs}s`;
|
|
18
|
+
const mins = Math.floor(secs / 60);
|
|
19
|
+
if (mins < 60) return `${mins}m`;
|
|
20
|
+
const hrs = Math.floor(mins / 60);
|
|
21
|
+
if (hrs < 24) return `${hrs}h ${mins % 60}m`;
|
|
22
|
+
const days = Math.floor(hrs / 24);
|
|
23
|
+
return `${days}d ${hrs % 24}h`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** `undefined` on both sides means the host cannot measure this metric for this
|
|
27
|
+
* row at all (contract: `undefined` = OS/tier cannot measure) — render an em
|
|
28
|
+
* dash rather than a misleading "0 B/s". A single defined side (e.g. read known,
|
|
29
|
+
* write not) still renders, treating the missing side as 0. */
|
|
30
|
+
export function formatDiskCell(readBps?: number, writeBps?: number): string {
|
|
31
|
+
if (readBps === undefined && writeBps === undefined) return "—";
|
|
32
|
+
return `↓ ${formatBps(readBps ?? 0)} ↑ ${formatBps(writeBps ?? 0)}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function formatNetCell(inBps?: number, outBps?: number): string {
|
|
36
|
+
if (inBps === undefined && outBps === undefined) return "—";
|
|
37
|
+
return `↓ ${formatBps(inBps ?? 0)} ↑ ${formatBps(outBps ?? 0)}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** GPU % and VRAM are measured independently on some platforms (e.g. NVIDIA
|
|
41
|
+
* consumer drivers on Linux only expose per-process memory, not per-process
|
|
42
|
+
* utilization) — each half renders its own dash when unmeasured. */
|
|
43
|
+
export function formatGpuCell(pct?: number, memMB?: number): string {
|
|
44
|
+
if (pct === undefined && memMB === undefined) return "—";
|
|
45
|
+
const pctText = pct === undefined ? "—" : `${pct.toFixed(0)}%`;
|
|
46
|
+
const memText = memMB === undefined ? "—" : formatRam(memMB);
|
|
47
|
+
return `${pctText} · ${memText}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Row-level `data-*` sort attribute for e2e/debugging: sums a disk or net pair
|
|
51
|
+
* into one comparable number, `undefined` only when NEITHER side is measured —
|
|
52
|
+
* same rule the sort comparator and the cell formatters use. */
|
|
53
|
+
export function sumOptionalBps(a?: number, b?: number): number | undefined {
|
|
54
|
+
if (a === undefined && b === undefined) return undefined;
|
|
55
|
+
return (a ?? 0) + (b ?? 0);
|
|
56
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { X } from "lucide-react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
import { formatRam } from "@/lib/format-bytes";
|
|
4
|
+
import { cpuColor, formatAge, formatDiskCell, formatGpuCell, formatNetCell, sumOptionalBps } from "./process-row-format";
|
|
5
|
+
import { optionalCellClassName, type ProcessGridResult } from "./process-columns-grid";
|
|
6
|
+
import type { ProcessInfo } from "../../../types/system-metrics";
|
|
7
|
+
|
|
8
|
+
const PROTECTED_TOOLTIP = "Protected: PPM or OS-critical process — cannot be ended.";
|
|
9
|
+
|
|
10
|
+
export interface ProcessRowProps {
|
|
11
|
+
proc: ProcessInfo;
|
|
12
|
+
indent: boolean;
|
|
13
|
+
grid: ProcessGridResult;
|
|
14
|
+
onKillClick: (proc: ProcessInfo) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function ProcessRow({ proc, indent, grid, onKillClick }: ProcessRowProps) {
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
className="grid items-center gap-1 min-h-11 md:min-h-7 px-3 text-xs group/proc hover:bg-surface-hover transition-colors grid-cols-[var(--sysmon-grid-n)] @lg:grid-cols-[var(--sysmon-grid-w)]"
|
|
21
|
+
data-testid="sysmon-process-row"
|
|
22
|
+
data-pid={proc.pid}
|
|
23
|
+
data-ppm={proc.ppm}
|
|
24
|
+
data-protected={proc.protected}
|
|
25
|
+
data-disk-bps={sumOptionalBps(proc.diskReadBps, proc.diskWriteBps)}
|
|
26
|
+
data-gpu-pct={proc.gpuPct}
|
|
27
|
+
data-net-bps={sumOptionalBps(proc.netInBps, proc.netOutBps)}
|
|
28
|
+
>
|
|
29
|
+
<div className={cn("flex items-start gap-1.5 min-w-0", indent && "pl-6")}>
|
|
30
|
+
<span className="text-text-subtle shrink-0">{proc.pid}</span>
|
|
31
|
+
<span className="truncate text-text-secondary" title={proc.command}>
|
|
32
|
+
{proc.command}
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
<span className={cn("text-right", cpuColor(proc.cpu))}>{proc.cpu.toFixed(1)}%</span>
|
|
36
|
+
<span className="text-right text-text-secondary">{formatRam(proc.ramMB)}</span>
|
|
37
|
+
{grid.columns.disk && (
|
|
38
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "disk"))}>
|
|
39
|
+
{formatDiskCell(proc.diskReadBps, proc.diskWriteBps)}
|
|
40
|
+
</span>
|
|
41
|
+
)}
|
|
42
|
+
{grid.columns.gpu && (
|
|
43
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "gpu"))}>
|
|
44
|
+
{formatGpuCell(proc.gpuPct, proc.gpuMemMB)}
|
|
45
|
+
</span>
|
|
46
|
+
)}
|
|
47
|
+
{grid.columns.net && (
|
|
48
|
+
<span className={cn("text-right text-text-secondary tabular-nums truncate", optionalCellClassName(grid, "net"))}>
|
|
49
|
+
{formatNetCell(proc.netInBps, proc.netOutBps)}
|
|
50
|
+
</span>
|
|
51
|
+
)}
|
|
52
|
+
<span
|
|
53
|
+
className="hidden @lg:block text-text-subtle text-right"
|
|
54
|
+
title={proc.startedAt ? new Date(proc.startedAt).toLocaleString() : ""}
|
|
55
|
+
>
|
|
56
|
+
{formatAge(proc.startedAt || undefined)}
|
|
57
|
+
</span>
|
|
58
|
+
<div className="flex justify-end">
|
|
59
|
+
<button
|
|
60
|
+
type="button"
|
|
61
|
+
onClick={(e) => {
|
|
62
|
+
e.stopPropagation();
|
|
63
|
+
onKillClick(proc);
|
|
64
|
+
}}
|
|
65
|
+
disabled={proc.protected}
|
|
66
|
+
aria-label={`End process ${proc.name} (${proc.pid})`}
|
|
67
|
+
title={proc.protected ? PROTECTED_TOOLTIP : `End process ${proc.name}`}
|
|
68
|
+
data-testid="sysmon-kill-btn"
|
|
69
|
+
className={cn(
|
|
70
|
+
"flex items-center justify-center size-11 md:size-7 rounded transition-all",
|
|
71
|
+
"can-hover:opacity-0 can-hover:group-hover/proc:opacity-100",
|
|
72
|
+
proc.protected
|
|
73
|
+
? "opacity-40 cursor-not-allowed"
|
|
74
|
+
: "hover:bg-error/20 hover:text-error active:bg-error/30",
|
|
75
|
+
)}
|
|
76
|
+
>
|
|
77
|
+
<X className="size-3.5" />
|
|
78
|
+
</button>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/** Pure filter/sort/flatten/rollup for the process table. No React, no I/O, so the
|
|
2
|
+
* filter/sort/expand/rollup rules are unit-testable without mounting a component.
|
|
3
|
+
* Sort comparator lives in `process-table-sort.ts`, totals accumulator in
|
|
4
|
+
* `process-table-totals.ts` — both split out to stay under the file-size guideline. */
|
|
5
|
+
import type {
|
|
6
|
+
MetricsHistoryPoint,
|
|
7
|
+
ProcessGroup,
|
|
8
|
+
ProcessInfo,
|
|
9
|
+
SortDir,
|
|
10
|
+
SortKey,
|
|
11
|
+
} from "../../../types/system-metrics";
|
|
12
|
+
import { sortByKey, sortFields } from "./process-table-sort";
|
|
13
|
+
import { accumulateTotals, EMPTY_TOTALS, type Totals } from "./process-table-totals";
|
|
14
|
+
|
|
15
|
+
export type { Totals } from "./process-table-totals";
|
|
16
|
+
|
|
17
|
+
export type TableRow =
|
|
18
|
+
| { kind: "group"; group: ProcessGroup; expanded: boolean; spark: number[] }
|
|
19
|
+
| { kind: "process"; proc: ProcessInfo; indent: boolean };
|
|
20
|
+
|
|
21
|
+
export interface BuildRowsInput {
|
|
22
|
+
processes: ProcessInfo[];
|
|
23
|
+
groups: ProcessGroup[];
|
|
24
|
+
history: MetricsHistoryPoint[];
|
|
25
|
+
mode: "grouped" | "flat";
|
|
26
|
+
ppmOnly: boolean;
|
|
27
|
+
query: string;
|
|
28
|
+
sortKey: SortKey;
|
|
29
|
+
sortDir: SortDir;
|
|
30
|
+
expanded: Set<string>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface BuildRowsResult {
|
|
34
|
+
rows: TableRow[];
|
|
35
|
+
totals: Totals;
|
|
36
|
+
/** Group keys the search auto-expanded (only in grouped mode with a non-empty query). */
|
|
37
|
+
autoExpanded: Set<string>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const SPARK_POINTS = 60;
|
|
41
|
+
|
|
42
|
+
function matches(text: string, query: string): boolean {
|
|
43
|
+
return text.toLowerCase().includes(query);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function processMatches(proc: ProcessInfo, query: string): boolean {
|
|
47
|
+
return matches(proc.name, query) || matches(proc.command, query);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function sparkFor(history: MetricsHistoryPoint[], groupKey: string): number[] {
|
|
51
|
+
return history.slice(-SPARK_POINTS).map((h) => h.groups[groupKey]?.cpu ?? 0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Order fixed: filter (ppmOnly) -> filter (query) -> sort -> flatten (expand). */
|
|
55
|
+
export function buildRows(input: BuildRowsInput): BuildRowsResult {
|
|
56
|
+
const { processes, groups, history, mode, ppmOnly, query, sortKey, sortDir, expanded } = input;
|
|
57
|
+
const q = query.trim().toLowerCase();
|
|
58
|
+
const byPid = new Map(processes.map((p) => [p.pid, p]));
|
|
59
|
+
|
|
60
|
+
if (mode === "flat") {
|
|
61
|
+
let flat = ppmOnly ? processes.filter((p) => p.ppm) : processes;
|
|
62
|
+
if (q) flat = flat.filter((p) => processMatches(p, q));
|
|
63
|
+
flat = sortByKey(flat, sortKey, sortDir, (p) => sortFields(p, p.name));
|
|
64
|
+
|
|
65
|
+
const totals = flat.reduce((acc, p) => accumulateTotals(acc, p, 1), EMPTY_TOTALS);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
rows: flat.map((proc) => ({ kind: "process" as const, proc, indent: false })),
|
|
69
|
+
totals,
|
|
70
|
+
autoExpanded: new Set(),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Grouped mode.
|
|
75
|
+
let filteredGroups = ppmOnly ? groups.filter((g) => g.ppm) : groups;
|
|
76
|
+
|
|
77
|
+
const autoExpanded = new Set<string>();
|
|
78
|
+
if (q) {
|
|
79
|
+
filteredGroups = filteredGroups.filter((g) => {
|
|
80
|
+
const labelMatch = matches(g.label, q);
|
|
81
|
+
const memberMatch = g.pids.some((pid) => {
|
|
82
|
+
const proc = byPid.get(pid);
|
|
83
|
+
return proc ? processMatches(proc, q) : false;
|
|
84
|
+
});
|
|
85
|
+
const isMatch = labelMatch || memberMatch;
|
|
86
|
+
if (isMatch && memberMatch) autoExpanded.add(g.key);
|
|
87
|
+
return isMatch;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
filteredGroups = sortByKey(filteredGroups, sortKey, sortDir, (g) => sortFields(g, g.label));
|
|
92
|
+
|
|
93
|
+
const rows: TableRow[] = [];
|
|
94
|
+
for (const group of filteredGroups) {
|
|
95
|
+
const isExpanded = q ? autoExpanded.has(group.key) || expanded.has(group.key) : expanded.has(group.key);
|
|
96
|
+
rows.push({
|
|
97
|
+
kind: "group",
|
|
98
|
+
group,
|
|
99
|
+
expanded: isExpanded,
|
|
100
|
+
spark: sparkFor(history, group.key),
|
|
101
|
+
});
|
|
102
|
+
if (!isExpanded) continue;
|
|
103
|
+
|
|
104
|
+
// Skip pids the current snapshot no longer has — a process can exit between the
|
|
105
|
+
// server's tick and the client's render, or the group's own snapshot is already
|
|
106
|
+
// one tick stale. Must not throw.
|
|
107
|
+
let children = group.pids
|
|
108
|
+
.map((pid) => byPid.get(pid))
|
|
109
|
+
.filter((p): p is ProcessInfo => p !== undefined);
|
|
110
|
+
if (q) children = children.filter((p) => processMatches(p, q));
|
|
111
|
+
children = sortByKey(children, sortKey, sortDir, (p) => sortFields(p, p.name));
|
|
112
|
+
for (const proc of children) {
|
|
113
|
+
rows.push({ kind: "process", proc, indent: true });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const totals = filteredGroups.reduce((acc, g) => accumulateTotals(acc, g, g.count), EMPTY_TOTALS);
|
|
118
|
+
|
|
119
|
+
return { rows, totals, autoExpanded };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Three-state sort toggle: desc -> asc -> off, shared by every sortable column. */
|
|
123
|
+
export function toggleSort(current: SortKey, dir: SortDir, clicked: Exclude<SortKey, null>): [SortKey, SortDir] {
|
|
124
|
+
if (current !== clicked) return [clicked, "desc"];
|
|
125
|
+
if (dir === "desc") return [clicked, "asc"];
|
|
126
|
+
return [null, "desc"];
|
|
127
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/** Sort comparator for the process table, split out of `process-table-model.ts`
|
|
2
|
+
* to keep that file under the repo's 200-line guideline once Disk/GPU/Net sort
|
|
3
|
+
* keys were added. No React, no I/O — pure so it's directly unit-testable. */
|
|
4
|
+
import type { SortDir, SortKey } from "../../../types/system-metrics";
|
|
5
|
+
|
|
6
|
+
/** Fields the comparator can read from either a `ProcessInfo` or a `ProcessGroup`
|
|
7
|
+
* roll-up — both carry the same six optional metric names per the contract.
|
|
8
|
+
* Optional metrics stay optional here: the "undefined sorts last, regardless of
|
|
9
|
+
* direction" rule below depends on being able to tell "unmeasured" from "0". */
|
|
10
|
+
export interface SortableFields {
|
|
11
|
+
cpu: number;
|
|
12
|
+
ramMB: number;
|
|
13
|
+
name: string;
|
|
14
|
+
diskReadBps?: number;
|
|
15
|
+
diskWriteBps?: number;
|
|
16
|
+
gpuPct?: number;
|
|
17
|
+
gpuMemMB?: number;
|
|
18
|
+
netInBps?: number;
|
|
19
|
+
netOutBps?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Maps a `ProcessInfo` or `ProcessGroup` into `SortableFields` — only `name`
|
|
23
|
+
* differs between the two shapes (process `name` vs. group `label`), so one
|
|
24
|
+
* function covers both sort inputs. */
|
|
25
|
+
export function sortFields(m: {
|
|
26
|
+
cpu: number;
|
|
27
|
+
ramMB: number;
|
|
28
|
+
diskReadBps?: number;
|
|
29
|
+
diskWriteBps?: number;
|
|
30
|
+
gpuPct?: number;
|
|
31
|
+
gpuMemMB?: number;
|
|
32
|
+
netInBps?: number;
|
|
33
|
+
netOutBps?: number;
|
|
34
|
+
}, name: string): SortableFields {
|
|
35
|
+
return {
|
|
36
|
+
cpu: m.cpu,
|
|
37
|
+
ramMB: m.ramMB,
|
|
38
|
+
name,
|
|
39
|
+
diskReadBps: m.diskReadBps,
|
|
40
|
+
diskWriteBps: m.diskWriteBps,
|
|
41
|
+
gpuPct: m.gpuPct,
|
|
42
|
+
gpuMemMB: m.gpuMemMB,
|
|
43
|
+
netInBps: m.netInBps,
|
|
44
|
+
netOutBps: m.netOutBps,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** `undefined` when neither side of the pair is measured — matches the
|
|
49
|
+
* ProcessInfo/ProcessGroup contract ("undefined when NO member has a value"). */
|
|
50
|
+
function sumPair(a?: number, b?: number): number | undefined {
|
|
51
|
+
if (a === undefined && b === undefined) return undefined;
|
|
52
|
+
return (a ?? 0) + (b ?? 0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function optionalValueFor(key: "disk" | "gpu" | "gpuMem" | "net", f: SortableFields): number | undefined {
|
|
56
|
+
if (key === "disk") return sumPair(f.diskReadBps, f.diskWriteBps);
|
|
57
|
+
if (key === "net") return sumPair(f.netInBps, f.netOutBps);
|
|
58
|
+
if (key === "gpu") return f.gpuPct;
|
|
59
|
+
return f.gpuMemMB;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function isOptionalSortKey(key: SortKey): key is "disk" | "gpu" | "gpuMem" | "net" {
|
|
63
|
+
return key === "disk" || key === "gpu" || key === "gpuMem" || key === "net";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function sortByKey<T>(items: T[], key: SortKey, dir: SortDir, get: (item: T) => SortableFields): T[] {
|
|
67
|
+
if (!key) return items;
|
|
68
|
+
return [...items].sort((a, b) => {
|
|
69
|
+
const av = get(a);
|
|
70
|
+
const bv = get(b);
|
|
71
|
+
if (key === "name") {
|
|
72
|
+
const cmp = av.name.localeCompare(bv.name);
|
|
73
|
+
return dir === "asc" ? cmp : -cmp;
|
|
74
|
+
}
|
|
75
|
+
if (key === "cpu") return dir === "asc" ? av.cpu - bv.cpu : bv.cpu - av.cpu;
|
|
76
|
+
if (key === "ram") return dir === "asc" ? av.ramMB - bv.ramMB : bv.ramMB - av.ramMB;
|
|
77
|
+
|
|
78
|
+
// disk/gpu/gpuMem/net: optional metrics. Undefined always sorts last, in
|
|
79
|
+
// EITHER direction — it means "unmeasurable", not "smallest value".
|
|
80
|
+
if (isOptionalSortKey(key)) {
|
|
81
|
+
const aVal = optionalValueFor(key, av);
|
|
82
|
+
const bVal = optionalValueFor(key, bv);
|
|
83
|
+
if (aVal === undefined && bVal === undefined) return 0;
|
|
84
|
+
if (aVal === undefined) return 1;
|
|
85
|
+
if (bVal === undefined) return -1;
|
|
86
|
+
return dir === "asc" ? aVal - bVal : bVal - aVal;
|
|
87
|
+
}
|
|
88
|
+
return 0;
|
|
89
|
+
});
|
|
90
|
+
}
|