From 987b070fbfa187e85009b45cd7e208fc6175ff6a Mon Sep 17 00:00:00 2001 From: akbash Date: Wed, 2 Sep 2026 18:00:44 +0300 Subject: [PATCH] fix: stop treating claude background shells as working (#3468) --- distribution/agent-detection/claude.toml | 12 +--- src/detect/manifest/tests.rs | 79 ++++++++++++++++++++++++ src/detect/manifests/claude.toml | 12 +--- 3 files changed, 83 insertions(+), 20 deletions(-) diff --git a/distribution/agent-detection/claude.toml b/distribution/agent-detection/claude.toml index 55adacd6..2a26a334 100644 --- a/distribution/agent-detection/claude.toml +++ b/distribution/agent-detection/claude.toml @@ -1,7 +1,7 @@ id = "claude" -version = "2026.08.29.1" +version = "2026.08.31.1" min_engine_version = 2 -updated_at = "2026-08-29T00:00:00Z" +updated_at = "2026-08-31T00:00:00Z" aliases = ["claude-code"] [[rules]] @@ -24,14 +24,6 @@ any = [ { line_regex = ['^\s*[\x{002A}\x{00B7}\x{2722}\x{2736}\x{273B}\x{273D}]\s+\S.*…(?:\s+\(\d+[smh](?:\s|·)|\s*$)'] }, ] -[[rules]] -id = "background_shell_working" -state = "working" -priority = 965 -region = "bottom_non_empty_lines(5)" -visible_working = true -line_regex = ['^\s*[⏸⏵].*·\s+[1-9]\d*\s+shells?\s+(?:·|$)'] - [[rules]] id = "background_agents_working" state = "working" diff --git a/src/detect/manifest/tests.rs b/src/detect/manifest/tests.rs index 8eb3b612..63345636 100644 --- a/src/detect/manifest/tests.rs +++ b/src/detect/manifest/tests.rs @@ -659,6 +659,85 @@ fn osc_explain( // --- Claude OSC rules --- +#[test] +fn claude_idle_prompt_with_background_shell_is_idle() { + // Captured from Claude Code 2.1.251 after its foreground turn ended while + // a long-lived background shell remained active (issue #3414). + let screen = concat!( + "✻ Sautéed for 10s · 1 shell still running\n\n", + "──────────────────────────────────────────────────────── WINDOWS ─\n", + "❯\n", + "────────────────────────────────────────────────────────────────\n", + " ⏵⏵ auto mode on · 1 shell · ← for agents /rc\n", + ); + let result = osc_explain(Agent::Claude, screen, "", ""); + + assert_eq!(result.state, AgentState::Idle); + assert_eq!( + result.matched_rule.as_ref().map(|rule| rule.id.as_str()), + Some("live_prompt_box") + ); + assert!(result.visible_idle); + assert!(!result.visible_working); +} + +#[test] +fn claude_background_shell_without_foreground_evidence_is_idle_fallback() { + let result = osc_explain( + Agent::Claude, + " ⏵⏵ auto mode on · 1 shell · ← for agents\n", + "", + "", + ); + + assert_eq!(result.state, AgentState::Idle); + assert_eq!(result.matched_rule, None); + assert_eq!( + result.fallback_reason.as_deref(), + Some(DEFAULT_KNOWN_AGENT_IDLE_FALLBACK) + ); + assert!(!result.visible_working); +} + +#[test] +fn claude_live_turn_with_background_shell_remains_working() { + let screen = concat!( + "────────────────────────────────────────────────────────────────\n", + "❯\n", + "────────────────────────────────────────────────────────────────\n", + " ⏵⏵ auto mode on · 1 shell · esc to interrupt\n", + ); + let result = osc_explain(Agent::Claude, screen, "", ""); + + assert_eq!(result.state, AgentState::Working); + assert_eq!( + result.matched_rule.as_ref().map(|rule| rule.id.as_str()), + Some("live_turn_working") + ); + assert!(result.visible_working); +} + +#[test] +fn claude_blocker_with_background_shell_remains_blocked() { + let screen = concat!( + "do you want to proceed?\n", + "bash command: rm -rf /tmp/test\n", + "❯ 1. Yes\n", + " 2. No\n\n", + "Esc to cancel · Tab to amend · ctrl+e to explain\n", + " ⏵⏵ auto mode on · 1 shell · ← for agents\n", + ); + let result = osc_explain(Agent::Claude, screen, "", ""); + + assert_eq!(result.state, AgentState::Blocked); + assert_eq!( + result.matched_rule.as_ref().map(|rule| rule.id.as_str()), + Some("bash_permission_prompt") + ); + assert!(result.visible_blocker); + assert!(!result.visible_working); +} + #[test] fn claude_osc_title_braille_prefix_is_working() { // "⠂" is U+2802, in the braille block U+2800-U+28FF diff --git a/src/detect/manifests/claude.toml b/src/detect/manifests/claude.toml index 55adacd6..2a26a334 100644 --- a/src/detect/manifests/claude.toml +++ b/src/detect/manifests/claude.toml @@ -1,7 +1,7 @@ id = "claude" -version = "2026.08.29.1" +version = "2026.08.31.1" min_engine_version = 2 -updated_at = "2026-08-29T00:00:00Z" +updated_at = "2026-08-31T00:00:00Z" aliases = ["claude-code"] [[rules]] @@ -24,14 +24,6 @@ any = [ { line_regex = ['^\s*[\x{002A}\x{00B7}\x{2722}\x{2736}\x{273B}\x{273D}]\s+\S.*…(?:\s+\(\d+[smh](?:\s|·)|\s*$)'] }, ] -[[rules]] -id = "background_shell_working" -state = "working" -priority = 965 -region = "bottom_non_empty_lines(5)" -visible_working = true -line_regex = ['^\s*[⏸⏵].*·\s+[1-9]\d*\s+shells?\s+(?:·|$)'] - [[rules]] id = "background_agents_working" state = "working"