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.
Files changed (4) hide show
  1. package/README.md +151 -0
  2. package/bin.js +19 -0
  3. package/package.json +33 -0
  4. 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
+ [![Bun](https://img.shields.io/badge/Bun-000000?style=for-the-badge&logo=bun&logoColor=white)](https://bun.sh)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
9
+ [![React](https://img.shields.io/badge/React%20Ink-61DAFB?style=for-the-badge&logo=react&logoColor=black)](https://github.com/vadimdemedes/ink)
10
+ [![npm](https://img.shields.io/npm/v/homelab-tui?style=for-the-badge&logo=npm&logoColor=white)](https://www.npmjs.com/package/homelab-tui)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge)](https://github.com/ACHRAF-YOUSSEF/homelab-tui/blob/main/LICENSE)
12
+
13
+ [![Linux](https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black)]()
14
+ [![macOS](https://img.shields.io/badge/macOS-000000?style=for-the-badge&logo=apple&logoColor=white)]()
15
+ [![Windows](https://img.shields.io/badge/Windows-0078D4?style=for-the-badge&logo=windows&logoColor=white)]()
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
+ });