feat: add web dashboard with slide-in drawer navigation

- Flask backend with 23 API routes (entertainment, telegram, docker, system)
- Alpine.js + Tailwind CSS dark-mode SPA with 4 tabs
- pos-dashboard CLI tool with port/config management
- Mobile slide-in drawer with swipe-to-close
- Sticky header stays pinned on scroll
- Tab completion fixes for category-less tools
- POST /api/telegram/commands endpoint for adding commands
This commit is contained in:
Your Name
2026-08-18 11:54:41 -04:00
parent 06b077db40
commit 99085adc76
63 changed files with 5905 additions and 122852 deletions
+34 -31
View File
@@ -10,19 +10,19 @@
<!-- GEN:START docmap -->
| ## 1. Project Overview | 2843 |
| ## 2. Directory Structure | 44195 |
| ## 3. Installation Flow | 196247 |
| ## 4. The `pos` CLI System | 248320 |
| ## 5. Shared Library — `lib/common.sh` | 321352 |
| ## 6. Docker Compose / ScaleTail | 353395 |
| ## 7. Optional Apps (`apps/`) | 396425 |
| ## 8. Entertainment Module | 426439 |
| ## 9. Systemd Services | 440451 |
| ## 10. Configuration Files | 452478 |
| ## 11. Coding Conventions | 479511 |
| ## 12. Development Workflow | 512564 |
| ## 13. Key File Quick Reference | 565628 |
| ## 14. Common Tasks for Agents | 629661 |
| ## 2. Directory Structure | 44196 |
| ## 3. Installation Flow | 197248 |
| ## 4. The `pos` CLI System | 249322 |
| ## 5. Shared Library — `lib/common.sh` | 323354 |
| ## 6. Docker Compose / ScaleTail | 355397 |
| ## 7. Optional Apps (`apps/`) | 398427 |
| ## 8. Entertainment Module | 428441 |
| ## 9. Systemd Services | 442453 |
| ## 10. Configuration Files | 454480 |
| ## 11. Coding Conventions | 481513 |
| ## 12. Development Workflow | 514566 |
| ## 13. Key File Quick Reference | 567631 |
| ## 14. Common Tasks for Agents | 632664 |
<!-- GEN:END docmap -->
## 1. Project Overview
@@ -96,6 +96,7 @@ Linux_post_install/
│ ├── pos-system-health # Host health dashboard (disk, RAM, services, backup age, fail2ban, docker); exit 1 if any FAIL
│ ├── pos-system-schedule # Scheduled jobs: run a command on a timer; notify on threshold/change/error/always or silently
│ ├── pos-config # Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry)
│ ├── pos-dashboard # Web dashboard: start/stop/status/config/url
│ ├── pos-tree # Show the pos CLI command tree: categories, commands, and subcommands
<!-- GEN:END tree -->
│ ├── flag-reader # Inspect feature flags (list/status/--raw)
@@ -299,6 +300,7 @@ All non-interactive `pos` commands log output to `~/.local/share/linux_post_inst
| system | health | `pos-system-health` | Host health dashboard (disk, RAM, services, backup age, fail2ban, docker); exit 1 if any FAIL |
| system | schedule | `pos-system-schedule` | Scheduled jobs: run a command on a timer; notify on threshold/change/error/always or silently |
| | config | `pos-config` | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
| | dashboard | `pos-dashboard` | Web dashboard: start/stop/status/config/url |
| | tree | `pos-tree` | Show the pos CLI command tree: categories, commands, and subcommands |
<!-- GEN:END dispatch -->
@@ -345,7 +347,7 @@ source "$(dirname "$0")/../lib/common.sh"
**Scripts that do NOT source common.sh** (self-contained):
<!-- GEN:START selfcontained -->
`pos`, `pos-communication-matrix-listener`, `pos-communication-matrix-sender`, `pos-communication-telegram-listener`, `pos-communication-telegram-sender`, `pos-network-checkport`, `pos-network-hotspot`, `pos-network-ip`, `pos-network-scan`, `pos-ssh-load-keys`, `pos-system-firewall`.
`pos`.
<!-- GEN:END selfcontained -->
---
@@ -584,43 +586,44 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
| `features/usb-automount.sh` | 138 | USB automount feature (udev rule + flag-gated service) |
<!-- GEN:START filetable -->
| `bin/pos` | 294 | CLI dispatcher with smart arg matching + logging + category help |
| `bin/pos-ai-gemini` | 311 | Chat with Google Gemini (ask, chat, models, sessions) |
| `bin/pos-communication-matrix-listener` | 568 | Matrix listener: map /command → bash, run them on room messages |
| `bin/pos-communication-matrix-sender` | 224 | Send messages to a Matrix room via the client-server API (send, test, login) |
| `bin/pos-communication-scrcpy` | 254 | Mirror/control an Android device via scrcpy+adb (mirror, devices, record, tcpip, connect, push, pull, screenshot, info) |
| `bin/pos-communication-telegram-listener` | 566 | Telegram bot listener: map /command → bash, run them on chat messages |
| `bin/pos-ai-gemini` | 297 | Chat with Google Gemini (ask, chat, models, sessions) |
| `bin/pos-communication-matrix-listener` | 566 | Matrix listener: map /command → bash, run them on room messages |
| `bin/pos-communication-matrix-sender` | 223 | Send messages to a Matrix room via the client-server API (send, test, login) |
| `bin/pos-communication-scrcpy` | 240 | Mirror/control an Android device via scrcpy+adb (mirror, devices, record, tcpip, connect, push, pull, screenshot, info) |
| `bin/pos-communication-telegram-listener` | 564 | Telegram bot listener: map /command → bash, run them on chat messages |
| `bin/pos-communication-telegram-sender` | 221 | Send Telegram messages/files/links/stickers via Bot API (send, test) |
| `bin/pos-docker-compose` | 366 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
| `bin/pos-docker-health` | 107 | One-glance container health dashboard (exits 1 if unhealthy) |
| `bin/pos-docker-compose` | 369 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
| `bin/pos-docker-health` | 108 | One-glance container health dashboard (exits 1 if unhealthy) |
| `bin/pos-docker-ps` | 125 | Enhanced container overview (health, IPs, ports, uptime) |
| `bin/pos-docker-stack` | 101 | Containers grouped by compose stack (project); standalone group; -a/--all includes stopped |
| `bin/pos-docker-vbox` | 158 | Disposable Docker-based VMs (create/enter/start/stop/rm/ls) |
| `bin/pos-entertainment-config` | 143 | Show or edit the entertainment config (ENABLED auto-trigger list, weather location) |
| `bin/pos-entertainment-disable` | 32 | Disable a plugin's auto-trigger (remove it from ENABLED) |
| `bin/pos-entertainment-config` | 145 | Show or edit the entertainment config (ENABLED auto-trigger list, weather location) |
| `bin/pos-entertainment-disable` | 36 | Disable a plugin's auto-trigger (remove it from ENABLED) |
| `bin/pos-entertainment-enable` | 49 | Enable an auto-trigger for a plugin on a schedule |
| `bin/pos-entertainment-send` | 95 | Run a public-API plugin and send its output via the configured notify platforms |
| `bin/pos-entertainment-status` | 62 | Show enabled plugins and scheduler state |
| `bin/pos-entertainment-status` | 67 | Show enabled plugins and scheduler state |
| `bin/pos-media-mp3` | 86 | Download audio as MP3 (yt-dlp) |
| `bin/pos-media-mp4` | 132 | Download video as MP4 (smart/interactive format select) |
| `bin/pos-media-sync` | 213 | Incremental Music → USB sync (mp3/mp4, add/update only) |
| `bin/pos-network-checkport` | 496 | Check TCP/UDP port reachability (nmap, or bash/nc fallback) + local interface view |
| `bin/pos-network-download` | 951 | aria2 RPC daemon + queue control (add/torrent/metalink, watch, limits) |
| `bin/pos-network-download` | 948 | aria2 RPC daemon + queue control (add/torrent/metalink, watch, limits) |
| `bin/pos-network-hotspot` | 93 | Wi-Fi hotspot via create_ap + wihotspot-gui |
| `bin/pos-network-ip` | 69 | Show interfaces, routes, public IP + location |
| `bin/pos-network-scan` | 272 | Parallel ping sweep of CIDR |
| `bin/pos-network-ip` | 63 | Show interfaces, routes, public IP + location |
| `bin/pos-network-scan` | 268 | Parallel ping sweep of CIDR |
| `bin/pos-share-nfs-client` | 138 | Mount NFS shares (ephemeral or persistent systemd mount units) |
| `bin/pos-share-nfs-server` | 134 | Manage the NFS kernel server (status, share/unshare exports, enable/disable) |
| `bin/pos-share-smb-client` | 217 | Mount SMB/CIFS shares (ephemeral or persistent systemd mount units) |
| `bin/pos-share-smb-server` | 253 | Manage the Samba server (status, share/unshare exports, users, enable/disable) |
| `bin/pos-share-usb-server` | 218 | USB Redirector server control (--ls, --share; prompts when args omitted) |
| `bin/pos-ssh-load-keys` | 31 | Load all SSH keys into the agent |
| `bin/pos-system-backup` | 216 | Encrypted (AES-256) folder snapshots (tar + gpg) |
| `bin/pos-system-firewall` | 308 | Interactive UFW management |
| `bin/pos-ssh-load-keys` | 42 | Load all SSH keys into the agent |
| `bin/pos-system-backup` | 225 | Encrypted (AES-256) folder snapshots (tar + gpg) |
| `bin/pos-system-firewall` | 304 | Interactive UFW management |
| `bin/pos-system-health` | 209 | Host health dashboard (disk, RAM, services, backup age, fail2ban, docker); exit 1 if any FAIL |
| `bin/pos-system-schedule` | 81 | Scheduled jobs: run a command on a timer; notify on threshold/change/error/always or silently |
| `bin/pos-config` | 80 | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
| `bin/pos-dashboard` | 275 | Web dashboard: start/stop/status/config/url |
| `bin/pos-tree` | 112 | Show the pos CLI command tree: categories, commands, and subcommands |
| `completions/pos.bash` | 294 | Dynamic bash completion |
| `completions/pos.bash` | 306 | Dynamic bash completion |
<!-- GEN:END filetable -->
| `apps/install.sh` | 171 | App install/uninstall picker/orchestrator |
+1108
View File
File diff suppressed because it is too large Load Diff
+21 -1
View File
@@ -83,7 +83,7 @@ Precedence: `--model` flag > `AI_GEMINI_MODEL` env > config file > `gemini-2.5-f
| Command | File | Purpose | Configuration |
|---------|------|---------|---------------|
| `pos network ip` | `bin/pos-network-ip` | Show interfaces, default route, public IP + location | None. Public IP via `https://ifconfig.me`; location via `ip-api.com` (5s timeouts) |
| `pos network checkport <ip:port>` | `bin/pos-network-checkport` | Check if a TCP port is open | None. Uses `/dev/tcp` with a 2s timeout; exit 0/1 via OPEN/CLOSED |
| `pos network checkport <ip:port>` | `bin/pos-network-checkport` | Check TCP/UDP port reachability (nmap engine with bash/nc fallback) + local interface view | None |
| `pos network scan <cidr> [--full] [--retries N]` | `bin/pos-network-scan` | Two-phase nmap scan | See below |
| `pos network hotspot [cmd]` | `bin/pos-network-hotspot` | Wi-Fi hotspot via `create_ap` (CLI) or `wihotspot-gui` (GUI) | Uses the precompiled binaries from `x64_bin/`; see below |
| `pos network download <cmd>` | `bin/pos-network-download` | aria2 RPC daemon + queue control (add/torrent/metalink, watch, limits) | `aria2c`/`jq`/`curl`; daemon = systemd user service; secret in `~/.config/linux_post_install/download.env`; see below |
@@ -220,9 +220,29 @@ The standalone `vbox` command still works and forwards to `pos docker vbox` (see
| `pos system backup --service` | `bin/pos-system-backup` | Lists folders under `/srv` and `~/srv`, lets you pick one, then runs the same backup | Roots via `BACKUP_SERVICE_ROOTS` (space-separated, default `/srv $HOME/srv`) or `~/.config/linux_post_install/system.env` |
| `pos system health` | `bin/pos-system-health` | Host health dashboard: disk per mount, RAM/swap, failed systemd units, backup age, fail2ban, docker containers. Exits 1 if any check FAILs | Console-only reporter — health itself never sends notifications; forward the output with a wrapper (e.g. the Telegram/Matrix listener map `/status=pos system health`) or schedule it via `pos system schedule` with a `NOTIFY` policy. `HEALTH_BACKUP_MAX_AGE_DAYS` (default 2) and `BACKUP_SERVICE_ROOTS` come from `~/.config/linux_post_install/system.env`; `--help` shows the effective values |
| `pos system schedule <cmd>` | `bin/pos-system-schedule` | Scheduled jobs — run a command on a timer, notify (or stay silent): `run [name\|all]`, `list`, `config`, `enable [name\|all]`, `disable [name\|all]`, `status`, `migrate`. Each job is a file in `~/.config/linux_post_install/schedule.d/<name>.env` with `INTERVAL` (`5m…59m`, `1h…23h`, `hourly`, `daily`, `weekly`, `OnCalendar=…`), `NOTIFY` policy, optional `MSG`, `RULE` (threshold only), and `COMMAND` = the literal rest of the line (pipes/quotes/`sudo` fine). Policies: `always` (full output every run), `onchange` (send when output differs from the last run; first run always sends), `onerror` (non-zero exit or empty output), `threshold` (first numeric output vs `RULE`, alert on false→true + one recovery — the old event-trigger behavior), `never` (side-effect jobs, no notify) | One systemd **user** timer pair per job (`pos-schedule-<name>.timer` + oneshot `.service`, `Persistent=true`), reconciled on `enable`/`disable`; the legacy single `pos-event-trigger` timer is auto-removed. `migrate` converts a pre-existing `event.env` rule set into `schedule.d/rule-N.env` threshold jobs. `config` is an interactive editor (add/edit/remove/enable/disable, validates interval + threshold); alerts via `lib/notify.sh`; `--dry-run` previews runs/writes/sends; jobs are arbitrary shell commands (chmod 600, same trust model as the Telegram map); starter jobs in `config/schedule.d/` auto-installed no-clobber by postinstall |
| `pos dashboard <cmd>` | `bin/pos-dashboard` | Web dashboard: start/stop/status/config/url — browser-based UI for managing entertainment, Telegram, Docker, and system health | `~/.config/linux_post_install/dashboard.env` (`DASHBOARD_PORT`, `DASHBOARD_HOST`, chmod 600). systemd user service (`pos-dashboard.service`) runs `python3 /usr/local/share/linux_post_install/dashboard/app.py` |
A scheduled job is the recommended way to run the health dashboard on a timer: a `daily` job with `COMMAND=pos system health` and `NOTIFY=always` sends the dashboard output as the alert — no separate systemd unit needed (the old `pos-health.{service,timer}` units are gone; a legacy install may still have them failed/leftover — disable and remove them).
`pos dashboard` in detail:
| Command | Behavior |
|---------|----------|
| `pos dashboard start` | Installs a systemd **user** service (`pos-dashboard.service`) and enables+starts it. Requires `python3-flask` (in `preinstall.sh` PACKAGES) and the dashboard app at `/usr/local/share/linux_post_install/dashboard/app.py`. Creates the config file from the template if missing. Prints the dashboard URL. Warns if linger is off |
| `pos dashboard stop` | Stops, disables, and removes the service unit |
| `pos dashboard status` | Shows service state (running/autostart), config path, and the dashboard URL |
| `pos dashboard config` | Shows current `DASHBOARD_PORT` and `DASHBOARD_HOST`; delegates to `pos config dashboard` interactive editor when available |
| `pos dashboard url` | Prints `http://<tailscale-ip>:<port>/` (auto-detects Tailscale IP, falls back to `hostname -I`) |
**Configuration** (`~/.config/linux_post_install/dashboard.env`, edit with `pos config dashboard`):
| Key | Required | Default | Purpose |
|-----|----------|---------|---------|
| `DASHBOARD_PORT` | no | `8080` | Port the dashboard listens on |
| `DASHBOARD_HOST` | no | `0.0.0.0` | Bind address (`0.0.0.0` for Tailscale, `127.0.0.1` for local only) |
The dashboard runs as a systemd user service that loads config via `EnvironmentFile=%h/.config/linux_post_install/dashboard.env`. The Flask app calls `pos-*` tools via `subprocess.run([...])` and returns JSON. Security perimeter is Tailscale — no auth middleware.
### ssh
| Command | File | Purpose | Configuration |