allow gt to run without quotes or without even using gt prefix

This commit is contained in:
Michael Neale
2025-11-24 10:45:05 +11:00
parent e1be322f46
commit 67a607437f
2 changed files with 52 additions and 19 deletions
+19 -15
View File
@@ -35,14 +35,6 @@ use std::io::Read;
use std::path::PathBuf;
use tracing::warn;
fn non_empty_string(s: &str) -> Result<String, String> {
if s.trim().is_empty() {
Err("Prompt cannot be empty".to_string())
} else {
Ok(s.to_string())
}
}
#[derive(Parser)]
#[command(author, version, display_name = "", about, long_about = None)]
struct Cli {
@@ -871,6 +863,14 @@ enum TermCommand {
/// Shell type (bash, zsh, fish, powershell)
#[arg(value_enum)]
shell: Shell,
/// Enable command_not_found_handler (sends unknown commands to goose)
#[arg(
long = "with-command-not-found",
help = "Enable command_not_found_handler for automatic goose invocation",
long_help = "When enabled, any command not found will be automatically sent to goose for interpretation. Only supported for zsh and bash."
)]
with_command_not_found: bool,
},
/// Log a shell command (called by shell hook)
@@ -885,13 +885,14 @@ enum TermCommand {
about = "Run a prompt in the terminal session",
long_about = "Run a prompt in the terminal-integrated session.\n\n\
Examples:\n \
goose term run \"list files in this directory\"\n \
goose term run \"create a python script that prints hello world\""
goose term run list files in this directory\n \
goose term run create a python script that prints hello world\n \
gt list files # using alias"
)]
Run {
/// The prompt to send to goose
#[arg(value_parser = non_empty_string)]
prompt: String,
/// The prompt to send to goose (multiple words allowed without quotes)
#[arg(required = true, num_args = 1..)]
prompt: Vec<String>,
},
/// Print session info for prompt integration
@@ -1470,14 +1471,17 @@ pub async fn cli() -> anyhow::Result<()> {
}
Some(Command::Term { command }) => {
match command {
TermCommand::Init { shell } => {
TermCommand::Init {
shell,
with_command_not_found,
} => {
let shell_str = match shell {
Shell::Bash => "bash",
Shell::Zsh => "zsh",
Shell::Fish => "fish",
Shell::Powershell => "powershell",
};
handle_term_init(shell_str)?;
handle_term_init(shell_str, with_command_not_found)?;
}
TermCommand::Log { command } => {
handle_term_log(command).await?;
+33 -4
View File
@@ -33,7 +33,7 @@ async fn ensure_terminal_session(
}
/// Handle `goose term init <shell>` - print shell initialization script
pub fn handle_term_init(shell: &str) -> Result<()> {
pub fn handle_term_init(shell: &str, with_command_not_found: bool) -> Result<()> {
let terminal_id = Uuid::new_v4().to_string();
// Get the path to the current goose binary
@@ -41,6 +41,34 @@ pub fn handle_term_init(shell: &str) -> Result<()> {
.map(|p| p.to_string_lossy().into_owned())
.unwrap_or_else(|_| "goose".to_string());
let command_not_found_handler = if with_command_not_found {
match shell.to_lowercase().as_str() {
"bash" => format!(
r#"
# Command not found handler - sends unknown commands to goose
command_not_found_handle() {{
echo "🪿 Command '$1' not found. Asking goose..."
'{goose_bin}' term run "$@"
return 0
}}"#
),
"zsh" => format!(
r#"
# Command not found handler - sends unknown commands to goose
command_not_found_handler() {{
echo "🪿 Command '$1' not found. Asking goose..."
'{goose_bin}' term run "$@"
return 0
}}"#
),
_ => String::new(),
}
} else {
String::new()
};
let script = match shell.to_lowercase().as_str() {
"bash" => {
format!(
@@ -58,7 +86,7 @@ goose_preexec() {{
if [[ -z "$goose_preexec_installed" ]]; then
goose_preexec_installed=1
trap 'goose_preexec "$BASH_COMMAND"' DEBUG
fi"#
fi{command_not_found_handler}"#
)
}
"zsh" => {
@@ -81,7 +109,7 @@ add-zsh-hook preexec goose_preexec
if [[ -z "$GOOSE_PROMPT_INSTALLED" ]]; then
export GOOSE_PROMPT_INSTALLED=1
PROMPT='%F{{cyan}}🪿%f '$PROMPT
fi"#
fi{command_not_found_handler}"#
)
}
"fish" => {
@@ -140,7 +168,8 @@ pub async fn handle_term_log(command: String) -> Result<()> {
}
/// Handle `goose term run <prompt>` - run a prompt in the terminal session
pub async fn handle_term_run(prompt: String) -> Result<()> {
pub async fn handle_term_run(prompt: Vec<String>) -> Result<()> {
let prompt = prompt.join(" ");
let terminal_id = std::env::var("GOOSE_TERMINAL_ID").map_err(|_| {
anyhow!(
"GOOSE_TERMINAL_ID not set.\n\n\