diff --git a/Cargo.lock b/Cargo.lock index b92d21d6c280..b75bd237845b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1521,6 +1521,15 @@ dependencies = [ "terminal_size", ] +[[package]] +name = "clap_complete" +version = "4.5.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004eef6b14ce34759aa7de4aea3217e368f463f46a3ed3764ca4b5a4404003b4" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.5.41" @@ -3141,6 +3150,7 @@ dependencies = [ "bat", "chrono", "clap", + "clap_complete", "cliclack", "console 0.16.2", "dotenvy", diff --git a/crates/goose-cli/Cargo.toml b/crates/goose-cli/Cargo.toml index 1cba3409f3e3..6be9774083d5 100644 --- a/crates/goose-cli/Cargo.toml +++ b/crates/goose-cli/Cargo.toml @@ -60,6 +60,7 @@ anstream = "0.6.18" url = "2.5.7" open = "5.3.2" urlencoding = "2.1" +clap_complete = "4.5.62" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["wincred"] } diff --git a/crates/goose-cli/src/cli.rs b/crates/goose-cli/src/cli.rs index cb664c49ace2..63e5c942c560 100644 --- a/crates/goose-cli/src/cli.rs +++ b/crates/goose-cli/src/cli.rs @@ -1,6 +1,6 @@ use anyhow::Result; -use clap::{Args, Parser, Subcommand}; - +use clap::{Args, CommandFactory, Parser, Subcommand}; +use clap_complete::{generate, Shell as ClapShell}; use goose::config::{Config, ExtensionConfig}; use goose_mcp::mcp_server_runner::{serve, McpCommand}; use goose_mcp::{ @@ -865,6 +865,12 @@ enum Command { #[command(subcommand)] command: TermCommand, }, + /// Generate completions for various shells + #[command(about = "Generate the autocompletion script for the specified shell")] + Completion { + #[arg(value_enum)] + shell: ClapShell, + }, } #[derive(Subcommand)] @@ -972,6 +978,7 @@ pub async fn cli() -> anyhow::Result<()> { Some(Command::Recipe { .. }) => "recipe", Some(Command::Web { .. }) => "web", Some(Command::Term { .. }) => "term", + Some(Command::Completion { .. }) => "completion", None => "default_session", }; @@ -982,6 +989,11 @@ pub async fn cli() -> anyhow::Result<()> { ); match cli.command { + Some(Command::Completion { shell }) => { + let mut cmd = Cli::command(); + let bin_name = cmd.get_name().to_string(); + generate(shell, &mut cmd, bin_name, &mut std::io::stdout()); + } Some(Command::Configure {}) => handle_configure().await?, Some(Command::Info { verbose }) => handle_info(verbose)?, Some(Command::Mcp { server }) => {