From 9c9c9dad93b16781ec2fc40bd7582db62240171c Mon Sep 17 00:00:00 2001 From: Igor Soarez Date: Fri, 23 Oct 2026 13:59:59 +0300 Subject: restore, step 3: offer it in the panel, menu, and status line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when tmux stops (and its sessions are missing from the running server, or no server runs), the daemon publishes the restore offer: offer.json for the menu bar app and @dingger_restore for the status line, withdrawn once restored or dismissed. - panel: a first row "↺ Restore 9 sessions · 22 agents" with when it was saved and how many agents were mid-turn; clicking restores, "Not now" dismisses. an offer shows the panel like a waiting agent; off stays off. - menu: the offer on top; restore all, one session, or not now. - status line: a clickable blue ↺N before the clock. - restore runs through the user's login shell, as a terminal starts tmux, so restored panes get a real environment, not launchd's; --report writes restore.log and notifies a summary. restore --dismiss. - commands log only warnings by default; SIGPIPE ends them quietly. e2e: the offer through the real menu bar binary, the summary notification, the offer clearing, a restore with no tmux running, and not now staying dismissed when a terminal starts tmux. the second test daemon is started directly (it leaked through a function's $! before, and dozens of leaked daemons fought over the test socket and loaded the machine); each run uses its own socket and checks its daemons stop. --- crates/dinggerd/src/watcher.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'crates/dinggerd/src/watcher.rs') diff --git a/crates/dinggerd/src/watcher.rs b/crates/dinggerd/src/watcher.rs index 24a2ecd..a2d6dae 100644 --- a/crates/dinggerd/src/watcher.rs +++ b/crates/dinggerd/src/watcher.rs @@ -182,6 +182,7 @@ pub fn advance( pub struct Watcher { tracks: HashMap, snapshots: crate::snapshot::Recorder, + offer: crate::restore::OfferPublisher, /// Last published (queue, blocked, done, working); avoids rewriting the /// global options every tick. last_published: Option<(String, usize, usize, usize)>, @@ -195,6 +196,7 @@ impl Watcher { Self { tracks: HashMap::new(), snapshots: Default::default(), + offer: Default::default(), last_published: None, interval_secs: interval_secs.max(1), sounds, @@ -226,6 +228,7 @@ impl Watcher { } // After the tick, so snapshots carry the states it just wrote. self.snapshots.tick(unix_now()); + self.offer.tick(); debug!(ms = started.elapsed().as_millis() as u64, "tick"); hooks::wait_for_wake(std::time::Duration::from_secs(self.interval_secs)); } -- cgit v1.2.3