pub mod crewai;
pub mod cursor_rules;
pub mod gpt_actions;
pub mod langchain;
pub mod mcp;
pub mod openclaw;
use std::path::Path;
use crate::error::{Result, ShieldError};
use crate::ir::{Framework, ScanTarget};
pub trait Adapter: Send + Sync {
fn framework(&self) -> Framework;
fn detect(&self, root: &Path) -> bool;
fn load(&self, root: &Path, ignore_tests: bool) -> Result<Vec<ScanTarget>>;
}
pub fn all_adapters() -> Vec<Box<dyn Adapter>> {
vec![
Box::new(mcp::McpAdapter),
Box::new(openclaw::OpenClawAdapter),
Box::new(crewai::CrewAiAdapter),
Box::new(langchain::LangChainAdapter),
Box::new(gpt_actions::GptActionsAdapter),
Box::new(cursor_rules::CursorRulesAdapter),
]
}
pub fn auto_detect_and_load(root: &Path, ignore_tests: bool) -> Result<Vec<ScanTarget>> {
let adapters = all_adapters();
let mut all_targets = Vec::new();
for adapter in &adapters {
if adapter.detect(root) {
match adapter.load(root, ignore_tests) {
Ok(targets) => all_targets.extend(targets),
Err(e) => {
tracing::warn!(
framework = %adapter.framework(),
error = %e,
"adapter failed to load, skipping"
);
}
}
}
}
if all_targets.is_empty() {
return Err(ShieldError::NoAdapter(root.display().to_string()));
}
Ok(all_targets)
}