agentshield/adapter/
mod.rs1pub mod crewai;
2pub mod cursor_rules;
3pub mod gpt_actions;
4pub mod langchain;
5pub mod mcp;
6pub mod openclaw;
7
8use std::path::Path;
9
10use crate::error::{Result, ShieldError};
11use crate::ir::{Framework, ScanTarget};
12
13pub trait Adapter: Send + Sync {
16 fn framework(&self) -> Framework;
18
19 fn detect(&self, root: &Path) -> bool;
21
22 fn load(&self, root: &Path, ignore_tests: bool) -> Result<Vec<ScanTarget>>;
25}
26
27pub fn all_adapters() -> Vec<Box<dyn Adapter>> {
29 vec![
30 Box::new(mcp::McpAdapter),
31 Box::new(openclaw::OpenClawAdapter),
32 Box::new(crewai::CrewAiAdapter),
33 Box::new(langchain::LangChainAdapter),
34 Box::new(gpt_actions::GptActionsAdapter),
35 Box::new(cursor_rules::CursorRulesAdapter),
36 ]
37}
38
39pub fn auto_detect_and_load(root: &Path, ignore_tests: bool) -> Result<Vec<ScanTarget>> {
44 let adapters = all_adapters();
45 let mut all_targets = Vec::new();
46
47 for adapter in &adapters {
48 if adapter.detect(root) {
49 match adapter.load(root, ignore_tests) {
50 Ok(targets) => all_targets.extend(targets),
51 Err(e) => {
52 tracing::warn!(
53 framework = %adapter.framework(),
54 error = %e,
55 "adapter failed to load, skipping"
56 );
57 }
58 }
59 }
60 }
61
62 if all_targets.is_empty() {
63 return Err(ShieldError::NoAdapter(root.display().to_string()));
64 }
65
66 Ok(all_targets)
67}