From e0758c32118f2aa006db3d8fa4b41833fe6e7ead Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Fri, 17 Jul 2026 23:55:08 +0300 Subject: feat: harden named agent cli workflows refs #1525 --- src/detect/mod.rs | 108 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 25 deletions(-) (limited to 'src/detect') diff --git a/src/detect/mod.rs b/src/detect/mod.rs index 5c220b52..53c3213a 100644 --- a/src/detect/mod.rs +++ b/src/detect/mod.rs @@ -65,6 +65,31 @@ pub enum Agent { } impl Agent { + #[cfg(test)] + pub const ALL: [Self; 21] = [ + Self::Pi, + Self::Claude, + Self::Codex, + Self::Gemini, + Self::Cursor, + Self::Devin, + Self::Antigravity, + Self::Cline, + Self::Omp, + Self::Mastracode, + Self::OpenCode, + Self::GithubCopilot, + Self::Kimi, + Self::Kiro, + Self::Droid, + Self::Amp, + Self::Grok, + Self::Hermes, + Self::Kilo, + Self::Qodercli, + Self::Maki, + ]; + pub const SCREEN_MANIFEST_AGENTS: [Self; 19] = [ Self::Pi, Self::Claude, @@ -114,6 +139,32 @@ pub fn agent_label(agent: Agent) -> &'static str { } } +pub fn interactive_agent_executable(agent: Agent) -> &'static str { + match agent { + Agent::Pi => "pi", + Agent::Claude => "claude", + Agent::Codex => "codex", + Agent::Gemini => "gemini", + Agent::Cursor => "cursor-agent", + Agent::Devin => "devin", + Agent::Antigravity => "agy", + Agent::Cline => "cline", + Agent::Omp => "omp", + Agent::Mastracode => "mastracode", + Agent::OpenCode => "opencode", + Agent::GithubCopilot => "copilot", + Agent::Kimi => "kimi", + Agent::Kiro => "kiro-cli", + Agent::Droid => "droid", + Agent::Amp => "amp", + Agent::Grok => "grok", + Agent::Hermes => "hermes", + Agent::Kilo => "kilo", + Agent::Qodercli => "qodercli", + Agent::Maki => "maki", + } +} + pub fn parse_agent_label(agent: &str) -> Option { let name = normalized_agent_lookup_name(agent); parse_canonical_agent_label(&name).or_else(|| lookup_agent(&name)) @@ -662,37 +713,44 @@ mod tests { #[test] fn every_agent_label_round_trips_through_canonical_and_alias_parsers() { - let agents = [ - Agent::Pi, - Agent::Claude, - Agent::Codex, - Agent::Gemini, - Agent::Cursor, - Agent::Devin, - Agent::Antigravity, - Agent::Cline, - Agent::Omp, - Agent::Mastracode, - Agent::OpenCode, - Agent::GithubCopilot, - Agent::Kimi, - Agent::Kiro, - Agent::Droid, - Agent::Amp, - Agent::Grok, - Agent::Hermes, - Agent::Kilo, - Agent::Qodercli, - Agent::Maki, - ]; - - for agent in agents { + for agent in Agent::ALL { let label = agent_label(agent); assert_eq!(parse_canonical_agent_label(label), Some(agent)); assert_eq!(parse_agent_label(label), Some(agent)); } } + #[test] + fn every_agent_has_a_canonical_interactive_executable() { + let expected = [ + (Agent::Pi, "pi"), + (Agent::Claude, "claude"), + (Agent::Codex, "codex"), + (Agent::Gemini, "gemini"), + (Agent::Cursor, "cursor-agent"), + (Agent::Devin, "devin"), + (Agent::Antigravity, "agy"), + (Agent::Cline, "cline"), + (Agent::Omp, "omp"), + (Agent::Mastracode, "mastracode"), + (Agent::OpenCode, "opencode"), + (Agent::GithubCopilot, "copilot"), + (Agent::Kimi, "kimi"), + (Agent::Kiro, "kiro-cli"), + (Agent::Droid, "droid"), + (Agent::Amp, "amp"), + (Agent::Grok, "grok"), + (Agent::Hermes, "hermes"), + (Agent::Kilo, "kilo"), + (Agent::Qodercli, "qodercli"), + (Agent::Maki, "maki"), + ]; + assert_eq!(expected.len(), Agent::ALL.len()); + for (agent, executable) in expected { + assert_eq!(interactive_agent_executable(agent), executable); + } + } + #[test] fn canonical_agent_labels_are_strict() { assert_eq!(parse_canonical_agent_label("claude-code"), None); -- cgit v1.2.3