homelab-tui 1.1.13
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.
- package/README.md +151 -0
- package/bin.js +19 -0
- package/package.json +33 -0
- package/postinstall.js +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# π₯οΈ homelab-tui
|
|
4
|
+
|
|
5
|
+
**A cross-platform terminal UI for monitoring your homelab over SSH**
|
|
6
|
+
|
|
7
|
+
[](https://bun.sh)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](https://github.com/vadimdemedes/ink)
|
|
10
|
+
[](https://www.npmjs.com/package/homelab-tui)
|
|
11
|
+
[](https://github.com/ACHRAF-YOUSSEF/homelab-tui/blob/main/LICENSE)
|
|
12
|
+
|
|
13
|
+
[]()
|
|
14
|
+
[]()
|
|
15
|
+
[]()
|
|
16
|
+
|
|
17
|
+
<p>
|
|
18
|
+
<a href="https://github.com/ACHRAF-YOUSSEF">
|
|
19
|
+
<img src="https://img.shields.io/badge/Author-Achraf%20Youssef-181717?style=for-the-badge&logo=github" />
|
|
20
|
+
</a>
|
|
21
|
+
<a href="https://achraf-youssef.github.io/portfolio/">
|
|
22
|
+
<img src="https://img.shields.io/badge/Portfolio-Visit-blueviolet?style=for-the-badge&logo=firefox" />
|
|
23
|
+
</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
> Discovers Docker containers and running programs (Jellyfin, Ollama, LM Studio, game serversβ¦), streams live logs, and shows system metrics β all over SSH. Supports Linux, macOS, and Windows remote hosts.
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm install -g homelab-tui
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The correct binary for your platform is downloaded automatically on install. No Bun runtime needed.
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
homelab-tui # launch TUI
|
|
44
|
+
homelab-tui --config /path/to/homelab.config.json # use a specific config (session only)
|
|
45
|
+
homelab-tui --set-config /path/to/homelab.config.json # persist config path as default
|
|
46
|
+
homelab-tui --update # self-update to latest release
|
|
47
|
+
homelab-tui --check-update # check latest version without installing
|
|
48
|
+
homelab-tui --version # print version
|
|
49
|
+
homelab-tui --help # print help
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
On first launch, a setup wizard lets you create or locate your `homelab.config.json`.
|
|
53
|
+
|
|
54
|
+
## Config
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"hosts": [
|
|
59
|
+
{
|
|
60
|
+
"name": "desktop",
|
|
61
|
+
"host": "192.168.1.20",
|
|
62
|
+
"port": 22,
|
|
63
|
+
"username": "achraf",
|
|
64
|
+
"authMethod": "password",
|
|
65
|
+
"discovery": {
|
|
66
|
+
"docker": true,
|
|
67
|
+
"nativeServices": false,
|
|
68
|
+
"includeStoppedContainers": true
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
| Field | Description |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `authMethod` | `"password"` (prompted at launch) or `"key"` (SSH private key, supports agent) |
|
|
78
|
+
| `group` | Optional label to group hosts in the selector (filter with `g`) |
|
|
79
|
+
| `refreshInterval` | Polling interval in ms (default `3000`, min `1000`, max `60000`) |
|
|
80
|
+
| `nativeServices` | Discover processes listening on TCP ports (Jellyfin, Ollama, LM Studio, game serversβ¦) |
|
|
81
|
+
| `includeStoppedContainers` | Show stopped Docker containers |
|
|
82
|
+
|
|
83
|
+
## Keyboard shortcuts
|
|
84
|
+
|
|
85
|
+
### Host selector
|
|
86
|
+
|
|
87
|
+
| Key | Action |
|
|
88
|
+
|-----|--------|
|
|
89
|
+
| `β` / `β` | Select host |
|
|
90
|
+
| `Enter` | Connect to selected host |
|
|
91
|
+
| `m` | Multi-host mode (select multiple hosts) |
|
|
92
|
+
| `Esc` | Back to previous monitor view (when coming from one) |
|
|
93
|
+
| `a` | Add new host |
|
|
94
|
+
| `e` | Edit selected host |
|
|
95
|
+
| `d` | Delete selected host |
|
|
96
|
+
|
|
97
|
+
In multi-host mode: `Space` to check/uncheck, `Enter` to open all in split-pane, `Esc` to cancel.
|
|
98
|
+
|
|
99
|
+
### Monitor
|
|
100
|
+
|
|
101
|
+
| Key | Action |
|
|
102
|
+
|-----|--------|
|
|
103
|
+
| `β` / `β` | Select service |
|
|
104
|
+
| `r` | Restart selected Docker container |
|
|
105
|
+
| `s` | Stop selected Docker container / kill selected process |
|
|
106
|
+
| `t` | Start selected Docker container |
|
|
107
|
+
| `l` | Toggle live log panel |
|
|
108
|
+
| `PgUp` / `PgDn` | Scroll log panel |
|
|
109
|
+
| `a` | Add another host as a new pane (stays connected) |
|
|
110
|
+
| `x` | Close the focused pane |
|
|
111
|
+
| `<` / `>` | Move focused pane left / right (swap, connections stay alive) |
|
|
112
|
+
| `Tab` / `Shift+Tab` | Switch focused pane |
|
|
113
|
+
| `/` | Search by name or image |
|
|
114
|
+
| `f` | Cycle filter: all β docker β processes β running β stopped β failed β restarting |
|
|
115
|
+
| `o` | Cycle sort: name β status β image |
|
|
116
|
+
| `h` | Switch host |
|
|
117
|
+
| `q` | Quit |
|
|
118
|
+
|
|
119
|
+
> Footer hints adapt to selection: Docker shows `r restart Β· s stop Β· t start`; processes show `r restart Β· s kill` (`r` uses systemd on Linux).
|
|
120
|
+
|
|
121
|
+
## Features
|
|
122
|
+
|
|
123
|
+
- **Multi-host split-pane** β monitor multiple hosts simultaneously side-by-side; compact per-pane headers with inline metrics; app bar shows all pane statuses; `Tab` to switch focus
|
|
124
|
+
- **Host groups** β tag hosts with `"group"` in config; press `g` in the selector to filter by group
|
|
125
|
+
- **Configurable refresh interval** β set per-host polling rate (`"refreshInterval": 5000`)
|
|
126
|
+
- **Service-down alerts** β audible bell + red banner on running β stopped/failed transitions
|
|
127
|
+
- **Disk full warnings** β β badge on disks above 85%
|
|
128
|
+
- **Compose stack restart** β `r` on a Compose service opens a scope picker (container vs whole stack)
|
|
129
|
+
- **Docker discovery** β containers with status, image, ports, health, Compose project
|
|
130
|
+
- **Process discovery** β finds programs listening on TCP ports (Jellyfin, Ollama, LM Studio, game serversβ¦) on Linux, macOS, and Windows
|
|
131
|
+
- **Context-aware controls** β Docker: restart/stop/start; discovered processes: kill + restart via systemd (Linux)
|
|
132
|
+
- **Live logs** β `docker logs -f` streamed over SSH; discovered processes stream via `journalctl -f` (Linux) or `log stream` (macOS); scrollable with auto-follow
|
|
133
|
+
- **System metrics** β CPU %, RAM, disk usage
|
|
134
|
+
- **Auth error handling** β wrong password shows an error and re-prompts immediately without leaving the app
|
|
135
|
+
- **Auto-reconnect** β SSH keepalive detects silent drops (15 s interval, 3 missed β reconnect); exponential backoff (3 β 5 β 10 β 20 β 30 s); attempt counter shown in header
|
|
136
|
+
- **Command timeout** β SSH commands time out after 30 s so a hanging command never blocks the refresh loop
|
|
137
|
+
- **Self-update** β `homelab-tui --update` checks version first, skips download if already up to date; otherwise replaces the binary in place with a live progress bar
|
|
138
|
+
- **Update notifications** β checks for a newer release on launch using proper semver comparison; shows `β vX.Y.Z available` in the app bar only when an actual upgrade exists
|
|
139
|
+
|
|
140
|
+
## Supported platforms
|
|
141
|
+
|
|
142
|
+
| Platform | Architecture |
|
|
143
|
+
|----------|-------------|
|
|
144
|
+
| Linux | x64, arm64 |
|
|
145
|
+
| macOS | x64, arm64 (Apple Silicon) |
|
|
146
|
+
| Windows | x64 |
|
|
147
|
+
|
|
148
|
+
## Links
|
|
149
|
+
|
|
150
|
+
- [GitHub](https://github.com/ACHRAF-YOUSSEF/homelab-tui)
|
|
151
|
+
- [Report an issue](https://github.com/ACHRAF-YOUSSEF/homelab-tui/issues)
|
package/bin.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { spawnSync } = require('node:child_process');
|
|
5
|
+
const { join } = require('node:path');
|
|
6
|
+
const { existsSync } = require('node:fs');
|
|
7
|
+
|
|
8
|
+
const ext = process.platform === 'win32' ? '.exe' : '';
|
|
9
|
+
const binary = join(__dirname, 'bin', `homelab-tui${ext}`);
|
|
10
|
+
|
|
11
|
+
if (!existsSync(binary)) {
|
|
12
|
+
process.stderr.write(
|
|
13
|
+
'homelab-tui: binary not found. Try reinstalling: npm install -g homelab-tui\n'
|
|
14
|
+
);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const result = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
19
|
+
process.exit(result.status ?? 1);
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "homelab-tui",
|
|
3
|
+
"version": "1.1.13",
|
|
4
|
+
"description": "Terminal UI for monitoring a remote homelab server over SSH",
|
|
5
|
+
"homepage": "https://github.com/ACHRAF-YOUSSEF/homelab-tui",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/ACHRAF-YOUSSEF/homelab-tui.git"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"homelab",
|
|
13
|
+
"tui",
|
|
14
|
+
"docker",
|
|
15
|
+
"ssh",
|
|
16
|
+
"terminal",
|
|
17
|
+
"monitoring"
|
|
18
|
+
],
|
|
19
|
+
"bin": {
|
|
20
|
+
"homelab-tui": "./bin.js"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"postinstall": "node postinstall.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"bin.js",
|
|
27
|
+
"postinstall.js",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require('node:child_process');
|
|
5
|
+
const { existsSync, writeFileSync, chmodSync } = require('node:fs');
|
|
6
|
+
const { join } = require('node:path');
|
|
7
|
+
const https = require('node:https');
|
|
8
|
+
|
|
9
|
+
const REPO = 'ACHRAF-YOUSSEF/homelab-tui';
|
|
10
|
+
const BIN_DIR = join(__dirname, 'bin');
|
|
11
|
+
const PLATFORM_MAP = {
|
|
12
|
+
'linux-x64': 'homelab-tui-linux-x64',
|
|
13
|
+
'linux-arm64': 'homelab-tui-linux-arm64',
|
|
14
|
+
'darwin-x64': 'homelab-tui-darwin-x64',
|
|
15
|
+
'darwin-arm64':'homelab-tui-darwin-arm64',
|
|
16
|
+
'win32-x64': 'homelab-tui-windows-x64.exe',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const key = `${process.platform}-${process.arch}`;
|
|
20
|
+
const assetName = PLATFORM_MAP[key];
|
|
21
|
+
|
|
22
|
+
if (!assetName) {
|
|
23
|
+
console.error(`homelab-tui: unsupported platform ${key}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const version = require('./package.json').version;
|
|
28
|
+
const ext = process.platform === 'win32' ? '.exe' : '';
|
|
29
|
+
const dest = join(BIN_DIR, `homelab-tui${ext}`);
|
|
30
|
+
|
|
31
|
+
if (existsSync(dest)) process.exit(0); // already installed
|
|
32
|
+
|
|
33
|
+
const url = `https://github.com/${REPO}/releases/download/v${version}/${assetName}`;
|
|
34
|
+
console.log(`homelab-tui: downloading ${assetName} from GitHub releasesβ¦`);
|
|
35
|
+
|
|
36
|
+
require('node:fs').mkdirSync(BIN_DIR, { recursive: true });
|
|
37
|
+
|
|
38
|
+
function download(url, dest, cb) {
|
|
39
|
+
const file = require('node:fs').createWriteStream(dest);
|
|
40
|
+
https.get(url, (res) => {
|
|
41
|
+
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
42
|
+
file.close();
|
|
43
|
+
return download(res.headers.location, dest, cb);
|
|
44
|
+
}
|
|
45
|
+
if (res.statusCode !== 200) return cb(new Error(`HTTP ${res.statusCode}`));
|
|
46
|
+
res.pipe(file);
|
|
47
|
+
file.on('finish', () => file.close(cb));
|
|
48
|
+
}).on('error', cb);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
download(url, dest, (err) => {
|
|
52
|
+
if (err) { console.error(`homelab-tui: download failed: ${err.message}`); process.exit(1); }
|
|
53
|
+
if (process.platform !== 'win32') chmodSync(dest, 0o755);
|
|
54
|
+
console.log(`homelab-tui: installed ${assetName}`);
|
|
55
|
+
});
|