From b0cfd10b80443d3f67d263ff4db177bb53cc90ed Mon Sep 17 00:00:00 2001 From: Igor Soarez Date: Fri, 30 Oct 2026 17:27:21 +0200 Subject: reload pi agents on an old extension: versioned extension, control socket, menu item and reload-agents --- crates/dinggerd/src/main.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'crates/dinggerd/src/main.rs') diff --git a/crates/dinggerd/src/main.rs b/crates/dinggerd/src/main.rs index 2c36198..1fc5cd2 100644 --- a/crates/dinggerd/src/main.rs +++ b/crates/dinggerd/src/main.rs @@ -90,6 +90,11 @@ enum Command { #[arg(long)] pane: Option, }, + /// Reload the pi agents that run an old dingger extension: those idle + /// and off screen now, the others once they are (a reload while busy, + /// or with a draft in the input box, waits). Until all are reloaded or + /// the daemon restarts. + ReloadAgents, /// Restore tmux sessions saved before tmux last stopped (a crash, /// shutdown, or kill-server): windows, panes, layouts, directories. /// Only adds what is missing; a bare session of the same name (what a @@ -166,6 +171,7 @@ fn main() { no_sounds, no_notifications, } => { + integrations::update_pi_extension(); if let Err(err) = hooks::spawn_listener() { eprintln!("dingger: {err}"); std::process::exit(1); @@ -208,6 +214,12 @@ fn main() { std::process::exit(1); } } + Command::ReloadAgents => { + if let Err(err) = reload_agents() { + eprintln!("dingger: {err}"); + std::process::exit(1); + } + } Command::Poke => { // Best effort: a stopped watcher just means nothing to wake. let _ = hooks::poke(); @@ -355,6 +367,44 @@ fn set_importance(level: Option<&str>, pane: Option) -> Result<(), Strin Ok(()) } +/// `dingger reload-agents`: ask the daemon to reload the agents on an old +/// extension; report what happened within a few seconds. +fn reload_agents() -> Result<(), String> { + let count = |name: &str| tmux::show_global(name).and_then(|v| v.trim().parse::().ok()).unwrap_or(0); + let by_hand = count("@dingger_outdated_by_hand"); + let by_hand_note = || { + if by_hand > 0 { + let agents = if by_hand == 1 { "agent runs" } else { "agents run" }; + println!("{by_hand} {agents} an extension too old to reload this way: type /reload in each"); + } + }; + let before = count("@dingger_outdated"); + if before == 0 { + if by_hand == 0 { + println!("every pi agent runs the current dingger extension"); + } + by_hand_note(); + return Ok(()); + } + if !integrations::pi_extension_installed_is_current() { + return Err("the installed pi extension is not this dingger's, so a reload would load the old one again: run `dingger install pi` first".into()); + } + hooks::send(r#"{"method":"agents.reload_outdated"}"#)?; + let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5); + let mut left = before; + while left > 0 && std::time::Instant::now() < deadline { + std::thread::sleep(std::time::Duration::from_millis(200)); + left = count("@dingger_outdated"); + } + let agents = |n: usize| if n == 1 { "agent" } else { "agents" }; + println!("reloaded {} of {before} {} on an old dingger extension", before.saturating_sub(left), agents(before)); + if left > 0 { + println!("the other {left} reload once idle and off screen, with an empty input box"); + } + by_hand_note(); + Ok(()) +} + /// `dingger unread`: ask the daemon to mark the pane's idle agent unread, /// and wait until it shows as done. fn mark_unread(pane: Option) -> Result<(), String> { -- cgit v1.2.3