From 4617cae7e0e4e47a471deeaebd810328ad857f38 Mon Sep 17 00:00:00 2001 From: Lifei Zhou Date: Mon, 12 Jan 2026 18:31:34 +1100 Subject: [PATCH] check skills with optional rules excluding the symlinks --- Cargo.lock | 2 +- src/agents/claude.rs | 6 +----- src/operations/claude_skills.rs | 30 +++++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2525cd0..8d32ab8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ [[package]] name = "ai-rules" -version = "1.2.0" +version = "1.3.0" dependencies = [ "anyhow", "clap", diff --git a/src/agents/claude.rs b/src/agents/claude.rs index 89b8890..ee1962f 100644 --- a/src/agents/claude.rs +++ b/src/agents/claude.rs @@ -41,11 +41,7 @@ impl AgentRuleGenerator for ClaudeGenerator { if output_file.exists() || output_file.is_symlink() { fs::remove_file(&output_file)?; } - - // Only clean skills if in skills mode - if self.skills_mode { - claude_skills::remove_generated_skills(current_dir)?; - } + claude_skills::remove_generated_skills(current_dir)?; Ok(()) } diff --git a/src/operations/claude_skills.rs b/src/operations/claude_skills.rs index 28a87d5..ac86ddd 100644 --- a/src/operations/claude_skills.rs +++ b/src/operations/claude_skills.rs @@ -113,7 +113,10 @@ pub fn check_skills_in_sync( std::fs::read_dir(&skills_dir)? .filter_map(Result::ok) .filter(|entry| { - entry.path().is_dir() + let path = entry.path(); + // Only count directories, not symlinks (symlinks are handled by ExternalSkillsGenerator) + path.is_dir() + && !path.is_symlink() && entry .file_name() .to_str() @@ -391,4 +394,29 @@ mod tests { let result = check_skills_in_sync(&source_files, temp_dir.path()).unwrap(); assert!(!result); } + + #[test] + fn test_check_skills_in_sync_ignores_symlinks() { + let temp_dir = TempDir::new().unwrap(); + let source_files = vec![create_test_source_file( + "optional", "Optional", false, "Content", + )]; + + create_skill_file( + temp_dir.path(), + "ai-rules-generated-optional", + &generate_skill_content("optional", "Optional", "optional"), + ); + + let skills_dir = temp_dir.path().join(CLAUDE_SKILLS_DIR); + let symlink_target = temp_dir.path().join("fake-skill"); + std::fs::create_dir_all(&symlink_target).unwrap(); + std::os::unix::fs::symlink( + &symlink_target, + skills_dir.join("ai-rules-generated-symlink"), + ) + .unwrap(); + + assert!(check_skills_in_sync(&source_files, temp_dir.path()).unwrap()); + } }