@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.
Files changed (510) hide show
  1. package/.spike/s.err +63 -0
  2. package/.spike/tunnel.err +42 -0
  3. package/.spike/w.err +96 -0
  4. package/CHANGELOG.md +16 -0
  5. package/CLAUDE.md +1 -0
  6. package/assets/skills/ppm/SKILL.md +1 -1
  7. package/assets/skills/ppm/references/http-api.md +5 -3
  8. package/dist/web/assets/{ai-resource-editor-DZQUyrsU.js → ai-resource-editor-DFCuNe-P.js} +1 -1
  9. package/dist/web/assets/{angular-html-jfMqUuRd.js → angular-html-Ctz0zN01.js} +1 -1
  10. package/dist/web/assets/{angular-ts-wytn9PMm.js → angular-ts-QXHpgB1C.js} +1 -1
  11. package/dist/web/assets/{api-settings-DlcoR5QT.js → api-settings-nblja3Rk.js} +1 -1
  12. package/dist/web/assets/{apl-i-ahKx6O.js → apl-b9KVk-O4.js} +1 -1
  13. package/dist/web/assets/architecture-PBZL5I3N-C7ra20CE.js +1 -0
  14. package/dist/web/assets/{astro-DVBCJfG6.js → astro-BlFEeGYr.js} +1 -1
  15. package/dist/web/assets/{audio-preview-GGksv6U8.js → audio-preview-CZLmhf__.js} +1 -1
  16. package/dist/web/assets/{blade-BHlL8SqU.js → blade-CGkj2MUI.js} +1 -1
  17. package/dist/web/assets/{bsl-D-UOfR1F.js → bsl-CVsbb6ap.js} +1 -1
  18. package/dist/web/assets/button-BA_fJOtX.js +1 -0
  19. package/dist/web/assets/{cairo-Bn6rucli.js → cairo-BbIHl2iE.js} +1 -1
  20. package/dist/web/assets/chat-tab-flMPLoKb.js +15 -0
  21. package/dist/web/assets/circle-hjUGru6R.js +1 -0
  22. package/dist/web/assets/circle-question-mark-CzR7YRc-.js +1 -0
  23. package/dist/web/assets/{cobol-Byn9FYKu.js → cobol-BWSGjmWb.js} +1 -1
  24. package/dist/web/assets/code-editor-C2VQbXzw.js +10 -0
  25. package/dist/web/assets/{coffee-DjBl4gm-.js → coffee-CWGNOxds.js} +1 -1
  26. package/dist/web/assets/{conflict-editor-Dg_JIcKq.js → conflict-editor-CdH_h0vD.js} +3 -3
  27. package/dist/web/assets/{context-menu-DkQdt6YA.js → context-menu-Cq0u3SK9.js} +1 -1
  28. package/dist/web/assets/{cpp-CKzic-3E.js → cpp-DHGV24J2.js} +1 -1
  29. package/dist/web/assets/{crystal-Bkg-Ly_g.js → crystal-Vlwf2UMP.js} +1 -1
  30. package/dist/web/assets/{csv-preview-DsJ_a2Op.js → csv-preview-CY_454vd.js} +1 -1
  31. package/dist/web/assets/{data-grid-overlay-editor-B1mTl3KS.js → data-grid-overlay-editor-D9il5DZS.js} +1 -1
  32. package/dist/web/assets/{database-viewer-CzjnrnMz.js → database-viewer-BCZOTrPT.js} +1 -1
  33. package/dist/web/assets/{diff-viewer-DUNkO-ll.js → diff-viewer-BwfMN-nW.js} +1 -1
  34. package/dist/web/assets/{docx-preview-DujpUDkE.js → docx-preview-D3Sdh_aT.js} +1 -1
  35. package/dist/web/assets/{edge-DVbZnd3Y.js → edge-Bhqk64zS.js} +1 -1
  36. package/dist/web/assets/{edit-diff-preview-BivQwZMD.js → edit-diff-preview-gq6ALf2B.js} +1 -1
  37. package/dist/web/assets/{elixir-Dwi8Wu7W.js → elixir-D466WCFm.js} +1 -1
  38. package/dist/web/assets/{elm-DtIv-HXJ.js → elm-Bfs2qNPR.js} +1 -1
  39. package/dist/web/assets/{erb-D3HEDz1x.js → erb-WI7jUaB6.js} +1 -1
  40. package/dist/web/assets/{erlang-2MjTCzGz.js → erlang-BCBe8nCc.js} +1 -1
  41. package/dist/web/assets/{esm-CZ8B8Ba2.js → esm-CZs9WVDO.js} +1 -1
  42. package/dist/web/assets/{explorer-body-DSDJUQs7.js → explorer-body-BKOMM566.js} +2 -2
  43. package/dist/web/assets/{explorer-window-content-CWYBapkj.js → explorer-window-content-Bbzijk8t.js} +1 -1
  44. package/dist/web/assets/{extension-webview-DBTFznQp.js → extension-webview-CuOQrHIS.js} +1 -1
  45. package/dist/web/assets/format-bytes-Dk7B73B7.js +1 -0
  46. package/dist/web/assets/{fortran-fixed-form-BLyAtyPM.js → fortran-fixed-form-CXLIv8Ox.js} +1 -1
  47. package/dist/web/assets/{fsharp-Bxbn_gbr.js → fsharp-CZsYmiw9.js} +1 -1
  48. package/dist/web/assets/{gdresource-sFMY4D2Q.js → gdresource-BGRvoWfC.js} +1 -1
  49. package/dist/web/assets/{git-commit-BzB9Lio5.js → git-commit-DH6mY3Km.js} +1 -1
  50. package/dist/web/assets/{git-log-panel-D8ZQdoYl.js → git-log-panel-DcV7PhqW.js} +1 -1
  51. package/dist/web/assets/{git-rebase-CKSVd848.js → git-rebase-C5Gql6Ma.js} +1 -1
  52. package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +1 -0
  53. package/dist/web/assets/{glide-data-grid-uIjdTT7c.js → glide-data-grid-Cehfgrzc.js} +7 -7
  54. package/dist/web/assets/{glimmer-js-BY8aExAJ.js → glimmer-js-1-6JMJlj.js} +1 -1
  55. package/dist/web/assets/{glimmer-ts-Bak54dBX.js → glimmer-ts-C_Njj0nK.js} +1 -1
  56. package/dist/web/assets/{glsl-nR2eaJQe.js → glsl-DbkxE1TN.js} +1 -1
  57. package/dist/web/assets/{graphql-CGPPFAU6.js → graphql-BK75fiXl.js} +1 -1
  58. package/dist/web/assets/group-chat-tab-BVPYxjz-.js +1 -0
  59. package/dist/web/assets/{hack-CXIMX-Ol.js → hack-DG151vit.js} +1 -1
  60. package/dist/web/assets/{haml-tPY-9Pfm.js → haml-DKeIPQWM.js} +1 -1
  61. package/dist/web/assets/{handlebars-BuW1LT7T.js → handlebars-398uCI13.js} +1 -1
  62. package/dist/web/assets/{html-bgVcwZ-t.js → html-NLWdst5q.js} +1 -1
  63. package/dist/web/assets/{html-derivative-D6-IxTgn.js → html-derivative-CJf_Le2z.js} +1 -1
  64. package/dist/web/assets/{http-CJ1zyB-h.js → http-G1K2FozA.js} +1 -1
  65. package/dist/web/assets/{hurl-CmoT7l3T.js → hurl-WDC6sSBz.js} +1 -1
  66. package/dist/web/assets/{hxml-CztOsL8o.js → hxml-Dc3jBXuf.js} +1 -1
  67. package/dist/web/assets/{image-preview-B0VXSpYu.js → image-preview-D-Ok10eZ.js} +1 -1
  68. package/dist/web/assets/index-CerSxGdf.js +52 -0
  69. package/dist/web/assets/index-DRA_OpWY.css +2 -0
  70. package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +1 -0
  71. package/dist/web/assets/{jinja-B1pq3jJq.js → jinja-CWsQj2y0.js} +1 -1
  72. package/dist/web/assets/{jison-D8B5pCwA.js → jison-CciJg2NW.js} +1 -1
  73. package/dist/web/assets/{julia-D0K3bwpU.js → julia-IOQNJAB7.js} +1 -1
  74. package/dist/web/assets/{just-B9Jlddu-.js → just-BGdHchwS.js} +1 -1
  75. package/dist/web/assets/{keybindings-store-FyolpNND.js → keybindings-store-aIY40k2o.js} +1 -1
  76. package/dist/web/assets/{latex-BPJSSE6j.js → latex-D6TOl-L2.js} +1 -1
  77. package/dist/web/assets/{liquid-lv10fo4U.js → liquid-CVSvu_Wn.js} +1 -1
  78. package/dist/web/assets/{lua-PNuaIBEF.js → lua-CcKiU6HW.js} +1 -1
  79. package/dist/web/assets/markdown-renderer-I89kyQhe.js +1 -0
  80. package/dist/web/assets/{markdown-renderer-BaBQ6Wm6.js → markdown-renderer-pVzBdkpl.js} +3 -3
  81. package/dist/web/assets/{marko-Du3frD6X.js → marko--UOicMGo.js} +1 -1
  82. package/dist/web/assets/{mdc-BeDVcFRl.js → mdc-D690aU2C.js} +1 -1
  83. package/dist/web/assets/media-url-CylYQld1.js +1 -0
  84. package/dist/web/assets/{mobile-explorer-sheet-Zxjl-e4c.js → mobile-explorer-sheet-5Uj9ZMM9.js} +1 -1
  85. package/dist/web/assets/{nextflow-DkcXP71s.js → nextflow-DR8PhpF8.js} +1 -1
  86. package/dist/web/assets/{nginx-C5n8N_bt.js → nginx-Qb9pUk1g.js} +1 -1
  87. package/dist/web/assets/{nim-CIhyfs-A.js → nim-DLa8R3NS.js} +1 -1
  88. package/dist/web/assets/{notification-store-DnGpxgkF.js → notification-store-DJ-OtAG3.js} +1 -1
  89. package/dist/web/assets/{number-overlay-editor-NgOsWJ7x.js → number-overlay-editor-D9SkFg1Y.js} +1 -1
  90. package/dist/web/assets/overview-panel-Cgi3UPY1.js +1 -0
  91. package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +1 -0
  92. package/dist/web/assets/{pdf-preview-xzAA4-kD.js → pdf-preview-Di5xHFyT.js} +1 -1
  93. package/dist/web/assets/{perl-Cf31sZYE.js → perl-AMNGIneF.js} +1 -1
  94. package/dist/web/assets/{php-Dzl_MDIW.js → php-CDsOOxXn.js} +1 -1
  95. package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +1 -0
  96. package/dist/web/assets/{postgres-viewer-Dkec6GyK.js → postgres-viewer-CR6VpTrX.js} +3 -3
  97. package/dist/web/assets/process-table-DL6shbzt.js +1 -0
  98. package/dist/web/assets/{pug-CxSYHrB3.js → pug-C2kdkhQ6.js} +1 -1
  99. package/dist/web/assets/{qml-DlEjGhwN.js → qml-DRDkUp75.js} +1 -1
  100. package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +1 -0
  101. package/dist/web/assets/{razor-KVt5uW14.js → razor-wY_6wUeC.js} +1 -1
  102. package/dist/web/assets/{rst-D5BwNTnw.js → rst-BRpofyNs.js} +1 -1
  103. package/dist/web/assets/{ruby-D5fejQwd.js → ruby-ieATBhWm.js} +1 -1
  104. package/dist/web/assets/{sas-Bj7B1CB2.js → sas-CoOOEbOO.js} +1 -1
  105. package/dist/web/assets/{scss-BB0CUoCL.js → scss-_nWV0bsb.js} +1 -1
  106. package/dist/web/assets/{settings-store-C9YT1Hir.js → settings-store-C20lqh0G.js} +2 -2
  107. package/dist/web/assets/settings-tab-jbiQwozX.js +1 -0
  108. package/dist/web/assets/{shaderlab-BdjEZUMc.js → shaderlab-XkqfIfO8.js} +1 -1
  109. package/dist/web/assets/{shellsession-Bp1OA1rR.js → shellsession-BKBIqTlM.js} +1 -1
  110. package/dist/web/assets/{soy-DlYz3wsC.js → soy-oVDnPzzh.js} +1 -1
  111. package/dist/web/assets/{sparql-CdfII5Jd.js → sparql-N2VclEsF.js} +1 -1
  112. package/dist/web/assets/{sql-query-editor-Bz1XrUqI.js → sql-query-editor-BPYsJDsn.js} +1 -1
  113. package/dist/web/assets/{sqlite-viewer-D5-NZw6b.js → sqlite-viewer-Bq9ZJA2y.js} +1 -1
  114. package/dist/web/assets/{stata-BvUA6GUW.js → stata-BuuClVDg.js} +1 -1
  115. package/dist/web/assets/{surrealql--DLNbTyI.js → surrealql-DE5_63MS.js} +1 -1
  116. package/dist/web/assets/{svelte-CBfSsG4n.js → svelte--YWjlOrK.js} +1 -1
  117. package/dist/web/assets/system-monitor-body-CKEYWyN9.js +2 -0
  118. package/dist/web/assets/system-monitor-tab-WjhFFHyM.js +1 -0
  119. package/dist/web/assets/system-monitor-window-content-CMiISeoC.js +1 -0
  120. package/dist/web/assets/team-member-sheet-oY5EkH53.js +2 -0
  121. package/dist/web/assets/{team-member-window-content-DSpZ2zhL.js → team-member-window-content-yCBeI_5X.js} +1 -1
  122. package/dist/web/assets/{templ-Dv8zpKZW.js → templ-MlpvJx4a.js} +1 -1
  123. package/dist/web/assets/{terminal-tab-DXazqejW.js → terminal-tab-BxHtMR7h.js} +3 -3
  124. package/dist/web/assets/{tex-CsrOiqh1.js → tex-0loAoXJG.js} +1 -1
  125. package/dist/web/assets/{tool-cards-Bgp8iceS.js → tool-cards-BcGrk1zk.js} +5 -5
  126. package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +1 -0
  127. package/dist/web/assets/{ts-tags-3T98k4EJ.js → ts-tags-pt-Ug0hK.js} +1 -1
  128. package/dist/web/assets/{twig-u6QZ45FH.js → twig-DOePpLOL.js} +1 -1
  129. package/dist/web/assets/{use-monaco-theme-CpF3A7JL.js → use-monaco-theme-CGucu3fb.js} +1 -1
  130. package/dist/web/assets/{use-open-team-member-CUvV02fA.js → use-open-team-member-DdrRXj-M.js} +1 -1
  131. package/dist/web/assets/{use-websocket-TnL2I1io.js → use-websocket-C-Rxv8JN.js} +1 -1
  132. package/dist/web/assets/{vendor-mermaid-Bg4vE8QA.js → vendor-mermaid-DrwG0NYt.js} +1 -1
  133. package/dist/web/assets/video-preview-DYAbbmd0.js +1 -0
  134. package/dist/web/assets/{vue-CxIsxtwn.js → vue-D6f-rprj.js} +1 -1
  135. package/dist/web/assets/{vue-html-BGL5qnuH.js → vue-html-DEYRkS1V.js} +1 -1
  136. package/dist/web/assets/{vue-vine-DHPh_gMr.js → vue-vine-CxSG2ojf.js} +1 -1
  137. package/dist/web/assets/{xml-C-vM2m7J.js → xml-DhrxbATj.js} +1 -1
  138. package/dist/web/assets/{xsl-DvTXNwuO.js → xsl-CU0ZndUO.js} +1 -1
  139. package/dist/web/index.html +18 -17
  140. package/dist/web/sw.js +1 -1
  141. package/docs/system-architecture.md +2 -2
  142. package/package.json +1 -1
  143. package/src/server/helpers/media-route-handlers.ts +22 -3
  144. package/src/server/index.ts +2 -8
  145. package/src/server/routes/files.ts +5 -2
  146. package/src/server/routes/fs-browse.ts +5 -2
  147. package/src/server/routes/resources.ts +119 -73
  148. package/src/services/autostart-generator.ts +79 -7
  149. package/src/services/autostart-register.ts +15 -2
  150. package/src/services/fs-path-guard.service.ts +17 -1
  151. package/src/services/media-transcode/transcode-stream.ts +27 -5
  152. package/src/services/proc-table-linux.ts +4 -0
  153. package/src/services/redact-secrets.ts +33 -0
  154. package/src/services/system-metrics/cpu-memory-collector.ts +101 -0
  155. package/src/services/system-metrics/disk-net-collector-darwin.ts +75 -0
  156. package/src/services/system-metrics/disk-net-collector-linux.ts +88 -0
  157. package/src/services/system-metrics/disk-net-collector-windows.ts +57 -0
  158. package/src/services/system-metrics/gpu-collector-nvidia.ts +78 -0
  159. package/src/services/system-metrics/gpu-process-memory-nvidia.ts +66 -0
  160. package/src/services/system-metrics/gpu-process-usage-windows.ts +138 -0
  161. package/src/services/system-metrics/kill-executor.ts +85 -0
  162. package/src/services/system-metrics/kill-guard.ts +124 -0
  163. package/src/services/system-metrics/kill-identity-resolver.ts +72 -0
  164. package/src/services/system-metrics/kill-request-handler.ts +79 -0
  165. package/src/services/system-metrics/metrics-collector-lock.ts +36 -0
  166. package/src/services/system-metrics/metrics-poll-scheduler.ts +83 -0
  167. package/src/services/system-metrics/metrics-subscriber-registry.ts +85 -0
  168. package/src/services/system-metrics/powershell-session-bootstrap.ts +48 -0
  169. package/src/services/system-metrics/powershell-session.ts +182 -0
  170. package/src/services/system-metrics/ppm-process-ownership.ts +34 -0
  171. package/src/services/system-metrics/ppm-protected-pids.ts +84 -0
  172. package/src/services/system-metrics/process-collector-darwin.ts +141 -0
  173. package/src/services/system-metrics/process-collector-linux.ts +85 -0
  174. package/src/services/system-metrics/process-collector-types.ts +80 -0
  175. package/src/services/system-metrics/process-collector-windows-parse.ts +153 -0
  176. package/src/services/system-metrics/process-collector-windows.ts +136 -0
  177. package/src/services/system-metrics/process-cpu-delta.ts +61 -0
  178. package/src/services/system-metrics/process-grouping.ts +142 -0
  179. package/src/services/system-metrics/process-io-delta.ts +84 -0
  180. package/src/services/system-metrics/process-io-linux.ts +46 -0
  181. package/src/services/system-metrics/process-net-collector-darwin.ts +103 -0
  182. package/src/services/system-metrics/process-rows-builder.ts +111 -0
  183. package/src/services/system-metrics/rate-delta.ts +47 -0
  184. package/src/services/system-metrics/system-metrics-platform.ts +51 -0
  185. package/src/services/system-metrics/system-metrics-tick.ts +178 -0
  186. package/src/services/system-metrics/system-metrics.service.ts +212 -0
  187. package/src/types/system-metrics.ts +199 -0
  188. package/src/web/components/editor/video-player/video-player.tsx +54 -22
  189. package/src/web/components/floating-window/window-content-registry.ts +2 -0
  190. package/src/web/components/floating-window/window-persistence.ts +1 -1
  191. package/src/web/components/floating-window/window-store-types.ts +1 -1
  192. package/src/web/components/system/build-kill-request.ts +9 -0
  193. package/src/web/components/system/chart-scale.ts +28 -0
  194. package/src/web/components/system/cpu-core-bars.tsx +33 -0
  195. package/src/web/components/system/kill-confirm-dialog.tsx +89 -0
  196. package/src/web/components/system/metric-chart-canvas.tsx +108 -0
  197. package/src/web/components/system/overview-cards/cpu-card.tsx +39 -0
  198. package/src/web/components/system/overview-cards/disk-card.tsx +41 -0
  199. package/src/web/components/system/overview-cards/gpu-card.tsx +33 -0
  200. package/src/web/components/system/overview-cards/mem-card.tsx +32 -0
  201. package/src/web/components/system/overview-cards/net-card.tsx +41 -0
  202. package/src/web/components/system/overview-panel.tsx +97 -0
  203. package/src/web/components/system/process-columns-grid.ts +93 -0
  204. package/src/web/components/system/process-group-row.tsx +71 -0
  205. package/src/web/components/system/process-row-format.ts +56 -0
  206. package/src/web/components/system/process-row.tsx +82 -0
  207. package/src/web/components/system/process-table-model.ts +127 -0
  208. package/src/web/components/system/process-table-sort.ts +90 -0
  209. package/src/web/components/system/process-table-toolbar.tsx +190 -0
  210. package/src/web/components/system/process-table-totals.ts +49 -0
  211. package/src/web/components/system/process-table.tsx +187 -0
  212. package/src/web/components/system/resolve-open-system-monitor-action.ts +29 -0
  213. package/src/web/components/system/resource-status-bar.tsx +17 -16
  214. package/src/web/components/system/sortable-header.tsx +65 -0
  215. package/src/web/components/system/sparkline-canvas.tsx +8 -9
  216. package/src/web/components/system/system-monitor-body.tsx +146 -0
  217. package/src/web/components/system/system-monitor-tab.tsx +2 -185
  218. package/src/web/components/system/system-monitor-window-content.tsx +18 -0
  219. package/src/web/components/system/use-open-system-monitor.ts +34 -0
  220. package/src/web/hooks/resource-monitor-lease.ts +55 -0
  221. package/src/web/hooks/use-element-width.ts +27 -0
  222. package/src/web/hooks/use-resource-monitor.ts +113 -35
  223. package/src/web/lib/format-bytes.ts +16 -0
  224. package/src/web/lib/media-url.ts +30 -4
  225. package/.release-run.sh +0 -5
  226. package/dist/web/assets/architecture-PBZL5I3N-Bs7wzj-W.js +0 -1
  227. package/dist/web/assets/arrow-right-DubGFkN8.js +0 -1
  228. package/dist/web/assets/button-B4MWPjWj.js +0 -1
  229. package/dist/web/assets/chat-tab-Xd2WMjdX.js +0 -15
  230. package/dist/web/assets/circle-question-mark-CENpx4oA.js +0 -1
  231. package/dist/web/assets/code-editor-DqXYJWAB.js +0 -10
  232. package/dist/web/assets/gitGraph-HDMCJU4V-D7i54kbM.js +0 -1
  233. package/dist/web/assets/group-chat-tab-B3sryFdA.js +0 -1
  234. package/dist/web/assets/index-DgbOF3xa.js +0 -52
  235. package/dist/web/assets/index-oxsyfDa0.css +0 -2
  236. package/dist/web/assets/info-3K5VOQVL-BV41AzR9.js +0 -1
  237. package/dist/web/assets/markdown-renderer-feiuhJ9n.js +0 -1
  238. package/dist/web/assets/media-url-CUpN5vI1.js +0 -1
  239. package/dist/web/assets/packet-RMMSAZCW-CaJoP44m.js +0 -1
  240. package/dist/web/assets/pie-UPGHQEXC-DSGZmNw2.js +0 -1
  241. package/dist/web/assets/radar-KQ55EAFF-Be4VUTs0.js +0 -1
  242. package/dist/web/assets/settings-tab-Bd8e6iqY.js +0 -1
  243. package/dist/web/assets/system-monitor-tab-A0jvt5Qw.js +0 -1
  244. package/dist/web/assets/team-member-sheet-5Oaqm8I_.js +0 -2
  245. package/dist/web/assets/treemap-KZPCXAKY-Cu2zgbxU.js +0 -1
  246. package/dist/web/assets/video-preview-CwtLPELG.js +0 -1
  247. package/src/services/resource-monitor-utils.ts +0 -141
  248. package/src/services/resource-monitor.service.ts +0 -147
  249. package/src/web/components/system/system-monitor-group-row.tsx +0 -153
  250. /package/dist/web/assets/{abap-C1K0-wzc.js → abap-MRbmsXOs.js} +0 -0
  251. /package/dist/web/assets/{actionscript-3-CJhQVjLA.js → actionscript-3-BDDHKqa4.js} +0 -0
  252. /package/dist/web/assets/{ada-Bt8r9fME.js → ada-DpuV9KwV.js} +0 -0
  253. /package/dist/web/assets/{andromeeda-DF1I8qi3.js → andromeeda-D6qUCKJo.js} +0 -0
  254. /package/dist/web/assets/{apache-CnlleE6P.js → apache-CX1NU_Tl.js} +0 -0
  255. /package/dist/web/assets/{apex-j0C6Xmk6.js → apex-B4-aoQ3K.js} +0 -0
  256. /package/dist/web/assets/{api-settings-DfNRPr1q.js → api-settings-kQHV6pYZ.js} +0 -0
  257. /package/dist/web/assets/{api-themes-8WTH6KpV.js → api-themes-CrK0tkW_.js} +0 -0
  258. /package/dist/web/assets/{applescript-DO7AnO8U.js → applescript-Dm9NI6KR.js} +0 -0
  259. /package/dist/web/assets/{apply-theme-CNj1iA-v.js → apply-theme-BH_d4amk.js} +0 -0
  260. /package/dist/web/assets/{ara-i83AydZj.js → ara-BGN8GAYn.js} +0 -0
  261. /package/dist/web/assets/{asciidoc-DbBA6-sF.js → asciidoc-s_yVuR3t.js} +0 -0
  262. /package/dist/web/assets/{asm-B5S47Rgr.js → asm-BzQdSvTe.js} +0 -0
  263. /package/dist/web/assets/{aurora-x-De_IaSKw.js → aurora-x-BJTLETG_.js} +0 -0
  264. /package/dist/web/assets/{awk-CfyLHXqS.js → awk-BQEGWxvX.js} +0 -0
  265. /package/dist/web/assets/{ayu-dark-DTLdZ1Si.js → ayu-dark-CpTORmLc.js} +0 -0
  266. /package/dist/web/assets/{ayu-light-DTOfkzhu.js → ayu-light-D8PVj-e6.js} +0 -0
  267. /package/dist/web/assets/{ayu-mirage-DsAECCMv.js → ayu-mirage-DyElQHtm.js} +0 -0
  268. /package/dist/web/assets/{ballerina-CumGp9A7.js → ballerina-C82NkRtj.js} +0 -0
  269. /package/dist/web/assets/{bat-Ca2SBbYN.js → bat-0X7DtGI-.js} +0 -0
  270. /package/dist/web/assets/{beancount-CqyXBwwF.js → beancount-Xgvy6YRl.js} +0 -0
  271. /package/dist/web/assets/{berry-yl-kJr_H.js → berry-CCT2pZcQ.js} +0 -0
  272. /package/dist/web/assets/{bibtex-DoFFszjV.js → bibtex-CpXgZ9M_.js} +0 -0
  273. /package/dist/web/assets/{bicep-CWPi4nfK.js → bicep-fkeSA62l.js} +0 -0
  274. /package/dist/web/assets/{bird2-DXew-ut0.js → bird2-Co7SeAI8.js} +0 -0
  275. /package/dist/web/assets/{c-clbySDvd.js → c-BpmrTvJh.js} +0 -0
  276. /package/dist/web/assets/{c3-B65jvSM1.js → c3-BZ_Z0RrR.js} +0 -0
  277. /package/dist/web/assets/{cadence-Cm8tQTHN.js → cadence-B0GBC8OF.js} +0 -0
  278. /package/dist/web/assets/{can-open-in-ppm-DXGOSUQc.js → can-open-in-ppm-omBzUBBq.js} +0 -0
  279. /package/dist/web/assets/{catppuccin-frappe-DLeGslh_.js → catppuccin-frappe-DIt_xR7m.js} +0 -0
  280. /package/dist/web/assets/{catppuccin-latte-CR5GeHws.js → catppuccin-latte-Dw40AcqA.js} +0 -0
  281. /package/dist/web/assets/{catppuccin-macchiato-p-XgjxhP.js → catppuccin-macchiato-BJ7DfVEF.js} +0 -0
  282. /package/dist/web/assets/{catppuccin-mocha-B8QOAZLl.js → catppuccin-mocha-NI2lfXzU.js} +0 -0
  283. /package/dist/web/assets/{clarity-DPulbvKH.js → clarity-F39L0xMJ.js} +0 -0
  284. /package/dist/web/assets/{clock-D493FU_D.js → clock-CvhF4DJP.js} +0 -0
  285. /package/dist/web/assets/{clojure-DFuWS20u.js → clojure-DloMkd8K.js} +0 -0
  286. /package/dist/web/assets/{cmake-DejCqcu4.js → cmake-CwerJun_.js} +0 -0
  287. /package/dist/web/assets/{code-CLF5x7KK.js → code-DDPoqVri.js} +0 -0
  288. /package/dist/web/assets/{codeowners-BwAyqWIH.js → codeowners-CQyVz4Qf.js} +0 -0
  289. /package/dist/web/assets/{codeql-DgSwFjqI.js → codeql-Bb229zuY.js} +0 -0
  290. /package/dist/web/assets/{common-lisp-CxIVJCtf.js → common-lisp-KMlIwq5I.js} +0 -0
  291. /package/dist/web/assets/{copy-BApI9v7Z.js → copy-DKn11Pye.js} +0 -0
  292. /package/dist/web/assets/{coq-DLSjSnmf.js → coq-DHX_3IIo.js} +0 -0
  293. /package/dist/web/assets/{csharp-C1HHzXBp.js → csharp-CEmCZv9Q.js} +0 -0
  294. /package/dist/web/assets/{css-VXsMY--y.js → css-CqZqBD05.js} +0 -0
  295. /package/dist/web/assets/{csv-BEbcJdHz.js → csv-l1g_V5MV.js} +0 -0
  296. /package/dist/web/assets/{csv-parser-BRtnJCfv.js → csv-parser-CnS0wqr6.js} +0 -0
  297. /package/dist/web/assets/{cue-BkDnFqUD.js → cue-BrxRmilg.js} +0 -0
  298. /package/dist/web/assets/{cypher-1cMqojSQ.js → cypher-rZkKwqZc.js} +0 -0
  299. /package/dist/web/assets/{d-BnYjRXtH.js → d-BALR-QuP.js} +0 -0
  300. /package/dist/web/assets/{dark-plus-XfbaH7kZ.js → dark-plus-Cj7rVwh-.js} +0 -0
  301. /package/dist/web/assets/{dart-Ca7s-8hK.js → dart-CWQcdkXk.js} +0 -0
  302. /package/dist/web/assets/{data-grid-types-BXwlFMzs.js → data-grid-types-CYvF-xK5.js} +0 -0
  303. /package/dist/web/assets/{database-B9okYLx6.js → database-BH0urvbs.js} +0 -0
  304. /package/dist/web/assets/{dax-CmuOw-mY.js → dax-BNHD-QBA.js} +0 -0
  305. /package/dist/web/assets/{desktop-C2gJ6Ovb.js → desktop-CN0IXPrP.js} +0 -0
  306. /package/dist/web/assets/{diff-BCEo1Ej7.js → diff-BtOXapES.js} +0 -0
  307. /package/dist/web/assets/{dist-CUPbqNnL.js → dist-DB1Oaqcc.js} +0 -0
  308. /package/dist/web/assets/{dist-DOlBnxFX.js → dist-Di6G_5jU.js} +0 -0
  309. /package/dist/web/assets/{docker-DN2jlyAh.js → docker-DNsAo_qO.js} +0 -0
  310. /package/dist/web/assets/{dotenv-NExMY2kS.js → dotenv-D6Pl6aOU.js} +0 -0
  311. /package/dist/web/assets/{download-D9UYwY0-.js → download-zCATy4x4.js} +0 -0
  312. /package/dist/web/assets/{dracula-B9lbE01y.js → dracula-C3m-w12D.js} +0 -0
  313. /package/dist/web/assets/{dracula-soft-CMBBfKF_.js → dracula-soft-BYqvXm6Z.js} +0 -0
  314. /package/dist/web/assets/{dream-maker-DEyDwFsd.js → dream-maker-DZAPbPTi.js} +0 -0
  315. /package/dist/web/assets/{emacs-lisp-D_qP2zS6.js → emacs-lisp-Ao5SW8ay.js} +0 -0
  316. /package/dist/web/assets/{everforest-dark-DbHa2U-p.js → everforest-dark-uC8QYotQ.js} +0 -0
  317. /package/dist/web/assets/{everforest-light-BISkJchP.js → everforest-light-CTgsVNMr.js} +0 -0
  318. /package/dist/web/assets/{fennel-6B22SfJR.js → fennel-WuBw6IR1.js} +0 -0
  319. /package/dist/web/assets/{file-exclamation-point-a8f3_w7a.js → file-exclamation-point-COAwgNGw.js} +0 -0
  320. /package/dist/web/assets/{fish-CubIIvJD.js → fish-Byy9dusu.js} +0 -0
  321. /package/dist/web/assets/{fluent-DF55zQ09.js → fluent-CDxb_sgw.js} +0 -0
  322. /package/dist/web/assets/{fortran-free-form-DvOu8jAt.js → fortran-free-form-DKWSTamT.js} +0 -0
  323. /package/dist/web/assets/{gdscript-DCPxdLpq.js → gdscript-prYHMgtD.js} +0 -0
  324. /package/dist/web/assets/{gdshader-CTZ381FO.js → gdshader-D-RM-SQk.js} +0 -0
  325. /package/dist/web/assets/{genie-C_QDtvgU.js → genie-CowkJhej.js} +0 -0
  326. /package/dist/web/assets/{gherkin-BcvK42tF.js → gherkin-CLFpoVYJ.js} +0 -0
  327. /package/dist/web/assets/{github-dark-default-CKGVrl3Z.js → github-dark-default-BK_1Qgb8.js} +0 -0
  328. /package/dist/web/assets/{github-dark-dimmed-C3dQZ_LC.js → github-dark-dimmed-Cv9lj6f-.js} +0 -0
  329. /package/dist/web/assets/{github-dark-high-contrast-DW78QukY.js → github-dark-high-contrast-CW5ZgIDh.js} +0 -0
  330. /package/dist/web/assets/{github-dark-C9afs_4w.js → github-dark-nW2F-RLd.js} +0 -0
  331. /package/dist/web/assets/{github-light-BnP2dznS.js → github-light-D4PqBHGZ.js} +0 -0
  332. /package/dist/web/assets/{github-light-default-C2fPZzPG.js → github-light-default-B-cHtJJV.js} +0 -0
  333. /package/dist/web/assets/{github-light-high-contrast-BzIuUFR2.js → github-light-high-contrast-Dt0HJq50.js} +0 -0
  334. /package/dist/web/assets/{gleam-BpeKwEIO.js → gleam-DwSyXJWP.js} +0 -0
  335. /package/dist/web/assets/{gn-nUb_Mit0.js → gn-Cv5WEzHc.js} +0 -0
  336. /package/dist/web/assets/{gnuplot-D7I0v20p.js → gnuplot-D7bRdY_M.js} +0 -0
  337. /package/dist/web/assets/{go-D7Qqska7.js → go-DiRVJ22U.js} +0 -0
  338. /package/dist/web/assets/{groovy-DS-pne5-.js → groovy-BHAgLTeO.js} +0 -0
  339. /package/dist/web/assets/{gruvbox-dark-hard-C0W01fsq.js → gruvbox-dark-hard-C8QZ3gzY.js} +0 -0
  340. /package/dist/web/assets/{gruvbox-dark-medium-Bqo6fQbg.js → gruvbox-dark-medium-Dp1eeid2.js} +0 -0
  341. /package/dist/web/assets/{gruvbox-dark-soft-D-XSM_fu.js → gruvbox-dark-soft-Cwq0dWVj.js} +0 -0
  342. /package/dist/web/assets/{gruvbox-light-hard-IVAwMJRl.js → gruvbox-light-hard-CLQCq2-w.js} +0 -0
  343. /package/dist/web/assets/{gruvbox-light-medium-38ATiG7i.js → gruvbox-light-medium-APHsh6Mo.js} +0 -0
  344. /package/dist/web/assets/{gruvbox-light-soft-DnZr3c_0.js → gruvbox-light-soft-CX-fYc64.js} +0 -0
  345. /package/dist/web/assets/{haskell-uQcywkDH.js → haskell-C4Tw-TDa.js} +0 -0
  346. /package/dist/web/assets/{haxe-c6bI4_GT.js → haxe-B7fSduTQ.js} +0 -0
  347. /package/dist/web/assets/{hcl-CQXTiEXq.js → hcl-Bi3ho6yC.js} +0 -0
  348. /package/dist/web/assets/{hjson-ChETf2bz.js → hjson-BXwae2M1.js} +0 -0
  349. /package/dist/web/assets/{hlsl-BMC4JGoE.js → hlsl-CRuQLBSa.js} +0 -0
  350. /package/dist/web/assets/{horizon-BusFlhLW.js → horizon-DtdQ6qjv.js} +0 -0
  351. /package/dist/web/assets/{horizon-bright-2oD0Mz7W.js → horizon-bright-BXSF_uKq.js} +0 -0
  352. /package/dist/web/assets/{houston-DdbbjqFg.js → houston-C6ASpUjT.js} +0 -0
  353. /package/dist/web/assets/{hy-D_SOuqw9.js → hy-BrWBHtHY.js} +0 -0
  354. /package/dist/web/assets/{image-gallery-CrM5fHKy.js → image-gallery-CGvlv8zR.js} +0 -0
  355. /package/dist/web/assets/{imba-BxLOHO5I.js → imba-C_JJXckG.js} +0 -0
  356. /package/dist/web/assets/{ini-ox-CFcg0.js → ini-DEE_vSHQ.js} +0 -0
  357. /package/dist/web/assets/{java-Bzo8yIal.js → java-CnmpcjcT.js} +0 -0
  358. /package/dist/web/assets/{javascript-DHuz9VXn.js → javascript-C-M7sa2e.js} +0 -0
  359. /package/dist/web/assets/{json-0_y80FD5.js → json-BjZ3dAk6.js} +0 -0
  360. /package/dist/web/assets/{json5-CEQ50pGM.js → json5-BQ2vpqjp.js} +0 -0
  361. /package/dist/web/assets/{jsonc-CfrLEAKA.js → jsonc-C5MjoWGx.js} +0 -0
  362. /package/dist/web/assets/{jsonl-fKbrANC2.js → jsonl-JvhrmQJI.js} +0 -0
  363. /package/dist/web/assets/{jsonnet-DKbkPaQ2.js → jsonnet-C5pdZVuo.js} +0 -0
  364. /package/dist/web/assets/{jssm-Dxxx1Hqu.js → jssm-Db17uybX.js} +0 -0
  365. /package/dist/web/assets/{jsx-DlJL-Oj3.js → jsx-tJp2Cyqu.js} +0 -0
  366. /package/dist/web/assets/{kanagawa-dragon-CwN4SV1c.js → kanagawa-dragon-BculT_Y1.js} +0 -0
  367. /package/dist/web/assets/{kanagawa-lotus-BHltayiE.js → kanagawa-lotus-yQgHUGwU.js} +0 -0
  368. /package/dist/web/assets/{kanagawa-wave-D-KXPjw6.js → kanagawa-wave-CyGoWN4d.js} +0 -0
  369. /package/dist/web/assets/{kdl-DvtoJdFo.js → kdl-Bn8R1REF.js} +0 -0
  370. /package/dist/web/assets/{kotlin-CTS4MLcx.js → kotlin-DWughK73.js} +0 -0
  371. /package/dist/web/assets/{kusto-HtSE_sKm.js → kusto--serPb0x.js} +0 -0
  372. /package/dist/web/assets/{laserwave-DaXZG9ge.js → laserwave-DfAPJ1tt.js} +0 -0
  373. /package/dist/web/assets/{lean-BYtGUfWx.js → lean-UAm1HOKl.js} +0 -0
  374. /package/dist/web/assets/{less-BoxmU_Mk.js → less-Xj6Ka0fF.js} +0 -0
  375. /package/dist/web/assets/{lib-B1clP4ai.js → lib-DgNcCtj3.js} +0 -0
  376. /package/dist/web/assets/{libesm-ah-mr-sh.js → libesm-CPh1Av0r.js} +0 -0
  377. /package/dist/web/assets/{light-plus-Bt5CyUuo.js → light-plus-BfS7gPcj.js} +0 -0
  378. /package/dist/web/assets/{llvm-CSdk9q9V.js → llvm-DvWiVwvU.js} +0 -0
  379. /package/dist/web/assets/{log-B-kp_3CL.js → log-Bo5z9bNz.js} +0 -0
  380. /package/dist/web/assets/{logo-DdIsXFDO.js → logo-CrIjcMZT.js} +0 -0
  381. /package/dist/web/assets/{luau-DUBpLlzQ.js → luau-C9TsYwNt.js} +0 -0
  382. /package/dist/web/assets/{make-B3JVjoW_.js → make-GYq4qVbx.js} +0 -0
  383. /package/dist/web/assets/{markdown-Seon0vHs.js → markdown-p5mNledS.js} +0 -0
  384. /package/dist/web/assets/{material-theme-Nq-ChX1P.js → material-theme-CWYOVxsP.js} +0 -0
  385. /package/dist/web/assets/{material-theme-darker-CPV4ayXJ.js → material-theme-darker-BDGty7YH.js} +0 -0
  386. /package/dist/web/assets/{material-theme-lighter-0kyjYqEd.js → material-theme-lighter-JbgOgV3n.js} +0 -0
  387. /package/dist/web/assets/{material-theme-ocean-DGpAp5co.js → material-theme-ocean-EMOpLpa2.js} +0 -0
  388. /package/dist/web/assets/{material-theme-palenight-B0AUn0NG.js → material-theme-palenight-CY5hgm7h.js} +0 -0
  389. /package/dist/web/assets/{matlab-C2waytxs.js → matlab-C-He_NTH.js} +0 -0
  390. /package/dist/web/assets/{mdx-DAis6R6I.js → mdx-Cr2TR5fj.js} +0 -0
  391. /package/dist/web/assets/{mermaid-_rnT2YGD.js → mermaid-BYc0-B0U.js} +0 -0
  392. /package/dist/web/assets/{min-dark-BSSjchUB.js → min-dark-CMJwqJqB.js} +0 -0
  393. /package/dist/web/assets/{min-light-DomAFQsa.js → min-light-Cx6vFiEX.js} +0 -0
  394. /package/dist/web/assets/{mipsasm-bBgtvPyG.js → mipsasm-Bjer5HwK.js} +0 -0
  395. /package/dist/web/assets/{mobile-bottom-sheet-CS3XMwFw.js → mobile-bottom-sheet-BUOJgiaZ.js} +0 -0
  396. /package/dist/web/assets/{mojo-Cp9BayW0.js → mojo-t90PR-Y2.js} +0 -0
  397. /package/dist/web/assets/{monokai-CL_9gbmn.js → monokai-dci_PdCm.js} +0 -0
  398. /package/dist/web/assets/{moonbit-BS_fcr-P.js → moonbit-AAzI-Hd-.js} +0 -0
  399. /package/dist/web/assets/{move-C79AH45U.js → move-kwBhnhrG.js} +0 -0
  400. /package/dist/web/assets/{narrat-CJ5s3BDf.js → narrat-CXww2YQL.js} +0 -0
  401. /package/dist/web/assets/{nextflow-groovy-ZHa4JrPJ.js → nextflow-groovy-CJXsuXGB.js} +0 -0
  402. /package/dist/web/assets/{night-owl-Jkf9zFQK.js → night-owl-_GD204Wr.js} +0 -0
  403. /package/dist/web/assets/{night-owl-light-DRPeaG5J.js → night-owl-light-DNgkw3kl.js} +0 -0
  404. /package/dist/web/assets/{nix-D2Jet9DN.js → nix-BgiorKFd.js} +0 -0
  405. /package/dist/web/assets/{nord-CREVs22j.js → nord-CaBmcxFC.js} +0 -0
  406. /package/dist/web/assets/{nushell-CAiDi_mR.js → nushell-DUh4UGx1.js} +0 -0
  407. /package/dist/web/assets/{objective-c-CVkmJkC1.js → objective-c-Cl9KU86S.js} +0 -0
  408. /package/dist/web/assets/{objective-cpp-DIKDO1Ly.js → objective-cpp-DVkIA8A0.js} +0 -0
  409. /package/dist/web/assets/{ocaml-R9qtGQhs.js → ocaml-vvoHTak0.js} +0 -0
  410. /package/dist/web/assets/{odin-DTYNQqVr.js → odin-Cyjw8woZ.js} +0 -0
  411. /package/dist/web/assets/{one-dark-pro-BSLWUJn5.js → one-dark-pro-B1cviILi.js} +0 -0
  412. /package/dist/web/assets/{one-light-DbkRXG3t.js → one-light-BPGUJeYI.js} +0 -0
  413. /package/dist/web/assets/{openscad-BlPcSnmT.js → openscad-BLMdTUU8.js} +0 -0
  414. /package/dist/web/assets/{pascal-B1Y46ZZB.js → pascal-i5niy3e7.js} +0 -0
  415. /package/dist/web/assets/{pkl-BhJSJbFv.js → pkl-CuOV7SsU.js} +0 -0
  416. /package/dist/web/assets/{plastic-BzxsCTpi.js → plastic-Bf_zE5KL.js} +0 -0
  417. /package/dist/web/assets/{plsql-DBba7dyP.js → plsql-cfqEtMD3.js} +0 -0
  418. /package/dist/web/assets/{plus-DmjC2iRB.js → plus-BM-Ty0fp.js} +0 -0
  419. /package/dist/web/assets/{po-BvgLlnNo.js → po-CFJcWgjr.js} +0 -0
  420. /package/dist/web/assets/{poimandres-DUaI_1JP.js → poimandres-G5YoaIFf.js} +0 -0
  421. /package/dist/web/assets/{polar-C7uILwJn.js → polar-rcjs3i9R.js} +0 -0
  422. /package/dist/web/assets/{postcss-BgJlpFdw.js → postcss-CBKY1FTZ.js} +0 -0
  423. /package/dist/web/assets/{powerquery-Dn1MIpZu.js → powerquery-Db7SXLbO.js} +0 -0
  424. /package/dist/web/assets/{powershell-Bo-DYzOS.js → powershell-LFy3MUTP.js} +0 -0
  425. /package/dist/web/assets/{prisma-CTLs5IdT.js → prisma-BE8GR1lH.js} +0 -0
  426. /package/dist/web/assets/{prolog-QRGun3eG.js → prolog-DOn5lR1e.js} +0 -0
  427. /package/dist/web/assets/{proto-B7PI7apn.js → proto-wr-TpAK_.js} +0 -0
  428. /package/dist/web/assets/{puppet-CBq0tLrP.js → puppet-D2Dkv62u.js} +0 -0
  429. /package/dist/web/assets/{purescript-DFewOQb2.js → purescript-DvgJgPdy.js} +0 -0
  430. /package/dist/web/assets/{python-iWuxKXvT.js → python-C7TlkHhK.js} +0 -0
  431. /package/dist/web/assets/{qmldir-cXiW3AsF.js → qmldir-CtZMwhcW.js} +0 -0
  432. /package/dist/web/assets/{qss-DASwAbBL.js → qss-dNZ2btnl.js} +0 -0
  433. /package/dist/web/assets/{r-TU2eaIPw.js → r-BlqnNkHS.js} +0 -0
  434. /package/dist/web/assets/{racket-SkRKqrLY.js → racket-CzRQrGc4.js} +0 -0
  435. /package/dist/web/assets/{raku-D31lthkZ.js → raku-BwutWhBF.js} +0 -0
  436. /package/dist/web/assets/{red-CTcQZevb.js → red-BMXMywmL.js} +0 -0
  437. /package/dist/web/assets/{reg-D8YAsTGf.js → reg-BqOKrIOw.js} +0 -0
  438. /package/dist/web/assets/{regexp-CD2uvAWx.js → regexp-Bero1BN2.js} +0 -0
  439. /package/dist/web/assets/{rel-CAaI-1fg.js → rel-BXKWIElA.js} +0 -0
  440. /package/dist/web/assets/{resolve-theme-CJvkL8hU.js → resolve-theme-IdhSR-gx.js} +0 -0
  441. /package/dist/web/assets/{riscv-DR-hJVIj.js → riscv-BbbBYJBo.js} +0 -0
  442. /package/dist/web/assets/{ron-CuUCJ0n4.js → ron-BtVTWW4b.js} +0 -0
  443. /package/dist/web/assets/{rose-pine-dawn-Bqz2sBRY.js → rose-pine-dawn-D7lwhUei.js} +0 -0
  444. /package/dist/web/assets/{rose-pine-aFHxW48i.js → rose-pine-hvkvQzvU.js} +0 -0
  445. /package/dist/web/assets/{rose-pine-moon-wqyh0an4.js → rose-pine-moon-CoHDmsIw.js} +0 -0
  446. /package/dist/web/assets/{rosmsg-CI1ywimO.js → rosmsg-CdaZFgI8.js} +0 -0
  447. /package/dist/web/assets/{run-in-terminal-CGW6o37_.js → run-in-terminal-CyS5Itj-.js} +0 -0
  448. /package/dist/web/assets/{rust-p7Imk4G_.js → rust-Dy2qsphD.js} +0 -0
  449. /package/dist/web/assets/{sass-C8JfaqCV.js → sass-Bz7NVxDb.js} +0 -0
  450. /package/dist/web/assets/{save-DRPrDfTt.js → save-C4z1p51e.js} +0 -0
  451. /package/dist/web/assets/{scala-DNxCW1By.js → scala-sXSwsNyq.js} +0 -0
  452. /package/dist/web/assets/{scheme-BYuUPJoL.js → scheme-DS7TUbN7.js} +0 -0
  453. /package/dist/web/assets/{sdbl-DbPeJPUr.js → sdbl-iISFvIep.js} +0 -0
  454. /package/dist/web/assets/{send-to-chat-YXHdAyLG.js → send-to-chat-BcO39BDR.js} +0 -0
  455. /package/dist/web/assets/{shellscript-DMiHlR3q.js → shellscript-BkIl4ApC.js} +0 -0
  456. /package/dist/web/assets/{shield-check-8GObuUAn.js → shield-check-C5laObJv.js} +0 -0
  457. /package/dist/web/assets/{shield-off-egKAZEwR.js → shield-off-DULFtyLS.js} +0 -0
  458. /package/dist/web/assets/{slack-dark-C4xGcQXI.js → slack-dark-B1eg0_m2.js} +0 -0
  459. /package/dist/web/assets/{slack-ochin-BzgRt_wm.js → slack-ochin-mdkc1ldu.js} +0 -0
  460. /package/dist/web/assets/{smalltalk-LDeL9PYH.js → smalltalk-CORtd03t.js} +0 -0
  461. /package/dist/web/assets/{snazzy-light-CXE7a5j_.js → snazzy-light-Bc6Q2G89.js} +0 -0
  462. /package/dist/web/assets/{solarized-dark-DgUhY74x.js → solarized-dark-CF83zRXM.js} +0 -0
  463. /package/dist/web/assets/{solarized-light-DD9C-H-9.js → solarized-light-BoKQZaYU.js} +0 -0
  464. /package/dist/web/assets/{solidity-CAbDB4D4.js → solidity-DOgi1N4w.js} +0 -0
  465. /package/dist/web/assets/{sparkles-n1hzh65o.js → sparkles-Dqsf3hq6.js} +0 -0
  466. /package/dist/web/assets/{splunk-kQREPfIc.js → splunk-BXfw5ZLy.js} +0 -0
  467. /package/dist/web/assets/{sql-CBzeNAD8.js → sql-BcVs-eX4.js} +0 -0
  468. /package/dist/web/assets/{ssh-config-L1euxrsM.js → ssh-config-CLCtNkkd.js} +0 -0
  469. /package/dist/web/assets/{stylus-DvBnYniP.js → stylus-DdP992aO.js} +0 -0
  470. /package/dist/web/assets/{swift-DF5NDQp6.js → swift-BnGb6Lgc.js} +0 -0
  471. /package/dist/web/assets/{synthwave-84-DbBhB_Hq.js → synthwave-84-cg9264l9.js} +0 -0
  472. /package/dist/web/assets/{system-verilog-D8s2ZW_k.js → system-verilog-GbHpszs3.js} +0 -0
  473. /package/dist/web/assets/{systemd-a5-XZJsG.js → systemd-Dz-bNsDQ.js} +0 -0
  474. /package/dist/web/assets/{table-BX2ZrJfM.js → table-CHmxuh6M.js} +0 -0
  475. /package/dist/web/assets/{talonscript-BLa0URTW.js → talonscript-CFIidoBA.js} +0 -0
  476. /package/dist/web/assets/{tasl-DIoV4XcC.js → tasl-Cu-TRTKx.js} +0 -0
  477. /package/dist/web/assets/{tcl-ztYAdXfQ.js → tcl-DwCHCB1K.js} +0 -0
  478. /package/dist/web/assets/{terraform-DvpCCiOZ.js → terraform-BzZw4T1z.js} +0 -0
  479. /package/dist/web/assets/{tokyo-night-BkHlYUv0.js → tokyo-night-RKsj2-tv.js} +0 -0
  480. /package/dist/web/assets/{toml-acIrxos6.js → toml-CirbOgDP.js} +0 -0
  481. /package/dist/web/assets/{tsv-BJB5EVCT.js → tsv-CraRcWdU.js} +0 -0
  482. /package/dist/web/assets/{tsx-B1MmXGT3.js → tsx-CjFg0lgw.js} +0 -0
  483. /package/dist/web/assets/{turtle-DFceTiqd.js → turtle-B-WBIOa6.js} +0 -0
  484. /package/dist/web/assets/{typescript-Dz9wU5Y1.js → typescript-MpLarYn1.js} +0 -0
  485. /package/dist/web/assets/{typespec-CPuYZijj.js → typespec-B7QlHMZ_.js} +0 -0
  486. /package/dist/web/assets/{typst-CfsCIYv8.js → typst-CcHSKFZj.js} +0 -0
  487. /package/dist/web/assets/{use-blob-url-BmlYYZ8L.js → use-blob-url-BKyVxOZw.js} +0 -0
  488. /package/dist/web/assets/{use-is-mobile-B8FA4kQf.js → use-is-mobile-BXGVvczu.js} +0 -0
  489. /package/dist/web/assets/{v-CGo0jcXA.js → v-xTGhWZuD.js} +0 -0
  490. /package/dist/web/assets/{vala-AsSR0hrb.js → vala-DwebjH3H.js} +0 -0
  491. /package/dist/web/assets/{vb-C7tvbXv1.js → vb-BxJT2RAy.js} +0 -0
  492. /package/dist/web/assets/{vendor-xterm-C1diXHJl.js → vendor-xterm-CU6zIYMB.js} +0 -0
  493. /package/dist/web/assets/{verilog--a33ND-p.js → verilog-CvV6RHPD.js} +0 -0
  494. /package/dist/web/assets/{vesper-B_Z0h4pn.js → vesper-CY3qd7E_.js} +0 -0
  495. /package/dist/web/assets/{vhdl-CWL5dZPN.js → vhdl-B9ZX-sUL.js} +0 -0
  496. /package/dist/web/assets/{viml-BglmT14Y.js → viml-Y42h_ExQ.js} +0 -0
  497. /package/dist/web/assets/{vitesse-black-RKFsSqQI.js → vitesse-black-DkXP6Sv-.js} +0 -0
  498. /package/dist/web/assets/{vitesse-dark-D7zDWNmc.js → vitesse-dark-B9CkIB6r.js} +0 -0
  499. /package/dist/web/assets/{vitesse-light-MAp87W5b.js → vitesse-light-C7DHrJCK.js} +0 -0
  500. /package/dist/web/assets/{vyper-CgCBYg1G.js → vyper-Cnd9s5j-.js} +0 -0
  501. /package/dist/web/assets/{wasm-Bwl4txwp.js → wasm-DQE71XTB.js} +0 -0
  502. /package/dist/web/assets/{wasm-BOG7ZeTT.js → wasm-iWe7Fzjc.js} +0 -0
  503. /package/dist/web/assets/{wenyan-DpShPKXZ.js → wenyan-Bc5Pnm9l.js} +0 -0
  504. /package/dist/web/assets/{wgsl-BakcCblK.js → wgsl-D-YUAWkP.js} +0 -0
  505. /package/dist/web/assets/{wikitext-NroRWVAO.js → wikitext-DYQDUYf2.js} +0 -0
  506. /package/dist/web/assets/{wit-B5CM2pg6.js → wit-P6u7mfwy.js} +0 -0
  507. /package/dist/web/assets/{wolfram-7MTFBJpR.js → wolfram-6SXLUqao.js} +0 -0
  508. /package/dist/web/assets/{yaml-Bwr01G2K.js → yaml-CQiMLVcZ.js} +0 -0
  509. /package/dist/web/assets/{zenscript-Dj8GATvi.js → zenscript-DFMywo_P.js} +0 -0
  510. /package/dist/web/assets/{zig-LAE-fbS-.js → zig-CtAjaIiF.js} +0 -0
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Whole-machine metrics: tiered subscribers, leases, one poll timer, atomic
3
+ * delta-state commits and demand-gated children.
4
+ *
5
+ * The tier gates COLLECTION, not just serialisation: the status bar mounts on
6
+ * every page, and if its stream drove full collection PPM would run a 174 ms
7
+ * PowerShell round trip plus a 400-process grouping pass every 2 s forever to
8
+ * render two numbers. So the PowerShell child, `nvidia-smi` and the disk/net
9
+ * queries run only while ≥1 full subscriber exists, and the child is torn down
10
+ * 60 s after the last one leaves (a window reopen then skips the bootstrap).
11
+ */
12
+ import type { KillProcessResult, MetricsSnapshot, MetricsTier } from "../../types/system-metrics.ts";
13
+ import { METRICS_INTERVAL_MS, METRICS_LEASE_TIMEOUT_MS, METRICS_LIGHT_INTERVAL_MS } from "../../types/system-metrics.ts";
14
+ import { collectMemory, sampleCpuTimes } from "./cpu-memory-collector.ts";
15
+ import { assembleTick, EMPTY_DELTA_STATE, projectLight, type TickDeltaState, type TickDeps } from "./system-metrics-tick.ts";
16
+ import { createPlatformCollectors, type PlatformCollectors } from "./system-metrics-platform.ts";
17
+ import { resolveProtectedPidsLive } from "./ppm-protected-pids.ts";
18
+ import { SubscriberRegistry, type MetricsSubscriber } from "./metrics-subscriber-registry.ts";
19
+ import { PollScheduler, installProcessExitHooks } from "./metrics-poll-scheduler.ts";
20
+ import { handleKillRequest, type KillOutcome } from "./kill-request-handler.ts";
21
+ import { executeKill } from "./kill-executor.ts";
22
+ import { CollectorLock } from "./metrics-collector-lock.ts";
23
+
24
+ /** Over a proxy a closed window's lease lives until the reap; 8 leaves room for
25
+ * a few open/close cycles across devices without a spurious 429. */
26
+ export const MAX_STREAM_SUBSCRIBERS = 8;
27
+ /** Grace before the PowerShell child is torn down after the last full subscriber leaves. */
28
+ export const FULL_IDLE_TEARDOWN_MS = 60_000;
29
+
30
+ export interface SystemMetricsServiceOptions {
31
+ collectors?: PlatformCollectors;
32
+ intervals?: { full: number; light: number };
33
+ idleTeardownMs?: number;
34
+ leaseTimeoutMs?: number;
35
+ now?: () => number;
36
+ resolveProtected?: TickDeps["resolveProtected"];
37
+ execute?: (pid: number, tree: boolean) => Promise<KillProcessResult>;
38
+ log?: (line: string) => void;
39
+ /** Register process exit/signal teardown of children (off in unit tests). */
40
+ exitHooks?: boolean;
41
+ }
42
+
43
+ export type SubscribeInit = Pick<MetricsSubscriber, "tier" | "deliver" | "close">;
44
+ export interface SubscribeResult { sid: string; tier: MetricsTier; intervalMs: number }
45
+
46
+ export class SystemMetricsService {
47
+ private readonly registry = new SubscriberRegistry();
48
+ private readonly scheduler: PollScheduler;
49
+ private readonly collectors: PlatformCollectors;
50
+ private readonly intervals: { full: number; light: number };
51
+ private readonly leaseTimeoutMs: number;
52
+ private readonly now: () => number;
53
+ private readonly tickDeps: TickDeps;
54
+ private readonly execute: NonNullable<SystemMetricsServiceOptions["execute"]>;
55
+ private readonly log: (line: string) => void;
56
+ private readonly exitHooks: boolean;
57
+
58
+ /** Serialises the one tick or kill collection allowed to hold the collector. */
59
+ private readonly collectorLock = new CollectorLock();
60
+ private state: TickDeltaState = EMPTY_DELTA_STATE;
61
+ private latest: { light: MetricsSnapshot | null; full: MetricsSnapshot | null } = { light: null, full: null };
62
+
63
+ constructor(opts: SystemMetricsServiceOptions = {}) {
64
+ this.collectors = opts.collectors ?? createPlatformCollectors();
65
+ this.intervals = opts.intervals ?? { full: METRICS_INTERVAL_MS, light: METRICS_LIGHT_INTERVAL_MS };
66
+ this.leaseTimeoutMs = opts.leaseTimeoutMs ?? METRICS_LEASE_TIMEOUT_MS;
67
+ this.now = opts.now ?? Date.now;
68
+ this.execute = opts.execute ?? executeKill;
69
+ this.log = opts.log ?? ((line) => console.log(line));
70
+ this.exitHooks = opts.exitHooks ?? true;
71
+ this.tickDeps = {
72
+ platform: this.collectors.platform,
73
+ memory: () => collectMemory(),
74
+ processes: this.collectors.processes,
75
+ diskNet: this.collectors.diskNet,
76
+ gpus: this.collectors.gpus,
77
+ resolveProtected: opts.resolveProtected ?? resolveProtectedPidsLive,
78
+ now: this.now,
79
+ sampleCpu: sampleCpuTimes,
80
+ };
81
+ this.scheduler = new PollScheduler({
82
+ intervals: this.intervals,
83
+ idleTeardownMs: opts.idleTeardownMs ?? FULL_IDLE_TEARDOWN_MS,
84
+ onTick: () => void this.runTick(),
85
+ onIdle: () => this.collectors.processes.stop(),
86
+ onFullStart: () => this.ensureExitHooks(),
87
+ });
88
+ }
89
+
90
+ /** Null when the cap of live subscribers is reached (expired leases are reaped first). */
91
+ subscribe(init: SubscribeInit): SubscribeResult | null {
92
+ this.reapExpired();
93
+ if (this.registry.count() >= MAX_STREAM_SUBSCRIBERS) return null;
94
+ const sid = crypto.randomUUID().replace(/-/g, "").slice(0, 8);
95
+ this.registry.add({ sid, ...init, lastPingAt: this.now() });
96
+ this.reconcile();
97
+ // A newcomer on an already-running tier would otherwise wait a whole
98
+ // interval. Deferred so the caller can write its `session` frame first.
99
+ const latest = this.latest[init.tier];
100
+ if (latest) queueMicrotask(() => { if (this.registry.has(sid)) init.deliver(latest); });
101
+ return { sid, tier: init.tier, intervalMs: this.intervals[init.tier] };
102
+ }
103
+
104
+ unsubscribe(sid: string): boolean {
105
+ const removed = this.registry.remove(sid);
106
+ if (removed) this.reconcile();
107
+ return removed;
108
+ }
109
+
110
+ ping(sid: string): boolean {
111
+ return this.registry.ping(sid, this.now());
112
+ }
113
+
114
+ getLatest(tier: MetricsTier): MetricsSnapshot | null {
115
+ return this.latest[tier];
116
+ }
117
+
118
+ liveCount(tier?: MetricsTier): number {
119
+ return this.registry.count(tier);
120
+ }
121
+
122
+ activeTier(): MetricsTier | null {
123
+ return this.scheduler.activeTier();
124
+ }
125
+
126
+ /** Drop leases silent for longer than the timeout; returns how many. */
127
+ reapExpired(): number {
128
+ const expired = this.registry.reap(this.now(), this.leaseTimeoutMs);
129
+ if (expired.length > 0) this.reconcile();
130
+ return expired.length;
131
+ }
132
+
133
+ /**
134
+ * A kill re-collects the process table through the same collector the tick
135
+ * uses, and the PowerShell session accepts one request at a time — so the
136
+ * kill waits for an in-flight tick, and ticks skip while a kill holds the
137
+ * collector, instead of one of them failing with "request already in flight".
138
+ */
139
+ async kill(body: unknown): Promise<KillOutcome> {
140
+ this.ensureExitHooks();
141
+ try {
142
+ return await this.collectorLock.runExclusive(() => handleKillRequest(body, {
143
+ platform: this.collectors.platform,
144
+ collector: this.collectors.processes,
145
+ resolveProtected: this.tickDeps.resolveProtected,
146
+ execute: this.execute,
147
+ log: this.log,
148
+ }));
149
+ } finally {
150
+ // The re-query may have started the PowerShell child with no window open.
151
+ if (this.registry.count("full") === 0) this.scheduler.armIdle();
152
+ }
153
+ }
154
+
155
+ /** One poll: assemble for the active tier, commit the baseline, publish. */
156
+ async runTick(): Promise<void> {
157
+ // A Windows tick is ~174 ms and can slip, and a kill re-collects through the
158
+ // same collector: an overlapping collection would consume the delta baseline
159
+ // twice (CPU% in the hundreds) or fail with "request already in flight".
160
+ // Dropping a poll instead is harmless — metrics are lossy by nature.
161
+ await this.collectorLock.tryRun(() => this.assembleAndPublish());
162
+ }
163
+
164
+ private async assembleAndPublish(): Promise<void> {
165
+ try {
166
+ this.reapExpired();
167
+ const tier = this.scheduler.activeTier();
168
+ if (!tier) return;
169
+ const { snapshot, nextState } = await assembleTick(tier, this.state, this.tickDeps, this.latest.full);
170
+ this.state = nextState;
171
+ this.publish(snapshot);
172
+ } catch (e) {
173
+ console.error("[SystemMetrics] tick failed:", (e as Error)?.message ?? e);
174
+ }
175
+ }
176
+
177
+ /** Drop every subscriber, stop timers and kill children. */
178
+ shutdown(): void {
179
+ this.registry.clear();
180
+ this.scheduler.stop();
181
+ this.teardownChildren();
182
+ }
183
+
184
+ private publish(snapshot: MetricsSnapshot): void {
185
+ if (snapshot.tier === "full") {
186
+ this.latest.full = snapshot;
187
+ this.latest.light = projectLight(snapshot);
188
+ } else {
189
+ this.latest.light = snapshot;
190
+ }
191
+ for (const s of this.registry.list("full")) if (this.latest.full) s.deliver(this.latest.full);
192
+ for (const s of this.registry.list("light")) if (this.latest.light) s.deliver(this.latest.light);
193
+ }
194
+
195
+ private reconcile(): void {
196
+ const changed = this.scheduler.reconcile(this.registry.count("full"), this.registry.count("light"));
197
+ // Leaving the full tier: its baselines would be stale by the time it resumes.
198
+ if (changed && this.scheduler.activeTier() !== "full") {
199
+ this.state = { ...this.state, procCpu: null, procIo: null, disk: null, net: null };
200
+ }
201
+ }
202
+
203
+ private teardownChildren = (): void => {
204
+ try { this.collectors.processes.stop(); } catch { /* already gone */ }
205
+ };
206
+
207
+ private ensureExitHooks(): void {
208
+ if (this.exitHooks) installProcessExitHooks(this.teardownChildren);
209
+ }
210
+ }
211
+
212
+ export const systemMetricsService = new SystemMetricsService();
@@ -0,0 +1,199 @@
1
+ /** Whole-machine metrics contract shared by the collectors, the REST/SSE routes
2
+ * and the web client. Types + constants only, no imports, so both bundles can
3
+ * take it. Import RELATIVELY — the "@" alias points at src/web, not src. */
4
+
5
+ export type MetricsPlatform = "win32" | "darwin" | "linux";
6
+
7
+ /** `light` = node:os only, no child processes, status-bar cadence.
8
+ * `full` = every collector, process rows, groups. */
9
+ export type MetricsTier = "light" | "full";
10
+
11
+ /** Aggregate + per-core busy percentage over the last tick (0-100, 1 decimal). */
12
+ export interface CpuMetrics {
13
+ total: number;
14
+ /** Index matches `os.cpus()` order. Core count is `cores.length`. */
15
+ cores: number[];
16
+ model: string;
17
+ }
18
+
19
+ export interface MemoryMetrics {
20
+ totalMB: number;
21
+ usedMB: number;
22
+ availableMB: number;
23
+ /** usedMB / totalMB × 100. */
24
+ percent: number;
25
+ }
26
+
27
+ /** Whole-machine throughput, bytes/second over the last tick. */
28
+ export interface RateMetrics {
29
+ /** Disk: read. Net: received/down. */
30
+ inBps: number;
31
+ /** Disk: write. Net: sent/up. */
32
+ outBps: number;
33
+ /** False in the light tier, on a missing OS source, and on the first tick
34
+ * (no baseline). The UI must render "n/a", never 0 B/s. */
35
+ available: boolean;
36
+ }
37
+
38
+ export interface GpuMetrics {
39
+ name: string;
40
+ /** 0-100. */
41
+ utilPercent: number;
42
+ vramUsedMB: number;
43
+ vramTotalMB: number;
44
+ }
45
+
46
+ export interface SystemMetrics {
47
+ cpu: CpuMetrics;
48
+ mem: MemoryMetrics;
49
+ /** light tier: available:false. */
50
+ disk: RateMetrics;
51
+ /** light tier: available:false. */
52
+ net: RateMetrics;
53
+ /** light tier: []. Empty also when no NVIDIA GPU — the UI hides the card. */
54
+ gpus: GpuMetrics[];
55
+ /** light tier: 0. Processes the collector could see this tick. */
56
+ processCount: number;
57
+ }
58
+
59
+ export interface ProcessInfo {
60
+ pid: number;
61
+ /** -1 when the parent is unknown. */
62
+ ppid: number;
63
+ /** Executable basename WITHOUT extension, lowercased for comparison by the
64
+ * guard: "explorer", "node", "chrome". Never "explorer.exe". */
65
+ name: string;
66
+ /** Command line, secrets redacted then truncated to 160 chars. Falls back to
67
+ * `name` when unreadable (Windows: ~53% of rows are unreadable unelevated). */
68
+ command: string;
69
+ /** Instantaneous machine-normalised CPU%: deltaCpuMs / (wallMs × coreCount) × 100.
70
+ * Always 0 on a process's first observed tick. */
71
+ cpu: number;
72
+ ramMB: number;
73
+ /** Epoch ms UTC; 0 when unknown. Identity guard for CPU deltas, grouping and kill. */
74
+ startedAt: number;
75
+ /** PPM server, supervisor, edge forwarder, their descendants, PPM-managed
76
+ * cloudflared. Drives the "PPM only" filter — NOT a safety mechanism. */
77
+ ppm: boolean;
78
+ /** The server will refuse to kill it. Produced by the same guard the route
79
+ * enforces, so the disabled button and the 403 cannot disagree. */
80
+ protected: boolean;
81
+ /** Per-process throughput/GPU. `undefined` means this OS or tier cannot
82
+ * measure it — the UI must render "—", never 0. All are omitted from the
83
+ * JSON frame when undefined, so an unsupported host pays nothing.
84
+ *
85
+ * Bytes/second, delta of a cumulative OS counter over the tick's wall
86
+ * interval; 0 on a process's first observed tick, like `cpu`. */
87
+ diskReadBps?: number;
88
+ diskWriteBps?: number;
89
+ /** Sum of this pid's GPU engine busy percentages (3D + Copy + Video + …),
90
+ * clamped 0-100. Rate over the counter's OWN clock, not the wall tick. */
91
+ gpuPct?: number;
92
+ /** Dedicated (on-card) VRAM in MB attributed to this pid. */
93
+ gpuMemMB?: number;
94
+ /** macOS only: per-process network has no supported source on Windows (ETW
95
+ * only) or Linux (packet capture). */
96
+ netInBps?: number;
97
+ netOutBps?: number;
98
+ }
99
+
100
+ export interface ProcessGroup {
101
+ /** Stable across ticks: "root:<pid>" for an ancestor roll-up, "exe:<name>" for
102
+ * the orphan bucket. React key and history-series key. */
103
+ key: string;
104
+ label: string;
105
+ /** Roll-up root pid; null for an "exe:" bucket. */
106
+ rootPid: number | null;
107
+ cpu: number;
108
+ ramMB: number;
109
+ count: number;
110
+ /** True when any member is PPM-owned. */
111
+ ppm: boolean;
112
+ /** Member pids, CPU-desc. Full rows are in `MetricsSnapshot.processes`. */
113
+ pids: number[];
114
+ /** Roll-ups of the optional per-process columns, with the same optionality:
115
+ * the sum over the members that HAVE a value, and `undefined` when no member
116
+ * has one — so "nothing measurable" never renders as a hard 0. */
117
+ diskReadBps?: number;
118
+ diskWriteBps?: number;
119
+ /** Summed engine busy across members, clamped 0-100. */
120
+ gpuPct?: number;
121
+ gpuMemMB?: number;
122
+ netInBps?: number;
123
+ netOutBps?: number;
124
+ }
125
+
126
+ /** Per-host availability of the optional process columns. A column is offered
127
+ * once the collector has actually produced a value for it on this host. */
128
+ export interface ProcessColumnAvailability {
129
+ disk: boolean;
130
+ gpu: boolean;
131
+ net: boolean;
132
+ }
133
+
134
+ /** CLIENT-SIDE history element: aggregates only. There is no server ring. */
135
+ export interface MetricsHistoryPoint {
136
+ ts: number;
137
+ system: SystemMetrics;
138
+ /** group.key → roll-up, so group sparklines survive across ticks. */
139
+ groups: Record<string, { cpu: number; ramMB: number }>;
140
+ }
141
+
142
+ export interface MetricsSnapshot {
143
+ ts: number;
144
+ platform: MetricsPlatform;
145
+ tier: MetricsTier;
146
+ /** Poll cadence in ms for THIS tier, so the client can label chart axes. */
147
+ intervalMs: number;
148
+ system: SystemMetrics;
149
+ /** Empty in the light tier. */
150
+ groups: ProcessGroup[];
151
+ /** Empty in the light tier. Latest snapshot only — never retained. */
152
+ processes: ProcessInfo[];
153
+ /** Which optional process columns THIS host can actually fill, so the UI can
154
+ * hide the unavailable ones instead of showing a wall of "—". All false in
155
+ * the light tier (no process rows at all). */
156
+ processColumns: ProcessColumnAvailability;
157
+ /** DEPRECATED, remove one release after this ships. Mirrors cpu/mem/count so a
158
+ * PWA-cached old bundle's `resource-status-bar.tsx:41` destructure of
159
+ * `latest.total` does not TypeError on every page. */
160
+ total: { cpu: number; ramMB: number; processCount: number };
161
+ /** Non-fatal collector failures, human readable. Rendered in the UI. */
162
+ warnings: string[];
163
+ }
164
+
165
+ export interface KillProcessRequest {
166
+ pid: number;
167
+ /** Identity guard: the `startedAt` the client saw. The server re-queries the
168
+ * live process and returns 409 on mismatch, so a recycled pid cannot be
169
+ * killed against a stale name. */
170
+ startedAt: number;
171
+ /** Kill descendants too (`taskkill /T` on Windows, collected tree on POSIX). */
172
+ tree?: boolean;
173
+ }
174
+
175
+ export interface KillProcessResult {
176
+ pid: number;
177
+ tree: boolean;
178
+ method: "taskkill" | "signal";
179
+ /** Pids actually signalled. On win32 with tree:true this is always `[pid]` —
180
+ * `taskkill /T` walks and kills the tree inside the OS and reports no member
181
+ * list, so the real count is unknowable from here. */
182
+ killed: number[];
183
+ }
184
+
185
+ /** Sort columns offered by the process table. `disk` sorts by read + write,
186
+ * `net` by in + out; rows without a value sort last. */
187
+ export type SortKey = "cpu" | "ram" | "disk" | "gpu" | "gpuMem" | "net" | "name" | null;
188
+ export type SortDir = "asc" | "desc";
189
+
190
+ /** Full-tier poll cadence. A Windows tick (one CIM round trip) costs ~175-200 ms,
191
+ * so 2 s leaves an order of magnitude of headroom before ticks would overlap. */
192
+ export const METRICS_INTERVAL_MS = 2000;
193
+ /** Light-tier poll cadence — node:os only, costs <0.1 ms. */
194
+ export const METRICS_LIGHT_INTERVAL_MS = 5000;
195
+ /** Client history cap: 30 min at METRICS_INTERVAL_MS. */
196
+ export const METRICS_HISTORY_MAX = 900;
197
+ /** Subscriber lease: client pings every 10 s, server reaps after 30 s silence. */
198
+ export const METRICS_PING_INTERVAL_MS = 10_000;
199
+ export const METRICS_LEASE_TIMEOUT_MS = 30_000;
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
2
  import { Loader2 } from "lucide-react";
3
3
  import { Button } from "@/components/ui/button";
4
- import { rawMediaUrl, transcodeMediaUrl } from "@/lib/media-url";
4
+ import { newMediaSessionId, rawMediaUrl, stopTranscode, transcodeMediaUrl } from "@/lib/media-url";
5
5
  import { VideoPlayerControls } from "./video-player-controls";
6
6
  import { SPEED_STEPS } from "./video-settings-menu";
7
7
  import { useVideoKeyboardShortcuts, type VideoPlayerActions } from "./use-video-keyboard-shortcuts";
@@ -30,7 +30,13 @@ export function VideoPlayer({ filePath, projectName, mode, probeDuration = null,
30
30
  const rootRef = useRef<HTMLDivElement>(null);
31
31
  const stageRef = useRef<HTMLDivElement>(null);
32
32
  const videoRef = useRef<HTMLVideoElement>(null);
33
- const resumeRef = useRef(true);
33
+ // Whether the user wants playback. Read after a transcode restart to decide between
34
+ // resuming and staying paused; derived from user actions, not `video.paused`, because
35
+ // the element reports paused while a fresh stream is still loading.
36
+ const wantPlayRef = useRef(true);
37
+ // One id per mounted player: the server replaces (kills) this player's previous
38
+ // ffmpeg job on every seek and stops it when told the player is gone.
39
+ const [sessionId] = useState(newMediaSessionId);
34
40
 
35
41
  const [start, setStart] = useState(0);
36
42
  const [elapsed, setElapsed] = useState(0);
@@ -47,7 +53,7 @@ export function VideoPlayer({ filePath, projectName, mode, probeDuration = null,
47
53
  const [error, setError] = useState<string | null>(null);
48
54
 
49
55
  const isTranscode = mode === "transcode";
50
- const src = isTranscode ? transcodeMediaUrl(filePath, projectName, start) : rawMediaUrl(filePath, projectName);
56
+ const src = isTranscode ? transcodeMediaUrl(filePath, projectName, start, sessionId) : rawMediaUrl(filePath, projectName);
51
57
  const duration = isTranscode ? probeDuration : nativeDuration;
52
58
  const position = scrub ?? (isTranscode ? start + elapsed : elapsed);
53
59
 
@@ -59,14 +65,26 @@ export function VideoPlayer({ filePath, projectName, mode, probeDuration = null,
59
65
  useEffect(() => { const v = videoRef.current; if (v) { v.volume = volume; v.muted = muted; } }, [volume, muted]);
60
66
  useEffect(() => { const v = videoRef.current; if (v) v.playbackRate = speed; }, [speed, src]);
61
67
 
62
- // A detached <video> keeps its network fetch alive until garbage-collected, which
63
- // would leave ffmpeg encoding for nobody. Emptying the source aborts the load now.
64
- // `isConnected` guards StrictMode's simulated unmount, where the element stays in the
65
- // DOM and React would not re-apply the src attribute afterwards.
68
+ // Leaving the player must stop its ffmpeg job explicitly: a detached <video> keeps its
69
+ // fetch alive until garbage-collected, and a proxy such as Cloudflare Tunnel keeps the
70
+ // origin request open even after the browser has dropped it. Emptying the source aborts
71
+ // the local load; the DELETE tells the server. `isConnected` guards StrictMode's
72
+ // simulated unmount, where the element stays in the DOM and React would not re-apply
73
+ // the src attribute afterwards. `pagehide` covers reload/close, where cleanups never run.
66
74
  useEffect(() => {
67
75
  const v = videoRef.current;
68
- return () => { if (v && !v.isConnected) { v.pause(); v.removeAttribute("src"); v.load(); } };
69
- }, []);
76
+ const stop = () => { if (isTranscode) stopTranscode(filePath, projectName, sessionId); };
77
+ window.addEventListener("pagehide", stop);
78
+ return () => {
79
+ window.removeEventListener("pagehide", stop);
80
+ if (v && !v.isConnected) {
81
+ v.pause();
82
+ v.removeAttribute("src");
83
+ v.load();
84
+ stop();
85
+ }
86
+ };
87
+ }, [filePath, projectName, isTranscode, sessionId]);
70
88
 
71
89
  useEffect(() => {
72
90
  const onFs = () => setFullscreen(document.fullscreenElement === rootRef.current);
@@ -90,12 +108,17 @@ export function VideoPlayer({ filePath, projectName, mode, probeDuration = null,
90
108
  if (!isTranscode) { if (v) v.currentTime = clamped; return; }
91
109
  // Restarting ffmpeg for a sub-second nudge is wasteful.
92
110
  if (Math.abs(clamped - (start + (v?.currentTime ?? 0))) < 0.5) return;
93
- resumeRef.current = !(v?.paused ?? false);
94
111
  setStart(clamped);
95
112
  }, [duration, isTranscode, start]);
96
113
 
97
114
  const actions = useMemo<VideoPlayerActions>(() => ({
98
- togglePlay: () => { const v = videoRef.current; if (!v) return; if (v.paused) void v.play().catch(() => {}); else v.pause(); },
115
+ togglePlay: () => {
116
+ const v = videoRef.current;
117
+ if (!v) return;
118
+ wantPlayRef.current = v.paused;
119
+ if (v.paused) void v.play().catch(() => {});
120
+ else v.pause();
121
+ },
99
122
  seekBy: (d) => seekTo((isTranscode ? start : 0) + (videoRef.current?.currentTime ?? 0) + d),
100
123
  toggleFullscreen: () => {
101
124
  if (document.fullscreenElement) void document.exitFullscreen();
@@ -113,14 +136,8 @@ export function VideoPlayer({ filePath, projectName, mode, probeDuration = null,
113
136
  const onKeyDown = useVideoKeyboardShortcuts(actions);
114
137
  const fitted = fittedMaxSize(transform, box);
115
138
 
116
- if (error) {
117
- return (
118
- <div className="flex flex-col items-center justify-center h-full gap-3 text-text-secondary p-4 text-center">
119
- <p className="text-sm">{error}</p>
120
- <Button variant="outline" size="sm" onClick={() => { setError(null); setStart((s) => s + 0.001); }}>Retry</Button>
121
- </div>
122
- );
123
- }
139
+ // Retry re-requests the same position; the nudge makes the URL differ so the element reloads.
140
+ const retry = () => { setError(null); setStart((s) => s + 0.001); };
124
141
 
125
142
  return (
126
143
  <div
@@ -144,10 +161,13 @@ export function VideoPlayer({ filePath, projectName, mode, probeDuration = null,
144
161
  preload={isTranscode ? "auto" : "metadata"}
145
162
  style={{ transform: toCssTransform(transform), maxWidth: fitted.maxWidth || undefined, maxHeight: fitted.maxHeight || undefined }}
146
163
  onLoadedMetadata={(e) => {
164
+ // Re-apply user settings: a fresh load (seek restart, retry) resets the element.
147
165
  const v = e.currentTarget;
148
166
  v.playbackRate = speed;
167
+ v.volume = volume;
168
+ v.muted = muted;
149
169
  if (!isTranscode && Number.isFinite(v.duration)) setNativeDuration(v.duration);
150
- if (isTranscode && !resumeRef.current) v.pause();
170
+ if (isTranscode && !wantPlayRef.current) v.pause();
151
171
  }}
152
172
  onPlay={() => setPlaying(true)}
153
173
  onPause={() => setPlaying(false)}
@@ -155,13 +175,25 @@ export function VideoPlayer({ filePath, projectName, mode, probeDuration = null,
155
175
  onPlaying={() => setWaiting(false)}
156
176
  onCanPlay={() => setWaiting(false)}
157
177
  onTimeUpdate={(e) => setElapsed(e.currentTarget.currentTime)}
158
- onEnded={() => setPlaying(false)}
178
+ onEnded={() => { setPlaying(false); wantPlayRef.current = false; }}
159
179
  onError={() => {
160
180
  if (!isTranscode) onNativeError?.();
161
181
  else setError("Transcoding failed. ffmpeg may have stopped or the file is corrupt.");
162
182
  }}
163
183
  />
164
- {waiting && <Loader2 className="absolute size-8 animate-spin text-white/80 pointer-events-none" />}
184
+ {waiting && !error && <Loader2 className="absolute size-8 animate-spin text-white/80 pointer-events-none" />}
185
+ {/* Overlay rather than a replacement tree: the <video> stays mounted so volume,
186
+ mute and speed survive a retry. */}
187
+ {error && (
188
+ <div
189
+ className="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-black/85 text-text-secondary p-4 text-center"
190
+ onClick={(e) => e.stopPropagation()}
191
+ onDoubleClick={(e) => e.stopPropagation()}
192
+ >
193
+ <p className="text-sm">{error}</p>
194
+ <Button variant="outline" size="sm" className="h-11 px-4" onClick={retry}>Retry</Button>
195
+ </div>
196
+ )}
165
197
  </div>
166
198
 
167
199
  <VideoPlayerControls
@@ -22,6 +22,7 @@ export interface WindowContentProps {
22
22
  export const WINDOW_CONTENT: Record<WindowKind, LazyExoticComponent<ComponentType<WindowContentProps>>> = {
23
23
  explorer: lazy(() => import("@/components/os-explorer/explorer-window-content")),
24
24
  "team-member": lazy(() => import("@/components/chat/team-member-window-content")),
25
+ "system-monitor": lazy(() => import("@/components/system/system-monitor-window-content")),
25
26
  };
26
27
 
27
28
  /**
@@ -46,6 +47,7 @@ export function windowTitle(kind: WindowKind, payload?: Record<string, unknown>)
46
47
  const member = payload?.memberName;
47
48
  return typeof member === "string" && member ? `Session — ${member}` : "Team member";
48
49
  }
50
+ if (kind === "system-monitor") return "System Monitor";
49
51
  const path = payload?.path;
50
52
  if (kind === "explorer" && typeof path === "string" && path) {
51
53
  const segments = path.split(/[\\/]/).filter(Boolean);
@@ -20,7 +20,7 @@ export interface PersistedWindow {
20
20
  payload?: Record<string, unknown>;
21
21
  }
22
22
 
23
- const KINDS: WindowKind[] = ["explorer"];
23
+ const KINDS: WindowKind[] = ["explorer", "system-monitor"];
24
24
  const STATES: WindowVisualState[] = ["normal", "maximized", "minimized"];
25
25
 
26
26
  function isRect(v: unknown): v is Rect {
@@ -3,7 +3,7 @@
3
3
  import type { Rect } from "./window-geometry";
4
4
 
5
5
  /** Content families the layer can host. The registry maps each kind to its body component. */
6
- export type WindowKind = "explorer" | "team-member";
6
+ export type WindowKind = "explorer" | "team-member" | "system-monitor";
7
7
 
8
8
  export type WindowVisualState = "normal" | "maximized" | "minimized";
9
9
 
@@ -0,0 +1,9 @@
1
+ import type { KillProcessRequest, ProcessInfo } from "../../../types/system-metrics";
2
+
3
+ /** Builds the kill request body from a process row's own identity fields — pulled out
4
+ * of the dialog's confirm handler so the payload shape is unit-testable without
5
+ * mounting the dialog. `startedAt` travels unchanged so the server can 409 a pid the
6
+ * OS recycled between the snapshot and the click. */
7
+ export function buildKillRequest(proc: ProcessInfo, tree: boolean): KillProcessRequest {
8
+ return { pid: proc.pid, startedAt: proc.startedAt, tree };
9
+ }
@@ -0,0 +1,28 @@
1
+ /** Shared scale resolution for the canvas charts: a fixed ceiling (percentage axes)
2
+ * or autoscale to the max of the visible window (byte-rate axes) — pulled out of
3
+ * `sparkline-canvas.tsx`/`metric-chart-canvas.tsx` so it is unit-testable without a
4
+ * canvas context. This is the fix for the bug where a 3% CPU reading rendered as a
5
+ * full-height sparkline: the old code always did `Math.max(...data, 1)`. */
6
+ export function resolveScaleMax(data: number[], maxValue?: number): number {
7
+ if (maxValue !== undefined) return maxValue;
8
+ return Math.max(...data, 1);
9
+ }
10
+
11
+ /** The minimal surface of `CSSStyleDeclaration` this needs — lets a test pass a plain
12
+ * fake object instead of a real computed style. */
13
+ export interface ComputedColorSource {
14
+ getPropertyValue(property: string): string;
15
+ }
16
+
17
+ /** Canvas 2D's `strokeStyle`/`fillStyle` parse as a standalone CSS `<color>` — `var(...)`
18
+ * is not resolvable without an element context, so assigning `"var(--color-primary)"`
19
+ * directly is silently ignored and the shape draws black. Resolve once per draw call
20
+ * against the canvas's own computed style (custom properties inherit from the
21
+ * document, so any element's computed style works) and fall back to the original
22
+ * string when it is not a `var(...)` reference or resolves to nothing. */
23
+ export function resolveCssColor(color: string, styles: ComputedColorSource): string {
24
+ const match = /^var\((--[\w-]+)\)$/.exec(color.trim());
25
+ if (!match) return color;
26
+ const resolved = styles.getPropertyValue(match[1]!).trim();
27
+ return resolved || color;
28
+ }
@@ -0,0 +1,33 @@
1
+ import { cn } from "@/lib/utils";
2
+
3
+ function loadColor(pct: number): string {
4
+ if (pct > 80) return "bg-error";
5
+ if (pct > 50) return "bg-warning";
6
+ return "bg-success";
7
+ }
8
+
9
+ /** One vertical bar per core, tooltip shows the exact percentage. `min-h-11` keeps the
10
+ * strip out of sub-44px touch-row territory even though nothing here is clickable —
11
+ * a future click-to-isolate-core affordance should not need a layout change. */
12
+ export function CpuCoreBars({ cores }: { cores: number[] }) {
13
+ return (
14
+ <div
15
+ className="flex items-end gap-0.5 min-h-11 w-full"
16
+ data-testid="sysmon-core-bars"
17
+ data-core-count={cores.length}
18
+ >
19
+ {cores.map((pct, i) => (
20
+ <div
21
+ key={i}
22
+ className="flex-1 h-11 flex items-end rounded-sm overflow-hidden bg-surface-hover"
23
+ title={`Core ${i}: ${pct.toFixed(0)}%`}
24
+ >
25
+ <div
26
+ className={cn("w-full transition-[height]", loadColor(pct))}
27
+ style={{ height: `${Math.max(2, Math.min(100, pct))}%` }}
28
+ />
29
+ </div>
30
+ ))}
31
+ </div>
32
+ );
33
+ }