diff --git a/crates/q_cli/src/cli/mod.rs b/crates/q_cli/src/cli/mod.rs index 49bcf6003..51bbf3831 100644 --- a/crates/q_cli/src/cli/mod.rs +++ b/crates/q_cli/src/cli/mod.rs @@ -65,6 +65,7 @@ use fig_util::{ system_info, }; use internal::InternalSubcommand; +use macos_utils::bundle::get_bundle_path_for_executable; use serde::Serialize; use tokio::signal::ctrl_c; use tracing::{ @@ -195,15 +196,16 @@ pub enum CliRootCommands { /// Open the dashboard Dashboard, /// AI assistant in your terminal + #[command(disable_help_flag = true)] Chat { - /// Args for the chat command + /// Args for the chat subcommand #[arg(trailing_var_arg = true, allow_hyphen_values = true)] args: Vec, }, /// Model Context Protocol (MCP) #[command(disable_help_flag = true)] Mcp { - /// Args for the MCP subcommand (passed through to `qchat mcp …`) + /// Args for the MCP subcommand #[arg(trailing_var_arg = true, allow_hyphen_values = true)] args: Vec, }, @@ -352,11 +354,18 @@ impl Cli { CliRootCommands::Telemetry(subcommand) => subcommand.execute().await, CliRootCommands::Version { changelog } => Self::print_version(changelog), CliRootCommands::Dashboard => launch_dashboard(false).await, - CliRootCommands::Chat { args } => Self::execute_chat("chat", Some(args), true).await, + CliRootCommands::Chat { args } => { + if args.iter().any(|arg| ["--help", "-h"].contains(&arg.as_str())) { + return Self::execute_chat("chat", Some(vec!["--help".to_owned()]), false).await; + } + + Self::execute_chat("chat", Some(args), true).await + }, CliRootCommands::Mcp { args } => { if args.iter().any(|arg| ["--help", "-h"].contains(&arg.as_str())) { return Self::execute_chat("mcp", Some(vec!["--help".to_owned()]), false).await; } + Self::execute_chat("mcp", Some(args), true).await }, CliRootCommands::Inline(subcommand) => subcommand.execute(&cli_context).await, @@ -367,6 +376,14 @@ impl Cli { } pub async fn execute_chat(subcmd: &str, args: Option>, enforce_login: bool) -> Result { + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let path = get_bundle_path_for_executable(CHAT_BINARY_NAME).unwrap_or(home_local_bin()?.join(CHAT_BINARY_NAME)); + } else { + let path = home_local_bin()?.join(CHAT_BINARY_NAME); + } + } + if enforce_login { assert_logged_in().await?; } @@ -382,7 +399,7 @@ impl Cli { } } - let mut cmd = tokio::process::Command::new(home_local_bin()?.join(CHAT_BINARY_NAME)); + let mut cmd = tokio::process::Command::new(&path); cmd.arg(subcmd); if let Some(args) = args { cmd.args(args); diff --git a/crates/q_cli/src/main.rs b/crates/q_cli/src/main.rs index 9f5b3e9ea..54d059acf 100644 --- a/crates/q_cli/src/main.rs +++ b/crates/q_cli/src/main.rs @@ -33,19 +33,6 @@ fn main() -> Result { Some("init" | "_" | "internal" | "completion" | "hook" | "chat") ); - let runtime = if multithread { - tokio::runtime::Builder::new_multi_thread() - } else { - tokio::runtime::Builder::new_current_thread() - } - .enable_all() - .build()?; - - // Hack as clap doesn't expose a custom command help. - if subcommand.as_deref() == Some("chat") && args.any(|arg| ["--help", "-h"].contains(&arg.as_str())) { - runtime.block_on(cli::Cli::execute_chat("chat", Some(vec!["--help".to_owned()]), true))?; - } - let parsed = match cli::Cli::try_parse() { Ok(cli) => cli, Err(err) => { @@ -73,6 +60,14 @@ fn main() -> Result { let verbose = parsed.verbose > 0; + let runtime = if multithread { + tokio::runtime::Builder::new_multi_thread() + } else { + tokio::runtime::Builder::new_current_thread() + } + .enable_all() + .build()?; + let result = runtime.block_on(async { let result = parsed.execute().await; fig_telemetry::finish_telemetry().await;