fastskill_core/validation/
dir_structure.rs1use crate::validation::result::{ErrorSeverity, ValidationResult};
4use std::path::Path;
5use tokio::fs;
6
7pub(crate) fn ensure_skill_md_exists(
8 skill_path: &Path,
9 mut result: ValidationResult,
10) -> ValidationResult {
11 let skill_file = skill_path.join("SKILL.md");
12 if !skill_file.exists() {
13 result = result.with_error(
14 "structure",
15 "Missing required SKILL.md file",
16 ErrorSeverity::Critical,
17 );
18 }
19 result
20}
21
22pub(crate) async fn scan_skill_directory_entries(
23 skill_path: &Path,
24 mut result: ValidationResult,
25) -> Result<(bool, bool, bool, ValidationResult), crate::core::service::ServiceError> {
26 let mut has_scripts = false;
27 let mut has_references = false;
28 let mut has_assets = false;
29 let mut entries = fs::read_dir(skill_path).await?;
30 while let Some(entry) = entries.next_entry().await? {
31 let path = entry.path();
32 let name = path
33 .file_name()
34 .map(|n| n.to_string_lossy().to_string())
35 .unwrap_or_else(|| "unknown".to_string());
36 match name.as_str() {
37 "SKILL.md" => {}
38 "scripts" => {
39 if path.is_dir() {
40 has_scripts = true;
41 } else {
42 result = result.with_warning("structure", "scripts should be a directory");
43 }
44 }
45 "references" => {
46 if path.is_dir() {
47 has_references = true;
48 } else {
49 result = result.with_warning("structure", "references should be a directory");
50 }
51 }
52 "assets" => {
53 if path.is_dir() {
54 has_assets = true;
55 } else {
56 result = result.with_warning("structure", "assets should be a directory");
57 }
58 }
59 _ => {
60 result = result
61 .with_warning("structure", &format!("Unexpected file/directory: {}", name));
62 }
63 }
64 }
65 Ok((has_scripts, has_references, has_assets, result))
66}