diff --git a/lib/crates/fabro-cli/src/cli_config.rs b/lib/crates/fabro-cli/src/cli_config.rs index 9be414a5b..359efc5db 100644 --- a/lib/crates/fabro-cli/src/cli_config.rs +++ b/lib/crates/fabro-cli/src/cli_config.rs @@ -16,14 +16,30 @@ pub(crate) fn load_cli_settings() -> anyhow::Result { ConfigLayer::cli()?.resolve() } +pub(crate) fn cli_layer_with_globals(globals: &GlobalArgs) -> anyhow::Result { + let layer = ConfigLayer::cli()?; + Ok(apply_global_overrides(layer, globals)) +} + pub(crate) fn load_cli_settings_with_globals( globals: &GlobalArgs, ) -> anyhow::Result { - let mut layer = ConfigLayer::cli()?; + cli_layer_with_globals(globals)?.resolve() +} + +pub(crate) fn apply_global_overrides(mut layer: ConfigLayer, globals: &GlobalArgs) -> ConfigLayer { if let Some(dir) = &globals.storage_dir { layer.storage_dir = Some(dir.clone()); + layer.mode = Some(ExecutionMode::Standalone); } - layer.resolve() + + #[cfg(feature = "server")] + if let Some(url) = &globals.server_url { + layer.server.get_or_insert_with(Default::default).base_url = Some(url.clone()); + layer.mode = Some(ExecutionMode::Server); + } + + layer } #[cfg(feature = "server")] diff --git a/lib/crates/fabro-cli/src/commands/config/mod.rs b/lib/crates/fabro-cli/src/commands/config/mod.rs index 2fcaa559e..c1b445053 100644 --- a/lib/crates/fabro-cli/src/commands/config/mod.rs +++ b/lib/crates/fabro-cli/src/commands/config/mod.rs @@ -2,6 +2,7 @@ use std::io::Write; use std::path::Path; use crate::args::{ConfigCommand, ConfigNamespace, ConfigShowArgs, GlobalArgs}; +use crate::cli_config; use fabro_config::{ConfigLayer, FabroSettings}; pub(crate) fn dispatch(ns: ConfigNamespace, globals: &GlobalArgs) -> anyhow::Result<()> { @@ -16,10 +17,7 @@ fn merged_config(workflow: Option<&Path>, globals: &GlobalArgs) -> anyhow::Resul Some(path) => ConfigLayer::for_workflow(path, &cwd)?, None => ConfigLayer::project(&cwd)?, }; - let mut cli = ConfigLayer::cli()?; - if let Some(dir) = &globals.storage_dir { - cli.storage_dir = Some(dir.clone()); - } + let cli = cli_config::cli_layer_with_globals(globals)?; base.combine(cli).resolve() } diff --git a/lib/crates/fabro-cli/src/commands/preflight.rs b/lib/crates/fabro-cli/src/commands/preflight.rs index fa27bac3d..77da2d39e 100644 --- a/lib/crates/fabro-cli/src/commands/preflight.rs +++ b/lib/crates/fabro-cli/src/commands/preflight.rs @@ -17,15 +17,12 @@ use fabro_workflows::git::{GitSyncStatus, sync_status}; use fabro_workflows::operations::{ValidateInput, WorkflowInput, validate}; use crate::args::{GlobalArgs, PreflightArgs}; -use crate::cli_config::load_cli_settings_with_globals; +use crate::cli_config::{cli_layer_with_globals, load_cli_settings_with_globals}; use crate::shared::github::build_github_app_credentials; pub(crate) async fn execute(mut args: PreflightArgs, globals: &GlobalArgs) -> anyhow::Result<()> { let styles: &'static Styles = Box::leak(Box::new(Styles::detect_stderr())); - let mut cli = ConfigLayer::cli()?; - if let Some(dir) = &globals.storage_dir { - cli.storage_dir = Some(dir.clone()); - } + let cli = cli_layer_with_globals(globals)?; let cli_settings: FabroSettings = load_cli_settings_with_globals(globals)?; args.verbose = args.verbose || cli_settings.verbose_enabled(); diff --git a/lib/crates/fabro-cli/src/commands/run/command.rs b/lib/crates/fabro-cli/src/commands/run/command.rs index dfff31f64..7d58c920d 100644 --- a/lib/crates/fabro-cli/src/commands/run/command.rs +++ b/lib/crates/fabro-cli/src/commands/run/command.rs @@ -1,20 +1,18 @@ use anyhow::Result; -use fabro_config::ConfigLayer; use fabro_util::terminal::Styles; use crate::args::{GlobalArgs, RunArgs}; -use crate::cli_config; +use crate::cli_config::{self, cli_layer_with_globals}; pub(crate) async fn execute(mut args: RunArgs, globals: &GlobalArgs) -> Result<()> { let styles: &'static Styles = Box::leak(Box::new(Styles::detect_stderr())); let cli_settings = cli_config::load_cli_settings_with_globals(globals)?; - let cli = ConfigLayer::cli()?; + let cli = cli_layer_with_globals(globals)?; args.verbose = args.verbose || cli_settings.verbose_enabled(); let quiet = args.detach; let prevent_idle_sleep = cli_settings.prevent_idle_sleep_enabled(); - let (run_id, run_dir) = - super::create::create_run(&args, cli, styles, quiet, globals.storage_dir.clone())?; + let (run_id, run_dir) = super::create::create_run(&args, cli, styles, quiet)?; #[cfg(feature = "sleep_inhibitor")] let _sleep_guard = crate::sleep_inhibitor::guard(prevent_idle_sleep); diff --git a/lib/crates/fabro-cli/src/commands/run/create.rs b/lib/crates/fabro-cli/src/commands/run/create.rs index d16338db4..b36d1835c 100644 --- a/lib/crates/fabro-cli/src/commands/run/create.rs +++ b/lib/crates/fabro-cli/src/commands/run/create.rs @@ -16,16 +16,12 @@ pub(crate) fn create_run( cli_defaults: ConfigLayer, styles: &Styles, quiet: bool, - storage_dir_override: Option, ) -> anyhow::Result<(String, PathBuf)> { let workflow_path = args .workflow .as_ref() .ok_or_else(|| anyhow::anyhow!("--workflow is required"))?; - let mut cli_args_config = ConfigLayer::try_from(args)?; - if let Some(dir) = storage_dir_override { - cli_args_config.storage_dir = Some(dir); - } + let cli_args_config = ConfigLayer::try_from(args)?; let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); let settings: FabroSettings = cli_args_config .combine(ConfigLayer::for_workflow(workflow_path, &cwd)?) diff --git a/lib/crates/fabro-cli/src/commands/run/mod.rs b/lib/crates/fabro-cli/src/commands/run/mod.rs index e1dec0e77..2e25ada0a 100644 --- a/lib/crates/fabro-cli/src/commands/run/mod.rs +++ b/lib/crates/fabro-cli/src/commands/run/mod.rs @@ -1,11 +1,10 @@ use anyhow::Result; -use fabro_config::ConfigLayer; use fabro_config::FabroSettingsExt; use fabro_util::terminal::Styles; use fabro_workflows::run_lookup::{resolve_run_combined, runs_base}; use crate::args::{GlobalArgs, RunCommands}; -use crate::cli_config::load_cli_settings_with_globals; +use crate::cli_config::{cli_layer_with_globals, load_cli_settings_with_globals}; use crate::store; pub(crate) mod attach; @@ -36,9 +35,8 @@ pub(crate) async fn dispatch(cmd: RunCommands, globals: &GlobalArgs) -> Result<( RunCommands::Run(args) => command::execute(args, globals).await, RunCommands::Create(args) => { let styles: &'static Styles = Box::leak(Box::new(Styles::detect_stderr())); - let cli = ConfigLayer::cli()?; - let (run_id, _run_dir) = - create::create_run(&args, cli, styles, true, globals.storage_dir.clone())?; + let cli = cli_layer_with_globals(globals)?; + let (run_id, _run_dir) = create::create_run(&args, cli, styles, true)?; println!("{run_id}"); Ok(()) } diff --git a/lib/crates/fabro-cli/tests/it/cli.rs b/lib/crates/fabro-cli/tests/it/cli.rs index 5e5e4eff3..66b4547a9 100644 --- a/lib/crates/fabro-cli/tests/it/cli.rs +++ b/lib/crates/fabro-cli/tests/it/cli.rs @@ -6,6 +6,8 @@ use std::time::Duration; use assert_cmd::Command; use chrono::TimeZone; use fabro_config::FabroSettings; +#[cfg(feature = "server")] +use fabro_config::cli::ExecutionMode; use fabro_config::mcp::McpTransport; use fabro_git_storage::branchstore::BranchStore; use fabro_git_storage::gitobj::Store as GitStore; @@ -2017,3 +2019,37 @@ fn config_show_missing_run_config_errors() { .failure() .stderr(predicate::str::contains("Workflow not found")); } + +#[test] +#[cfg(feature = "server")] +fn config_show_server_url_overrides_cli_defaults() { + let (home, project) = setup_config_show_fixture(); + let cli_toml = home.path().join(".fabro").join("cli.toml"); + std::fs::write( + &cli_toml, + format!( + "{}\nmode = \"standalone\"\n[server]\nbase_url = \"https://config.example.com\"\n", + std::fs::read_to_string(&cli_toml).unwrap() + ), + ) + .unwrap(); + + let output = arc() + .env("HOME", home.path()) + .current_dir(project.path()) + .args(["--server-url", "https://cli.example.com", "config", "show"]) + .assert() + .success() + .get_output() + .stdout + .clone(); + + let cfg = parse_config_show(&output); + assert_eq!(cfg.mode, Some(ExecutionMode::Server)); + assert_eq!( + cfg.server + .as_ref() + .and_then(|server| server.base_url.as_deref()), + Some("https://cli.example.com") + ); +}