fix(summon): skip non-recipe project config files (#9808)

Signed-off-by: Douwe M Osinga <douwe@sidewalklabs.com>
Co-authored-by: Douwe M Osinga <douwe@sidewalklabs.com>
This commit is contained in:
Thump604
2026-06-17 11:23:08 -05:00
committed by GitHub
parent e3dbb86742
commit 80a286da8c
@@ -142,6 +142,7 @@ fn parse_agent_content(content: &str, path: &Path) -> Option<SourceEntry> {
fn scan_recipes_from_dir(
dir: &Path,
kind: SourceType,
suppress_config_warnings: bool,
sources: &mut Vec<SourceEntry>,
seen: &mut std::collections::HashSet<String>,
) {
@@ -187,6 +188,13 @@ fn scan_recipes_from_dir(
});
}
Err(e) => {
// The working directory commonly contains project config like package.json
// and tsconfig.json, which parse as valid JSON but lack Recipe fields. In that
// case treat them as "not a recipe" rather than warning. Dedicated recipe
// directories still warn so a real recipe with a typo is not silently dropped.
if suppress_config_warnings && e.to_string().contains("missing field") {
continue;
}
warn!("Failed to parse recipe {}: {}", path.display(), e);
}
}
@@ -239,7 +247,6 @@ pub fn discover_filesystem_sources(working_dir: &Path) -> Vec<SourceEntry> {
let config = Paths::config_dir();
let local_recipe_dirs: Vec<PathBuf> = vec![
working_dir.to_path_buf(),
working_dir.join(".goose/recipes"),
working_dir.join(".agents/recipes"),
];
@@ -278,8 +285,16 @@ pub fn discover_filesystem_sources(working_dir: &Path) -> Vec<SourceEntry> {
.flatten()
.collect();
scan_recipes_from_dir(
working_dir,
SourceType::Recipe,
true,
&mut sources,
&mut seen,
);
for dir in local_recipe_dirs {
scan_recipes_from_dir(&dir, SourceType::Recipe, &mut sources, &mut seen);
scan_recipes_from_dir(&dir, SourceType::Recipe, false, &mut sources, &mut seen);
}
for dir in local_agent_dirs {
@@ -287,7 +302,7 @@ pub fn discover_filesystem_sources(working_dir: &Path) -> Vec<SourceEntry> {
}
for dir in global_recipe_dirs {
scan_recipes_from_dir(&dir, SourceType::Recipe, &mut sources, &mut seen);
scan_recipes_from_dir(&dir, SourceType::Recipe, false, &mut sources, &mut seen);
}
for dir in global_agent_dirs {
@@ -2072,6 +2087,40 @@ You review code."#;
assert_eq!(sources[0].name, "reviewer");
}
#[test]
fn test_recipe_scan_skips_non_recipe_project_config_files() {
let temp_dir = TempDir::new().unwrap();
fs::write(
temp_dir.path().join("package.json"),
r#"{"scripts":{"test":"cargo test"}}"#,
)
.unwrap();
fs::write(
temp_dir.path().join("tsconfig.json"),
r#"{"compilerOptions":{"strict":true}}"#,
)
.unwrap();
fs::write(
temp_dir.path().join("valid.yaml"),
"title: Valid\ndescription: Real recipe\ninstructions: Run valid steps",
)
.unwrap();
let mut sources = Vec::new();
let mut seen = HashSet::new();
scan_recipes_from_dir(
temp_dir.path(),
SourceType::Recipe,
true,
&mut sources,
&mut seen,
);
assert_eq!(sources.len(), 1);
assert_eq!(sources[0].name, "valid");
assert_eq!(sources[0].description, "Real recipe");
}
#[tokio::test]
async fn test_discover_recipes_and_agents() {
let temp_dir = TempDir::new().unwrap();