From 2ba84be748ccd19bcdb96c3e12f175cf1caa7c06 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 14 Apr 2026 15:16:21 -0400 Subject: [PATCH] Improve install command output ordering and path display Reorder output so file-write confirmations appear immediately after secret generation, move "To start Fabro" call-to-action to the end, collapse duplicate blank line, shorten home-dir paths with ~, and style the `fabro server start` command with bold cyan. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/crates/fabro-cli/src/commands/install.rs | 32 ++++++++++---------- lib/crates/fabro-util/src/path.rs | 26 ++++++++++++++++ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/lib/crates/fabro-cli/src/commands/install.rs b/lib/crates/fabro-cli/src/commands/install.rs index 3ab986ee0..c8ff73ab1 100644 --- a/lib/crates/fabro-cli/src/commands/install.rs +++ b/lib/crates/fabro-cli/src/commands/install.rs @@ -260,9 +260,10 @@ fn prompt_input(prompt: &str) -> Result { .interact_on(&Term::stderr())?) } -fn prompt_select(prompt: &str, items: &[String]) -> Result { +fn prompt_select(prompt: &str, items: &[String], default: usize) -> Result { Ok(Select::with_theme(&ColorfulTheme::default()) .with_prompt(prompt) + .default(default) .items(items) .interact_on(&Term::stderr())?) } @@ -483,7 +484,7 @@ impl InstallInputSource for InteractiveInstallInputSource { .collect(); let primary_idx: usize = spawn_blocking({ let labels = primary_labels.clone(); - move || prompt_select("Choose your first LLM provider", &labels) + move || prompt_select("Choose your first LLM provider", &labels, 0) }) .await??; @@ -536,7 +537,7 @@ impl InstallInputSource for InteractiveInstallInputSource { ]; let strategy = spawn_blocking({ let options = strategy_options.clone(); - move || prompt_select("How should Fabro authenticate with GitHub?", &options) + move || prompt_select("How should Fabro authenticate with GitHub?", &options, 0) }) .await??; @@ -830,7 +831,7 @@ async fn prompt_github_app_owner(_s: &Styles) -> Result<(GitHubAppOwner, Option< let selected: usize = spawn_blocking({ let items = items.clone(); - move || prompt_select("Where should the GitHub App be created?", &items) + move || prompt_select("Where should the GitHub App be created?", &items, 0) }) .await??; @@ -1463,7 +1464,6 @@ async fn run_install_inner( None => {} } - fabro_util::printerr!(printer, ""); toml::to_string_pretty(&doc)? }; @@ -1511,12 +1511,6 @@ async fn run_install_inner( ("FABRO_DEV_TOKEN".to_string(), dev_token), ]; server_env_pairs.extend(generated_server_env_pairs); - fabro_util::printerr!(printer, ""); - - fabro_util::printerr!(printer, " To start Fabro, run these commands:"); - fabro_util::printerr!(printer, ""); - fabro_util::printerr!(printer, " fabro server start"); - fabro_util::printerr!(printer, ""); } persist_install_outputs( @@ -1548,9 +1542,7 @@ async fn run_install_inner( " {} Saved {} runtime secrets to {}", s.green.apply_to("✔"), server_env_pairs.len(), - Storage::new(&storage_dir) - .server_state() - .env_path() + fabro_util::path::contract_tilde(&Storage::new(&storage_dir).server_state().env_path()) .display() ); fabro_util::printerr!( @@ -1558,13 +1550,13 @@ async fn run_install_inner( " {} Saved {} workflow-visible secrets to {}", s.green.apply_to("✔"), vault_secrets.len(), - Storage::new(&storage_dir).secrets_path().display() + fabro_util::path::contract_tilde(&Storage::new(&storage_dir).secrets_path()).display() ); fabro_util::printerr!( printer, " {} Wrote {}", s.green.apply_to("✔"), - config_path.display() + fabro_util::path::contract_tilde(&config_path).display() ); if server_was_running { fabro_util::printerr!( @@ -1573,6 +1565,14 @@ async fn run_install_inner( ); } fabro_util::printerr!(printer, ""); + fabro_util::printerr!(printer, " To start Fabro, run these commands:"); + fabro_util::printerr!(printer, ""); + fabro_util::printerr!( + printer, + " {}", + s.bold_cyan.apply_to("fabro server start") + ); + fabro_util::printerr!(printer, ""); // Verify setup let run_doctor = input_source.should_run_doctor().await?; diff --git a/lib/crates/fabro-util/src/path.rs b/lib/crates/fabro-util/src/path.rs index 992cefb96..a95ed78e6 100644 --- a/lib/crates/fabro-util/src/path.rs +++ b/lib/crates/fabro-util/src/path.rs @@ -10,6 +10,17 @@ pub fn expand_tilde(path: &Path) -> PathBuf { path.to_path_buf() } +/// Replace the user's home directory prefix with `~` for display. +/// Returns the path unchanged if it is not under the home directory. +pub fn contract_tilde(path: &Path) -> PathBuf { + if let Some(home) = dirs::home_dir() { + if let Ok(rest) = path.strip_prefix(&home) { + return Path::new("~").join(rest); + } + } + path.to_path_buf() +} + #[cfg(test)] mod tests { use super::*; @@ -25,4 +36,19 @@ mod tests { fn expand_tilde_without_prefix() { assert_eq!(expand_tilde(Path::new("/abs/path")), Path::new("/abs/path")); } + + #[test] + fn contract_tilde_under_home() { + let home = dirs::home_dir().unwrap(); + let path = home.join("foo/bar"); + assert_eq!(contract_tilde(&path), Path::new("~/foo/bar")); + } + + #[test] + fn contract_tilde_outside_home() { + assert_eq!( + contract_tilde(Path::new("/tmp/other")), + Path::new("/tmp/other") + ); + } }