@hienlh/ppm 0.18.7 → 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 +16 -0
- package/CLAUDE.md +1 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +5 -3
- package/dist/web/assets/{ai-resource-editor-DZQUyrsU.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-GGksv6U8.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-Dg_JIcKq.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-DsJ_a2Op.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-CzjnrnMz.js → database-viewer-BCZOTrPT.js} +1 -1
- package/dist/web/assets/{diff-viewer-DUNkO-ll.js → diff-viewer-BwfMN-nW.js} +1 -1
- package/dist/web/assets/{docx-preview-DujpUDkE.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-DSDJUQs7.js → explorer-body-BKOMM566.js} +2 -2
- package/dist/web/assets/{explorer-window-content-CWYBapkj.js → explorer-window-content-Bbzijk8t.js} +1 -1
- package/dist/web/assets/{extension-webview-DBTFznQp.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-D8ZQdoYl.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-uIjdTT7c.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-B0VXSpYu.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-FyolpNND.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-BaBQ6Wm6.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/media-url-CylYQld1.js +1 -0
- package/dist/web/assets/{mobile-explorer-sheet-Zxjl-e4c.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-DnGpxgkF.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-xzAA4-kD.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-Dkec6GyK.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-Bz1XrUqI.js → sql-query-editor-BPYsJDsn.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-D5-NZw6b.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-DSpZ2zhL.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-DXazqejW.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-Bgp8iceS.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-CpF3A7JL.js → use-monaco-theme-CGucu3fb.js} +1 -1
- package/dist/web/assets/{use-open-team-member-CUvV02fA.js → use-open-team-member-DdrRXj-M.js} +1 -1
- package/dist/web/assets/{use-websocket-TnL2I1io.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-DYAbbmd0.js +1 -0
- 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/src/server/helpers/media-route-handlers.ts +22 -3
- package/src/server/index.ts +2 -8
- package/src/server/routes/files.ts +5 -2
- package/src/server/routes/fs-browse.ts +5 -2
- 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/fs-path-guard.service.ts +17 -1
- package/src/services/media-transcode/transcode-stream.ts +27 -5
- 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/types/system-metrics.ts +199 -0
- package/src/web/components/editor/video-player/video-player.tsx +54 -22
- 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/src/web/lib/media-url.ts +30 -4
- package/.release-run.sh +0 -5
- 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-Xd2WMjdX.js +0 -15
- package/dist/web/assets/circle-question-mark-CENpx4oA.js +0 -1
- package/dist/web/assets/code-editor-DqXYJWAB.js +0 -10
- package/dist/web/assets/gitGraph-HDMCJU4V-D7i54kbM.js +0 -1
- package/dist/web/assets/group-chat-tab-B3sryFdA.js +0 -1
- package/dist/web/assets/index-DgbOF3xa.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-feiuhJ9n.js +0 -1
- package/dist/web/assets/media-url-CUpN5vI1.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-Bd8e6iqY.js +0 -1
- package/dist/web/assets/system-monitor-tab-A0jvt5Qw.js +0 -1
- package/dist/web/assets/team-member-sheet-5Oaqm8I_.js +0 -2
- package/dist/web/assets/treemap-KZPCXAKY-Cu2zgbxU.js +0 -1
- package/dist/web/assets/video-preview-CwtLPELG.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/{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,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS disk + net cumulative counters via `ioreg` and `netstat -ib`.
|
|
3
|
+
* Runner-injected; parsers are pure. UNVERIFIED on real macOS hardware — on any
|
|
4
|
+
* parse failure the result is `null` (→ `available:false` + warning), never 0.
|
|
5
|
+
*/
|
|
6
|
+
import type { Runner } from "../host-info/spawn-runner.ts";
|
|
7
|
+
import { defaultRunner } from "../host-info/spawn-runner.ts";
|
|
8
|
+
import type { CounterSample } from "./rate-delta.ts";
|
|
9
|
+
import type { DiskNetCounters } from "./disk-net-collector-linux.ts";
|
|
10
|
+
|
|
11
|
+
/** Sum every `"Bytes (Read)"=N` / `"Bytes (Write)"=N` pair from `ioreg -rc IOBlockStorageDriver -w0`. */
|
|
12
|
+
export function parseIoregBytes(text: string): { inBytes: number; outBytes: number } | null {
|
|
13
|
+
let read = 0;
|
|
14
|
+
let written = 0;
|
|
15
|
+
let matched = false;
|
|
16
|
+
for (const m of text.matchAll(/"Bytes \((Read|Write)\)"\s*=\s*(\d+)/g)) {
|
|
17
|
+
const n = Number(m[2]);
|
|
18
|
+
if (!Number.isFinite(n)) continue;
|
|
19
|
+
matched = true;
|
|
20
|
+
if (m[1] === "Read") read += n;
|
|
21
|
+
else written += n;
|
|
22
|
+
}
|
|
23
|
+
return matched ? { inBytes: read, outBytes: written } : null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* `netstat -ib` repeats an interface once per address family; only the
|
|
28
|
+
* `<Link#N>` row (the first per interface) carries the hardware counters, so
|
|
29
|
+
* summing every row would double-count. The Address column is blank on some
|
|
30
|
+
* virtual interfaces, so Ibytes/Obytes are located from the right-hand end.
|
|
31
|
+
*/
|
|
32
|
+
export function parseNetstatIb(text: string): { inBytes: number; outBytes: number } | null {
|
|
33
|
+
let rx = 0;
|
|
34
|
+
let tx = 0;
|
|
35
|
+
let matched = false;
|
|
36
|
+
const seen = new Set<string>();
|
|
37
|
+
for (const line of text.split("\n")) {
|
|
38
|
+
const f = line.trim().split(/\s+/);
|
|
39
|
+
if (f.length < 10) continue;
|
|
40
|
+
const iface = f[0]!;
|
|
41
|
+
if (iface === "Name" || iface.startsWith("lo") || seen.has(iface)) continue;
|
|
42
|
+
if (!(f[2] ?? "").startsWith("<Link#")) continue;
|
|
43
|
+
const ibytes = Number(f[f.length - 5]);
|
|
44
|
+
const obytes = Number(f[f.length - 2]);
|
|
45
|
+
if (!Number.isFinite(ibytes) || !Number.isFinite(obytes)) continue;
|
|
46
|
+
seen.add(iface);
|
|
47
|
+
matched = true;
|
|
48
|
+
rx += ibytes;
|
|
49
|
+
tx += obytes;
|
|
50
|
+
}
|
|
51
|
+
return matched ? { inBytes: rx, outBytes: tx } : null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function collectDarwinDiskNet(run: Runner = defaultRunner, now: () => number = Date.now): Promise<DiskNetCounters> {
|
|
55
|
+
const warnings: string[] = [];
|
|
56
|
+
const atSec = now() / 1000;
|
|
57
|
+
let disk: CounterSample | null = null;
|
|
58
|
+
let net: CounterSample | null = null;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const r = await run(["ioreg", "-rc", "IOBlockStorageDriver", "-w0"], 3000);
|
|
62
|
+
const parsed = r.code === 0 ? parseIoregBytes(r.stdout) : null;
|
|
63
|
+
if (parsed) disk = { ...parsed, atSec };
|
|
64
|
+
} catch { /* fall through to the warning */ }
|
|
65
|
+
if (!disk) warnings.push("Disk throughput unavailable: ioreg IOBlockStorageDriver statistics not readable");
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const r = await run(["netstat", "-ib"], 3000);
|
|
69
|
+
const parsed = r.code === 0 ? parseNetstatIb(r.stdout) : null;
|
|
70
|
+
if (parsed) net = { ...parsed, atSec };
|
|
71
|
+
} catch { /* fall through to the warning */ }
|
|
72
|
+
if (!net) warnings.push("Network throughput unavailable: netstat -ib not readable");
|
|
73
|
+
|
|
74
|
+
return { disk, net, warnings };
|
|
75
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Linux disk + net cumulative counters from `/proc`. No subprocess; the reader
|
|
3
|
+
* is injectable so the parsers are fixture-tested without a real `/proc`.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import type { CounterSample } from "./rate-delta.ts";
|
|
7
|
+
|
|
8
|
+
export interface DiskNetCounters {
|
|
9
|
+
disk: CounterSample | null;
|
|
10
|
+
net: CounterSample | null;
|
|
11
|
+
warnings: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type FileReader = (path: string) => string | null;
|
|
15
|
+
|
|
16
|
+
const SECTOR_BYTES = 512;
|
|
17
|
+
/** Whole devices only — partitions, `loop*`, `dm-*` would double-count every byte. */
|
|
18
|
+
const WHOLE_DEVICE = /^(sd[a-z]+|nvme\d+n\d+|vd[a-z]+|mmcblk\d+|xvd[a-z]+)$/;
|
|
19
|
+
|
|
20
|
+
/** `/proc/diskstats`: field 6 = sectors read, field 10 = sectors written (1-based after major/minor/name). */
|
|
21
|
+
export function parseDiskstats(text: string): { inBytes: number; outBytes: number } | null {
|
|
22
|
+
let read = 0;
|
|
23
|
+
let written = 0;
|
|
24
|
+
let matched = false;
|
|
25
|
+
for (const line of text.split("\n")) {
|
|
26
|
+
const f = line.trim().split(/\s+/);
|
|
27
|
+
if (f.length < 10) continue;
|
|
28
|
+
const name = f[2] ?? "";
|
|
29
|
+
if (!WHOLE_DEVICE.test(name)) continue;
|
|
30
|
+
const r = Number(f[5]);
|
|
31
|
+
const w = Number(f[9]);
|
|
32
|
+
if (!Number.isFinite(r) || !Number.isFinite(w)) continue;
|
|
33
|
+
matched = true;
|
|
34
|
+
read += r;
|
|
35
|
+
written += w;
|
|
36
|
+
}
|
|
37
|
+
return matched ? { inBytes: read * SECTOR_BYTES, outBytes: written * SECTOR_BYTES } : null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** `/proc/net/dev`: `iface: rx_bytes … tx_bytes …` with rx at col 0 and tx at col 8 after the colon. `lo` excluded. */
|
|
41
|
+
export function parseNetDev(text: string): { inBytes: number; outBytes: number } | null {
|
|
42
|
+
let rx = 0;
|
|
43
|
+
let tx = 0;
|
|
44
|
+
let matched = false;
|
|
45
|
+
for (const line of text.split("\n")) {
|
|
46
|
+
const colon = line.indexOf(":");
|
|
47
|
+
if (colon < 0) continue;
|
|
48
|
+
const iface = line.slice(0, colon).trim();
|
|
49
|
+
if (!iface || iface === "lo") continue;
|
|
50
|
+
const f = line.slice(colon + 1).trim().split(/\s+/);
|
|
51
|
+
if (f.length < 9) continue;
|
|
52
|
+
const r = Number(f[0]);
|
|
53
|
+
const t = Number(f[8]);
|
|
54
|
+
if (!Number.isFinite(r) || !Number.isFinite(t)) continue;
|
|
55
|
+
matched = true;
|
|
56
|
+
rx += r;
|
|
57
|
+
tx += t;
|
|
58
|
+
}
|
|
59
|
+
return matched ? { inBytes: rx, outBytes: tx } : null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const defaultFileReader: FileReader = (path) => {
|
|
63
|
+
try {
|
|
64
|
+
return readFileSync(path, "utf-8");
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/** `/proc` carries no counter clock, so the wall clock is the only option here. */
|
|
71
|
+
export function collectLinuxDiskNet(read: FileReader = defaultFileReader, now: () => number = Date.now): DiskNetCounters {
|
|
72
|
+
const warnings: string[] = [];
|
|
73
|
+
const atSec = now() / 1000;
|
|
74
|
+
|
|
75
|
+
const diskText = read("/proc/diskstats");
|
|
76
|
+
const diskRaw = diskText ? parseDiskstats(diskText) : null;
|
|
77
|
+
if (!diskRaw) warnings.push("Disk throughput unavailable: /proc/diskstats has no whole-device rows");
|
|
78
|
+
|
|
79
|
+
const netText = read("/proc/net/dev");
|
|
80
|
+
const netRaw = netText ? parseNetDev(netText) : null;
|
|
81
|
+
if (!netRaw) warnings.push("Network throughput unavailable: /proc/net/dev unreadable");
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
disk: diskRaw ? { ...diskRaw, atSec } : null,
|
|
85
|
+
net: netRaw ? { ...netRaw, atSec } : null,
|
|
86
|
+
warnings,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windows disk + net counters — a PURE parser over the tagged lines the
|
|
3
|
+
* PowerShell session returns inside the per-tick process round trip. Spawns
|
|
4
|
+
* nothing; the raw `Win32_PerfRawData_*` classes cost 22 ms in-session versus
|
|
5
|
+
* a hard ≥1 s block for `Get-Counter`, and their class/property names are
|
|
6
|
+
* culture-invariant, so a localised Windows needs no special case.
|
|
7
|
+
*
|
|
8
|
+
* D<TAB>DiskReadBytesPerSec<TAB>DiskWriteBytesPerSec<TAB>Timestamp_PerfTime<TAB>Frequency_PerfTime
|
|
9
|
+
* N<TAB>Name<TAB>BytesReceivedPersec<TAB>BytesSentPersec<TAB>Timestamp_Sys100NS
|
|
10
|
+
*/
|
|
11
|
+
import type { CounterSample } from "./rate-delta.ts";
|
|
12
|
+
|
|
13
|
+
/** Pseudo-adapters that would count local traffic; virtual NICs (Tailscale,
|
|
14
|
+
* Hyper-V) stay in on purpose — dropping them would hide real tunnel traffic. */
|
|
15
|
+
const EXCLUDED_NIC = /^(Loopback|isatap|Teredo)/i;
|
|
16
|
+
|
|
17
|
+
export interface WindowsDiskNetCounters {
|
|
18
|
+
disk: CounterSample | null;
|
|
19
|
+
net: CounterSample | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function parsePerfRawDiskNet(lines: readonly string[]): WindowsDiskNetCounters {
|
|
23
|
+
let disk: CounterSample | null = null;
|
|
24
|
+
let rx = 0;
|
|
25
|
+
let tx = 0;
|
|
26
|
+
let netTs = 0;
|
|
27
|
+
let nics = 0;
|
|
28
|
+
|
|
29
|
+
for (const line of lines) {
|
|
30
|
+
const f = line.split("\t");
|
|
31
|
+
if (f[0] === "D" && f.length >= 5) {
|
|
32
|
+
const read = Number(f[1]);
|
|
33
|
+
const write = Number(f[2]);
|
|
34
|
+
const ts = Number(f[3]);
|
|
35
|
+
const freq = Number(f[4]);
|
|
36
|
+
if ([read, write, ts, freq].every(Number.isFinite) && freq > 0) {
|
|
37
|
+
disk = { inBytes: read, outBytes: write, atSec: ts / freq };
|
|
38
|
+
}
|
|
39
|
+
} else if (f[0] === "N" && f.length >= 5) {
|
|
40
|
+
const name = f[1] ?? "";
|
|
41
|
+
if (EXCLUDED_NIC.test(name)) continue;
|
|
42
|
+
const recv = Number(f[2]);
|
|
43
|
+
const sent = Number(f[3]);
|
|
44
|
+
const ts = Number(f[4]);
|
|
45
|
+
if (![recv, sent, ts].every(Number.isFinite)) continue;
|
|
46
|
+
nics++;
|
|
47
|
+
rx += recv;
|
|
48
|
+
tx += sent;
|
|
49
|
+
netTs = Math.max(netTs, ts);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const net = nics > 0 && netTs > 0
|
|
54
|
+
? { inBytes: rx, outBytes: tx, atSec: netTs / 1e7 }
|
|
55
|
+
: null;
|
|
56
|
+
return { disk, net };
|
|
57
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NVIDIA GPU utilisation + VRAM via a one-shot `nvidia-smi` per full-tier tick
|
|
3
|
+
* (measured 31 ms, ~60 bytes). No long-lived child: loop mode would keep an
|
|
4
|
+
* Optimus dGPU awake permanently, and the per-spawn leak this repo knows about
|
|
5
|
+
* concerns building a PowerShell process map inside Bun, not a tiny read.
|
|
6
|
+
*/
|
|
7
|
+
import type { GpuMetrics } from "../../types/system-metrics.ts";
|
|
8
|
+
import type { Runner } from "../host-info/spawn-runner.ts";
|
|
9
|
+
import { defaultRunner } from "../host-info/spawn-runner.ts";
|
|
10
|
+
|
|
11
|
+
export const NVIDIA_SMI_ARGV = [
|
|
12
|
+
"nvidia-smi",
|
|
13
|
+
"--query-gpu=name,utilization.gpu,memory.used,memory.total",
|
|
14
|
+
"--format=csv,noheader,nounits",
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const SPAWN_TIMEOUT_MS = 3000;
|
|
18
|
+
/** After this many consecutive failures the machine is treated as GPU-less for
|
|
19
|
+
* the rest of the server's life — a machine does not grow a GPU. */
|
|
20
|
+
const MAX_FAILURES = 3;
|
|
21
|
+
|
|
22
|
+
/** One row per GPU: `name, util, memUsed, memTotal`. `[N/A]` fields become 0
|
|
23
|
+
* rather than NaN; a row without a name is dropped. */
|
|
24
|
+
export function parseNvidiaSmiCsv(text: string): GpuMetrics[] {
|
|
25
|
+
const out: GpuMetrics[] = [];
|
|
26
|
+
for (const raw of text.split("\n")) {
|
|
27
|
+
const line = raw.trim();
|
|
28
|
+
if (!line) continue;
|
|
29
|
+
const f = line.split(",").map((s) => s.trim());
|
|
30
|
+
const name = f[0] ?? "";
|
|
31
|
+
if (!name || f.length < 4) continue;
|
|
32
|
+
out.push({
|
|
33
|
+
name,
|
|
34
|
+
utilPercent: clampPercent(num(f[1])),
|
|
35
|
+
vramUsedMB: Math.max(0, Math.round(num(f[2]))),
|
|
36
|
+
vramTotalMB: Math.max(0, Math.round(num(f[3]))),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function num(s: string | undefined): number {
|
|
43
|
+
if (s === undefined || /^\[?N\/A\]?$/i.test(s)) return 0;
|
|
44
|
+
const n = Number(s);
|
|
45
|
+
return Number.isFinite(n) ? n : 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function clampPercent(v: number): number {
|
|
49
|
+
return Math.round(Math.min(100, Math.max(0, v)) * 10) / 10;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface GpuCollector {
|
|
53
|
+
collect(): Promise<GpuMetrics[]>;
|
|
54
|
+
/** True once the collector has given up (no binary / repeated failures). */
|
|
55
|
+
isDisabled(): boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function createNvidiaGpuCollector(run: Runner = defaultRunner): GpuCollector {
|
|
59
|
+
let failures = 0;
|
|
60
|
+
let disabled = false;
|
|
61
|
+
return {
|
|
62
|
+
isDisabled: () => disabled,
|
|
63
|
+
async collect() {
|
|
64
|
+
if (disabled) return [];
|
|
65
|
+
try {
|
|
66
|
+
const r = await run(NVIDIA_SMI_ARGV, SPAWN_TIMEOUT_MS);
|
|
67
|
+
if (r.code !== 0 || r.timedOut) throw new Error(r.stderr || `exit ${r.code}`);
|
|
68
|
+
failures = 0;
|
|
69
|
+
return parseNvidiaSmiCsv(r.stdout);
|
|
70
|
+
} catch {
|
|
71
|
+
// ENOENT (no NVIDIA driver) throws synchronously from the spawn; a
|
|
72
|
+
// present-but-broken nvidia-smi fails a few times, then is given up on.
|
|
73
|
+
if (++failures >= MAX_FAILURES) disabled = true;
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-process VRAM on NVIDIA via one `nvidia-smi --query-compute-apps` per
|
|
3
|
+
* full-tier tick (same one-shot shape and give-up rule as the whole-GPU
|
|
4
|
+
* collector next door).
|
|
5
|
+
*
|
|
6
|
+
* There is deliberately no per-process utilisation here: NVML exposes
|
|
7
|
+
* per-process SM utilisation only through accounting mode / MIG, which is off
|
|
8
|
+
* on consumer cards, so `gpuPct` stays undefined on Linux and only the memory
|
|
9
|
+
* column is filled.
|
|
10
|
+
*/
|
|
11
|
+
import type { Runner } from "../host-info/spawn-runner.ts";
|
|
12
|
+
import { defaultRunner } from "../host-info/spawn-runner.ts";
|
|
13
|
+
|
|
14
|
+
export const NVIDIA_COMPUTE_APPS_ARGV = [
|
|
15
|
+
"nvidia-smi",
|
|
16
|
+
"--query-compute-apps=pid,used_memory",
|
|
17
|
+
"--format=csv,noheader,nounits",
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const SPAWN_TIMEOUT_MS = 3000;
|
|
21
|
+
/** A machine does not grow a GPU: after this many failures, stop asking. */
|
|
22
|
+
const MAX_FAILURES = 3;
|
|
23
|
+
|
|
24
|
+
/** `pid, usedMB` per row. A pid appearing twice (two GPUs) is summed. */
|
|
25
|
+
export function parseComputeAppsCsv(text: string): Map<number, number> {
|
|
26
|
+
const byPid = new Map<number, number>();
|
|
27
|
+
for (const raw of text.split("\n")) {
|
|
28
|
+
const line = raw.trim();
|
|
29
|
+
if (!line) continue;
|
|
30
|
+
const f = line.split(",").map((s) => s.trim());
|
|
31
|
+
const pid = Number(f[0]);
|
|
32
|
+
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
33
|
+
// "[N/A]" / "[Not Supported]" appear on some drivers: the pid is real but
|
|
34
|
+
// the figure is not, so the row contributes 0 rather than NaN.
|
|
35
|
+
const mb = /^\d+(\.\d+)?$/.test(f[1] ?? "") ? Number(f[1]) : 0;
|
|
36
|
+
byPid.set(pid, (byPid.get(pid) ?? 0) + Math.max(0, Math.round(mb * 10) / 10));
|
|
37
|
+
}
|
|
38
|
+
return byPid;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ProcessGpuMemoryCollector {
|
|
42
|
+
/** Null when the query is unavailable (no binary, repeated failures) — the
|
|
43
|
+
* caller then leaves `gpuMemMB` undefined instead of publishing zeros. */
|
|
44
|
+
collect(): Promise<Map<number, number> | null>;
|
|
45
|
+
isDisabled(): boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function createNvidiaProcessMemoryCollector(run: Runner = defaultRunner): ProcessGpuMemoryCollector {
|
|
49
|
+
let failures = 0;
|
|
50
|
+
let disabled = false;
|
|
51
|
+
return {
|
|
52
|
+
isDisabled: () => disabled,
|
|
53
|
+
async collect() {
|
|
54
|
+
if (disabled) return null;
|
|
55
|
+
try {
|
|
56
|
+
const r = await run(NVIDIA_COMPUTE_APPS_ARGV, SPAWN_TIMEOUT_MS);
|
|
57
|
+
if (r.code !== 0 || r.timedOut) throw new Error(r.stderr || `exit ${r.code}`);
|
|
58
|
+
failures = 0;
|
|
59
|
+
return parseComputeAppsCsv(r.stdout);
|
|
60
|
+
} catch {
|
|
61
|
+
if (++failures >= MAX_FAILURES) disabled = true;
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-process GPU busy % and dedicated VRAM on Windows — a PURE parser plus the
|
|
3
|
+
* rate maths over the two tagged sections the per-tick PowerShell round trip
|
|
4
|
+
* already returns. Spawns nothing.
|
|
5
|
+
*
|
|
6
|
+
* G<TAB>Name<TAB>UtilizationPercentage<TAB>Timestamp_Sys100NS (busy > 0 only)
|
|
7
|
+
* M<TAB>Name<TAB>DedicatedUsage
|
|
8
|
+
*
|
|
9
|
+
* `Name` is an instance path, not a friendly name:
|
|
10
|
+
* pid_29876_luid_0x00000000_0x0000A1B2_phys_0_eng_3_engtype_3D (GPUEngine)
|
|
11
|
+
* pid_29876_luid_0x00000000_0x0000A1B2_phys_0 (GPUProcessMemory)
|
|
12
|
+
*
|
|
13
|
+
* `UtilizationPercentage` is NOT a percentage despite the name: it is a raw
|
|
14
|
+
* cumulative 100 ns busy-time counter, which is why an absolute read is
|
|
15
|
+
* meaningless and it has to be differentiated against the counter's own
|
|
16
|
+
* `Timestamp_Sys100NS` clock rather than the tick's wall interval.
|
|
17
|
+
*/
|
|
18
|
+
import { toRate, type CounterSample } from "./rate-delta.ts";
|
|
19
|
+
|
|
20
|
+
/** Both classes prefix the instance with the owning pid. */
|
|
21
|
+
const PID_IN_INSTANCE = /(?:^|_)pid_(\d+)_/;
|
|
22
|
+
const HUNDRED_NS_PER_SEC = 1e7;
|
|
23
|
+
/** busy-100ns/second → percent: (bps / 1e7) × 100. */
|
|
24
|
+
const BPS_PER_PERCENT = HUNDRED_NS_PER_SEC / 100;
|
|
25
|
+
const BYTES_PER_MB = 1024 * 1024;
|
|
26
|
+
|
|
27
|
+
export interface GpuEngineSample {
|
|
28
|
+
pid: number;
|
|
29
|
+
/** The full instance path: unique per (pid, adapter, engine), so it is the
|
|
30
|
+
* delta key. Two engines of the same pid stay separate samples and are
|
|
31
|
+
* summed only after each has its own rate. */
|
|
32
|
+
engine: string;
|
|
33
|
+
busy100ns: number;
|
|
34
|
+
/** Counter's own clock, seconds. */
|
|
35
|
+
atSec: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ParsedGpuLines {
|
|
39
|
+
engines: GpuEngineSample[];
|
|
40
|
+
/** pid → dedicated VRAM bytes, summed across physical adapters. */
|
|
41
|
+
memBytesByPid: Map<number, number>;
|
|
42
|
+
/** True when the tick carried either section at all — i.e. the host has the
|
|
43
|
+
* GPU perf provider. An all-idle machine emits no `G` lines but still emits
|
|
44
|
+
* `M` lines, so absence of BOTH is what means "unavailable". */
|
|
45
|
+
present: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface GpuUsageState {
|
|
49
|
+
byKey: Map<string, CounterSample>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function pidFromInstanceName(name: string): number | null {
|
|
53
|
+
const m = PID_IN_INSTANCE.exec(name);
|
|
54
|
+
if (!m) return null;
|
|
55
|
+
const pid = Number(m[1]);
|
|
56
|
+
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function parseGpuLines(lines: readonly string[]): ParsedGpuLines {
|
|
60
|
+
const engines: GpuEngineSample[] = [];
|
|
61
|
+
const memBytesByPid = new Map<number, number>();
|
|
62
|
+
let present = false;
|
|
63
|
+
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
const f = line.split("\t");
|
|
66
|
+
if (f[0] === "G" && f.length >= 4) {
|
|
67
|
+
present = true;
|
|
68
|
+
const pid = pidFromInstanceName(f[1] ?? "");
|
|
69
|
+
const busy = Number(f[2]);
|
|
70
|
+
const ts = Number(f[3]);
|
|
71
|
+
if (pid === null || !Number.isFinite(busy) || !Number.isFinite(ts) || ts <= 0) continue;
|
|
72
|
+
engines.push({ pid, engine: f[1] ?? "", busy100ns: busy, atSec: ts / HUNDRED_NS_PER_SEC });
|
|
73
|
+
} else if (f[0] === "M" && f.length >= 3) {
|
|
74
|
+
present = true;
|
|
75
|
+
const pid = pidFromInstanceName(f[1] ?? "");
|
|
76
|
+
const bytes = Number(f[2]);
|
|
77
|
+
if (pid === null || !Number.isFinite(bytes) || bytes < 0) continue;
|
|
78
|
+
memBytesByPid.set(pid, (memBytesByPid.get(pid) ?? 0) + bytes);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { engines, memBytesByPid, present };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Cumulative engine busy counters → per-pid busy %.
|
|
86
|
+
*
|
|
87
|
+
* - Delta key is `<engine instance>:<startedAt>` so a recycled pid inheriting a
|
|
88
|
+
* dead process's instance name gets a fresh baseline instead of its busy time.
|
|
89
|
+
* - A pid absent from this tick's process table is dropped: the table is what
|
|
90
|
+
* the UI shows, and the perf provider keeps instances of exited processes
|
|
91
|
+
* around for a while.
|
|
92
|
+
* - Per pid the figure is the BUSIEST engine, not the sum across engines — the
|
|
93
|
+
* same definition Task Manager's GPU column uses. Engines run in parallel, so
|
|
94
|
+
* a sum would exceed 100 % for any process that renders and copies at once
|
|
95
|
+
* and would pin at the clamp instead of showing a real load figure.
|
|
96
|
+
* - First observation of an engine → 0 (never a guess), like `cpu`.
|
|
97
|
+
* - Counter going backwards → 0 and a fresh baseline. These are 64-bit 100 ns
|
|
98
|
+
* counters, so a decrease is a provider restart, never a wrap.
|
|
99
|
+
* - Dead keys are dropped from `next` every tick, so a long session with a lot
|
|
100
|
+
* of short-lived GPU clients cannot grow the map without bound.
|
|
101
|
+
*/
|
|
102
|
+
export function computeGpuPercents(
|
|
103
|
+
prev: GpuUsageState | null,
|
|
104
|
+
engines: readonly GpuEngineSample[],
|
|
105
|
+
startedAtOf: (pid: number) => number | undefined,
|
|
106
|
+
): { pctByPid: Map<number, number>; next: GpuUsageState } {
|
|
107
|
+
const pctByPid = new Map<number, number>();
|
|
108
|
+
const nextByKey = new Map<string, CounterSample>();
|
|
109
|
+
|
|
110
|
+
for (const e of engines) {
|
|
111
|
+
const startedAt = startedAtOf(e.pid);
|
|
112
|
+
if (startedAt === undefined) continue;
|
|
113
|
+
const key = `${e.engine}:${startedAt}`;
|
|
114
|
+
const sample: CounterSample = { inBytes: e.busy100ns, outBytes: 0, atSec: e.atSec };
|
|
115
|
+
const before = prev?.byKey.get(key);
|
|
116
|
+
nextByKey.set(key, sample);
|
|
117
|
+
const pct = enginePercent(before ?? null, sample);
|
|
118
|
+
pctByPid.set(e.pid, Math.max(pctByPid.get(e.pid) ?? 0, pct));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (const [pid, pct] of pctByPid) pctByPid.set(pid, clampPercent(pct));
|
|
122
|
+
return { pctByPid, next: { byKey: nextByKey } };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function enginePercent(prev: CounterSample | null, next: CounterSample): number {
|
|
126
|
+
if (!prev || next.inBytes < prev.inBytes) return 0;
|
|
127
|
+
const rate = toRate(prev, next);
|
|
128
|
+
if (!rate.available) return 0;
|
|
129
|
+
return rate.inBps / BPS_PER_PERCENT;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function clampPercent(v: number): number {
|
|
133
|
+
return Math.round(Math.min(100, Math.max(0, v)) * 10) / 10;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function memBytesToMB(bytes: number): number {
|
|
137
|
+
return Math.round((bytes / BYTES_PER_MB) * 10) / 10;
|
|
138
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ends a process (or its tree) after the guard has already said yes. POSIX reuses the
|
|
3
|
+
* repo's process-tree helpers, whose own `killable()` filter (never init, never
|
|
4
|
+
* ourselves) is a second, independent guard. Pids are validated integers and
|
|
5
|
+
* only ever passed as argv elements or to `process.kill` — never interpolated
|
|
6
|
+
* into a shell string.
|
|
7
|
+
*/
|
|
8
|
+
import type { KillProcessResult } from "../../types/system-metrics.ts";
|
|
9
|
+
import type { Runner } from "../host-info/spawn-runner.ts";
|
|
10
|
+
import { defaultRunner } from "../host-info/spawn-runner.ts";
|
|
11
|
+
import { collectProcessTree, terminateTree } from "../windows-process-tree.ts";
|
|
12
|
+
|
|
13
|
+
/** Grace between SIGTERM and SIGKILL on POSIX. */
|
|
14
|
+
const GRACE_MS = 3000;
|
|
15
|
+
|
|
16
|
+
export interface KillExecutorDeps {
|
|
17
|
+
platform: NodeJS.Platform;
|
|
18
|
+
run: Runner;
|
|
19
|
+
signal: (pid: number, sig: NodeJS.Signals | 0) => void;
|
|
20
|
+
collectTree: (pid: number) => number[];
|
|
21
|
+
terminateTree: (pids: number[], graceMs: number) => Promise<void>;
|
|
22
|
+
sleep: (ms: number) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const defaultKillExecutorDeps: KillExecutorDeps = {
|
|
26
|
+
platform: process.platform,
|
|
27
|
+
run: defaultRunner,
|
|
28
|
+
signal: (pid, sig) => { process.kill(pid, sig); },
|
|
29
|
+
collectTree: collectProcessTree,
|
|
30
|
+
terminateTree,
|
|
31
|
+
sleep: (ms) => Bun.sleep(ms),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function assertPid(pid: number): void {
|
|
35
|
+
if (!Number.isInteger(pid) || pid <= 0) throw new Error(`Invalid PID ${pid}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Throws on executor failure; the route maps that to 500. */
|
|
39
|
+
export async function executeKill(
|
|
40
|
+
pid: number,
|
|
41
|
+
tree: boolean,
|
|
42
|
+
deps: KillExecutorDeps = defaultKillExecutorDeps,
|
|
43
|
+
): Promise<KillProcessResult> {
|
|
44
|
+
assertPid(pid);
|
|
45
|
+
|
|
46
|
+
if (deps.platform === "win32") {
|
|
47
|
+
// Async spawn, never execFileSync: taskkill can block up to its timeout and
|
|
48
|
+
// the event loop must keep serving. A non-zero exit (access denied on an
|
|
49
|
+
// elevated target is common) is reported, never masked by a fallback kill.
|
|
50
|
+
// `taskkill /T` walks the tree inside the OS and reports no member list, so
|
|
51
|
+
// `[pid]` is the only honest value for the tree case.
|
|
52
|
+
const argv = tree ? ["taskkill", "/PID", String(pid), "/T", "/F"] : ["taskkill", "/PID", String(pid), "/F"];
|
|
53
|
+
const r = await deps.run(argv, 5000);
|
|
54
|
+
if (r.code !== 0 || r.timedOut) {
|
|
55
|
+
throw new Error((r.stderr || r.stdout || `taskkill exited ${r.timedOut ? "on timeout" : r.code}`).trim());
|
|
56
|
+
}
|
|
57
|
+
return { pid, tree, method: "taskkill", killed: [pid] };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (tree) {
|
|
61
|
+
// Enumerate BEFORE signalling: once the root dies its children reparent to
|
|
62
|
+
// init and the tree can no longer be recovered.
|
|
63
|
+
const pids = deps.collectTree(pid);
|
|
64
|
+
await deps.terminateTree(pids, GRACE_MS);
|
|
65
|
+
return { pid, tree: true, method: "signal", killed: pids };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
deps.signal(pid, "SIGTERM");
|
|
69
|
+
const deadline = Date.now() + GRACE_MS;
|
|
70
|
+
while (Date.now() < deadline) {
|
|
71
|
+
if (!isAlive(pid, deps)) return { pid, tree: false, method: "signal", killed: [pid] };
|
|
72
|
+
await deps.sleep(100);
|
|
73
|
+
}
|
|
74
|
+
try { deps.signal(pid, "SIGKILL"); } catch { /* exited between the check and the kill */ }
|
|
75
|
+
return { pid, tree: false, method: "signal", killed: [pid] };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isAlive(pid: number, deps: KillExecutorDeps): boolean {
|
|
79
|
+
try {
|
|
80
|
+
deps.signal(pid, 0);
|
|
81
|
+
return true;
|
|
82
|
+
} catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|