skilllite_evolution/skill_synth/
scan.rs1use std::path::Path;
4
5use anyhow::Result;
6
7use skilllite_sandbox::security::scanner::ScriptScanner;
8
9use super::SkillMeta;
10
11pub(super) fn skill_md_needs_network(skill_md: &str) -> bool {
13 let lower = skill_md.to_lowercase();
14 lower.contains("network access")
15 || lower.contains("network")
16 || lower.contains("需网络")
17 || lower.contains("需网络权限")
18 || lower.contains("internet")
19 || lower.contains("api access")
20}
21
22pub(super) fn run_l4_scan(
23 script_content: &str,
24 script_path: &Path,
25 allow_network: bool,
26) -> Result<bool> {
27 let scanner = ScriptScanner::new().allow_network(allow_network);
28 let result = scanner.scan_content(script_content, script_path)?;
29 if !result.is_safe {
30 tracing::warn!("L4 security scan found issues in {}", script_path.display());
31 }
32 Ok(result.is_safe)
33}
34
35pub fn track_skill_usage(evolved_dir: &Path, skill_name: &str, success: bool) {
37 let meta_path = evolved_dir.join(skill_name).join(".meta.json");
38 if !meta_path.exists() {
39 return;
40 }
41 let mut meta: SkillMeta = match skilllite_fs::read_file(&meta_path)
42 .ok()
43 .and_then(|s| serde_json::from_str(&s).ok())
44 {
45 Some(m) => m,
46 None => return,
47 };
48
49 meta.call_count += 1;
50 if success {
51 meta.success_count += 1;
52 } else {
53 meta.failure_count += 1;
54 }
55 meta.last_used = Some(chrono::Utc::now().to_rfc3339());
56
57 let _ = skilllite_fs::write_file(
58 &meta_path,
59 &serde_json::to_string_pretty(&meta).unwrap_or_default(),
60 );
61}