Bundle
dsh-dock-vitals
Live CPU, memory and GPU readout in the DeepSeek Harness composer status bar: a clickable badge with a details panel, per-metric toggles and three refresh speeds in settings.
- Source
- MM998LI
- License
- MIT
- Updated
- Updated 6 days ago
Readme
# dsh-dock-vitals
Live **CPU / memory / GPU** readout in the DeepSeek Harness composer status bar — a small clickable badge next to the built-in context meter.
```
2 turns 30 steps · 98 tok/s │ 1.8M tok · cache 84% │ 6%
CPU 13% MEM 87% GPU 15%
↑ this plugin's badge, right of the context meter
```
- **Display-only plugin.** It registers no tools for the model. Samples never enter the conversation context and are never sent anywhere.
- Three metrics out of the box — **CPU / memory / GPU**; video memory and GPU temperature are one toggle away in settings.
- GPU works across vendors, no admin rights: `nvidia-smi`, `rocm-smi`, macOS `ioreg`, and Windows PDH counters as the catch-all. Whichever backend answers is named in the snapshot, and a backend that cannot report a field leaves it blank instead of printing `0`.
- Click the badge for a details panel: per-metric values, GPU model, core count and capacity.
- Three refresh presets: **fast 1.5 s / medium 3 s / slow 10 s** (default `3000 ms`).
- Opening ten sessions still samples once — every badge shares one snapshot and one timer.
- Sampling stops on its own 15 seconds after the last reader.
- Follows the host language (Chinese / English), including the details panel and tooltips.
## Install
```bash
dsh plugin --profile <profile> add dsh-dock-vitals
```
Or drop the tarball in:
```bash
dsh plugin --profile <profile> add ./dsh-dock-vitals-0.1.0.tgz
```
Restart DSH afterwards.
## Data sources
| Metric | Source | Notes |
| --- | --- | --- |
| CPU | Node `os.cpus()` sampled twice | Machine-wide busy percentage (`1 - Δidle/Δtotal`), not per-core. The first sample has no baseline and reads empty. |
| Memory | `os.totalmem()` / `os.freemem()` | |
| GPU | A vendor CLI, probed per platform (see below) | When nothing answers, GPU shows `—` while CPU and memory keep working. |
GPU backends, tried in this order on each platform — the first that answers wins, and the winner is remembered so later ticks skip the dead ones:
| Platform | Backend | Command | Permission | Video memory / temperature |
| --- | --- | --- | --- | --- |
| Windows / Linux, NVIDIA | `nvidia-smi` | `--query-gpu=... --format=csv,noheader,nounits` | none | both |
| Windows, any vendor | PDH counters via `typeperf` | `"\GPU Engine(*)\Utilization Percentage" -sc 2 -si 1` | none | **neither** |
| Linux, AMD | `rocm-smi` | `-u --showmemuse --showmeminfo vram -t --showtemp --showproductname --csv` | none | both |
| macOS, any GPU | `ioreg` (IOKit registry) | `-r -d 1 -w 0 -c IOAccelerator` | **none** | used only (no total) |
`typeperf` is the only way to read a GPU on Windows for AMD/Intel — ROCm is Linux-only — so it is worth knowing its cost: **one round takes ~2.7 s**, where `nvidia-smi` takes ~50 ms. That is why GPU sampling is decoupled from the badge refresh rate: CPU and memory keep their own cadence, and the GPU value is served from the last completed reading.
Aggregation follows Task Manager: sum each process per engine type, then take the **busiest engine type** per adapter, then the busiest adapter. Summing every instance together over-reports, and reading only the 3D engine misses video encode/decode load entirely.
A field the active backend cannot report is `null` in the snapshot, never `0` — a missing temperature and a 0 °C temperature are different things. The details panel hides those rows rather than printing a made-up number.
The host side exposes one read-only endpoint:
```
GET /dsh-dock-vitals/snapshot
```
```json
{
"cpu": { "percent": 13.2, "cores": 24 },
"memory": { "usedPercent": 87.3, "usedGiB": 13.7, "totalGiB": 15.7 },
"gpu": {
"available": true,
"name": "NVIDIA GeForce RTX 4060 Laptop GPU",
"utilPercent": 15,
"memoryUsedMiB": 1816,
"memoryTotalMiB": 8188,
"temperatureC": 64,
"clockMegahertz": 2370
},
"gpuError": null,
"gpuBackend": "nvidia-smi",
"host": { "platform": "win32", "release": "10.0.26300" },
"intervalMs": 3000,
"updatedAt": 0
}
```
`gpuBackend` names the backend that produced the reading, so "why is my GPU blank / missing a temperature" is answerable from the payload itself. Non-loopback callers get `403`; anything but `GET`/`HEAD` gets `405`.
## Settings
Settings → **System Status**:
| Option | Default | Notes |
| --- | --- | --- |
| Enable badge | on | Off means the badge never renders and never fetches |
| CPU | on | |
| Memory | on | |
| GPU | on | |
| Video memory | off | Unavailable while GPU is off |
| GPU temperature | off | Same |
| Refresh interval | 3000 ms | 1500 – 60000 ms |
Every field is `volatile`, so changes apply immediately without a restart. Configuration lives in the settings namespace `dock-vitals` — the `id` of the plugin's entry in your profile.
## Compatibility
- dsh `>=0.2.0-rc.1` (developed and verified on `0.2.0-rc.2`).
- Node `>=22`.
- Windows / macOS / Linux. CPU and memory come from Node's `os`; the GPU backends are read-only CLIs and registry reads (`nvidia-smi`, `typeperf`, `rocm-smi`, `ioreg`). Nothing needs administrator rights — this deliberately avoids `powermetrics`, which is macOS's richest GPU source but requires `sudo` on every call.
- Works in both the desktop app and the browser GUI: `dsh.client.platform` is `web`, and the desktop app is a shell around the same web frontend.
## Development notes
- Client components may only `require` modules from the host whitelist (`react`, `react/jsx-runtime`, `react-dom`, `react-dom/client`, `@deepseek-ai/cordis`, `@deepseek-ai/dsh-client-store`, `@deepseek-ai/dsh-client-ui-slots`, `@deepseek-ai/dsh-client-ui-primitives`, `@deepseek-ai/dsh-client-ui-dockkit`). Anything else fails to resolve, and a throwing `require` kills the factory → the entry fails → the desktop build refuses to open. **Wrap every `require` in `try/catch` and ship a fallback.**
- Never call a hook inside `apply()`. `useSyncExternalStore`'s `getSnapshot` must return a **stable reference** — an object rebuilt on every call causes an infinite re-render loop.
- Styles use `--dsw-*` theme tokens only; literal colours are reserved for graphics.
- UI is contributed through `ctx.slots.inject(ownerKey, () => ctx.slots.register(...))`.
## License
MIT
Install
dsh plugin --profile web add github:MM998LI/dsh-dock-vitals
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-dock-vitals from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.