forked from kent/consciousness
Without -l, tmux send-keys treats spaces as key-name separators, so multi-word messages like "This is your time" get split into individual unrecognized key names instead of being typed as text. This caused idle nudges to arrive as blank messages.
66 lines
1.7 KiB
Rust
66 lines
1.7 KiB
Rust
// Tmux interaction: pane detection and prompt injection.
|
|
|
|
use std::process::Command;
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
use tracing::info;
|
|
|
|
/// Find Claude Code's tmux pane by scanning for the "claude" process.
|
|
pub fn find_claude_pane() -> Option<String> {
|
|
let out = Command::new("tmux")
|
|
.args([
|
|
"list-panes",
|
|
"-a",
|
|
"-F",
|
|
"#{session_name}:#{window_index}.#{pane_index}\t#{pane_current_command}",
|
|
])
|
|
.output()
|
|
.ok()?;
|
|
|
|
let stdout = String::from_utf8_lossy(&out.stdout);
|
|
for line in stdout.lines() {
|
|
if let Some((pane, cmd)) = line.split_once('\t') {
|
|
if cmd == "claude" {
|
|
return Some(pane.to_string());
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
/// Send a prompt to a tmux pane. Returns true on success.
|
|
///
|
|
/// Sequence: Escape q C-c C-u (clear input), wait, type message, Enter.
|
|
pub fn send_prompt(pane: &str, msg: &str) -> bool {
|
|
let preview: String = msg.chars().take(100).collect();
|
|
info!("SEND [{pane}]: {preview}...");
|
|
|
|
let send = |keys: &[&str]| {
|
|
Command::new("tmux")
|
|
.arg("send-keys")
|
|
.arg("-t")
|
|
.arg(pane)
|
|
.args(keys)
|
|
.output()
|
|
.is_ok()
|
|
};
|
|
|
|
// Clear any partial input
|
|
if !send(&["Escape", "q", "C-c", "C-u"]) {
|
|
return false;
|
|
}
|
|
thread::sleep(Duration::from_secs(1));
|
|
|
|
// Type the message (literal mode so spaces aren't key separators)
|
|
let ok = Command::new("tmux")
|
|
.args(["send-keys", "-t", pane, "-l", msg])
|
|
.output()
|
|
.is_ok();
|
|
if !ok {
|
|
return false;
|
|
}
|
|
thread::sleep(Duration::from_millis(500));
|
|
|
|
// Submit
|
|
send(&["Enter"])
|
|
}
|