Custom Wave Terminal apps for multi-machine infrastructure monitoring.
Module: github.com/PhenixStar/waveterm-apps
ANSI terminal dashboard that polls CPU, memory, disk, GPU, Docker, and MikroTik
metrics from all configured machines via SSH (or PowerShell locally on Windows).
Renders in a Wave Terminal view:term block with live countdown.
Status: Fully implemented. Build and run.
HTTP + SSE backend that connects to Docker hosts via SSH. Serves a JSON API
consumed by the React frontend (frontend/docker-panel/docker-panel.tsx).
Supports container start/stop/restart/remove, log streaming, and inspect.
Status: Backend implemented. Frontend is standalone React (not compiled here).
Interactive D3 force-graph of the full network topology with VLAN clusters, live status dots, and click-to-inspect. React + D3 frontend.
Status: Frontend reference complete. Go backend is TODO (Phase 2).
Requires Go 1.22+.
# Build dashboard binary
go build -o bin/wt-dashboard.exe ./cmd/dashboard/
# Build docker-panel backend
go build -o bin/wt-docker-panel.exe ./cmd/docker-panel/
# Build both
make all
# Clean
make cleanRun directly:
bin/wt-dashboard.exe
# or with custom config:
bin/wt-dashboard.exe path/to/machines.jsonDefault config file: machines.json (in the same directory as the binary, or cwd).
bin/wt-docker-panel.exe
# or:
bin/wt-docker-panel.exe -port 9173 -config /path/to/hosts.jsonThen open frontend/docker-panel/docker-panel.tsx in a Wave Terminal view:web
pointing at http://localhost:9173.
Add these to your widgets.json (usually ~/.config/waveterm/widgets.json):
"machine-health": {
"display:order": 50,
"icon": "heart-pulse",
"color": "#10b981",
"label": "health",
"description": "Multi-machine SSH health dashboard — polls every 15s",
"blockdef": {
"meta": {
"view": "term",
"controller": "cmd",
"cmd": "D:/Dev/terminolgy-apps/bin/wt-dashboard.exe",
"cmd:shell": false,
"cmd:runonstart": true,
"cmd:persistent": true,
"cmd:cwd": "D:/Dev/terminolgy-apps"
}
}
},
"docker-panel": {
"display:order": 51,
"icon": "container",
"color": "#06b6d4",
"label": "docker",
"description": "Docker orchestration panel — multi-host container management",
"blockdef": {
"meta": {
"view": "web",
"url": "http://localhost:9173"
}
}
}{
"pollIntervalSeconds": 15,
"sshTimeoutSeconds": 10,
"machines": [
{
"name": "MyServer",
"host": "192.168.1.10",
"port": 22,
"user": "admin",
"type": "linux",
"keyPath": "~/.ssh/id_ed25519"
},
{
"name": "LocalWin",
"host": "localhost",
"port": 0,
"user": "Kratos",
"type": "windows",
"keyPath": ""
},
{
"name": "RouterOS",
"host": "192.168.88.1",
"port": 22,
"user": "admin",
"type": "mikrotik",
"keyPath": "~/.ssh/id_ed25519"
}
]
}Machine types:
linux— SSH into Linux host, reads/proc/*,nvidia-smi,docker pswindows— Local PowerShell only (no SSH), reads Win32 WMI countersmikrotik— SSH into RouterOS, runs:put [/system/resource/get ...]
waveterm-apps/
├── cmd/dashboard/main.go # Monolithic dashboard (poll + render loop)
├── cmd/docker-panel/main.go # HTTP/SSE backend for React frontend
├── cmd/network-topology/main.go # Placeholder — Phase 2
├── internal/
│ ├── collector/types.go # Shared data types (Phase 2 refactor target)
│ ├── ssh/pool.go # SSH pool placeholder
│ └── render/ansi.go # ANSI renderer placeholder
├── frontend/
│ ├── dashboard/ # React web version (optional)
│ ├── docker-panel/ # React + ANSI log viewer
│ └── network-topology/ # React + D3 force graph
└── machines.json # Machine inventory
Dashboard polling loop:
startup → render skeleton → poll all machines (concurrent goroutines)
ticker (15s) → re-poll → re-render
countTicker (1s) → re-render countdown footer only
SSH strategy:
- One
*gossh.Clientperuser@host:port, reused across polls (keepalive test) - Linux CPU: two
/proc/statreads 500ms apart (delta method) - MikroTik: individual
:putcommands per metric (RouterOS limitation) - Windows (Sweep):
powershell.exelocally viaexec.Command— no SSH
| Metric | Warning | Critical |
|---|---|---|
| CPU | > 80% | > 95% |
| Memory | > 85% | > 95% |
| Disk | > 80% | > 90% |
| GPU util | > 80% | > 95% |
| GPU mem | > 85% | > 95% |
Any SSH connection failure = HealthUnknown (gray dot, "UNREACHABLE").
| App | Go backend | React frontend | Notes |
|---|---|---|---|
| wt-dashboard | Ready | Ready (optional) | ANSI term is primary UI |
| wt-docker-panel | Ready | Ready | Run backend, open via view:web |
| wt-network-topology | TODO | Ready | Phase 2 |
- Refactor
cmd/dashboard/main.gointointernal/collector/,internal/ssh/,internal/render/ - Add HTTP API endpoint to dashboard for React frontend at port 9876
- Implement
wt-network-topologyGo backend with/api/topology+ WebSocket/ws/status - Add SSH ping-based live status updates to topology
- Package frontend with esbuild into single-file bundles served by Go