@hienlh/ppm 0.18.8 → 0.18.10
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/group-protected-probe.ts +21 -0
- package/.spike/s.err +63 -0
- package/.spike/tunnel.err +22 -0
- package/.spike/w.err +28 -0
- package/CHANGELOG.md +21 -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-mdDKG-rw.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-C060A94y.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-WELegzdp.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-fRTU3f1o.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-D1d0cxOJ.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-DevnWTV4.js} +1 -1
- package/dist/web/assets/{diff-viewer-BMr7vOvZ.js → diff-viewer-DGxVg1pD.js} +1 -1
- package/dist/web/assets/{docx-preview-BpG2kr_-.js → docx-preview-Cx-zLwAw.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-j_4hVc34.js} +2 -2
- package/dist/web/assets/{explorer-window-content-B3krk4G1.js → explorer-window-content-DdrGwk3w.js} +1 -1
- package/dist/web/assets/{extension-webview-12M45CGq.js → extension-webview-BH_mWYMe.js} +1 -1
- package/dist/web/assets/format-bytes-BE_W3UBg.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-CfpXRJcP.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-n4ox_uev.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-dYuuknLN.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-Ss38ex8g.js} +1 -1
- package/dist/web/assets/index-BiTiXgBZ.css +2 -0
- package/dist/web/assets/index-Ch8l9de-.js +52 -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-CDfTjwZX.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-DPcoPjmO.js → markdown-renderer-B317vEys.js} +3 -3
- package/dist/web/assets/markdown-renderer-CpRlpLHw.js +1 -0
- 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-D1Bv9UCT.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-KwTAZT8b.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-BxDohIEa.js +1 -0
- package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +1 -0
- package/dist/web/assets/{pdf-preview-BslNoDFw.js → pdf-preview-dwRe54ht.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-BWZLW7kI.js} +3 -3
- package/dist/web/assets/process-table-CI-fnVsy.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/resolve-theme-B9ABAH_3.js +1 -0
- 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-mPxrKkfm.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-BwPjEaP9.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-CJbP6ruh.js → sqlite-viewer-Cs-_D942.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-CV7-0hZG.js +2 -0
- package/dist/web/assets/system-monitor-tab-Ce-8Axhh.js +1 -0
- package/dist/web/assets/system-monitor-window-content-CetwYOQy.js +1 -0
- package/dist/web/assets/team-member-sheet-CjgaQjsZ.js +2 -0
- package/dist/web/assets/{team-member-window-content-Cxh-HF2V.js → team-member-window-content-DNJiYWS7.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-DF7521sT.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-DCAXGDJI.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-DSCdlrjO.js} +1 -1
- package/dist/web/assets/{use-open-team-member-DKpstvLS.js → use-open-team-member-H4k74HnV.js} +1 -1
- package/dist/web/assets/{use-websocket-KVhDtbwK.js → use-websocket-iJfc7EbK.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-B0ZWpX0F.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 +36 -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 +105 -0
- package/src/web/components/system/metric-chart-canvas.tsx +107 -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 +103 -0
- package/src/web/components/system/process-group-row.tsx +94 -0
- package/src/web/components/system/process-row-format.ts +56 -0
- package/src/web/components/system/process-row.tsx +81 -0
- package/src/web/components/system/process-table-model.ts +109 -0
- package/src/web/components/system/process-table-sort.ts +90 -0
- package/src/web/components/system/process-table-toolbar.tsx +159 -0
- package/src/web/components/system/process-table-totals.ts +49 -0
- package/src/web/components/system/process-table.tsx +146 -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 +90 -0
- 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-column-widths.ts +91 -0
- package/src/web/components/system/use-open-system-monitor.ts +34 -0
- package/src/web/components/system/use-process-kill.ts +100 -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/styles/globals.css +5 -3
- package/src/web/theme/builtin/aurora.ts +8 -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-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/resolve-theme-CJvkL8hU.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/sparkline-canvas.tsx +0 -64
- 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/{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,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared shell for the System Monitor: connection indicator, warning strip, and the
|
|
3
|
+
* Overview/Processes sub-tabs. Rendered identically by the desktop window and the
|
|
4
|
+
* mobile tab, so this file and the panels beneath it are written once for both hosts.
|
|
5
|
+
*/
|
|
6
|
+
import { lazy, memo, Suspense, useState } from "react";
|
|
7
|
+
import { Wifi, WifiOff } from "lucide-react";
|
|
8
|
+
import { cn } from "@/lib/utils";
|
|
9
|
+
import { useResourceMonitor } from "@/hooks/use-resource-monitor";
|
|
10
|
+
|
|
11
|
+
const OverviewPanel = lazy(() =>
|
|
12
|
+
import("./overview-panel").then((m) => ({ default: m.OverviewPanel })),
|
|
13
|
+
);
|
|
14
|
+
const ProcessTable = lazy(() =>
|
|
15
|
+
import("./process-table").then((m) => ({ default: m.ProcessTable })),
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
type SysMonTab = "overview" | "processes";
|
|
19
|
+
|
|
20
|
+
export interface SystemMonitorBodyProps {
|
|
21
|
+
initialTab?: SysMonTab;
|
|
22
|
+
onTabChange?: (tab: SysMonTab) => void;
|
|
23
|
+
/** "window" (desktop floating window) suppresses the inner "System Monitor" title —
|
|
24
|
+
* the window's own titlebar already shows it — and moves the connection indicator
|
|
25
|
+
* into the tab strip instead. "tab" (default; the mobile route, which has no
|
|
26
|
+
* titlebar) keeps the full header. */
|
|
27
|
+
variant?: "window" | "tab";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function ConnectionIndicator({
|
|
31
|
+
isConnected,
|
|
32
|
+
elapsed,
|
|
33
|
+
tickCount,
|
|
34
|
+
}: {
|
|
35
|
+
isConnected: boolean;
|
|
36
|
+
elapsed: number;
|
|
37
|
+
tickCount: number;
|
|
38
|
+
}) {
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
className="flex items-center gap-1.5 text-[10px] text-text-subtle"
|
|
42
|
+
data-testid="sysmon-connection"
|
|
43
|
+
data-tick-count={tickCount}
|
|
44
|
+
>
|
|
45
|
+
{isConnected ? (
|
|
46
|
+
<Wifi className="size-3 text-success" />
|
|
47
|
+
) : (
|
|
48
|
+
<WifiOff className="size-3 text-error" />
|
|
49
|
+
)}
|
|
50
|
+
<span>{isConnected ? `Updated ${elapsed}s ago` : "Disconnected"}</span>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const SystemMonitorBody = memo(function SystemMonitorBody({
|
|
56
|
+
initialTab = "overview",
|
|
57
|
+
onTabChange,
|
|
58
|
+
variant = "tab",
|
|
59
|
+
}: SystemMonitorBodyProps) {
|
|
60
|
+
const { latest, history, isConnected, tickCount } = useResourceMonitor({ processes: true });
|
|
61
|
+
const [tab, setTab] = useState<SysMonTab>(initialTab);
|
|
62
|
+
|
|
63
|
+
const selectTab = (next: SysMonTab) => {
|
|
64
|
+
setTab(next);
|
|
65
|
+
onTabChange?.(next);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const elapsed = latest ? Math.round((Date.now() - latest.ts) / 1000) : 0;
|
|
69
|
+
const warnings = latest?.warnings ?? [];
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className="h-full flex flex-col overflow-hidden" data-testid="system-monitor-window">
|
|
73
|
+
{variant === "tab" && (
|
|
74
|
+
<div className="flex items-center justify-between px-3 py-2 border-b border-border shrink-0">
|
|
75
|
+
<h2 className="text-sm font-medium">System Monitor</h2>
|
|
76
|
+
<ConnectionIndicator isConnected={isConnected} elapsed={elapsed} tickCount={tickCount} />
|
|
77
|
+
</div>
|
|
78
|
+
)}
|
|
79
|
+
|
|
80
|
+
{warnings.length > 0 && (
|
|
81
|
+
<div
|
|
82
|
+
className="px-3 py-1.5 text-[11px] text-warning bg-warning/10 border-b border-border shrink-0 space-y-0.5"
|
|
83
|
+
data-testid="sysmon-warnings"
|
|
84
|
+
>
|
|
85
|
+
{warnings.map((w, i) => (
|
|
86
|
+
<div key={i}>{w}</div>
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
{/* Sub-tab switcher */}
|
|
92
|
+
<div className="flex items-center border-b border-border shrink-0" role="tablist">
|
|
93
|
+
<button
|
|
94
|
+
type="button"
|
|
95
|
+
role="tab"
|
|
96
|
+
aria-selected={tab === "overview"}
|
|
97
|
+
data-testid="sysmon-tab-overview"
|
|
98
|
+
onClick={() => selectTab("overview")}
|
|
99
|
+
className={cn(
|
|
100
|
+
"flex-1 md:flex-none min-h-11 px-4 text-sm font-medium transition-colors",
|
|
101
|
+
tab === "overview"
|
|
102
|
+
? "text-text-primary border-b-2 border-primary -mb-px"
|
|
103
|
+
: "text-text-subtle hover:text-text-secondary",
|
|
104
|
+
)}
|
|
105
|
+
>
|
|
106
|
+
Overview
|
|
107
|
+
</button>
|
|
108
|
+
<button
|
|
109
|
+
type="button"
|
|
110
|
+
role="tab"
|
|
111
|
+
aria-selected={tab === "processes"}
|
|
112
|
+
data-testid="sysmon-tab-processes"
|
|
113
|
+
onClick={() => selectTab("processes")}
|
|
114
|
+
className={cn(
|
|
115
|
+
"flex-1 md:flex-none min-h-11 px-4 text-sm font-medium transition-colors",
|
|
116
|
+
tab === "processes"
|
|
117
|
+
? "text-text-primary border-b-2 border-primary -mb-px"
|
|
118
|
+
: "text-text-subtle hover:text-text-secondary",
|
|
119
|
+
)}
|
|
120
|
+
>
|
|
121
|
+
Processes
|
|
122
|
+
</button>
|
|
123
|
+
{variant === "window" && (
|
|
124
|
+
<div className="ml-auto pr-3">
|
|
125
|
+
<ConnectionIndicator isConnected={isConnected} elapsed={elapsed} tickCount={tickCount} />
|
|
126
|
+
</div>
|
|
127
|
+
)}
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{/* Body — scrolls internally, never the page */}
|
|
131
|
+
<div className="flex-1 min-h-0 overflow-y-auto">
|
|
132
|
+
<Suspense fallback={<div className="p-4 text-xs text-text-subtle">Loading…</div>}>
|
|
133
|
+
{!latest ? (
|
|
134
|
+
<div className="flex items-center justify-center h-full text-text-subtle text-sm p-4">
|
|
135
|
+
{isConnected ? "Waiting for data…" : "Connecting to resource monitor…"}
|
|
136
|
+
</div>
|
|
137
|
+
) : tab === "overview" ? (
|
|
138
|
+
<OverviewPanel system={latest.system} history={history} />
|
|
139
|
+
) : (
|
|
140
|
+
<ProcessTable snapshot={latest} />
|
|
141
|
+
)}
|
|
142
|
+
</Suspense>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
});
|
|
@@ -1,186 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
Server, Monitor, Bot, Hammer, HelpCircle,
|
|
4
|
-
Wifi, WifiOff,
|
|
5
|
-
} from "lucide-react";
|
|
6
|
-
import { useResourceMonitor, type ResourceGroup } from "@/hooks/use-resource-monitor";
|
|
7
|
-
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
8
|
-
import { api } from "@/lib/api-client";
|
|
9
|
-
import { toast } from "sonner";
|
|
10
|
-
import { cn } from "@/lib/utils";
|
|
11
|
-
import {
|
|
12
|
-
GroupRow, SortableHeader, cpuColor, formatRam,
|
|
13
|
-
type SortKey, type SortDir,
|
|
14
|
-
} from "./system-monitor-group-row";
|
|
1
|
+
import { SystemMonitorBody } from "./system-monitor-body";
|
|
15
2
|
|
|
16
|
-
const
|
|
17
|
-
server: Server,
|
|
18
|
-
terminal: Monitor,
|
|
19
|
-
"ai-tool": Bot,
|
|
20
|
-
build: Hammer,
|
|
21
|
-
unknown: HelpCircle,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const SPARKLINE_POINTS = 200;
|
|
25
|
-
|
|
26
|
-
function toggleSort(
|
|
27
|
-
current: SortKey, dir: SortDir, clicked: "cpu" | "ram",
|
|
28
|
-
): [SortKey, SortDir] {
|
|
29
|
-
if (current !== clicked) return [clicked, "desc"];
|
|
30
|
-
if (dir === "desc") return [clicked, "asc"];
|
|
31
|
-
return [null, "desc"]; // third click resets
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function sortGroups(groups: ResourceGroup[], key: SortKey, dir: SortDir) {
|
|
35
|
-
if (!key) return groups;
|
|
36
|
-
const sorted = [...groups].sort((a, b) => {
|
|
37
|
-
const av = key === "cpu" ? a.cpu : a.ramMB;
|
|
38
|
-
const bv = key === "cpu" ? b.cpu : b.ramMB;
|
|
39
|
-
return dir === "asc" ? av - bv : bv - av;
|
|
40
|
-
});
|
|
41
|
-
return sorted;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const SystemMonitorTab = memo(function SystemMonitorTab() {
|
|
45
|
-
const { latest, history, isConnected } = useResourceMonitor();
|
|
46
|
-
const [expanded, setExpanded] = useState<Set<string>>(() => new Set(["server"]));
|
|
47
|
-
const [sortKey, setSortKey] = useState<SortKey>(null);
|
|
48
|
-
const [sortDir, setSortDir] = useState<SortDir>("desc");
|
|
49
|
-
const isMobile = useIsMobile();
|
|
50
|
-
|
|
51
|
-
const groupSparklines = useMemo(() => {
|
|
52
|
-
const map = new Map<string, number[]>();
|
|
53
|
-
const recentHistory = history.slice(-SPARKLINE_POINTS);
|
|
54
|
-
for (const snap of recentHistory) {
|
|
55
|
-
for (const group of snap.groups) {
|
|
56
|
-
const key = `${group.type}:${group.label}`;
|
|
57
|
-
const arr = map.get(key) ?? [];
|
|
58
|
-
arr.push(group.cpu);
|
|
59
|
-
map.set(key, arr);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return map;
|
|
63
|
-
}, [history]);
|
|
64
|
-
|
|
65
|
-
const sortedGroups = useMemo(() => {
|
|
66
|
-
if (!latest) return [];
|
|
67
|
-
return sortGroups(latest.groups, sortKey, sortDir);
|
|
68
|
-
}, [latest, sortKey, sortDir]);
|
|
69
|
-
|
|
70
|
-
const killProcess = useCallback(async (pid: number) => {
|
|
71
|
-
try {
|
|
72
|
-
await api.post(`/api/system/resources/kill/${pid}`);
|
|
73
|
-
toast.success(`Sent SIGTERM to PID ${pid}`);
|
|
74
|
-
} catch (e: any) {
|
|
75
|
-
toast.error(e.message || `Failed to kill PID ${pid}`);
|
|
76
|
-
}
|
|
77
|
-
}, []);
|
|
78
|
-
|
|
79
|
-
const toggle = (key: string) => {
|
|
80
|
-
setExpanded((prev) => {
|
|
81
|
-
const next = new Set(prev);
|
|
82
|
-
if (next.has(key)) next.delete(key);
|
|
83
|
-
else next.add(key);
|
|
84
|
-
return next;
|
|
85
|
-
});
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const handleSort = (clicked: "cpu" | "ram") => {
|
|
89
|
-
const [newKey, newDir] = toggleSort(sortKey, sortDir, clicked);
|
|
90
|
-
setSortKey(newKey);
|
|
91
|
-
setSortDir(newDir);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
if (!latest) {
|
|
95
|
-
return (
|
|
96
|
-
<div className="flex items-center justify-center h-full text-text-subtle text-sm">
|
|
97
|
-
{isConnected ? "Waiting for data..." : "Connecting to resource monitor..."}
|
|
98
|
-
</div>
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const elapsed = Math.round((Date.now() - latest.timestamp) / 1000);
|
|
103
|
-
|
|
104
|
-
return (
|
|
105
|
-
<div className="h-full flex flex-col overflow-hidden">
|
|
106
|
-
{/* Header */}
|
|
107
|
-
<div className="flex items-center justify-between px-3 py-2 border-b border-border shrink-0">
|
|
108
|
-
<h2 className="text-sm font-medium">System Monitor</h2>
|
|
109
|
-
<div className="flex items-center gap-1.5 text-[10px] text-text-subtle">
|
|
110
|
-
{isConnected
|
|
111
|
-
? <Wifi className="size-3 text-success" />
|
|
112
|
-
: <WifiOff className="size-3 text-error" />}
|
|
113
|
-
<span>{isConnected ? `Updated ${elapsed}s ago` : "Disconnected"}</span>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
|
|
117
|
-
{/* Group list */}
|
|
118
|
-
<div className="flex-1 overflow-y-auto min-h-0">
|
|
119
|
-
<table className="w-full text-xs">
|
|
120
|
-
<thead>
|
|
121
|
-
<tr className="text-text-subtle border-b border-border">
|
|
122
|
-
<th className="text-left py-1.5 px-3 font-medium">Process</th>
|
|
123
|
-
<SortableHeader
|
|
124
|
-
label="CPU"
|
|
125
|
-
field="cpu"
|
|
126
|
-
activeKey={sortKey}
|
|
127
|
-
activeDir={sortDir}
|
|
128
|
-
onClick={handleSort}
|
|
129
|
-
className="w-16"
|
|
130
|
-
/>
|
|
131
|
-
<SortableHeader
|
|
132
|
-
label="RAM"
|
|
133
|
-
field="ram"
|
|
134
|
-
activeKey={sortKey}
|
|
135
|
-
activeDir={sortDir}
|
|
136
|
-
onClick={handleSort}
|
|
137
|
-
className="w-20"
|
|
138
|
-
/>
|
|
139
|
-
{!isMobile && (
|
|
140
|
-
<th className="py-1.5 px-2 font-medium w-[130px]">Trend / Age</th>
|
|
141
|
-
)}
|
|
142
|
-
</tr>
|
|
143
|
-
</thead>
|
|
144
|
-
<tbody>
|
|
145
|
-
{sortedGroups.map((group) => {
|
|
146
|
-
const key = `${group.type}:${group.label}`;
|
|
147
|
-
const Icon = GROUP_ICONS[group.type] ?? HelpCircle;
|
|
148
|
-
const isExpanded = expanded.has(key);
|
|
149
|
-
const sparkData = groupSparklines.get(key) ?? [];
|
|
150
|
-
|
|
151
|
-
return (
|
|
152
|
-
<GroupRow
|
|
153
|
-
key={key}
|
|
154
|
-
group={group}
|
|
155
|
-
Icon={Icon}
|
|
156
|
-
isExpanded={isExpanded}
|
|
157
|
-
sparkData={sparkData}
|
|
158
|
-
isMobile={isMobile}
|
|
159
|
-
sortKey={sortKey}
|
|
160
|
-
sortDir={sortDir}
|
|
161
|
-
onToggle={() => toggle(key)}
|
|
162
|
-
onKill={killProcess}
|
|
163
|
-
/>
|
|
164
|
-
);
|
|
165
|
-
})}
|
|
166
|
-
</tbody>
|
|
167
|
-
{/* Total row */}
|
|
168
|
-
<tfoot>
|
|
169
|
-
<tr className="border-t border-border font-medium">
|
|
170
|
-
<td className="py-1.5 px-3">
|
|
171
|
-
Total ({latest.total.processCount} processes)
|
|
172
|
-
</td>
|
|
173
|
-
<td className={cn("text-right py-1.5 px-2", cpuColor(latest.total.cpu))}>
|
|
174
|
-
{latest.total.cpu.toFixed(1)}%
|
|
175
|
-
</td>
|
|
176
|
-
<td className="text-right py-1.5 px-2 text-text-secondary">
|
|
177
|
-
{formatRam(latest.total.ramMB)}
|
|
178
|
-
</td>
|
|
179
|
-
{!isMobile && <td />}
|
|
180
|
-
</tr>
|
|
181
|
-
</tfoot>
|
|
182
|
-
</table>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
|
-
);
|
|
186
|
-
});
|
|
3
|
+
export const SystemMonitorTab = () => <SystemMonitorBody />;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Floating-window body for the System Monitor. Persists the active sub-tab on the
|
|
2
|
+
* window's payload so a reload restores it. */
|
|
3
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
4
|
+
import type { WindowContentProps } from "@/components/floating-window/window-content-registry";
|
|
5
|
+
import { SystemMonitorBody } from "./system-monitor-body";
|
|
6
|
+
|
|
7
|
+
export default function SystemMonitorWindowContent({ id, payload }: WindowContentProps) {
|
|
8
|
+
const setPayload = useWindowStore((s) => s.setPayload);
|
|
9
|
+
const initialTab = payload?.tab === "processes" ? "processes" : "overview";
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<SystemMonitorBody
|
|
13
|
+
initialTab={initialTab}
|
|
14
|
+
onTabChange={(tab) => setPayload(id, { tab })}
|
|
15
|
+
variant="window"
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { clampColumnWidth, columnWidthPx, type ColumnWidths, type ResizableColumnKey } from "./process-columns-grid";
|
|
3
|
+
|
|
4
|
+
/** One entry for the whole app: column widths are a per-device preference, not
|
|
5
|
+
* per-window state, so they survive reloads and apply to the mobile tab too. */
|
|
6
|
+
export const COLUMN_WIDTHS_STORAGE_KEY = "ppm-sysmon-col-widths";
|
|
7
|
+
|
|
8
|
+
function loadWidths(): ColumnWidths {
|
|
9
|
+
try {
|
|
10
|
+
const raw = localStorage.getItem(COLUMN_WIDTHS_STORAGE_KEY);
|
|
11
|
+
if (!raw) return {};
|
|
12
|
+
const parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
13
|
+
const out: ColumnWidths = {};
|
|
14
|
+
for (const k of ["cpu", "ram", "disk", "gpu", "net"] as ResizableColumnKey[]) {
|
|
15
|
+
const v = parsed[k];
|
|
16
|
+
if (typeof v === "number" && Number.isFinite(v)) out[k] = clampColumnWidth(v);
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
} catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function saveWidths(widths: ColumnWidths): void {
|
|
25
|
+
try {
|
|
26
|
+
if (Object.keys(widths).length === 0) localStorage.removeItem(COLUMN_WIDTHS_STORAGE_KEY);
|
|
27
|
+
else localStorage.setItem(COLUMN_WIDTHS_STORAGE_KEY, JSON.stringify(widths));
|
|
28
|
+
} catch {
|
|
29
|
+
/* private mode / quota — widths just don't persist */
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Drag-to-resize state for the process table's fixed-width columns.
|
|
35
|
+
*
|
|
36
|
+
* `begin(key, event)` is wired to `pointerdown` on a header's right-edge handle;
|
|
37
|
+
* the drag then follows `pointermove`/`pointerup` on `window`, so the pointer may
|
|
38
|
+
* leave the handle (or the window body) without dropping the drag. Widths persist
|
|
39
|
+
* on release, not on every move. `reset(key)` (double-click) returns one column
|
|
40
|
+
* to its default.
|
|
41
|
+
*/
|
|
42
|
+
export function useColumnWidths() {
|
|
43
|
+
const [widths, setWidths] = useState<ColumnWidths>(() => (typeof localStorage === "undefined" ? {} : loadWidths()));
|
|
44
|
+
const drag = useRef<{ key: ResizableColumnKey; startX: number; startWidth: number } | null>(null);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const onMove = (e: PointerEvent) => {
|
|
48
|
+
const d = drag.current;
|
|
49
|
+
if (!d) return;
|
|
50
|
+
const next = clampColumnWidth(d.startWidth + (e.clientX - d.startX));
|
|
51
|
+
setWidths((prev) => (prev[d.key] === next ? prev : { ...prev, [d.key]: next }));
|
|
52
|
+
};
|
|
53
|
+
const onUp = () => {
|
|
54
|
+
if (!drag.current) return;
|
|
55
|
+
drag.current = null;
|
|
56
|
+
document.body.style.cursor = "";
|
|
57
|
+
setWidths((prev) => {
|
|
58
|
+
saveWidths(prev);
|
|
59
|
+
return prev;
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
window.addEventListener("pointermove", onMove);
|
|
63
|
+
window.addEventListener("pointerup", onUp);
|
|
64
|
+
window.addEventListener("pointercancel", onUp);
|
|
65
|
+
return () => {
|
|
66
|
+
window.removeEventListener("pointermove", onMove);
|
|
67
|
+
window.removeEventListener("pointerup", onUp);
|
|
68
|
+
window.removeEventListener("pointercancel", onUp);
|
|
69
|
+
};
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
72
|
+
const begin = useCallback(
|
|
73
|
+
(key: ResizableColumnKey, e: { clientX: number; preventDefault: () => void }) => {
|
|
74
|
+
e.preventDefault(); // no text selection while dragging
|
|
75
|
+
drag.current = { key, startX: e.clientX, startWidth: columnWidthPx(key, widths) };
|
|
76
|
+
document.body.style.cursor = "col-resize";
|
|
77
|
+
},
|
|
78
|
+
[widths],
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const reset = useCallback((key: ResizableColumnKey) => {
|
|
82
|
+
setWidths((prev) => {
|
|
83
|
+
if (!(key in prev)) return prev;
|
|
84
|
+
const { [key]: _dropped, ...rest } = prev;
|
|
85
|
+
saveWidths(rest);
|
|
86
|
+
return rest;
|
|
87
|
+
});
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
return { widths, begin, reset };
|
|
91
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opening the System Monitor on whichever presentation the device has.
|
|
3
|
+
*
|
|
4
|
+
* `WindowLayer` renders nothing below the `md` breakpoint, so `openWindow("system-monitor")`
|
|
5
|
+
* would be a silent no-op on a phone. Desktop gets the floating window; mobile gets the
|
|
6
|
+
* existing `system-monitor` tab route — both host the same `SystemMonitorBody`. On
|
|
7
|
+
* desktop, a second click focuses the already-open window rather than stacking a
|
|
8
|
+
* duplicate — there is only one machine to monitor, so a repeat open is never a
|
|
9
|
+
* distinct instance.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { useCallback } from "react";
|
|
13
|
+
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
14
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
15
|
+
import { useTabStore } from "@/stores/tab-store";
|
|
16
|
+
import { resolveOpenSystemMonitorAction } from "./resolve-open-system-monitor-action";
|
|
17
|
+
|
|
18
|
+
/** Callback that opens the System Monitor the right way for this viewport. */
|
|
19
|
+
export function useOpenSystemMonitor(): () => void {
|
|
20
|
+
const isMobile = useIsMobile();
|
|
21
|
+
const openWindow = useWindowStore((s) => s.open);
|
|
22
|
+
const focusWindow = useWindowStore((s) => s.focus);
|
|
23
|
+
const openTab = useTabStore((s) => s.openTab);
|
|
24
|
+
|
|
25
|
+
return useCallback(() => {
|
|
26
|
+
const existing = Object.values(useWindowStore.getState().windows).find(
|
|
27
|
+
(w) => w.kind === "system-monitor",
|
|
28
|
+
);
|
|
29
|
+
const action = resolveOpenSystemMonitorAction(isMobile, existing?.id ?? null);
|
|
30
|
+
if (action.kind === "tab") openTab(action.tab);
|
|
31
|
+
else if (action.kind === "focus") focusWindow(action.id);
|
|
32
|
+
else openWindow("system-monitor");
|
|
33
|
+
}, [isMobile, openWindow, focusWindow, openTab]);
|
|
34
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
import { toast } from "sonner";
|
|
3
|
+
import { getAuthToken } from "@/lib/api-client";
|
|
4
|
+
import { buildGroupKillRequests, buildKillRequest, isGroupProtected, type KillTarget } from "./build-kill-request";
|
|
5
|
+
import type {
|
|
6
|
+
KillProcessRequest,
|
|
7
|
+
KillProcessResult,
|
|
8
|
+
MetricsSnapshot,
|
|
9
|
+
ProcessGroup,
|
|
10
|
+
ProcessInfo,
|
|
11
|
+
} from "../../../types/system-metrics";
|
|
12
|
+
|
|
13
|
+
/** `api.post` (src/web/lib/api-client.ts) has no way to add a bespoke header, and the
|
|
14
|
+
* kill route requires `X-PPM-Request: 1` — CSRF hardening, since a cross-origin HTML
|
|
15
|
+
* form cannot set a custom header, so a preflight becomes mandatory. A raw fetch here
|
|
16
|
+
* mirrors `handleResponse`'s single-Error-on-any-failure contract exactly, so the
|
|
17
|
+
* caller still has exactly one catch path. */
|
|
18
|
+
export async function killProcess(request: KillProcessRequest): Promise<KillProcessResult> {
|
|
19
|
+
const token = getAuthToken();
|
|
20
|
+
const headers: Record<string, string> = {
|
|
21
|
+
"Content-Type": "application/json",
|
|
22
|
+
"X-PPM-Request": "1",
|
|
23
|
+
};
|
|
24
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
25
|
+
|
|
26
|
+
const res = await fetch("/api/system/resources/kill", {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers,
|
|
29
|
+
body: JSON.stringify(request),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
let json: { ok: boolean; data?: KillProcessResult; error?: string };
|
|
33
|
+
try {
|
|
34
|
+
json = await res.json();
|
|
35
|
+
} catch {
|
|
36
|
+
throw new Error(res.ok ? "Empty response from server" : `Server error (HTTP ${res.status})`);
|
|
37
|
+
}
|
|
38
|
+
if (json.ok === false) throw new Error(json.error ?? `HTTP ${res.status}`);
|
|
39
|
+
return json.data as KillProcessResult;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Pending-kill state plus the confirm handler for single processes and whole app
|
|
44
|
+
* groups. Members are resolved against the CURRENT snapshot at click time, so a
|
|
45
|
+
* helper that exited since the row was drawn is simply not in the list.
|
|
46
|
+
*/
|
|
47
|
+
export function useProcessKill(snapshot: MetricsSnapshot) {
|
|
48
|
+
const [pendingKill, setPendingKill] = useState<KillTarget | null>(null);
|
|
49
|
+
|
|
50
|
+
const membersOf = useCallback(
|
|
51
|
+
(group: ProcessGroup): ProcessInfo[] => {
|
|
52
|
+
const byPid = new Map(snapshot.processes.map((p) => [p.pid, p]));
|
|
53
|
+
return group.pids.map((pid) => byPid.get(pid)).filter((p): p is ProcessInfo => !!p);
|
|
54
|
+
},
|
|
55
|
+
[snapshot.processes],
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/** group key → true when any member is refused by the guard (button disabled). */
|
|
59
|
+
const groupProtected = useMemo(
|
|
60
|
+
() => new Map(snapshot.groups.map((g) => [g.key, isGroupProtected(membersOf(g))])),
|
|
61
|
+
[snapshot.groups, membersOf],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const requestKillProcess = useCallback((proc: ProcessInfo) => setPendingKill({ kind: "process", proc }), []);
|
|
65
|
+
const requestKillGroup = useCallback(
|
|
66
|
+
(group: ProcessGroup) => setPendingKill({ kind: "group", group, members: membersOf(group) }),
|
|
67
|
+
[membersOf],
|
|
68
|
+
);
|
|
69
|
+
const cancelKill = useCallback(() => setPendingKill(null), []);
|
|
70
|
+
|
|
71
|
+
const confirmKill = useCallback(async (target: KillTarget, tree: boolean) => {
|
|
72
|
+
setPendingKill(null);
|
|
73
|
+
if (target.kind === "process") {
|
|
74
|
+
const { proc } = target;
|
|
75
|
+
try {
|
|
76
|
+
await killProcess(buildKillRequest(proc, tree));
|
|
77
|
+
toast.success(`Ended ${proc.name} (${proc.pid})`);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
toast.error(e instanceof Error ? e.message : `Failed to end ${proc.name}`);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// Whole app: one tree kill on the root when it exists, else one per member.
|
|
84
|
+
// Requests run sequentially so the guard's 403/409 for one member is reported,
|
|
85
|
+
// not lost in a Promise.all rejection.
|
|
86
|
+
const { group, members } = target;
|
|
87
|
+
const failures: string[] = [];
|
|
88
|
+
for (const req of buildGroupKillRequests(group, members)) {
|
|
89
|
+
try {
|
|
90
|
+
await killProcess(req);
|
|
91
|
+
} catch (e) {
|
|
92
|
+
failures.push(e instanceof Error ? e.message : `pid ${req.pid}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (failures.length === 0) toast.success(`Ended ${group.label} (${members.length} processes)`);
|
|
96
|
+
else toast.error(`${group.label}: ${failures.length} of ${members.length} could not be ended — ${failures[0]}`);
|
|
97
|
+
}, []);
|
|
98
|
+
|
|
99
|
+
return { pendingKill, groupProtected, requestKillProcess, requestKillGroup, confirmKill, cancelKill };
|
|
100
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Pure/network helpers for `use-resource-monitor.ts`'s subscriber lease and history
|
|
2
|
+
* retention — split out to keep that file under the repo's 200-line guideline and so
|
|
3
|
+
* the lease request shape and retention rule are unit-testable in isolation. */
|
|
4
|
+
import { getAuthToken } from "@/lib/api-client";
|
|
5
|
+
import type { MetricsHistoryPoint } from "../../types/system-metrics";
|
|
6
|
+
|
|
7
|
+
/** Group aggregates are only ever read for the last 60 points (process-table-model's
|
|
8
|
+
* sparklines); retaining them for the full 900-point/30-min history window wastes
|
|
9
|
+
* tens of MB of small objects on a phone for data nothing reads. System aggregates
|
|
10
|
+
* keep the full window. */
|
|
11
|
+
export const GROUPS_RETENTION = 60;
|
|
12
|
+
|
|
13
|
+
/** Same bearer the kill request uses — every route under `/api/*` requires it, and the
|
|
14
|
+
* lease endpoints have no `?token=` fallback (that exists only for the GET-based SSE
|
|
15
|
+
* stream itself, which cannot set headers). Without this, ping/DELETE 401 silently,
|
|
16
|
+
* the server reaps the lease at 30s, and the client reconnects forever. */
|
|
17
|
+
export function authHeaders(): Record<string, string> {
|
|
18
|
+
const token = getAuthToken();
|
|
19
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Fire-and-forget ping keeping the subscriber lease alive — a missed one just costs
|
|
23
|
+
* one server-side reap cycle. */
|
|
24
|
+
export async function pingLease(sid: string): Promise<void> {
|
|
25
|
+
await fetch(`/api/system/resources/stream/${encodeURIComponent(sid)}/ping`, {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: authHeaders(),
|
|
28
|
+
}).catch(() => {});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Best-effort lease teardown — the server-side 30s reap is the real backstop (a proxy
|
|
32
|
+
* can buffer this DELETE away exactly when the client actually disconnected). */
|
|
33
|
+
export async function deleteLease(sid: string): Promise<void> {
|
|
34
|
+
await fetch(`/api/system/resources/stream/${encodeURIComponent(sid)}`, {
|
|
35
|
+
method: "DELETE",
|
|
36
|
+
headers: authHeaders(),
|
|
37
|
+
}).catch(() => {});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Drops `groups` from every history point older than the last `retain` entries.
|
|
41
|
+
* Pure so the retention behaviour is unit-testable without a live EventSource. */
|
|
42
|
+
export function withGroupsRetention(
|
|
43
|
+
history: MetricsHistoryPoint[],
|
|
44
|
+
retain: number,
|
|
45
|
+
): MetricsHistoryPoint[] {
|
|
46
|
+
const cutoff = history.length - retain;
|
|
47
|
+
if (cutoff <= 0) return history;
|
|
48
|
+
let changed = false;
|
|
49
|
+
const next = history.map((point, i) => {
|
|
50
|
+
if (i >= cutoff || Object.keys(point.groups).length === 0) return point;
|
|
51
|
+
changed = true;
|
|
52
|
+
return { ...point, groups: {} };
|
|
53
|
+
});
|
|
54
|
+
return changed ? next : history;
|
|
55
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useEffect, useState, type RefObject } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Live `clientWidth` of an element, tracked through `ResizeObserver`.
|
|
5
|
+
*
|
|
6
|
+
* Canvas charts cannot size themselves with CSS alone — the bitmap needs a pixel
|
|
7
|
+
* width — so a chart inside a resizable card or floating window has to be told how
|
|
8
|
+
* wide its box currently is. Returns 0 until the first measurement.
|
|
9
|
+
*/
|
|
10
|
+
export function useElementWidth(ref: RefObject<HTMLElement | null>): number {
|
|
11
|
+
const [width, setWidth] = useState(0);
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const el = ref.current;
|
|
15
|
+
if (!el) return;
|
|
16
|
+
setWidth(el.clientWidth);
|
|
17
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
18
|
+
const observer = new ResizeObserver((entries) => {
|
|
19
|
+
const next = Math.floor(entries[0]?.contentRect.width ?? el.clientWidth);
|
|
20
|
+
setWidth((prev) => (prev === next ? prev : next));
|
|
21
|
+
});
|
|
22
|
+
observer.observe(el);
|
|
23
|
+
return () => observer.disconnect();
|
|
24
|
+
}, [ref]);
|
|
25
|
+
|
|
26
|
+
return width;
|
|
27
|
+
}
|