From 21ceb3d325905140531bfb31363cb12e7db1460b Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Fri, 8 May 2026 09:52:24 -0400 Subject: [PATCH] properties and global --- crates/goose/src/sources.rs | 39 +++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/crates/goose/src/sources.rs b/crates/goose/src/sources.rs index 26f1a55cc3..dc31141cb7 100644 --- a/crates/goose/src/sources.rs +++ b/crates/goose/src/sources.rs @@ -164,6 +164,18 @@ fn read_existing_project_properties(file: &Path) -> HashMap HashMap { + let raw = match fs::read_to_string(file) { + Ok(s) => s, + Err(_) => return HashMap::new(), + }; + match parse_agent_frontmatter(&raw) { + Ok((frontmatter, _)) => frontmatter.properties, + Err(_) => HashMap::new(), + } +} + fn project_entry_from_file(file: &Path) -> Option { let slug = file.file_stem().and_then(|s| s.to_str())?.to_string(); if slug.is_empty() { @@ -419,6 +431,7 @@ fn reject_read_only_agent_file(path: &Path, additional_roots: &[SourceRoot]) -> fn is_global_agent_file(path: &Path) -> bool { let canonical_path = canonicalize_or_original(path); let mut global_roots = Vec::new(); + global_roots.push(Paths::agents_dir()); if let Some(home) = dirs::home_dir() { global_roots.push(home.join(".agents").join("agents")); global_roots.push(home.join(".goose").join("agents")); @@ -488,6 +501,10 @@ fn list_agent_dirs(working_dir: Option<&Path>, additional_roots: &[SourceRoot]) }); } + dirs.push(SourceRoot { + path: Paths::agents_dir(), + writable: true, + }); if let Some(home) = dirs::home_dir() { dirs.push(SourceRoot { path: home.join(".agents").join("agents"), @@ -510,6 +527,13 @@ fn list_agent_dirs(working_dir: Option<&Path>, additional_roots: &[SourceRoot]) dirs } +fn is_project_agent_file(path: &Path, working_dir: &Path) -> bool { + [".agents", ".goose", ".claude"] + .into_iter() + .map(|dir| working_dir.join(dir).join("agents")) + .any(|root| is_under_root(path, &root)) +} + fn list_agent_sources( project_dir: Option<&str>, additional_roots: &[SourceRoot], @@ -531,7 +555,10 @@ fn list_agent_sources( if path.extension().and_then(|ext| ext.to_str()) != Some("md") { continue; } - match agent_source_entry(&path, !root.writable, root.writable) { + let global = working_dir + .as_deref() + .is_none_or(|working_dir| !is_project_agent_file(&path, working_dir)); + match agent_source_entry(&path, global, root.writable) { Ok(source) => { let key = source.name.to_lowercase(); if seen.insert(key) { @@ -584,14 +611,18 @@ fn update_agent_source( name: &str, description: &str, content: &str, - properties: HashMap, + properties: Option>, additional_roots: &[SourceRoot], ) -> Result { validate_agent_name(name)?; let file_path = resolve_agent_file_with_roots(path, additional_roots)?; reject_read_only_agent_file(&file_path, additional_roots)?; let global = is_global_agent_file(&file_path); - let md = build_source_markdown(name, description, content, &properties)?; + let resolved_properties = match properties { + Some(p) => p, + None => read_existing_agent_properties(&file_path), + }; + let md = build_source_markdown(name, description, content, &resolved_properties)?; fs::write(&file_path, md) .map_err(|e| Error::internal_error().data(format!("Failed to write agent file: {e}")))?; @@ -711,7 +742,7 @@ pub fn update_source_with_roots( name, description, content, - options.properties.unwrap_or_default(), + options.properties, options.additional_roots, ); }