Skip to main content

skilllite_evolution/skill_synth/
scan.rs

1//! L4 安全扫描、技能使用追踪
2
3use std::path::Path;
4
5use anyhow::Result;
6
7use skilllite_sandbox::security::scanner::ScriptScanner;
8
9use super::SkillMeta;
10
11/// Detect if skill_md_content declares network requirement.
12pub(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
35/// Update .meta.json after a skill execution (called from agent_loop).
36pub 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}