From 8b279efcbb3f0735fb5cec8ac1c81ac634708065 Mon Sep 17 00:00:00 2001 From: Kalvin Chau Date: Wed, 12 Mar 2025 18:27:08 -0700 Subject: [PATCH 1/3] feat(cli): add better error message, support stdin via -i - or just no args --- crates/goose-cli/src/main.rs | 41 +++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/crates/goose-cli/src/main.rs b/crates/goose-cli/src/main.rs index ba533f0606f6..03e9aa2f1f90 100644 --- a/crates/goose-cli/src/main.rs +++ b/crates/goose-cli/src/main.rs @@ -140,14 +140,16 @@ enum Command { }, /// Execute commands from an instruction file - #[command(about = "Execute commands from an instruction file or stdin")] + #[command( + about = "Execute commands from an instruction file or stdin. Use no arguments for stdin." + )] Run { /// Path to instruction file containing commands #[arg( short, long, value_name = "FILE", - help = "Path to instruction file containing commands", + help = "Path to instruction file containing commands. Use - for stdin.", conflicts_with = "input_text" )] instructions: Option, @@ -360,24 +362,27 @@ async fn main() -> Result<()> { extension, builtin, }) => { - // Validate that we have some input source - if instructions.is_none() && input_text.is_none() { - eprintln!("Error: Must provide either --instructions or --text"); - std::process::exit(1); + fn read_stdin() -> String { + let mut buffer = String::new(); + std::io::stdin() + .read_to_string(&mut buffer) + .expect("Failed to read from stdin"); + buffer } - let contents = if let Some(file_name) = instructions { - let file_path = std::path::Path::new(&file_name); - std::fs::read_to_string(file_path).expect("Failed to read the instruction file") - } else if let Some(input_text) = input_text { - input_text - } else { - let mut stdin = String::new(); - io::stdin() - .read_to_string(&mut stdin) - .expect("Failed to read from stdin"); - stdin + let contents = match (instructions, input_text) { + (Some(file), _) if file == "-" => read_stdin(), + (Some(file), _) => std::fs::read_to_string(&file).unwrap_or_else(|err| { + eprintln!( + "Instruction file not found — did you mean to use --text?\n{}", + err + ); + std::process::exit(1); + }), + (None, Some(text)) => text, + (None, None) => read_stdin(), }; + let mut session = build_session( identifier.map(extract_identifier), resume, @@ -386,6 +391,7 @@ async fn main() -> Result<()> { debug, ) .await; + setup_logging( session.session_file().file_stem().and_then(|s| s.to_str()), None, @@ -396,6 +402,7 @@ async fn main() -> Result<()> { } else { session.headless(contents).await?; } + return Ok(()); } Some(Command::Agents(cmd)) => { From 84027d10c13b73b89ad90a22645439957949b588 Mon Sep 17 00:00:00 2001 From: Kalvin Chau Date: Wed, 12 Mar 2025 18:50:21 -0700 Subject: [PATCH 2/3] chore: fix import --- crates/goose-cli/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/goose-cli/src/main.rs b/crates/goose-cli/src/main.rs index 03e9aa2f1f90..eb785505a150 100644 --- a/crates/goose-cli/src/main.rs +++ b/crates/goose-cli/src/main.rs @@ -12,7 +12,7 @@ use goose_cli::commands::session::handle_session_list; use goose_cli::logging::setup_logging; use goose_cli::session; use goose_cli::session::build_session; -use std::io::{self, Read}; +use std::io::Read; use std::path::PathBuf; #[derive(Parser)] From 09c612204dafb4aa415cf6348ea988d8d2f6ab4b Mon Sep 17 00:00:00 2001 From: Kalvin Chau Date: Wed, 12 Mar 2025 19:06:52 -0700 Subject: [PATCH 3/3] chore: update cli messaging, remove goose run with no params as stdin --- crates/goose-cli/src/main.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/crates/goose-cli/src/main.rs b/crates/goose-cli/src/main.rs index eb785505a150..803cb462d230 100644 --- a/crates/goose-cli/src/main.rs +++ b/crates/goose-cli/src/main.rs @@ -140,9 +140,7 @@ enum Command { }, /// Execute commands from an instruction file - #[command( - about = "Execute commands from an instruction file or stdin. Use no arguments for stdin." - )] + #[command(about = "Execute commands from an instruction file or stdin")] Run { /// Path to instruction file containing commands #[arg( @@ -362,25 +360,26 @@ async fn main() -> Result<()> { extension, builtin, }) => { - fn read_stdin() -> String { - let mut buffer = String::new(); - std::io::stdin() - .read_to_string(&mut buffer) - .expect("Failed to read from stdin"); - buffer - } - let contents = match (instructions, input_text) { - (Some(file), _) if file == "-" => read_stdin(), + (Some(file), _) if file == "-" => { + let mut stdin = String::new(); + std::io::stdin() + .read_to_string(&mut stdin) + .expect("Failed to read from stdin"); + stdin + } (Some(file), _) => std::fs::read_to_string(&file).unwrap_or_else(|err| { eprintln!( - "Instruction file not found — did you mean to use --text?\n{}", + "Instruction file not found — did you mean to use goose run --text?\n{}", err ); std::process::exit(1); }), (None, Some(text)) => text, - (None, None) => read_stdin(), + (None, None) => { + eprintln!("Error: Must provide either --instructions (-i) or --text (-t). Use -i - for stdin."); + std::process::exit(1); + } }; let mut session = build_session(