fix: resolve all 23 MAINTENANCE audit tickets
- deps guards before -h|--help in docker-health/ps, network-scan, usb-server, media-mp3/mp4 (--dry-run pre-scan kept); system-firewall gains usage()/--help; autostart/usb-automount get flags.sh + template - install.sh: normalize N-M range syntax in --steps - bin/pos: INTERACTIVE_CMDS += docker-compose docker-vbox network-hotspot - common.sh: canonical XDG-aware CONFIG_DIR + DIM color var; notify.sh stderr fallback; ent_plugin_* registry renames (runtime plugin API kept) - docker-compose SCALE_DIR/CONFIG_ENV env seams; ffmpeg in PACKAGES; scrcpy.sh exec bit - docs: health is console-only (--send/--markdown removed), POS.md file refs for config/tree/entertainment, DEV.md no-guard exception, docmap/ filetable regenerated (make gen), hand-maintained line rows bumped - add scripts/lint-conventions.sh gate + Makefile lint target; record all VERIFIED outcomes in MAINTENANCE.md; AGENT_TODO Done entry (2026-08-14) - gates: make gen/check/lint all green (0 FAIL, 0 WARN); bash -n sweep clean; restricted-PATH dep tests + step-matrix dry-runs verified
This commit is contained in:
@@ -562,12 +562,12 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||
|
||||
| File | Lines | Purpose |
|
||||
|------|-------|---------|
|
||||
| `install.sh` | 223 | Main orchestrator — 4 phases with CLI flags, `--feature`, prebuilt arch bins |
|
||||
| `preinstall.sh` | 75 | System packages + hotspot deps + yt-dlp + fail2ban |
|
||||
| `install.sh` | 248 | Main orchestrator — 4 phases with CLI flags, `--feature`, prebuilt arch bins |
|
||||
| `preinstall.sh` | 76 | System packages + hotspot deps + yt-dlp + fail2ban |
|
||||
| `postinstall.sh` | 168 | fail2ban config, PATH, bash completion, systemd (flag-gated) |
|
||||
| `lib/common.sh` | 144 | Shared library (log/warn/err/run/spawn, dry-run aware, `load_system_env`) |
|
||||
| `lib/common.sh` | 151 | Shared library (log/warn/err/run/spawn, dry-run aware, `load_system_env`, CONFIG_DIR) |
|
||||
| `lib/flags.sh` | 60 | Feature flag store (set/clear/is_set/value/list/status) |
|
||||
| `lib/notify.sh` | 76 | Multi-platform alerting (`notify_send`) — opt-in source, silent-fails |
|
||||
| `lib/notify.sh` | 87 | Multi-platform alerting (`notify_send`) — opt-in source, silent-fails |
|
||||
| `lib/entertainment-lib.sh` | 311 | Entertainment module lib (ENABLED parsing, last-run state, scheduler sync via user-timers-lib) |
|
||||
| `lib/entertainment-plugin-lib.sh` | 67 | Message-safe helpers for plugins (config load, require, fetch+retry) — plugins MAY source it |
|
||||
| `lib/scheduler-lib.sh` | 760 | Scheduler lib (job parsing, notify policies, per-job user timers via user-timers-lib, legacy migrate) |
|
||||
@@ -575,8 +575,8 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||
| `bin/flag-reader` | 58 | Inspect flags (list/status/`--raw`) |
|
||||
| `bin/flag-set` | 21 | Set a flag (optionally with a value) |
|
||||
| `bin/flag-clear` | 21 | Unset a flag |
|
||||
| `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) |
|
||||
| `features/usb-automount.sh` | 134 | USB automount feature (udev rule + flag-gated service) |
|
||||
| `features/autostart.sh` | 50 | Boot-time feature (moved from `bin/`, flag-gated service) |
|
||||
| `features/usb-automount.sh` | 138 | USB automount feature (udev rule + flag-gated service) |
|
||||
<!-- GEN:START filetable -->
|
||||
| `bin/pos` | 292 | CLI dispatcher with smart arg matching + logging + category help |
|
||||
| `bin/pos-ai-gemini` | 311 | Chat with Google Gemini (ask, chat, models, sessions) |
|
||||
@@ -587,21 +587,21 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||
| `bin/pos-communication-telegram-sender` | 221 | Send Telegram messages/files/links/stickers via Bot API (send, test) |
|
||||
| `bin/pos-config` | 80 | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) |
|
||||
| `bin/pos-docker-compose` | 366 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
|
||||
| `bin/pos-docker-health` | 110 | One-glance container health dashboard (exits 1 if unhealthy) |
|
||||
| `bin/pos-docker-ps` | 128 | Enhanced container overview (health, IPs, ports, uptime) |
|
||||
| `bin/pos-docker-health` | 107 | One-glance container health dashboard (exits 1 if unhealthy) |
|
||||
| `bin/pos-docker-ps` | 125 | Enhanced container overview (health, IPs, ports, uptime) |
|
||||
| `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-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-media-mp3` | 80 | Download audio as MP3 (yt-dlp) |
|
||||
| `bin/pos-media-mp4` | 126 | Download video as MP4 (smart/interactive format select) |
|
||||
| `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-network-checkport` | 496 | Check TCP/UDP port reachability (nmap, or bash/nc fallback) + local interface view |
|
||||
| `bin/pos-network-download` | 952 | aria2 RPC daemon + queue control (add/torrent/metalink, watch, limits) |
|
||||
| `bin/pos-network-download` | 951 | 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` | 271 | Parallel ping sweep of CIDR |
|
||||
| `bin/pos-network-scan` | 272 | 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) |
|
||||
@@ -609,7 +609,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||
| `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` | 220 | Encrypted (AES-256) folder snapshots (tar + gpg) |
|
||||
| `bin/pos-system-firewall` | 291 | Interactive UFW management |
|
||||
| `bin/pos-system-firewall` | 308 | 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-tree` | 112 | Show the pos CLI command tree: categories, commands, and subcommands |
|
||||
|
||||
@@ -108,6 +108,7 @@ esac
|
||||
- Strict mode: `set -euo pipefail`
|
||||
- `--help` flag: accept `-h` / `--help` via `case` pattern
|
||||
- **Deps guards run before `--help`:** `command -v <bin> &>/dev/null || err "… (install <pkg>)"` lines sit at the top of the script, **before** the `-h|--help` case — so `--help` also errors when a dependency is missing. This matches every existing deps-gated tool; keep it that way.
|
||||
- Exception — tools with **no required deps** (every check degrades gracefully): `pos system health` probes binaries at runtime (`if command -v systemctl; then …`) and needs no guard. The lint (`scripts/lint-conventions.sh`) only enforces guard-before-help for lines that are actual guards (`command -v … ||`, `if ! command -v`, `command -v … \` continuation), never for graceful-degradation probes. If you add a tool like this, keep all checks optional and note it in `usage()`.
|
||||
- Shared library: always source `common.sh` for colors, logging, spinners
|
||||
- Exit codes: `0` success, `1` error
|
||||
- No shared lib? Inline fallbacks:
|
||||
|
||||
+2
-2
@@ -71,8 +71,8 @@ Adding another platform = create `bin/pos-communication-<p>` implementing
|
||||
|
||||
### Scheduling
|
||||
|
||||
- **Daily health digest** — add a `daily` schedule job `pos system health --send --markdown`
|
||||
via `pos system schedule config` (the old `pos-health.{service,timer}` units are gone). See [system](howto/system.md).
|
||||
- **Daily health digest** — add a `daily` schedule job `COMMAND=pos system health` with
|
||||
`NOTIFY=always` via `pos system schedule config` (the old `pos-health.{service,timer}` units are gone). See [system](howto/system.md).
|
||||
- **Entertainment auto-triggers** — per-plugin `pos entertainment enable <plugin> <interval>`,
|
||||
uses systemd user timers (or cron fallback). See [entertainment](howto/entertainment.md).
|
||||
- **`pos system schedule` jobs** — run any command on a per-job timer and notify
|
||||
|
||||
+9
-5
@@ -214,10 +214,10 @@ The standalone `vbox` command still works and forwards to `pos docker vbox` (see
|
||||
| `sudo pos system firewall` | `bin/pos-system-firewall` | Interactive UFW ("UFW POWER") menu: add/delete rules, status, enable/disable/reset, default policies | Must run as root. Every command is previewed and confirmed before execution; supports `--dry-run`; keeps a history of executed commands. Executed mutating changes are announced via `lib/notify.sh` |
|
||||
| `pos system backup <folder-path>` | `bin/pos-system-backup` | Create a gpg-encrypted (AES-256) `tar.gz` snapshot of a folder and verify it | Prompts twice for a password (never stored). Uses `sudo tar`; needs `gnupg` (in `preinstall.sh` PACKAGES). Artifact `<name>_<date>.tar.gz.gpg` in the current directory, `chmod 600`. Once the archive verifies, connected USB storage is offered (auto-detected removable mounts via `lsblk`, or pinned with `BACKUP_USB_ROOT`): the copy lands in `<usb>/backups/` and is proven 100% by sha256 before it is announced. Success/failure are announced via `lib/notify.sh` |
|
||||
| `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 [--send] [--markdown]` | `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 | `--send`/`--markdown` are notification-only: they send the summary via `lib/notify.sh` to every platform in `NOTIFY_PLATFORM` and do NOT print the dashboard (so wrappers like the Telegram listener don't echo it back — pair with the listener's `@quiet` marker). `HEALTH_BACKUP_MAX_AGE_DAYS` (default 2) and `BACKUP_SERVICE_ROOTS` come from `~/.config/linux_post_install/system.env`; `--help` shows the effective values. Platform list from `~/.config/linux_post_install/notify.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 |
|
||||
|
||||
A scheduled job is the recommended way to run the health dashboard on a timer, e.g. a `daily` job with `COMMAND=pos system health --send` — 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).
|
||||
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).
|
||||
|
||||
### ssh
|
||||
|
||||
@@ -295,7 +295,7 @@ The bot token is a secret — it is stored only in `~/.config/linux_post_install
|
||||
| `pos communication telegram listener --sync-commands` | Push the mapped `/commands` to the bot's `/` menu (`setMyCommands`) — also run automatically after every map edit, on `--enable`, and at daemon start |
|
||||
| `pos communication telegram listener --run` | Run the polling loop in the foreground (what the service executes) |
|
||||
|
||||
The map file is re-read for every message — edits apply without a restart. The listener only reacts to the owner chat (`TELEGRAM_CHAT_ID`); anyone else's message is ignored. `/help` lists mapped commands; an unmapped command replies "Unknown command". Non-command text starting with `ai ` (case-insensitive, e.g. `ai what is Nvidia`) is forwarded to Gemini via `pos ai gemini ask` and the answer is replied verbatim; an AI failure replies the error plus a `pos config ai` hint. Commands run as your user via `timeout 60 bash -c "…"` (stdout + stderr are replied, truncated to ~3800 chars; empty output → `OK`), so `sudo` inside them needs a NOPASSWD rule. A map value prefixed with `@quiet ` runs the command but does NOT reply — for commands that already send their own notification (e.g. `/status=@quiet pos system health --send`), avoiding a double message. `--enable` warns if linger is off — the service stops when you log out unless you run `sudo loginctl enable-linger $(whoami)`.
|
||||
The map file is re-read for every message — edits apply without a restart. The listener only reacts to the owner chat (`TELEGRAM_CHAT_ID`); anyone else's message is ignored. `/help` lists mapped commands; an unmapped command replies "Unknown command". Non-command text starting with `ai ` (case-insensitive, e.g. `ai what is Nvidia`) is forwarded to Gemini via `pos ai gemini ask` and the answer is replied verbatim; an AI failure replies the error plus a `pos config ai` hint. Commands run as your user via `timeout 60 bash -c "…"` (stdout + stderr are replied, truncated to ~3800 chars; empty output → `OK`), so `sudo` inside them needs a NOPASSWD rule. A map value prefixed with `@quiet ` runs the command but does NOT reply — for commands that already send their own notification (e.g. `pos system backup` self-notifies, so `/backup=@quiet pos system backup $HOME/Documents` avoids a double message). `--enable` warns if linger is off — the service stops when you log out unless you run `sudo loginctl enable-linger $(whoami)`.
|
||||
|
||||
Map entries may carry an optional **description** shown in the bot's `/` menu: `/cmd::short description=bash command` (the description falls back to the bash command, truncated to ~40 chars, when omitted). After every add/edit/remove the command list is pushed to the bot via `setMyCommands`, so the menu stays in sync; an empty map clears the menu. Telegram only registers lowercase `[a-z0-9_]` names (1–32 chars) — commands like `/Status` or `/my-cmd` are skipped from the menu with a warning but still resolve when typed.
|
||||
|
||||
@@ -321,7 +321,7 @@ The access token is a secret — it is stored only in `~/.config/linux_post_inst
|
||||
| `pos communication matrix listener --disable` | Stops, disables, and removes the service |
|
||||
| `pos communication matrix listener --run` | Run the polling loop in the foreground (what the service executes) |
|
||||
|
||||
The daemon long-polls `/sync` (30s timeout, per-sync `since` token, compact filter that drops presence/account_data/device noise and only requests `m.room.message` timeline events). It reacts only to messages **from `MATRIX_USER_ID`** (your own account — resolved via `/account/whoami` if unset); a `MATRIX_ROOM_ID` restricts it to one room, otherwise every joined room is watched. `/` and `!` prefixes both resolve (`!status` = `/status`). `/help` lists mapped commands; an unmapped command replies "Unknown command". Non-command text starting with `ai ` (case-insensitive, e.g. `ai what is Nvidia`) is forwarded to Gemini via `pos ai gemini ask` with a per-room session (`matrix-<room>`; `ai /reset` clears it) and the answer is replied verbatim with markdown stripped. Replies are sent as `m.text` threaded with `m.in_reply_to` on your message. Commands run as your user via `timeout 60 bash -c "…"` (stdout + stderr are replied, truncated to ~3800 chars; empty output → `OK`; non-zero exit is prefixed with `exit <rc>`), so `sudo` inside them needs a NOPASSWD rule. A map value prefixed with `@quiet ` runs the command but does NOT reply — for commands that already send their own notification (e.g. `/status=@quiet pos system health --send`). Map lines may carry a `/cmd::description=…` description. `--enable` warns if linger is off — the service stops when you log out unless you run `sudo loginctl enable-linger $(whoami)`.
|
||||
The daemon long-polls `/sync` (30s timeout, per-sync `since` token, compact filter that drops presence/account_data/device noise and only requests `m.room.message` timeline events). It reacts only to messages **from `MATRIX_USER_ID`** (your own account — resolved via `/account/whoami` if unset); a `MATRIX_ROOM_ID` restricts it to one room, otherwise every joined room is watched. `/` and `!` prefixes both resolve (`!status` = `/status`). `/help` lists mapped commands; an unmapped command replies "Unknown command". Non-command text starting with `ai ` (case-insensitive, e.g. `ai what is Nvidia`) is forwarded to Gemini via `pos ai gemini ask` with a per-room session (`matrix-<room>`; `ai /reset` clears it) and the answer is replied verbatim with markdown stripped. Replies are sent as `m.text` threaded with `m.in_reply_to` on your message. Commands run as your user via `timeout 60 bash -c "…"` (stdout + stderr are replied, truncated to ~3800 chars; empty output → `OK`; non-zero exit is prefixed with `exit <rc>`), so `sudo` inside them needs a NOPASSWD rule. A map value prefixed with `@quiet ` runs the command but does NOT reply — for commands that already send their own notification (e.g. `pos system backup` self-notifies, so `/backup=@quiet pos system backup $HOME/Documents` avoids a double message). Map lines may carry a `/cmd::description=…` description. `--enable` warns if linger is off — the service stops when you log out unless you run `sudo loginctl enable-linger $(whoami)`.
|
||||
|
||||
`pos communication scrcpy` in detail:
|
||||
|
||||
@@ -358,7 +358,7 @@ Requires `scrcpy` + `adb`. `adb` is in `preinstall.sh` PACKAGES; `scrcpy` is **n
|
||||
|
||||
### entertainment
|
||||
|
||||
**File:** `bin/pos-entertainment-send`
|
||||
**File:** `bin/pos-entertainment-send` (management subcommands: `bin/pos-entertainment-config`, `bin/pos-entertainment-enable`, `bin/pos-entertainment-disable`, `bin/pos-entertainment-status`)
|
||||
**Purpose:** run a public-API plugin and send its output via `notify_send` — the platform follows `NOTIFY_PLATFORM` (default Telegram, silent-fail when none configured). Plugins are standalone scripts in `entertainment/` that fetch a public API and **print the message to stdout** — that stdout is what gets sent.
|
||||
|
||||
| Command | Behavior |
|
||||
@@ -436,6 +436,8 @@ Feature-flag management CLIs (see [SCRIPTS.md → lib/flags.sh](SCRIPTS.md#libfl
|
||||
|
||||
### config
|
||||
|
||||
**File:** `bin/pos-config`
|
||||
|
||||
`pos config` is the interactive editor for the tools' runtime config (see [DEV.md](DEV.md#config-files) and §10 of AGENT_Context). Every tool exposes its configuration by declaring a `# POS_CONFIG:` header; `pos config` reads those at runtime — it knows nothing about the variables themselves. Values live in `~/.config/linux_post_install/<scope>.env` (chmod 600).
|
||||
|
||||
| Command | Purpose |
|
||||
@@ -446,6 +448,8 @@ Feature-flag management CLIs (see [SCRIPTS.md → lib/flags.sh](SCRIPTS.md#libfl
|
||||
|
||||
### tree
|
||||
|
||||
**File:** `bin/pos-tree`
|
||||
|
||||
`pos tree` prints the `pos` command tree — every category, command, and subcommand the dispatcher can reach, annotated with each tool's `# POS:` description. Data is derived live from the `bin/pos-*` filenames and their `# POS_SUBCMDS:` headers, so it always matches what `pos` can actually run.
|
||||
|
||||
| Command | Purpose |
|
||||
|
||||
@@ -80,7 +80,7 @@ pos communication telegram listener --disable # remove it
|
||||
one `/cmd=bash command` per line — re-read on every message, so edits apply
|
||||
instantly. Example:
|
||||
```
|
||||
/status=@quiet pos system health --send
|
||||
/status=pos system health
|
||||
/temp=sensors | grep -i 'Tctl\|package id 0'
|
||||
/update=cd /path/to/repo && git pull
|
||||
```
|
||||
@@ -88,7 +88,7 @@ pos communication telegram listener --disable # remove it
|
||||
(`setMyCommands`) after every map edit, on `--enable`, and at daemon start
|
||||
(force it anytime with `--sync-commands`). Add a short description with the
|
||||
`/cmd::description=bash command` syntax — e.g.
|
||||
`/backup::Encrypted nightly backup=@quiet pos system backup --send` — or it
|
||||
`/backup::Encrypted nightly backup=@quiet pos system backup $HOME/Documents` — or it
|
||||
falls back to the bash command. Telegram only registers lowercase `[a-z0-9_]`
|
||||
names (1–32 chars); `/Status` or `/my-cmd` are skipped from the menu but still
|
||||
work when typed. An empty map clears the menu.
|
||||
@@ -99,8 +99,10 @@ pos communication telegram listener --disable # remove it
|
||||
`sudo` inside a command needs a NOPASSWD rule.
|
||||
- **`@quiet` prefix:** a map value starting with `@quiet ` runs the command but
|
||||
does NOT reply — for commands that already send their own notification, so
|
||||
you don't get it twice. `/status=@quiet pos system health --send` delivers
|
||||
one digest via the notify system and nothing else.
|
||||
you don't get it twice. `pos system backup` self-notifies, so
|
||||
`/backup=@quiet pos system backup $HOME/Documents` sends the backup notification
|
||||
and nothing else. `pos system health` is console-only (it never sends), so map
|
||||
it WITHOUT `@quiet` — `/status=pos system health` replies with the dashboard.
|
||||
- **Daemon lifecycle:** the service is a systemd **user** unit; it stops at
|
||||
logout unless you enable linger: `sudo loginctl enable-linger $(whoami)`.
|
||||
`--enable` prints this warning if linger is off.
|
||||
@@ -197,7 +199,7 @@ pos communication matrix listener --disable # remove it
|
||||
one `/cmd=bash command` per line — re-read on every message, so edits apply
|
||||
instantly. Example:
|
||||
```
|
||||
/status=@quiet pos system health --send
|
||||
/status=pos system health
|
||||
/temp=sensors | grep -i 'Tctl\|package id 0'
|
||||
/update=cd /path/to/repo && git pull
|
||||
```
|
||||
@@ -212,7 +214,9 @@ pos communication matrix listener --disable # remove it
|
||||
(truncated ~3800 chars; empty → `OK`). `sudo` inside a command needs a
|
||||
NOPASSWD rule.
|
||||
- **`@quiet` prefix:** a map value starting with `@quiet ` runs the command but
|
||||
does NOT reply — for commands that already send their own notification.
|
||||
does NOT reply — for commands that already send their own notification
|
||||
(`pos system backup` self-notifies, e.g. `/backup=@quiet pos system backup $HOME/Documents`).
|
||||
`pos system health` is console-only (never sends), so map it WITHOUT `@quiet`.
|
||||
- **`ai …` bridge:** non-command messages starting with `ai ` are answered by
|
||||
`pos ai gemini` (per-room memory session; `ai /reset` clears it) — replying
|
||||
with the model's answer, markdown stripped.
|
||||
@@ -314,4 +318,4 @@ screen/file without a desktop.
|
||||
|
||||
- Reference + config file details: [DOC/POS.md → communication](../POS.md)
|
||||
- Alerting contract: [DOC/DEV.md → Alerting](../DEV.md)
|
||||
- Health digest (uses `--send --markdown`): [system.md](system.md)
|
||||
- Health dashboard + scheduled digest: [system.md](system.md)
|
||||
|
||||
+8
-13
@@ -15,19 +15,17 @@ Host care: encrypted backups, firewall, and the health dashboard. Tools:
|
||||
|
||||
```bash
|
||||
pos system health # console report; exits 1 if any check FAILs
|
||||
pos system health --send # also send the summary via notify platforms
|
||||
pos system health --markdown # same, markdown parse mode (implies --send)
|
||||
```
|
||||
|
||||
Checks: disk per mount (>90% = FAIL), RAM/swap, failed systemd units, backup
|
||||
age, fail2ban, docker containers. Header shows hostname, uptime, load, public IP.
|
||||
|
||||
`--help` prints the **effective** config values (env > `system.env` > default),
|
||||
e.g.:
|
||||
Health is a **console-only reporter — it never sends notifications**; deliver
|
||||
its output with a wrapper or a scheduled job (below). `--help` prints the
|
||||
**effective** config values (env > `system.env` > default), e.g.:
|
||||
|
||||
```
|
||||
Environment (effective values):
|
||||
NOTIFY_PLATFORM telegram
|
||||
HEALTH_BACKUP_MAX_AGE_DAYS 2
|
||||
BACKUP_SERVICE_ROOTS /srv $HOME/srv
|
||||
```
|
||||
@@ -41,8 +39,6 @@ Environment (effective values):
|
||||
BACKUP_SERVICE_ROOTS=/srv $HOME/srv # roots for backup-age check + backup --service
|
||||
BACKUP_USB_ROOT=/mnt/usb # optional: copy finished backups to <root>/backups/ (auto-detects a mounted USB when unset)
|
||||
HEALTH_BACKUP_MAX_AGE_DAYS=3 # WARN if newest backup older (default 2)
|
||||
# ~/.config/linux_post_install/notify.env
|
||||
NOTIFY_PLATFORM=telegram
|
||||
```
|
||||
|
||||
### Daily digest (automated)
|
||||
@@ -50,14 +46,15 @@ NOTIFY_PLATFORM=telegram
|
||||
Run the health report on a timer with a scheduled job (no systemd unit needed):
|
||||
|
||||
```bash
|
||||
pos system schedule config # add a job: INTERVAL=daily,
|
||||
# COMMAND=pos system health --send --markdown
|
||||
pos system schedule config # add a job: INTERVAL=daily, NOTIFY=always,
|
||||
# COMMAND=pos system health
|
||||
systemctl --user list-timers | grep pos-schedule
|
||||
pos system schedule run <name> # run once now
|
||||
```
|
||||
|
||||
The old `pos-health.{service,timer}` systemd units are gone — a legacy install
|
||||
may still have them failed/leftover; disable and remove them:
|
||||
The `NOTIFY=always` policy sends the job's full output — i.e. the dashboard —
|
||||
as the alert. The old `pos-health.{service,timer}` systemd units are gone — a
|
||||
legacy install may still have them failed/leftover; disable and remove them:
|
||||
|
||||
```bash
|
||||
sudo systemctl disable --now pos-health.timer pos-health.service 2>/dev/null
|
||||
@@ -75,8 +72,6 @@ sudo rm -f /etc/systemd/system/pos-health.{service,timer} && sudo systemctl daem
|
||||
active; start it (`sudo systemctl enable --now fail2ban`) or ignore.
|
||||
- `[FAIL] services: nbd-server.service …` → a failed unit; inspect with
|
||||
`systemctl status <unit>`.
|
||||
- `--send` prints a warn and exits 0 when no platform is configured — by design
|
||||
(see [communication](communication.md)).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user