diff --git a/crates/goose/src/acp/server/tool_calls/conversion.rs b/crates/goose/src/acp/server/tool_calls/conversion.rs index a41d06e18..bd1c14c76 100644 --- a/crates/goose/src/acp/server/tool_calls/conversion.rs +++ b/crates/goose/src/acp/server/tool_calls/conversion.rs @@ -29,9 +29,15 @@ fn default_tool_title(tool_name: &str, arguments: Option<&serde_json::Value>) -> let detail = arguments.and_then(|args| { let obj = args.as_object()?; - let keys = [ - "path", "file", "command", "query", "url", "uri", "name", "pattern", "source", - ]; + let keys = if matches!(tool_name, "developer__shell" | "shell") { + [ + "command", "path", "file", "query", "url", "uri", "name", "pattern", "source", + ] + } else { + [ + "path", "file", "command", "query", "url", "uri", "name", "pattern", "source", + ] + }; for key in &keys { if let Some(v) = obj.get(*key) { let s = match v { @@ -39,8 +45,9 @@ fn default_tool_title(tool_name: &str, arguments: Option<&serde_json::Value>) -> other => other.to_string(), }; if !s.is_empty() { - let first_line = s.lines().next().unwrap_or(&s); - if first_line.len() > 60 { + let mut lines = s.lines(); + let first_line = lines.next().unwrap_or(&s); + if first_line.len() > 60 || lines.next().is_some() { return Some(format!("{}…", crate::utils::safe_truncate(first_line, 57))); } return Some(first_line.to_string()); @@ -362,6 +369,31 @@ mod tests { ); } + #[test] + fn shell_command_takes_precedence_over_ignored_path() { + let args = serde_json::json!({ + "path": "/tmp/harmless", + "command": "rm -rf /tmp/important" + }); + assert_eq!( + default_tool_title("developer__shell", Some(&args)), + "developer: shell · rm -rf /tmp/important" + ); + assert_eq!( + default_tool_title("shell", Some(&args)), + "shell · rm -rf /tmp/important" + ); + } + + #[test] + fn multiline_shell_command_marks_omitted_lines() { + let args = serde_json::json!({"command": "echo harmless\nrm -rf /tmp/important"}); + assert_eq!( + default_tool_title("developer__shell", Some(&args)), + "developer: shell · echo harmless…" + ); + } + #[test] fn long_value_is_truncated() { let long_path = "a".repeat(80);