fix(waybar): supervisor respawn + clean-restart switches; add sys-rebuild

Recovers the crashed iteration #7 (items 21+23, Latitude QA findings):

- nomarchy-waybar supervisor (waybar.nix, exec-once'd from
  hyprland.nix): any waybar exit respawns the bar; crash-loop guard
  (5 fast exits -> critical notify + stop); TERM trapped for a real
  stop. Fixes the bar-less session after a theme-switch crash.
- nomarchy-theme-sync prefers a clean `pkill -x waybar` (supervisor
  restart with fresh config+style) over the crash-prone in-place
  SIGUSR2 reload when the supervisor is running; SIGUSR2 stays as the
  unsupervised fallback.
- sys-rebuild: snapshot-first system rebuild against the CURRENT lock
  (no `nix flake update`) — the no-update twin of sys-update;
  README §3/§5 + motd list it.

Verified: V0 re-run green after crash recovery (flake check --no-build
+ py_compile); V1/V2 per the crashed session's journal entry (HM
renders exec-once=nomarchy-waybar; headless software-GL VM:
SIGKILL -> new pid, clean kill -> respawn, SIGUSR2 -> alive).
V3 pending on the Latitude (queued in HARDWARE-QUEUE.md).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-07-04 18:07:05 +01:00
parent f70838c5b5
commit 18b854563b
9 changed files with 116 additions and 34 deletions

View File

@@ -204,11 +204,22 @@ def run_switch() -> None:
notify("Rebuild FAILED — see terminal / journal", urgency="critical")
die("rebuild failed (state file already updated; fix and re-run)")
notify("Changes applied ✓")
# Waybar runs from Hyprland's exec-once (not a systemd unit HM would restart
# on switch), so nudge the running bar to re-read its freshly rebuilt
# config/style. SIGUSR2 = reload; harmless no-op if waybar isn't running.
# Waybar runs from Hyprland's exec-once (not a systemd unit HM would
# restart on switch), so nudge the running bar onto the freshly rebuilt
# config/style. Under the nomarchy-waybar supervisor a plain kill IS a
# clean restart with the new files — waybar's in-place SIGUSR2 reload
# is what crashed the bar on hardware (double-reload race with
# reload_style_on_change while the symlinks flip), so prefer the
# restart whenever the supervisor is there to catch it; fall back to
# SIGUSR2 for unsupervised/custom bars. No-ops if nothing is running.
if shutil.which("pkill"):
subprocess.run(["pkill", "--signal", "SIGUSR2", "-x", "waybar"], check=False)
supervised = subprocess.run(
["pgrep", "-f", "nomarchy-waybar"], capture_output=True
).returncode == 0
if supervised:
subprocess.run(["pkill", "-x", "waybar"], check=False)
else:
subprocess.run(["pkill", "--signal", "SIGUSR2", "-x", "waybar"], check=False)
# ─── Theme assets (wallpapers) ────────────────────────────────────────────