aboutsummaryrefslogtreecommitdiff
path: root/crates/dinggerd/src/main.rs
blob: f04673227484a6aeb41fc0b15b738499e8d3b377 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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(())
}