use crate::model::Strategy;
use crate::provider::Provider;
use crate::workspace::{FsResult, Workspace};
pub fn evidence(providers: &[&Provider], ws: &dyn Workspace) -> FsResult<Vec<String>> {
let mut found = Vec::new();
for provider in providers {
if has_evidence(provider, ws)? {
found.push(provider.id.clone());
}
}
Ok(found)
}
fn has_evidence(provider: &Provider, ws: &dyn Workspace) -> FsResult<bool> {
for capability in &provider.capabilities {
if capability.strategy == Strategy::Native {
continue;
}
if ws.probe(&capability.path)?.is_some() {
return Ok(true);
}
}
Ok(false)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::layout::Layout;
use crate::registry::Registry;
use crate::testing::FakeWorkspace;
fn registry() -> Registry {
Registry::builtin(&Layout::default()).unwrap()
}
fn ids(registry: &Registry, ws: &FakeWorkspace) -> Vec<String> {
let providers: Vec<&Provider> = registry.all().iter().collect();
evidence(&providers, ws).unwrap()
}
#[test]
fn a_repository_that_only_ever_used_claude_code_detects_only_it() {
let ws = FakeWorkspace::unix();
ws.add_file("CLAUDE.md", "# rules\n");
ws.add_dir(".claude/skills");
assert_eq!(ids(®istry(), &ws), vec!["claude-code".to_string()]);
}
#[test]
fn a_fully_native_provider_never_counts_as_evidence() {
let ws = FakeWorkspace::unix();
ws.add_file("AGENTS.md", "# rules\n");
ws.add_dir(".agents/skills");
assert!(ids(®istry(), &ws).is_empty());
}
#[test]
fn an_empty_workspace_detects_nothing() {
assert!(ids(®istry(), &FakeWorkspace::unix()).is_empty());
}
#[test]
fn a_link_at_a_provider_path_is_still_evidence() {
let ws = FakeWorkspace::unix();
ws.add_dir(".agents/skills");
ws.add_link(
".cursor/skills",
crate::model::NodeKind::Dir,
".agents/skills",
);
assert_eq!(ids(®istry(), &ws), vec!["cursor".to_string()]);
}
}