Skip to main content
X

dsh-client-ui-sidebar-perfmon

xmwengxing/dsh-client-ui-sidebar-perfmon

Real-time host performance monitor for the DeepSeek Harness right Sidebar: CPU / memory / swap gauges, a GPU clock and VRAM line, CPU / GPU / motherboard / drive temperatures, a sortable process table, and a keep-awake toggle for remote sessions — on Linu

Install

dsh plugin --profile web add github:xmwengxing/dsh-client-ui-sidebar-perfmon

README

@xmwengxing/dsh-client-ui-sidebar-perfmon

Real-time host performance monitoring for the DeepSeek Harness right Sidebar: CPU, memory and swap gauges, GPU clock and VRAM, CPU / GPU / motherboard / drive temperatures, plus a sortable process table — on Linux, macOS and Windows.

English | 中文

The performance monitoring panel: resource gauges, the GPU bar, four temperature tiles and the process list

What it does

One page in the right Sidebar, one button in the Session header:

  • Resource usage — ring gauges for CPU, memory and swap, each with a supporting line (cores and load, used of total, swap state); a GPU bar splitting the core clock and dedicated VRAM into two halves with progress fills; the viewed session's project-folder size on demand; the host's name and uptime in the card header.
  • Temperatures — CPU, GPU, motherboard and drive tiles on a cool / warm / hot scale (70 °C and 85 °C). A tile shows its hottest sensor, so a multi-core package or a pair of drives stays readable, and its tooltip names every sensor it covers. See Temperatures for what each platform can answer.
  • Windows CPU temperature installs itself — the card's title bar carries a pill for LibreHardwareMonitor: monitor missing → Install LHM (winget's pinned package), installed but silent → Start LHM (one elevated launch), running → the button retires itself and the readings flow. The tooltip states up front that the UAC prompt answers on the host's desktop, and a host without winget gets the official download link instead of a dead end.
  • Processes — one row per process: CPU share, resident memory, its share of RAM, PID and thread count. Sort by CPU, memory or name, filter by name or PID, drag a column divider to resize (widths are remembered per browser). The metric columns never shrink, so a narrow Sidebar loses names before it loses numbers.
  • Refresh — one interval drives every window (2 s Linux / 3 s macOS / 4 s Windows by default), and polling pauses while the browser tab is hidden. The temperature card is the exception: it moves on its own calmer cadence, because a temperature is an absolute reading and is expensive to read on Windows.
  • Keep awake — a footer toggle so a remote session is not cut off by the host's idle sleep. The click runs on the host, which holds the OS wake lock (Windows SetThreadExecutionState, macOS caffeinate, Linux systemd-inhibit --what=sleep:idle — never shutdown) until clicked again or the GUI exits. While off it costs nothing at all; while on it costs one sleeping helper process, and its "log" is a 10-event ring in memory — no file, ever. A host without the platform tool shows the button disabled with the reason.

A figure no platform can answer shows — with the reason in its tooltip — never a 0, because zero reads as a measurement.

Requirements

  • Linux, macOS or Windows — which figures each one can answer is in Platform support.
  • DeepSeek Harness 0.2.0-rc.1 or a compatible release, on a profile that boots @deepseek-ai/dsh-web-app (the web profile does).

No runtime dependencies: the host half uses node:os and each platform's own tools, and the browser half uses the React the GUI already provides.

Install

# From npm
dsh plugin --profile web add @xmwengxing/dsh-client-ui-sidebar-perfmon

# From a local checkout
dsh plugin --profile web add /path/to/dsh-client-ui-sidebar-perfmon

# From git (pnpm must be allowed to run the build first)
dsh plugin --profile web add github:xmwengxing/dsh-client-ui-sidebar-perfmon

Then restart the GUI. Remove it again with dsh plugin --profile web remove @xmwengxing/dsh-client-ui-sidebar-perfmon.

To open the panel: the right Sidebar's guide page lists a 性能监控 card that opens the page as a tab; from then on the 性能监控信息 button in the Session header opens or focuses that tab.

Configuration

The defaults are deliberately calm — one /proc walk every two seconds, shared between every open panel. Override them in a profile patch when needed:

# ~/.dsh/profiles/web/cordis.patch.yml
- id: perfmon
  name: '@xmwengxing/dsh-client-ui-sidebar-perfmon'
  config:
    refreshIntervalMs: 1000        # 500–60000; default 2000 Linux / 3000 macOS / 4000 Windows
    processLimit: 100              # 5–500; rows served per response
    cacheMillis: 800               # 0–10000; polls inside this window share one reading
    sampleMillis: 150              # 0–2000; length of the first reading's priming sample
    projectDirEntryBudget: 50000   # 100–1000000; entries one folder's scan may examine
    projectDirMaxDirs: 12          # 1–100; distinct folders one scan may cover
    temperatureIntervalMs: 15000   # 2000–600000; how long one temperature reading is reused
    gpuIntervalMs: 4000            # 500–60000; defaults to refreshIntervalMs
    # gpu: false                   # hide the GPU line entirely
    # temperature: false           # hide the temperature card entirely
    # keepAwake: false             # hide the keep-awake (anti-sleep) footer button
    # projectDir: /srv/demo        # pin one folder instead of the viewed session's workspace
    # projectDir: ''               # or hide the directory-size line entirely

Platform support

One reader per platform family, each reading the platform's own source.

LinuxmacOSWindows
CPU %, per-core/proc/statos.cpus()os.cpus()
Load averageyesyesno — Windows has no such concept, so the line is omitted
Memory total / used / available/proc/meminfo (MemAvailable)vm_stat (free + reclaimable pages)Win32_OperatingSystem + AvailableBytes
Cache / buffers lineCached, Buffersfile-backed pages as cache; no buffer figureCacheBytes; no buffer figure
Swap/proc/meminfosysctl vm.swapusagepage file (SizeStoredInPagingFiles)
Process list/proc/<pid>/stat, in-processps -Ao pid=,state=,time=,rss=,comm=one PowerShell call
Process stateyesyesno — shown as —
Thread countyesno — BSD ps has no portable keywordyes
Temperatures/sys/class/hwmon, else /sys/class/thermalpowermetrics (root), osx-cpu-temp, istatsLibreHardwareMonitor / OpenHardwareMonitor, ACPI zone, storage counters, nvidia-smi
Project-directory sizein-process walk, all three platforms alikesamesame

Anything a platform cannot answer is reported as null and rendered as —, with the reason in the panel: a temperature tile's reason is in that tile's tooltip, and the reading's other warnings hang on the footer timestamp. Nothing is filled in with a zero.

Cost. Linux reads /proc in-process and spawns nothing. macOS and Windows spawn one helper per sample, so their default refresh is calmer — 3 s and 4 s against Linux's 2 s — and refreshIntervalMs overrides it. A platform without a dedicated reader (FreeBSD, Solaris, …) falls back to a node:os-only reader: real CPU and memory totals, with swap and the process table marked unavailable rather than guessed.

How the numbers are produced

Every percentage is a difference between two samples of a cumulative counter, so the plugin never assumes a tick rate. Two conventions are worth knowing:

  • Process CPU is scaled so 100% means one core — the top convention, so an eight-thread process on four cores can read above 100%.
  • Memory "used" means "not available": page cache is reclaimable, so it counts as available, not as used.

The first reading of a session is primed with a short second sample, so the panel opens on a real percentage rather than a zero. Two states are reported honestly instead: a process first seen in the current window shows — until it has a second sample to difference against, and a host without swap shows "未启用" rather than an empty 0% ring.

The project-directory line

Measuring a folder is CPU- and IO-heavy work, so the line under the gauges is manual by design: its button scans the workspace folder of the session you are viewing, can be stopped mid-walk (keeping the partial figures with an explicit "stopped" note), and is bounded — 50,000 entries per folder, 12 folders per scan, symlinks neither followed nor counted, with every shortcut named beside the figure. Between scans the polling reads only the stored result, so an open panel costs nothing.

GPU clock and VRAM

FigureLinuxmacOSWindows
VRAM used / totalamdgpu sysfs (mem_info_vram_*); nvidia-sminvidia-smi onlythe OS's own GPUPerformanceCounters memory counter (any vendor, nothing installed), plus the 64-bit adapter total from the registry; nvidia-smi when present
Core clockgt_cur_freq_mhz (i915) or amdgpu pp_dpm_sclk; nvidia-sminvidia-smi onlynvidia-smi (NVIDIA) or a running LibreHardwareMonitor / OpenHardwareMonitor (other vendors)
  • VRAM needs no third-party software. On Windows the operating system reports dedicated usage for NVIDIA, AMD and Intel alike, and the adapter's true 64-bit total comes from the display class registry key — deliberately not Win32_VideoController.AdapterRAM, a 32-bit field that wraps at 4 GiB.
  • The clock has no OS-level source on Windows, so on a machine with neither nvidia-smi nor a hardware monitor the clock shows — while VRAM still reads, instead of a percentage invented from a guessed maximum clock.

The two figures share one row — clock left, VRAM right, each a track with its own fill (the clock's against its own boost ceiling, VRAM's as used-of-capacity) — wrapping to two full-width rows rather than clipping when the Sidebar is too narrow for both. The bar refreshes with the panel (gpuIntervalMs, defaulting to refreshIntervalMs), because VRAM is the figure that matters while a model loads. gpu: false hides it.

Temperatures

A temperature is an absolute value, not a counter, so it gets its own calmer cadence: one reading is reused for temperatureIntervalMs (15 seconds by default) because a Windows read costs a second-plus PowerShell call.

ComponentLinuxmacOSWindows
CPUcoretemp / k10temp / zenpower / cpu_thermal and friends; x86_pkg_temp zonepowermetrics CPU die; osx-cpu-temp; istatsLibreHardwareMonitor / OpenHardwareMonitor /intelcpu/, /amdcpu/
GPUamdgpu / radeon / nouveau / i915 / xe chipspowermetrics GPU die; istatsthe monitor's /nvidiagpu/, /atigpu/; else nvidia-smi
Motherboardacpitz, it87, nct6775, dell_smm, thinkpad and friends—ACPI zones; the monitor's /lpc/
Drivesnvme, drivetemp chips—Get-StorageReliabilityCounter per physical drive
  • The ACPI thermal zone is the motherboard, never the CPU — by ACPI's own definition it is a board sensor, and on many desktop boards it is a near-constant placeholder (this machine reported 27.9 °C under an all-core load).
  • Windows CPU temperature needs a hardware monitor: run LibreHardwareMonitor 0.9.4 (the portable zip, as administrator — 0.9.6 dropped the WMI provider this plugin reads) or OpenHardwareMonitor; without one the CPU tile is — with the reason. Intel's Distance to TjMax is headroom, not a temperature, and is excluded.
  • macOS needs a root or user-installed source: powermetrics as root, or osx-cpu-temp / istats installed. With none of them every tile is —.

Privacy

The plugin reads local kernel counters and returns them only to the browser that asked. It makes no network requests of its own, sends nothing anywhere, and writes no files. The route is protected by the same auth as the rest of the GUI.

Limitations

  • No process owner, command line or process tree. Each row carries name, PID, state, thread count, CPU and resident memory.
  • Temperatures depend on what the platform exposes (see Temperatures); a machine with no source shows — and the reason rather than a borrowed number.
  • No fan speeds, voltages or per-core detail in the tiles: the headline is a component's hottest sensor, and every sensor it covers is in the tooltip.
  • No history — current readings only, no sparklines or retained samples.
  • Polling, not streaming — refreshes are interval requests, not pushed.
  • The header button opens the panel, it does not toggle it; closing it is the Sidebar's own control.

License

MIT

Related plugins