aboutsummaryrefslogtreecommitdiff
path: root/crates/dinggerd/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/dinggerd/src/main.rs')
-rw-r--r--crates/dinggerd/src/main.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/crates/dinggerd/src/main.rs b/crates/dinggerd/src/main.rs
new file mode 100644
index 0000000..f046732
--- /dev/null
+++ b/crates/dinggerd/src/main.rs
@@ -0,0 +1,100 @@
+//! dingger: agent state watching for tmux panes.
+
+mod manifest_update;
+mod notify;
+mod tmux;
+mod watcher;
+
+use clap::{Parser, Subcommand};
+use tracing_subscriber::EnvFilter;
+
+#[derive(Parser)]
+#[command(name = "dingger", about = "Agent state watching for tmux panes")]
+struct Cli {
+ #[command(subcommand)]
+ command: Command,
+}
+
+#[derive(Subcommand)]
+enum Command {
+ /// Watch all tmux panes and notify on agent state transitions.
+ Watch {
+ /// Poll interval in seconds.
+ #[arg(long, default_value_t = 1)]
+ interval_secs: u64,
+ /// Disable notification sounds.
+ #[arg(long)]
+ no_sounds: bool,
+ },
+ /// Print the current agent state of every tmux pane.
+ Status,
+ /// Refresh detection manifests from herdr's published catalog.
+ Manifests {
+ #[command(subcommand)]
+ command: ManifestCommand,
+ },
+}
+
+#[derive(Subcommand)]
+enum ManifestCommand {
+ /// Download newer manifests from herdr's published catalog into the
+ /// local remote store; bundled manifests are the offline fallback.
+ /// Restart `dingger watch` to pick them up.
+ Update,
+}
+
+fn main() {
+ tracing_subscriber::fmt()
+ .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
+ .init();
+
+ match Cli::parse().command {
+ Command::Watch {
+ interval_secs,
+ no_sounds,
+ } => {
+ let mut watcher = watcher::Watcher::new(interval_secs, !no_sounds);
+ if let Err(err) = watcher.run() {
+ eprintln!("dingger: {err}");
+ std::process::exit(1);
+ }
+ }
+ Command::Status => {
+ if let Err(err) = status() {
+ eprintln!("dingger: {err}");
+ std::process::exit(1);
+ }
+ }
+ Command::Manifests { command } => match command {
+ ManifestCommand::Update => {
+ if let Err(err) = manifest_update::update() {
+ eprintln!("dingger: {err}");
+ std::process::exit(1);
+ }
+ }
+ },
+ }
+}
+
+fn status() -> Result<(), String> {
+ let panes = tmux::list_panes()?;
+ if panes.is_empty() {
+ println!("no tmux panes");
+ return Ok(());
+ }
+ println!("{:<22} {:<10} {:<12} COMMAND", "TARGET", "AGENT", "STATE");
+ for pane in panes {
+ println!(
+ "{:<22} {:<10} {:<12} {}",
+ pane.target,
+ pane.agent.map(detect_core::agent_label).unwrap_or("-"),
+ if pane.written_state.is_empty() {
+ "-"
+ } else {
+ &pane.written_state
+ },
+ pane.current_command,
+ );
+ }
+ Ok(())
+}