pub(crate) const KNOWN_AGENTS: &[&str] = &[
"claude",
"codex",
"opencode",
"gemini",
"cursor",
"cline",
"devin",
"qwen-code",
"copilot-cli",
"vscode-copilot",
"jetbrains-copilot",
"kimi",
"kiro",
"zed",
"omp",
"openclaw",
"kilo",
"antigravity",
"antigravity-cli",
"pi",
"goose",
"amp",
"crush",
"droid",
"augment",
];
pub(crate) fn feature_const_ident(id: &str) -> String {
id.replace('-', "_").to_uppercase()
}
#[cfg(test)]
mod tests {
use super::*;
const REGISTRY: &str = include_str!("../../agentgear/src/agents/mod.rs");
const FEATURE_CHECK: &str = include_str!("../../agentgear/src/__feature_check.rs");
fn leading_quoted(line: &str) -> Option<&str> {
line.trim_start().strip_prefix('"')?.split('"').next()
}
#[test]
fn known_agents_match_the_lib() {
let mut known: Vec<&str> = KNOWN_AGENTS.to_vec();
known.sort_unstable();
let mut arms: Vec<&str> = REGISTRY.lines().filter(|line| line.contains("=> Some(Box::new(")).filter_map(leading_quoted).collect();
arms.sort_unstable();
assert!(!arms.is_empty(), "no `backend_for` arms found; the extraction pattern is stale");
assert_eq!(arms, known, "derive KNOWN_AGENTS vs lib backend_for arms");
let mut consts: Vec<(String, String)> = FEATURE_CHECK
.lines()
.map(str::trim)
.filter(|line| line.starts_with('"') && line.contains("=>"))
.filter_map(|line| {
let feature = leading_quoted(line)?;
let ident = line.split("=>").nth(1)?.trim().trim_end_matches(',');
Some((feature.to_string(), ident.to_string()))
})
.collect();
consts.sort_unstable();
let mut expected: Vec<(String, String)> = KNOWN_AGENTS.iter().map(|id| (id.to_string(), feature_const_ident(id))).collect();
expected.sort_unstable();
assert_eq!(consts, expected, "derive KNOWN_AGENTS vs lib __feature_check consts");
}
}