Bundle
dsh-top
System monitoring tool for the dsh web GUI: live CPU, RAM, disk, network, and top processes in a floating, collapsible panel.
- Source
- glenngit
- stars
- 1 stars
- License
- MIT
- Updated
- Updated yesterday
Readme
# dsh-top A plugin for the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) **web GUI**: a system monitoring tool that shows live system stats in a floating, collapsible panel pinned to the **top-right corner**. <p align="center"> <img src="docs/screenshot.png" alt="dsh-top System Monitor panel" width="342" /> </p> [](https://www.dsh.so/artifact/dsh-top/) ## Features - **CPU** — live utilisation (computed from `os.cpus()` tick deltas) + core count - **MEM** — used / total with percentage bar (from `os.totalmem()` / `os.freemem()`) - **DISK** — used / total with percentage bar (platform-specific) - **NETWORK** — download / upload throughput (platform-specific byte deltas) - **Top 6 processes** — PID, name, CPU%, MEM% (platform-specific) - Dark color-coded palette (cyan CPU, magenta RAM, yellow disk, blue/green network), monospace - **Draggable** via the title bar, **collapsible** via the `–` / `+` button - Transient monitor processes (`ps`, `awk`, `head`, …) are filtered out of the top-processes list ## How it works | Part | File | What it does | |---|---|---| | Host half | `lib/index.js` | Registers `GET /api/dsh-top-stats`; CPU + memory use Node `os` APIs with container-aware cgroup overrides; disk, network and processes use per-platform collectors that degrade to `null` when unavailable. | | Browser half | `lib/client.js` | `dsh.client` web bundle; registers the panel into the frame-wide `shell.overlay` slot; polls every 2 s (pauses while collapsed). | | Composition | `cordis.patch.yml` | The `dsh.bundle` patch layer that inserts the loader entry. | ## Platform support DSH host code runs on Linux, but the DSH *server* can be run on any OS Node.js supports. `dsh-top` is multi-platform: it always reports at least CPU + memory (Node `os`, no subprocess), and fills in disk / network / processes where the platform allows. Missing sections are shown as **n/a** in the widget rather than failing the whole request. | Platform | CPU | MEM | DISK | NETWORK | PROCESSES | |---|---|:---:|:---:|:---:|:---:| | Linux | ✅ | ✅ | `df` | `/proc/net/dev` | `ps` | | macOS | ✅ | ✅ | `df` | `netstat -ib` | `ps` (BSD) | | Windows | ✅ | ✅ | PowerShell `Get-PSDrive` | PowerShell `Get-NetAdapterStatistics` | PowerShell `Get-Process`† | | Containers (cgroup) | ✅* | ✅* | `df`* | `/proc/net/dev`* | `ps`* | | Other / unknown | ✅ | ✅ | n/a | n/a | n/a | † Windows process CPU is a **lifetime-average percentage** — `Get-Process.CPU` (cumulative CPU seconds) divided by process age, the same semantics Linux `ps pcpu` reports — and MEM% is derived from the real RSS bytes, not the raw working-set value. Every external collector (`ps`, `df`, `powershell`, …) runs with a **5 s timeout**, so a wedged tool degrades its section to n/a instead of hanging the request. \* Container support is **container-aware and graceful**: - **Memory** — when a cgroup memory limit is set (Docker `--memory`, a Kubernetes limit, systemd unit limit), the MEM meter reports the container's *limit* and current usage (cgroup v2 `memory.max`/`memory.current`, or v1 `memory.limit_in_bytes`/`usage_in_bytes`) instead of the host's total. On an unlimited cgroup it falls back to the host `os.totalmem()` view. - **CPU cores** — when the cgroup restricts CPU (v2 `cpu.max` quota/period, or v1 `cpu.cfs_quota_us/period_us`), the core count reflects the quota; otherwise it uses `os.cpus().length`. - **Tightest ancestor wins, sentinels are safe** — the limit files are read by walking *our own* cgroup path upward (not just the cgroup root), so a Docker limit under a host-level cap is reported correctly. Kernel-default sentinels are treated as "no limit": v2 `max`, v1 CFS `-1`, and the ~2^63 bytes v1 `memory.limit_in_bytes` reports on an unrestricted root — so an unrestricted host is never misread as having exabyte-sized RAM. - **Slim/distroless images** that lack `df`/`ps` still report CPU + memory; the missing DISK/NETWORK/PROCESSES sections render as **n/a**. The CPU + memory meters work on every Node platform. Disk, network and process meters depend on the listed command/pseudo-file being present — otherwise those sections render as **n/a** while the rest keep working. ## Testing ```sh npm test ``` Runs a zero-dependency suite (`node --test`) over the pure collector parsers with realistic fixtures: Linux (`df`, `/proc/net/dev`, `ps`), macOS (`netstat -ib`, BSD `ps`), and Windows (PowerShell JSON output — including the CPU-seconds→percentage and RSS-bytes→percent conversions), plus the cgroup file parsers (`memory.max`, `cpu.max`, CFS quota, and the "no limit" sentinels) and the live container memory/CPU fallback contract. The macOS/Windows parsers are verified here without needing a live Mac or Windows machine — only the thin command-execution wrapper around them is platform-bound. ## Security Because it is a *system monitor*, the host half reads host-wide CPU, memory, disk, network and process state. The cross-platform core (CPU + memory) uses Node's built-in `os` module — no subprocess and no OS-specific pseudo-files. Linux `/proc` reads go through Node's own `fs.readFileSync`. Only the platform collectors that need system tools invoke them — `ps`, `df`, and on Windows `powershell` — every time via `execFileSync` with a **static argv array** (never a shell string, no shell `-Command` interpolation of untrusted data), so there is **no shell-injection surface** and no attacker-controlled input. On Windows the PowerShell sub-command is a fixed script literal; none of its values come from the HTTP request. No data leaves the host, no credentials are read, and every read is **read-only**. > `dsh.so`'s static scanner flags `node:child_process` as "critical". That is a heuristic signal on the mere presence of process access — not a vulnerability. Process access is intrinsic to a monitoring tool; review the (small) source yourself: the collectors are platform-whitelisted, argument-confined, and read-only, and any failure degrades to "n/a" rather than failing the request. ## Install ```sh dsh plugin --profile web add dsh-top ``` Then restart the web app and refresh the page — the panel appears at the top-right. ## License [MIT](LICENSE)
Install
dsh plugin --profile web add github:glenngit/dsh-top
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-top from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.