From b4f45632debe6b8dc2f44ca6cc1b003d9093ad33 Mon Sep 17 00:00:00 2001 From: Igor Soarez Date: Fri, 23 Oct 2026 18:45:06 +0300 Subject: session groups: list each pane once, save each group once a pane in several sessions (a session group, `new-session -t`, or a linked window) was listed once per session: every agent of a group showed twice in the menu, panel, search, `dingger status`, and the counts. and snapshots saved each session of a group with its own copy of the windows, so restore would have rebuilt them twice and resumed each agent twice on one session file. - a pane keeps its first listing (tmux lists sessions by name) and is attended if the user looks at it through any session of the group. - snapshots keep the first session of each group; the others are not restored. e2e step 19 covers both; the previous binaries fail it. two checks (step 11's and this one) waited for idle after a turn that started from idle, which passed before the turn was even processed: they now wait for working first, and the negative control for group attendance fails as it should. step 18 now waits for the snapshot it later restores from. --- crates/dinggerd/src/snapshot.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'crates/dinggerd/src/snapshot.rs') diff --git a/crates/dinggerd/src/snapshot.rs b/crates/dinggerd/src/snapshot.rs index d4ee321..715bf37 100644 --- a/crates/dinggerd/src/snapshot.rs +++ b/crates/dinggerd/src/snapshot.rs @@ -197,13 +197,22 @@ pub fn capture(now_ms: u64) -> Option { "#{@agent_session}", "#{@dingger_cmd}", "#{pane_dead}", + "#{?session_grouped,#{session_group},}", ] .join("\t"); let out = tmux::run(&["list-panes", "-a", "-F", &format]).ok()?; let lines: Vec> = out .lines() .map(|line| line.split('\t').collect::>()) - .filter(|f| f.len() >= 21) + .filter(|f| f.len() >= 22) + .collect(); + // One session per group: the others show the same windows, and saving + // them would restore every window, and resume every agent, twice. The + // first listed (tmux lists sessions by name) stands for its group. + let mut group_of_kept: std::collections::HashMap<&str, &str> = std::collections::HashMap::new(); + let lines: Vec> = lines + .into_iter() + .filter(|f| f[21].is_empty() || *group_of_kept.entry(f[21]).or_insert(f[0]) == f[0]) .collect(); // What runs in the foreground of each pane's terminal. let pane_pids: Vec = lines -- cgit v1.2.3