From fc77a2fb24de4a5427b6474df88937a9e25faec5 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 10 Mar 2026 19:16:59 -0400 Subject: [PATCH] Gate --mode and --server-url CLI args behind server feature When compiled without the server feature, these args are useless since there is no server to delegate to. Wraps the CLI fields, parser, resolve_mode, build_server_client, and related tests in cfg(feature = "server"), with standalone-only fallback paths in each command handler. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/crates/arc-cli/src/cli_config.rs | 7 +- lib/crates/arc-cli/src/main.rs | 172 +++++++++++++++++---------- 2 files changed, 114 insertions(+), 65 deletions(-) diff --git a/lib/crates/arc-cli/src/cli_config.rs b/lib/crates/arc-cli/src/cli_config.rs index 82e70081b..276be4f34 100644 --- a/lib/crates/arc-cli/src/cli_config.rs +++ b/lib/crates/arc-cli/src/cli_config.rs @@ -1,7 +1,9 @@ pub use arc_config::cli::*; +#[cfg(feature = "server")] use tracing::debug; +#[cfg(feature = "server")] #[derive(Debug, PartialEq)] pub struct ResolvedMode { pub mode: ExecutionMode, @@ -9,8 +11,10 @@ pub struct ResolvedMode { pub tls: Option, } +#[cfg(feature = "server")] const DEFAULT_SERVER_URL: &str = "http://localhost:3000"; +#[cfg(feature = "server")] pub fn resolve_mode( cli_mode: Option, cli_server_url: Option<&str>, @@ -36,6 +40,7 @@ pub fn resolve_mode( } } +#[cfg(feature = "server")] pub fn build_server_client(tls: Option<&ClientTlsConfig>) -> anyhow::Result { let Some(tls) = tls else { return Ok(reqwest::Client::new()); @@ -65,7 +70,7 @@ pub fn build_server_client(tls: Option<&ClientTlsConfig>) -> anyhow::Result, /// Server URL (overrides server.base_url from cli.toml) + #[cfg(feature = "server")] #[arg(long, global = true)] server_url: Option, @@ -31,6 +33,7 @@ struct Cli { command: Command, } +#[cfg(feature = "server")] fn parse_execution_mode(s: &str) -> Result { match s { "standalone" => Ok(cli_config::ExecutionMode::Standalone), @@ -237,41 +240,63 @@ async fn main_inner() -> Result<()> { if args.model.is_none() { args.model = llm_defaults.and_then(|l| l.model.clone()); } - let resolved = - cli_config::resolve_mode(cli.mode, cli.server_url.as_deref(), &cli_config); - match resolved.mode { - cli_config::ExecutionMode::Server => { - let client = cli_config::build_server_client(resolved.tls.as_ref())?; - let server = arc_llm::cli::ServerConnection { - client, - base_url: resolved.server_base_url, - }; - arc_llm::cli::run_prompt_via_server(args, &server).await? - } - cli_config::ExecutionMode::Standalone => { - arc_llm::cli::run_prompt(args).await? + #[cfg(feature = "server")] + { + let resolved = cli_config::resolve_mode( + cli.mode, + cli.server_url.as_deref(), + &cli_config, + ); + match resolved.mode { + cli_config::ExecutionMode::Server => { + let client = + cli_config::build_server_client(resolved.tls.as_ref())?; + let server = arc_llm::cli::ServerConnection { + client, + base_url: resolved.server_base_url, + }; + arc_llm::cli::run_prompt_via_server(args, &server).await? + } + cli_config::ExecutionMode::Standalone => { + arc_llm::cli::run_prompt(args).await? + } } } + #[cfg(not(feature = "server"))] + { + arc_llm::cli::run_prompt(args).await? + } } LlmCommand::Chat(mut args) => { if args.model.is_none() { args.model = llm_defaults.and_then(|l| l.model.clone()); } - let resolved = - cli_config::resolve_mode(cli.mode, cli.server_url.as_deref(), &cli_config); - match resolved.mode { - cli_config::ExecutionMode::Server => { - let client = cli_config::build_server_client(resolved.tls.as_ref())?; - let server = arc_llm::cli::ServerConnection { - client, - base_url: resolved.server_base_url, - }; - arc_llm::cli::run_chat_via_server(args, &server).await? - } - cli_config::ExecutionMode::Standalone => { - arc_llm::cli::run_chat(args).await? + #[cfg(feature = "server")] + { + let resolved = cli_config::resolve_mode( + cli.mode, + cli.server_url.as_deref(), + &cli_config, + ); + match resolved.mode { + cli_config::ExecutionMode::Server => { + let client = + cli_config::build_server_client(resolved.tls.as_ref())?; + let server = arc_llm::cli::ServerConnection { + client, + base_url: resolved.server_base_url, + }; + arc_llm::cli::run_chat_via_server(args, &server).await? + } + cli_config::ExecutionMode::Standalone => { + arc_llm::cli::run_chat(args).await? + } } } + #[cfg(not(feature = "server"))] + { + arc_llm::cli::run_chat(args).await? + } } } } @@ -284,6 +309,7 @@ async fn main_inner() -> Result<()> { exec_defaults.and_then(|a| a.permissions), exec_defaults.and_then(|a| a.output_format), ); + #[cfg(feature = "server")] let resolved = cli_config::resolve_mode(cli.mode, cli.server_url.as_deref(), &cli_config); let mcp_servers: Vec = cli_config @@ -291,35 +317,44 @@ async fn main_inner() -> Result<()> { .into_iter() .map(|(name, entry)| entry.into_config(name)) .collect(); - match resolved.mode { - cli_config::ExecutionMode::Server => { - tracing::info!(mode = "server", "Agent session starting"); - let http_client = cli_config::build_server_client(resolved.tls.as_ref())?; - let provider_name = args - .provider - .clone() - .unwrap_or_else(|| "anthropic".to_string()); - let adapter = std::sync::Arc::new(arc_llm::providers::ArcServerAdapter::new( - http_client, - &resolved.server_base_url, - &provider_name, - )); - let mut client = arc_llm::client::Client::new( - std::collections::HashMap::new(), - None, - vec![], - ); - client.register_provider(adapter).await.map_err(|e| { - anyhow::anyhow!("Failed to register arc server adapter: {e}") - })?; - arc_agent::cli::run_with_args_and_client(args, Some(client), mcp_servers) - .await? - } - cli_config::ExecutionMode::Standalone => { - tracing::info!(mode = "standalone", "Agent session starting"); - arc_agent::cli::run_with_args(args, mcp_servers).await? + #[cfg(feature = "server")] + { + match resolved.mode { + cli_config::ExecutionMode::Server => { + tracing::info!(mode = "server", "Agent session starting"); + let http_client = cli_config::build_server_client(resolved.tls.as_ref())?; + let provider_name = args + .provider + .clone() + .unwrap_or_else(|| "anthropic".to_string()); + let adapter = + std::sync::Arc::new(arc_llm::providers::ArcServerAdapter::new( + http_client, + &resolved.server_base_url, + &provider_name, + )); + let mut client = arc_llm::client::Client::new( + std::collections::HashMap::new(), + None, + vec![], + ); + client.register_provider(adapter).await.map_err(|e| { + anyhow::anyhow!("Failed to register arc server adapter: {e}") + })?; + arc_agent::cli::run_with_args_and_client(args, Some(client), mcp_servers) + .await? + } + cli_config::ExecutionMode::Standalone => { + tracing::info!(mode = "standalone", "Agent session starting"); + arc_agent::cli::run_with_args(args, mcp_servers).await? + } } } + #[cfg(not(feature = "server"))] + { + tracing::info!(mode = "standalone", "Agent session starting"); + arc_agent::cli::run_with_args(args, mcp_servers).await? + } } Command::Run(mut args) => { let styles: &'static arc_util::terminal::Styles = @@ -362,18 +397,27 @@ async fn main_inner() -> Result<()> { arc_workflows::cli::diff::diff_command(args).await?; } Command::Model { command } => { - let cli_config = cli_config::load_cli_config(None)?; - let resolved = - cli_config::resolve_mode(cli.mode, cli.server_url.as_deref(), &cli_config); - let server = match resolved.mode { - cli_config::ExecutionMode::Server => { - let client = cli_config::build_server_client(resolved.tls.as_ref())?; - Some(arc_llm::cli::ServerConnection { - client, - base_url: resolved.server_base_url, - }) + let server = { + #[cfg(feature = "server")] + { + let cli_config = cli_config::load_cli_config(None)?; + let resolved = + cli_config::resolve_mode(cli.mode, cli.server_url.as_deref(), &cli_config); + match resolved.mode { + cli_config::ExecutionMode::Server => { + let client = cli_config::build_server_client(resolved.tls.as_ref())?; + Some(arc_llm::cli::ServerConnection { + client, + base_url: resolved.server_base_url, + }) + } + cli_config::ExecutionMode::Standalone => None, + } + } + #[cfg(not(feature = "server"))] + { + None } - cli_config::ExecutionMode::Standalone => None, }; arc_llm::cli::run_models(command, server).await? }