Allow sharing nested skill files

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
This commit is contained in:
morgmart
2026-05-04 19:49:34 -07:00
parent ec61ffbe5a
commit a8a3de5773
2 changed files with 57 additions and 6 deletions
+24 -6
View File
@@ -103,6 +103,24 @@ fn has_sequence_with_remaining(path: &Path, sequence: &[&str], remaining: usize)
})
}
fn has_sequence_with_min_remaining(
path: &Path,
sequence: &[&str],
minimum_remaining: usize,
) -> bool {
let components = path_components(path);
components
.windows(sequence.len())
.enumerate()
.any(|(index, window)| {
window
.iter()
.map(String::as_str)
.eq(sequence.iter().copied())
&& components.len() >= index + sequence.len() + minimum_remaining
})
}
fn is_shareable_agent_file(path: &Path) -> bool {
path.extension().and_then(|extension| extension.to_str()) == Some("md")
&& (has_sequence_with_remaining(path, &[".agents", "agents"], 1)
@@ -111,11 +129,11 @@ fn is_shareable_agent_file(path: &Path) -> bool {
fn is_shareable_skill_file(path: &Path) -> bool {
path.file_name().and_then(|name| name.to_str()) == Some("SKILL.md")
&& (has_sequence_with_remaining(path, &[".agents", "skills"], 2)
|| has_sequence_with_remaining(path, &[".goose", "skills"], 2)
|| has_sequence_with_remaining(path, &[".claude", "skills"], 2)
|| has_sequence_with_remaining(path, &[".config", "agents", "skills"], 2)
|| has_sequence_with_remaining(path, &["goose", "skills"], 2)
&& (has_sequence_with_min_remaining(path, &[".agents", "skills"], 2)
|| has_sequence_with_min_remaining(path, &[".goose", "skills"], 2)
|| has_sequence_with_min_remaining(path, &[".claude", "skills"], 2)
|| has_sequence_with_min_remaining(path, &[".config", "agents", "skills"], 2)
|| has_sequence_with_min_remaining(path, &["goose", "skills"], 2)
|| is_plugin_skill_file(path))
}
@@ -125,7 +143,7 @@ fn is_plugin_skill_file(path: &Path) -> bool {
window[0] == "goose"
&& window[1] == "plugins"
&& window[3] == "skills"
&& components.len() == index + 6
&& components.len() >= index + 6
})
}
@@ -281,6 +281,13 @@ fn shareable_source_validation_accepts_agent_and_skill_files() {
.join("skills")
.join("review")
.join("SKILL.md");
let nested_skill_file = dir
.path()
.join(".agents")
.join("skills")
.join("team")
.join("review")
.join("SKILL.md");
let config_skill_file = dir
.path()
.join("Block")
@@ -297,21 +304,47 @@ fn shareable_source_validation_accepts_agent_and_skill_files() {
.join("skills")
.join("plugin-review")
.join("SKILL.md");
let nested_plugin_skill_file = dir
.path()
.join("Block")
.join("goose")
.join("plugins")
.join("plugin-a")
.join("skills")
.join("team")
.join("plugin-review")
.join("SKILL.md");
fs::create_dir_all(agent_file.parent().expect("agent parent")).expect("agent dir");
fs::create_dir_all(skill_file.parent().expect("skill parent")).expect("skill dir");
fs::create_dir_all(nested_skill_file.parent().expect("nested skill parent"))
.expect("nested skill dir");
fs::create_dir_all(config_skill_file.parent().expect("config skill parent"))
.expect("config skill dir");
fs::create_dir_all(plugin_skill_file.parent().expect("plugin skill parent"))
.expect("plugin skill dir");
fs::create_dir_all(
nested_plugin_skill_file
.parent()
.expect("nested plugin skill parent"),
)
.expect("nested plugin skill dir");
fs::write(&agent_file, "---\nname: Helper\n---\n").expect("agent file");
fs::write(&skill_file, "---\nname: review\n---\n").expect("skill file");
fs::write(&nested_skill_file, "---\nname: team-review\n---\n").expect("nested skill file");
fs::write(&config_skill_file, "---\nname: legacy\n---\n").expect("config skill file");
fs::write(&plugin_skill_file, "---\nname: plugin-review\n---\n").expect("plugin skill file");
fs::write(
&nested_plugin_skill_file,
"---\nname: nested-plugin-review\n---\n",
)
.expect("nested plugin skill file");
assert!(validate_shareable_source_file(&agent_file).is_ok());
assert!(validate_shareable_source_file(&skill_file).is_ok());
assert!(validate_shareable_source_file(&nested_skill_file).is_ok());
assert!(validate_shareable_source_file(&config_skill_file).is_ok());
assert!(validate_shareable_source_file(&plugin_skill_file).is_ok());
assert!(validate_shareable_source_file(&nested_plugin_skill_file).is_ok());
}
#[test]