diff --git a/agent/BACKLOG.md b/agent/BACKLOG.md index 68ecaba..b512ead 100644 --- a/agent/BACKLOG.md +++ b/agent/BACKLOG.md @@ -234,9 +234,6 @@ them as composable commands, not dead ends. - **Night-light geo mode**: lat/long auto sunset/sunrise (means wlsunset). - **Per-theme icon overrides** / more icon packs (ROADMAP § Icon themes). - **MIPI/IPU software-ISP camera** support (no-UVC machines). -- **Doctor Waybar warning**: a self-gating bar indicator fed by - `nomarchy-doctor` (shipped 2026-07-04) — appears only when the sheet - has a ✖; click opens the sheet. - **Auto-timezone Waybar tooltip** showing the detected zone (optional). - **VPN exit-node richer display** (country/city) (optional). - **NixOS release bump → v2** `[human]`: deliberate, hand-edited, never diff --git a/agent/HARDWARE-QUEUE.md b/agent/HARDWARE-QUEUE.md index 2b81c6b..0d240d4 100644 --- a/agent/HARDWARE-QUEUE.md +++ b/agent/HARDWARE-QUEUE.md @@ -167,6 +167,12 @@ QA machine), the **T14s** (webcam case). (tooltips, fastfetch labels) is visible on summer-day + flexoki-light, kanagawa floats are lighter than the bg (upstream sumiInk4). Anything that reads worse than before → reopen 28b. +- [ ] **Doctor bar tripwire (LATER item)** — with everything healthy + the bar shows nothing; `systemctl --user start doomed`-style + induced failure → within ~5 min a red appears (tooltip lists + the ✖ lines), clicking opens the sheet in a terminal; + reset-failed → it disappears on the next poll. Also visible on + both summer bars. - [ ] **OCR region (LATER item)** — Tools › Capture › "OCR region → clipboard": select a region with visible text → toast reports the word count and `wl-paste` yields the text; Esc in slurp diff --git a/agent/JOURNAL.md b/agent/JOURNAL.md index ead5369..7a91c4e 100644 --- a/agent/JOURNAL.md +++ b/agent/JOURNAL.md @@ -17,6 +17,28 @@ Template: --- +## 2026-07-05 — doctor bar tripwire (iteration #42, LATER item) +- **Task:** LATER › doctor Waybar warning. Bullet deleted. +- **Did:** nomarchy-doctor-status (named bin, PATH): silent exit 0 + while the doctor is healthy or absent (self-gate), else JSON with + the first ✖ lines jq-escaped into the tooltip, in @bad; click = + nomarchy-menu doctor (the sheet). custom/doctor added to the + generated bar (after battery, interval 300 — the check is real + work, this is a tripwire not a monitor) + CSS, AND both summer + whole-swaps (module list, jsonc block, CSS membership + @red rule) + per the parity rule. +- **Verified:** V0; V1 — template-home builds, status bash -n, config + + CSS each carry the module, both summer jsonc still parse (jq) + with the block; FUNCTIONAL — self-gate silent, and a shimmed + failing doctor produces valid JSON (jq-verified: class bad, ✖ + lines in tooltip). Live render → V3 queued. +- **Pending:** V3. LATER remaining: wallpapers-artifact split + (deferred by decision), installer round 2 [big], boot-from- + snapshot, night-light geo, icon overrides, MIPI camera [hw], + auto-timezone tooltip, VPN richer display, release bump [human]. +- **Next suggestion:** auto-timezone Waybar tooltip (small) — or a + QA sweep; the meatier LATER items deserve a fresh session. + ## 2026-07-05 — OCR screenshot-to-text (iteration #41, LATER item) - **Task:** LATER › OCR (NEXT is fully human/event-gated, so LATER is in play per LOOP.md). Bullet deleted. diff --git a/modules/home/waybar.nix b/modules/home/waybar.nix index 6676aa5..aa5c130 100644 --- a/modules/home/waybar.nix +++ b/modules/home/waybar.nix @@ -95,6 +95,18 @@ let printf '{"text":"󰦝","tooltip":"VPN active (click to manage)","class":"on"}\n' ''; + # Health warning — self-gates: prints nothing while nomarchy-doctor + # exits 0, so the module only appears when the sheet has a ✖ (the + # same self-hide discipline as vpn/nightlight/updates). The tooltip + # carries the first failing lines; click opens the full sheet. + doctorStatus = pkgs.writeShellScriptBin "nomarchy-doctor-status" '' + command -v nomarchy-doctor >/dev/null 2>&1 || exit 0 + out=$(nomarchy-doctor 2>/dev/null) && exit 0 + tip=$(printf '%s\n' "$out" | grep '✖' | head -5 \ + | ${pkgs.jq}/bin/jq -Rs 'rtrimstr("\n") + "\n(click for the full sheet)"') + printf '{"text":"","tooltip":%s,"class":"bad"}\n' "$tip" + ''; + # Per-theme override probe. assetDir = config.nomarchy.themesDir + "/${t.slug}"; styleOverride = assetDir + "/waybar.css"; @@ -123,7 +135,7 @@ let modules-center = [ "clock" ]; modules-right = [ "custom/recording" "idle_inhibitor" "tray" "custom/vpn" "pulseaudio" "cpu" "memory" "custom/powerprofile" "custom/nightlight" ] ++ lib.optional showLanguage "hyprland/language" - ++ [ "battery" "custom/updates" "custom/notification" ]; + ++ [ "battery" "custom/doctor" "custom/updates" "custom/notification" ]; "hyprland/workspaces" = { format = "{icon}"; @@ -197,6 +209,15 @@ let on-click = "nomarchy-vpn"; }; + # Health check is real work (systemctl/disk/git sweeps), so a long + # interval — this is a tripwire, not a monitor. + "custom/doctor" = { + exec = "nomarchy-doctor-status"; + return-type = "json"; + interval = 300; + on-click = "nomarchy-menu doctor"; + }; + # Screen recording indicator. Self-gates: visible only while # nomarchy-record runs (status prints nothing otherwise), and the # click IS the stop surface — the menu only starts recordings. @@ -310,7 +331,7 @@ let font-weight: bold; } - #tray, #pulseaudio, #cpu, #memory, #custom-powerprofile, #custom-nightlight, #custom-updates, #custom-vpn, #custom-recording, #idle_inhibitor, #language, #battery, #custom-notification { + #tray, #pulseaudio, #cpu, #memory, #custom-powerprofile, #custom-nightlight, #custom-updates, #custom-vpn, #custom-recording, #idle_inhibitor, #language, #battery, #custom-doctor, #custom-notification { color: alpha(@text, 0.85); padding: 0 10px; } @@ -337,6 +358,10 @@ let /* Updates pending → accent, to draw the eye. */ #custom-updates.available { color: @accent; } + /* Doctor tripwire — only rendered when something is ✖, so it is + always the alert color. */ + #custom-doctor { color: @bad; } + /* The power-profile speedometer glyph renders small in its em box — size it up so it reads at a glance like the other indicators. */ #custom-powerprofile { font-size: ${toString (t.fonts.size + 3)}pt; } @@ -386,5 +411,5 @@ in # whole-swap themes' static waybar.jsonc can exec them by name — plus # the supervisor hyprland.nix exec-onces. home.packages = lib.optionals config.nomarchy.waybar.enable - [ waybarSupervisor powerProfileStatus powerProfileCycle vpnStatus ]; + [ waybarSupervisor powerProfileStatus powerProfileCycle vpnStatus doctorStatus ]; } diff --git a/themes/summer-day/waybar.css b/themes/summer-day/waybar.css index 80ea1a0..34e4eff 100755 --- a/themes/summer-day/waybar.css +++ b/themes/summer-day/waybar.css @@ -55,6 +55,7 @@ window#waybar { #custom-updates, #battery, #tray, +#custom-doctor, #custom-notification, #custom-powermenu { background-color: @bg0; @@ -127,3 +128,8 @@ window#waybar { #custom-recording.recording { color: @red; } + +/* Doctor tripwire: only rendered when something is broken. */ +#custom-doctor { + color: @red; +} diff --git a/themes/summer-day/waybar.jsonc b/themes/summer-day/waybar.jsonc index 3c7c069..490dc61 100644 --- a/themes/summer-day/waybar.jsonc +++ b/themes/summer-day/waybar.jsonc @@ -11,7 +11,7 @@ "modules-left": ["custom/launcher", "clock", "clock#date"], "modules-center": ["hyprland/workspaces"], - "modules-right": ["custom/recording", "idle_inhibitor", "pulseaudio", "custom/powerprofile", "custom/nightlight", "hyprland/language", "custom/updates", "battery", "tray", "custom/vpn", "custom/notification", "custom/powermenu"], + "modules-right": ["custom/recording", "idle_inhibitor", "pulseaudio", "custom/powerprofile", "custom/nightlight", "hyprland/language", "custom/updates", "battery", "tray", "custom/vpn", "custom/doctor", "custom/notification", "custom/powermenu"], "hyprland/workspaces": { "disable-scroll": true, @@ -95,6 +95,13 @@ "on-click": "nomarchy-record stop" }, + "custom/doctor": { + "return-type": "json", + "interval": 300, + "exec": "nomarchy-doctor-status", + "on-click": "nomarchy-menu doctor" + }, + "custom/vpn": { "return-type": "json", "interval": 5, diff --git a/themes/summer-night/waybar.css b/themes/summer-night/waybar.css index bea7a80..1ba24c1 100644 --- a/themes/summer-night/waybar.css +++ b/themes/summer-night/waybar.css @@ -60,6 +60,7 @@ window#waybar { #custom-updates, #idle_inhibitor, #battery, +#custom-doctor, #custom-notification, #custom-powermenu { background-color: @bg0; @@ -139,3 +140,8 @@ window#waybar { #custom-recording.recording { color: @red; } + +/* Doctor tripwire: only rendered when something is broken. */ +#custom-doctor { + color: @red; +} diff --git a/themes/summer-night/waybar.jsonc b/themes/summer-night/waybar.jsonc index 56a4317..272a34c 100644 --- a/themes/summer-night/waybar.jsonc +++ b/themes/summer-night/waybar.jsonc @@ -11,7 +11,7 @@ "modules-left": ["custom/nomarchy", "clock", "clock#date"], "modules-center": ["hyprland/workspaces"], - "modules-right": ["custom/recording", "idle_inhibitor", "pulseaudio", "custom/powerprofile", "custom/nightlight", "hyprland/language", "custom/updates", "battery", "tray", "custom/vpn", "custom/notification", "custom/powermenu"], + "modules-right": ["custom/recording", "idle_inhibitor", "pulseaudio", "custom/powerprofile", "custom/nightlight", "hyprland/language", "custom/updates", "battery", "tray", "custom/vpn", "custom/doctor", "custom/notification", "custom/powermenu"], "hyprland/workspaces": { "disable-scroll": true, @@ -94,6 +94,13 @@ "on-click": "nomarchy-record stop" }, + "custom/doctor": { + "return-type": "json", + "interval": 300, + "exec": "nomarchy-doctor-status", + "on-click": "nomarchy-menu doctor" + }, + "custom/vpn": { "return-type": "json", "interval": 5,