aboutsummaryrefslogtreecommitdiff
path: root/crates/dinggerd/src/main.rs
diff options
context:
space:
mode:
authorIgor Soarez <igor@soarez.org>2026-10-19 16:55:30 +0300
committerIgor Soarez <igor@soarez.org>2026-10-19 16:55:30 +0300
commitea1dda2f056fdfd56bffe8b978c0b0786b82aa7d (patch)
tree2a6451f2a956cdd2345d6a77a2db00e0fff1d376 /crates/dinggerd/src/main.rs
parent9c6b10426bd897afe6cf6f0c022f45310c5ab3d3 (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.rs42
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> {