diff --git a/crates/goose-mcp/src/developer/mod.rs b/crates/goose-mcp/src/developer/mod.rs index 5c5cb971..6d322e80 100644 --- a/crates/goose-mcp/src/developer/mod.rs +++ b/crates/goose-mcp/src/developer/mod.rs @@ -805,13 +805,56 @@ impl DeveloperRouter { ]) } + // Helper function to handle Mac screenshot filenames that contain U+202F (narrow no-break space) + fn normalize_mac_screenshot_path(&self, path: &Path) -> PathBuf { + // Only process if the path has a filename + if let Some(filename) = path.file_name().and_then(|f| f.to_str()) { + // Check if this matches Mac screenshot pattern: + // "Screenshot YYYY-MM-DD at H.MM.SS AM/PM.png" + if let Some(captures) = regex::Regex::new(r"^Screenshot \d{4}-\d{2}-\d{2} at \d{1,2}\.\d{2}\.\d{2} (AM|PM)(?: \(\d+\))?\.png$") + .ok() + .and_then(|re| re.captures(filename)) + { + + // Get the AM/PM part + let meridian = captures.get(1).unwrap().as_str(); + + // Find the last space before AM/PM and replace it with U+202F + let space_pos = filename.rfind(meridian) + .map(|pos| filename[..pos].trim_end().len()) + .unwrap_or(0); + + if space_pos > 0 { + let parent = path.parent().unwrap_or(Path::new("")); + let new_filename = format!( + "{}{}{}", + &filename[..space_pos], + '\u{202F}', + &filename[space_pos+1..] + ); + let new_path = parent.join(new_filename); + + return new_path; + } + } + } + path.to_path_buf() + } + async fn image_processor(&self, params: Value) -> Result, ToolError> { let path_str = params .get("path") .and_then(|v| v.as_str()) .ok_or_else(|| ToolError::InvalidParameters("Missing 'path' parameter".into()))?; - let path = self.resolve_path(path_str)?; + let path = { + let p = self.resolve_path(path_str)?; + if cfg!(target_os = "macos") { + self.normalize_mac_screenshot_path(&p) + } else { + p + } + }; // Check if file is ignored before proceeding if self.is_ignored(&path) {