Fix auto-lookback trigger and add version tracking (#20)
* Fix auto-lookback trigger and add version tracking - Trigger on stdin inactivity instead of render time - Only dump when new output exists since last dump - Default timeout 5s -> 15s - Embed git hash in version output - Document macOS config path
This commit is contained in:
38
crates/claude-chill/build.rs
Normal file
38
crates/claude-chill/build.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=.git/HEAD");
|
||||
println!("cargo:rerun-if-changed=.git/index");
|
||||
|
||||
let git_hash = get_git_hash();
|
||||
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
|
||||
}
|
||||
|
||||
fn get_git_hash() -> String {
|
||||
let hash = match Command::new("git")
|
||||
.args(["rev-parse", "--short", "HEAD"])
|
||||
.output()
|
||||
{
|
||||
Ok(output) if output.status.success() => String::from_utf8(output.stdout)
|
||||
.ok()
|
||||
.map(|s| s.trim().to_string()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let Some(hash) = hash else {
|
||||
return "git not found during build, version unavailable".to_string();
|
||||
};
|
||||
|
||||
let is_dirty = Command::new("git")
|
||||
.args(["status", "--porcelain"])
|
||||
.output()
|
||||
.ok()
|
||||
.map(|output| !output.stdout.is_empty())
|
||||
.unwrap_or(false);
|
||||
|
||||
if is_dirty {
|
||||
format!("{}-dirty", hash)
|
||||
} else {
|
||||
hash
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
use clap::Parser;
|
||||
|
||||
const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", env!("GIT_HASH"), ")");
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(
|
||||
name = "claude-chill",
|
||||
version,
|
||||
version = VERSION,
|
||||
about = "A PTY proxy that tames Claude Code's massive terminal updates"
|
||||
)]
|
||||
pub struct Cli {
|
||||
@@ -22,7 +24,7 @@ pub struct Cli {
|
||||
#[arg(short = 'k', long = "lookback-key")]
|
||||
pub lookback_key: Option<String>,
|
||||
|
||||
/// Auto-lookback timeout in ms, 0 to disable (default: 5000)
|
||||
/// Auto-lookback timeout in ms, 0 to disable (default: 15000)
|
||||
#[arg(short = 'a', long = "auto-lookback-timeout")]
|
||||
pub auto_lookback_timeout: Option<u64>,
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::path::PathBuf;
|
||||
|
||||
const DEFAULT_LOOKBACK_KEY: &str = "[ctrl][6]";
|
||||
const DEFAULT_REFRESH_RATE: u64 = 20;
|
||||
const DEFAULT_AUTO_LOOKBACK_TIMEOUT_MS: u64 = 5000;
|
||||
const DEFAULT_AUTO_LOOKBACK_TIMEOUT_MS: u64 = 15000;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(default)]
|
||||
@@ -100,7 +100,7 @@ mod tests {
|
||||
assert_eq!(config.lookback_key, "[ctrl][6]");
|
||||
assert_eq!(config.refresh_rate, 20);
|
||||
assert_eq!(config.redraw_throttle_ms(), 50);
|
||||
assert_eq!(config.auto_lookback_timeout_ms, 5000);
|
||||
assert_eq!(config.auto_lookback_timeout_ms, 15000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -58,7 +58,7 @@ impl Default for ProxyConfig {
|
||||
max_history_lines: 100_000,
|
||||
lookback_key: "[ctrl][6]".to_string(),
|
||||
lookback_sequence: vec![0x1E],
|
||||
auto_lookback_timeout_ms: 5000,
|
||||
auto_lookback_timeout_ms: 15000,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,8 @@ pub struct Proxy {
|
||||
vt_prev_screen: Option<vt100::Screen>,
|
||||
last_output_time: Option<Instant>,
|
||||
last_render_time: Option<Instant>,
|
||||
last_stdin_time: Option<Instant>,
|
||||
last_auto_lookback_time: Option<Instant>,
|
||||
auto_lookback_timeout: Duration,
|
||||
sync_buffer: Vec<u8>,
|
||||
in_sync_block: bool,
|
||||
@@ -182,6 +184,8 @@ impl Proxy {
|
||||
vt_prev_screen: None,
|
||||
last_output_time: None,
|
||||
last_render_time: None,
|
||||
last_stdin_time: None,
|
||||
last_auto_lookback_time: None,
|
||||
auto_lookback_timeout,
|
||||
sync_buffer: Vec::with_capacity(SYNC_BUFFER_CAPACITY),
|
||||
in_sync_block: false,
|
||||
@@ -581,14 +585,38 @@ impl Proxy {
|
||||
if self.in_lookback_mode || self.in_alternate_screen {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Check if enough time has passed since last stdin activity
|
||||
let Some(stdin_time) = self.last_stdin_time else {
|
||||
return Ok(());
|
||||
};
|
||||
if stdin_time.elapsed() < self.auto_lookback_timeout {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Check if there's been new output since last auto-lookback
|
||||
// AND enough time has passed since we last dumped
|
||||
let Some(render_time) = self.last_render_time else {
|
||||
return Ok(());
|
||||
};
|
||||
if render_time.elapsed() < self.auto_lookback_timeout {
|
||||
return Ok(());
|
||||
if let Some(last_auto) = self.last_auto_lookback_time {
|
||||
let no_new_output = render_time <= last_auto;
|
||||
let too_soon = last_auto.elapsed() < self.auto_lookback_timeout;
|
||||
if no_new_output || too_soon {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
"auto_lookback triggered: stdin_idle={}ms render_age={}ms last_auto_age={}ms",
|
||||
stdin_time.elapsed().as_millis(),
|
||||
render_time.elapsed().as_millis(),
|
||||
self.last_auto_lookback_time
|
||||
.map(|t| t.elapsed().as_millis())
|
||||
.unwrap_or(0)
|
||||
);
|
||||
self.dump_history(stdout_fd)?;
|
||||
self.last_render_time = None;
|
||||
self.last_auto_lookback_time = Some(Instant::now());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -611,6 +639,8 @@ impl Proxy {
|
||||
}
|
||||
|
||||
fn process_input<F: AsFd>(&mut self, data: &[u8], stdout_fd: &F) -> Result<()> {
|
||||
self.last_stdin_time = Some(Instant::now());
|
||||
|
||||
if self.in_alternate_screen {
|
||||
return write_all(&self.pty_master, data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user