diff options
| author | Igor Soarez <igor@soarez.org> | 2026-10-19 16:55:30 +0300 |
|---|---|---|
| committer | Igor Soarez <igor@soarez.org> | 2026-10-19 16:55:30 +0300 |
| commit | ea1dda2f056fdfd56bffe8b978c0b0786b82aa7d (patch) | |
| tree | 2a6451f2a956cdd2345d6a77a2db00e0fff1d376 /crates/dinggerd/src/main.rs | |
| parent | 9c6b10426bd897afe6cf6f0c022f45310c5ab3d3 (diff) | |
ready-queue fifo with click-to-focus; redesign presentation per design panel
daemon tracks when each agent became ready (idle/blocked, unacked) and
publishes fifo queue + numeric counts as server-global options; unknown
to idle transitions stay out of the queue (restart spam). new dingger
focus subcommand jumps to the longest-waiting pane and acks it, bound to
status-right clicks in tmux. menu bar redesigned per two-model design
panel: monochrome sf-symbol bell + queue depth, queue-ordered rows with
state glyphs and right-aligned targets, row clicks ack like focus does.
tmux segment renders glyph+count with a single red accent for blocked;
fixes unescaped comma in the conditional format that truncated the
segment entirely.
Diffstat (limited to 'crates/dinggerd/src/main.rs')
| -rw-r--r-- | crates/dinggerd/src/main.rs | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/crates/dinggerd/src/main.rs b/crates/dinggerd/src/main.rs index f046732..4c8521c 100644 --- a/crates/dinggerd/src/main.rs +++ b/crates/dinggerd/src/main.rs @@ -33,6 +33,12 @@ enum Command { #[command(subcommand)] command: ManifestCommand, }, + /// Switch to the agent that has been waiting the longest (FIFO). Bound to + /// a mouse click on the tmux status line by the packaged config. + Focus { + /// Name of the tmux client that clicked, passed as #{client_name}. + client: Option<String>, + }, } #[derive(Subcommand)] @@ -73,7 +79,43 @@ fn main() { } } }, + Command::Focus { client } => { + if let Err(err) = focus(client) { + eprintln!("dingger: {err}"); + std::process::exit(1); + } + } + } +} + +/// Jump to the head of the ready queue (oldest waiting agent) and ack it, so +/// the next focus moves on to the following one. +fn focus(client: Option<String>) -> Result<(), String> { + let queue = tmux::show_global("@dingger_queue") + .unwrap_or_default() + .split(',') + .filter(|entry| !entry.is_empty()) + .map(|entry| entry.split(':').next().unwrap_or("").to_string()) + .collect::<Vec<_>>(); + let Some(pane_id) = queue.first() else { + return Ok(()); // nothing waiting + }; + let target = tmux::show_pane_format(pane_id, "#{session_name}:#{window_index}.#{pane_index}") + .unwrap_or_default(); + if target.is_empty() { + return Err("ready pane no longer exists".to_string()); + } + tmux::ack(pane_id)?; + let mut args = vec!["switch-client".to_string()]; + if let Some(client) = client { + args.push("-c".to_string()); + args.push(client); } + args.push("-t".to_string()); + args.push(target); + tmux::run_tmux_client( + &args.iter().map(String::as_str).collect::<Vec<_>>(), + ) } fn status() -> Result<(), String> { |
