190 lines
6.4 KiB
Rust
190 lines
6.4 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use ai::skills::{ParsedSkill, SkillProvider, SkillScope};
|
|
use warp_util::host_id::HostId;
|
|
use warp_util::local_or_remote_path::LocalOrRemotePath;
|
|
use warp_util::remote_path::RemotePath;
|
|
use warp_util::standardized_path::StandardizedPath;
|
|
|
|
use super::*;
|
|
|
|
fn remote_location(path: &str) -> LocalOrRemotePath {
|
|
LocalOrRemotePath::Remote(RemotePath::new(
|
|
HostId::new("remote-host".to_string()),
|
|
StandardizedPath::try_new(path).unwrap(),
|
|
))
|
|
}
|
|
|
|
#[test]
|
|
fn skill_path_from_unix_encoded_remote_location() {
|
|
let location = remote_location("/repo/.agents/skills/deploy/scripts/run.sh");
|
|
|
|
assert_eq!(
|
|
skill_path_from_location(&location),
|
|
Some(remote_location("/repo/.agents/skills/deploy/SKILL.md"))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn skill_path_from_windows_encoded_remote_location() {
|
|
let location = remote_location(r"C:\repo\.agents\skills\deploy\scripts\run.ps1");
|
|
|
|
assert_eq!(
|
|
skill_path_from_location(&location),
|
|
Some(remote_location(r"C:\repo\.agents\skills\deploy\SKILL.md"))
|
|
);
|
|
}
|
|
#[test]
|
|
fn test_unique_skills_dedupes_identical_skills_same_dir() {
|
|
let shared_skill_dir = PathBuf::from("/home/user");
|
|
let skill_path1 = shared_skill_dir.join(".agents/skills/my-skill/SKILL.md");
|
|
let skill_path2 = shared_skill_dir.join(".claude/skills/my-skill/SKILL.md");
|
|
|
|
let content = "---\nname: test-skill\ndescription: A test skill\n---\nContent here";
|
|
let skill = ParsedSkill {
|
|
path: LocalOrRemotePath::Local(skill_path1.clone()),
|
|
name: "test-skill".to_string(),
|
|
description: "A test skill".to_string(),
|
|
content: content.to_string(),
|
|
line_range: Some(8..18),
|
|
provider: SkillProvider::Agents,
|
|
scope: SkillScope::Home,
|
|
};
|
|
|
|
let skill2 = ParsedSkill {
|
|
path: LocalOrRemotePath::Local(skill_path2.clone()),
|
|
name: "test-skill".to_string(),
|
|
description: "A test skill".to_string(),
|
|
content: content.to_string(),
|
|
line_range: Some(8..18),
|
|
provider: SkillProvider::Claude,
|
|
scope: SkillScope::Home,
|
|
};
|
|
|
|
let mut skills_by_path = HashMap::new();
|
|
skills_by_path.insert(LocalOrRemotePath::Local(skill_path1.clone()), skill);
|
|
skills_by_path.insert(LocalOrRemotePath::Local(skill_path2.clone()), skill2);
|
|
|
|
let skill_paths = vec![
|
|
(
|
|
LocalOrRemotePath::Local(shared_skill_dir.clone()),
|
|
LocalOrRemotePath::Local(skill_path1),
|
|
),
|
|
(
|
|
LocalOrRemotePath::Local(shared_skill_dir),
|
|
LocalOrRemotePath::Local(skill_path2),
|
|
),
|
|
];
|
|
|
|
let result = unique_skills(&skill_paths, &skills_by_path);
|
|
assert_eq!(result.len(), 1);
|
|
// Agents has higher priority (index 0) than Claude, so it should be preferred
|
|
assert_eq!(result[0].provider, SkillProvider::Agents);
|
|
}
|
|
|
|
#[test]
|
|
fn test_unique_skills_does_not_dedupe_different_dirs() {
|
|
let home_dir = PathBuf::from("/home/user");
|
|
let project_dir = PathBuf::from("/home/user/projects/repo");
|
|
let home_path = home_dir.join(".agents/skills/my-skill/SKILL.md");
|
|
let project_path = project_dir.join(".agents/skills/my-skill/SKILL.md");
|
|
|
|
let content = "---\nname: test-skill\ndescription: A test skill\n---\nContent here";
|
|
let home_skill = ParsedSkill {
|
|
path: LocalOrRemotePath::Local(home_path.clone()),
|
|
name: "test-skill".to_string(),
|
|
description: "A test skill".to_string(),
|
|
content: content.to_string(),
|
|
line_range: Some(8..18),
|
|
provider: SkillProvider::Agents,
|
|
scope: SkillScope::Home,
|
|
};
|
|
|
|
let project_skill = ParsedSkill {
|
|
path: LocalOrRemotePath::Local(project_path.clone()),
|
|
name: "test-skill".to_string(),
|
|
description: "A test skill".to_string(),
|
|
content: content.to_string(),
|
|
line_range: Some(8..18),
|
|
provider: SkillProvider::Agents,
|
|
scope: SkillScope::Project,
|
|
};
|
|
|
|
let mut skills_by_path = HashMap::new();
|
|
skills_by_path.insert(LocalOrRemotePath::Local(home_path.clone()), home_skill);
|
|
skills_by_path.insert(
|
|
LocalOrRemotePath::Local(project_path.clone()),
|
|
project_skill,
|
|
);
|
|
|
|
let skill_paths = vec![
|
|
(
|
|
LocalOrRemotePath::Local(home_dir),
|
|
LocalOrRemotePath::Local(home_path),
|
|
),
|
|
(
|
|
LocalOrRemotePath::Local(project_dir),
|
|
LocalOrRemotePath::Local(project_path),
|
|
),
|
|
];
|
|
|
|
let result = unique_skills(&skill_paths, &skills_by_path);
|
|
assert_eq!(
|
|
result.len(),
|
|
2,
|
|
"Skills with same content but different directories should not be deduped"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_unique_skills_does_not_dedupe_different_content() {
|
|
let shared_skill_dir = PathBuf::from("/home/user");
|
|
let skill_path1 = shared_skill_dir.join(".agents/skills/my-skill/SKILL.md");
|
|
let skill_path2 = shared_skill_dir.join(".claude/skills/my-skill/SKILL.md");
|
|
|
|
let content1 = "---\nname: test-skill\ndescription: A test skill\n---\nContent here";
|
|
let content2 = "---\nname: test-skill\ndescription: A test skill\n---\nDifferent content";
|
|
|
|
let skill1 = ParsedSkill {
|
|
path: LocalOrRemotePath::Local(skill_path1.clone()),
|
|
name: "test-skill".to_string(),
|
|
description: "A test skill".to_string(),
|
|
content: content1.to_string(),
|
|
line_range: Some(8..18),
|
|
provider: SkillProvider::Agents,
|
|
scope: SkillScope::Home,
|
|
};
|
|
|
|
let skill2 = ParsedSkill {
|
|
path: LocalOrRemotePath::Local(skill_path2.clone()),
|
|
name: "test-skill".to_string(),
|
|
description: "A test skill".to_string(),
|
|
content: content2.to_string(),
|
|
line_range: Some(8..18),
|
|
provider: SkillProvider::Claude,
|
|
scope: SkillScope::Home,
|
|
};
|
|
|
|
let mut skills_by_path = HashMap::new();
|
|
skills_by_path.insert(LocalOrRemotePath::Local(skill_path1.clone()), skill1);
|
|
skills_by_path.insert(LocalOrRemotePath::Local(skill_path2.clone()), skill2);
|
|
|
|
let skill_paths = vec![
|
|
(
|
|
LocalOrRemotePath::Local(shared_skill_dir.clone()),
|
|
LocalOrRemotePath::Local(skill_path1),
|
|
),
|
|
(
|
|
LocalOrRemotePath::Local(shared_skill_dir),
|
|
LocalOrRemotePath::Local(skill_path2),
|
|
),
|
|
];
|
|
|
|
let result = unique_skills(&skill_paths, &skills_by_path);
|
|
assert_eq!(
|
|
result.len(),
|
|
2,
|
|
"Skills with different content should not be deduped even if same directory and name"
|
|
);
|
|
}
|