From f18bee9f5c43e56ebdcb7e5fad17f3236de4d08e Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Mon, 8 Jun 2026 21:52:48 +0300 Subject: fix: smooth agent status transitions --- src/detect/mod.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'src/detect/mod.rs') diff --git a/src/detect/mod.rs b/src/detect/mod.rs index 24393c59..10ecfc6b 100644 --- a/src/detect/mod.rs +++ b/src/detect/mod.rs @@ -35,6 +35,12 @@ pub struct AgentDetection { pub visible_working: bool, } +/// A narrow screen-derived exception that can veto PTY activity as semantic work. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AgentActivityVeto { + ClaudeIdleRecap, +} + /// Which agent we detected running in a pane. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Agent { @@ -180,6 +186,18 @@ pub fn detect_agent(agent: Option, screen_content: &str) -> AgentDetectio agents::detect(agent, screen_content) } +pub(crate) fn agent_activity_veto( + agent: Option, + screen_content: &str, +) -> Option { + match agent { + Some(Agent::Claude) if agents::claude_code::has_idle_recap_notice(screen_content) => { + Some(AgentActivityVeto::ClaudeIdleRecap) + } + _ => None, + } +} + pub fn should_skip_state_update(agent: Option, screen_content: &str) -> bool { agent.is_some_and(|agent| agents::should_skip_state_update(agent, screen_content)) } @@ -1271,6 +1289,33 @@ mod tests { assert_eq!(detect_claude(screen), AgentState::Idle); } + #[test] + fn claude_idle_recap_notice_is_activity_veto() { + let screen = "✻ Churned for 9s\n\n※ recap: We’re debugging issue 494: kitty graphics render in shell panes but not inside Neovim. Next, I’m tracing the snacks.nvim inline-image path against Herdr’s placeholder\n handling to confirm the exact failure point. (disable recaps in /config)\n\n────────────────────────────────────────────────────────────────────────────────\n❯ \n────────────────────────────────────────────────────────────────────────────────"; + + assert_eq!( + agent_activity_veto(Some(Agent::Claude), screen), + Some(AgentActivityVeto::ClaudeIdleRecap) + ); + } + + #[test] + fn wrapped_claude_idle_recap_notice_is_activity_veto() { + let screen = "※ recap: We’re debugging issue 494: kitty graphics render in shell panes but\n not inside Neovim. Next, I’m tracing the snacks.nvim inline-image path\n against Herdr’s placeholder handling to confirm the exact failure point…\n and then I will inspect the redraw cache. (disable recaps in /config)\n\n────────────────────────────────────────────────────────────────────────────────\n❯ \n────────────────────────────────────────────────────────────────────────────────"; + + assert_eq!( + agent_activity_veto(Some(Agent::Claude), screen), + Some(AgentActivityVeto::ClaudeIdleRecap) + ); + } + + #[test] + fn stale_claude_recap_above_new_work_does_not_veto_activity() { + let screen = "※ recap: Old recap. (disable recaps in /config)\n\n● Reading src/pane.rs\n\n✻ Crunching…\n\n────────────────────────────────────────────────────────────────────────────────\n❯ \n────────────────────────────────────────────────────────────────────────────────"; + + assert_eq!(agent_activity_veto(Some(Agent::Claude), screen), None); + } + #[test] fn claude_prompt_box_does_not_set_screen_idle_signal() { let screen = "Interrupted.\n─────────────\n❯ \n─────────────"; -- cgit v1.2.3