aboutsummaryrefslogtreecommitdiff
path: root/src/detect/agents/mod.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-30 23:54:41 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-30 23:54:41 +0300
commitd477341e6af816ff4396042b084a0378ef437b4a (patch)
treee332b6f7a0d23d9effd21c3ca8ab27698ed83444 /src/detect/agents/mod.rs
parent8df1639048529b383358000879b5ee078a90b9f9 (diff)
refactor: split agent detection by agent
Move screen detection into per-agent modules and keep visible-state arbitration centralized in terminal state. Tighten Codex prompt-scoped working detection and Claude hook/screen recovery for stale blocked and idle reports. Add a focused just recipe for single-test runs. refs #349 refs #352
Diffstat (limited to 'src/detect/agents/mod.rs')
-rw-r--r--src/detect/agents/mod.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/detect/agents/mod.rs b/src/detect/agents/mod.rs
new file mode 100644
index 00000000..87b4043f
--- /dev/null
+++ b/src/detect/agents/mod.rs
@@ -0,0 +1,86 @@
+pub(super) mod amp;
+pub(super) mod antigravity;
+pub(super) mod claude_code;
+pub(super) mod cline;
+pub(super) mod codex;
+pub(super) mod cursor;
+pub(super) mod droid;
+pub(super) mod gemini;
+pub(super) mod github_copilot;
+pub(super) mod grok;
+pub(super) mod hermes;
+pub(super) mod kimi;
+pub(super) mod kiro;
+pub(super) mod opencode;
+pub(super) mod pi;
+pub(super) mod qodercli;
+
+use super::{Agent, AgentDetection, AgentState};
+
+pub(super) fn detect(agent: Agent, screen_content: &str) -> AgentDetection {
+ let state = match agent {
+ Agent::Pi => pi::detect(screen_content),
+ Agent::Claude => claude_code::detect(screen_content),
+ Agent::Codex => codex::detect(screen_content),
+ Agent::Gemini => gemini::detect(screen_content),
+ Agent::Cursor => cursor::detect(screen_content),
+ Agent::Antigravity => antigravity::detect(screen_content),
+ Agent::Cline => cline::detect(screen_content),
+ Agent::OpenCode => opencode::detect(screen_content),
+ Agent::GithubCopilot => github_copilot::detect(screen_content),
+ Agent::Kimi => kimi::detect(screen_content),
+ Agent::Kiro => kiro::detect(screen_content),
+ Agent::Droid => droid::detect(screen_content),
+ Agent::Amp => amp::detect(screen_content),
+ Agent::Grok => grok::detect(screen_content),
+ Agent::Hermes => hermes::detect(screen_content),
+ Agent::Qodercli => qodercli::detect(screen_content),
+ };
+
+ AgentDetection {
+ state,
+ visible_blocker: has_visible_blocker(agent, screen_content, state),
+ visible_idle: has_visible_idle(agent, screen_content, state),
+ visible_working: has_visible_working(agent, screen_content, state),
+ }
+}
+
+fn has_visible_blocker(agent: Agent, content: &str, state: AgentState) -> bool {
+ if state != AgentState::Blocked {
+ return false;
+ }
+
+ match agent {
+ // Strong visible blockers are opt-in because this flag can override
+ // hook authority. Plain blocked heuristics remain valid fallback state,
+ // but they must not become hook overrides unless the current UI chrome
+ // is known to be structural and live.
+ Agent::Claude => claude_code::has_visible_blocker(content),
+ Agent::Codex => codex::has_visible_blocker(content),
+ _ => false,
+ }
+}
+
+fn has_visible_idle(agent: Agent, content: &str, state: AgentState) -> bool {
+ if state != AgentState::Idle {
+ return false;
+ }
+
+ match agent {
+ Agent::Claude => claude_code::has_prompt_box(content),
+ Agent::Codex => codex::has_prompt(content),
+ _ => false,
+ }
+}
+
+fn has_visible_working(agent: Agent, content: &str, state: AgentState) -> bool {
+ if state != AgentState::Working {
+ return false;
+ }
+
+ match agent {
+ Agent::Claude => claude_code::has_working_chrome(content),
+ Agent::Codex => codex::has_visible_working(content),
+ _ => false,
+ }
+}