agentshield/adapter/
openclaw.rs1use std::path::Path;
2
3use crate::error::Result;
4use crate::ir::*;
5use crate::parser;
6
7pub struct OpenClawAdapter;
11
12impl super::Adapter for OpenClawAdapter {
13 fn framework(&self) -> Framework {
14 Framework::OpenClaw
15 }
16
17 fn detect(&self, root: &Path) -> bool {
18 root.join("SKILL.md").exists()
19 }
20
21 fn load(&self, root: &Path) -> Result<Vec<ScanTarget>> {
22 let name = root
23 .file_name()
24 .map(|n| n.to_string_lossy().to_string())
25 .unwrap_or_else(|| "openclaw-skill".into());
26
27 let mut source_files = Vec::new();
28 let mut execution = execution_surface::ExecutionSurface::default();
29
30 let walker = ignore::WalkBuilder::new(root)
32 .hidden(true)
33 .git_ignore(true)
34 .max_depth(Some(3))
35 .build();
36
37 for entry in walker.flatten() {
38 let path = entry.path();
39 if !path.is_file() {
40 continue;
41 }
42 let ext = path
43 .extension()
44 .map(|e| e.to_string_lossy().to_string())
45 .unwrap_or_default();
46 let lang = Language::from_extension(&ext);
47
48 if !matches!(
49 lang,
50 Language::Python | Language::Shell | Language::Markdown
51 ) {
52 continue;
53 }
54
55 let metadata = std::fs::metadata(path)?;
56 if metadata.len() > 1_048_576 {
57 continue;
58 }
59
60 if let Ok(content) = std::fs::read_to_string(path) {
61 use sha2::Digest;
62 let hash = format!(
63 "{:x}",
64 sha2::Sha256::new()
65 .chain_update(content.as_bytes())
66 .finalize()
67 );
68 source_files.push(SourceFile {
69 path: path.to_path_buf(),
70 language: lang,
71 size_bytes: metadata.len(),
72 content_hash: hash,
73 content,
74 });
75 }
76 }
77
78 for sf in &source_files {
80 if let Some(parser) = parser::parser_for_language(sf.language) {
81 if let Ok(parsed) = parser.parse_file(&sf.path, &sf.content) {
82 execution.commands.extend(parsed.commands);
83 execution.file_operations.extend(parsed.file_operations);
84 execution
85 .network_operations
86 .extend(parsed.network_operations);
87 execution.env_accesses.extend(parsed.env_accesses);
88 execution.dynamic_exec.extend(parsed.dynamic_exec);
89 }
90 }
91 }
92
93 Ok(vec![ScanTarget {
94 name,
95 framework: Framework::OpenClaw,
96 root_path: root.to_path_buf(),
97 tools: vec![],
98 execution,
99 data: Default::default(),
100 dependencies: Default::default(),
101 provenance: Default::default(),
102 source_files,
103 }])
104 }
105}