From fa2cb2a839a377e1bb7923b3d452c4c212069376 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Wed, 29 Apr 2026 14:41:05 -0400 Subject: [PATCH] feat(preflight): show spinner while server runs checks `fabro preflight` blocks on a single server-side `run_preflight` call. Without feedback the terminal sits blank until it returns. Mirror the existing `fabro doctor` spinner (cyan braille, "Running checks...", 80ms tick), gated on `!ctx.json_output()` so JSON and piped callers stay clean. The network calls run inside an inline async block so the spinner is `finish_and_clear`ed before any `?`-propagated error prints. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../fabro-cli/src/commands/preflight.rs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/crates/fabro-cli/src/commands/preflight.rs b/lib/crates/fabro-cli/src/commands/preflight.rs index 17b38026d..37cba56d2 100644 --- a/lib/crates/fabro-cli/src/commands/preflight.rs +++ b/lib/crates/fabro-cli/src/commands/preflight.rs @@ -30,8 +30,30 @@ pub(crate) async fn execute( run_id: None, user_settings_path: Some(active_settings_path(None)), })?; - let client = ctx.server().await?; - let response = client.run_preflight(manifest.manifest).await?; + + let spinner = if ctx.json_output() { + None + } else { + let spinner = indicatif::ProgressBar::new_spinner(); + spinner.set_style( + indicatif::ProgressStyle::with_template("{spinner:.cyan} {msg}") + .expect("valid template") + .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", ""]), + ); + spinner.set_message("Running checks..."); + spinner.enable_steady_tick(std::time::Duration::from_millis(80)); + Some(spinner) + }; + + let result = async { + let client = ctx.server().await?; + client.run_preflight(manifest.manifest).await + } + .await; + if let Some(spinner) = spinner.as_ref() { + spinner.finish_and_clear(); + } + let response = result?; let diagnostics = api_diagnostics_to_local(&response.workflow.diagnostics); if ctx.json_output() {