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(())
}
|