From be748a880d6d53cc7be03e4e58720981c5ab8c7c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 14 Apr 2026 15:22:25 -0400 Subject: [PATCH] Show `fabro secret set` command in doctor remediation output Doctor warnings for Sandbox and Brave Search now display the exact command needed to configure the secret. Backtick-delimited text in remediation strings renders in bold cyan, matching the conventional CLI command styling used elsewhere. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/crates/fabro-server/src/diagnostics.rs | 10 +++- lib/crates/fabro-util/src/check_report.rs | 63 +++++++++++++++++++++- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/lib/crates/fabro-server/src/diagnostics.rs b/lib/crates/fabro-server/src/diagnostics.rs index bf0181afa..7c2b38189 100644 --- a/lib/crates/fabro-server/src/diagnostics.rs +++ b/lib/crates/fabro-server/src/diagnostics.rs @@ -424,7 +424,10 @@ fn check_sandbox(state: &AppState) -> CheckResult { status: CheckStatus::Warning, summary: "recommended, not configured".to_string(), details: Vec::new(), - remediation: Some("Set DAYTONA_API_KEY to enable cloud sandbox execution".to_string()), + remediation: Some( + "Run `fabro secret set DAYTONA_API_KEY ` to enable cloud sandbox execution" + .to_string(), + ), } } } @@ -436,7 +439,10 @@ async fn check_brave_search(state: &AppState) -> CheckResult { status: CheckStatus::Warning, summary: "optional, not configured".to_string(), details: Vec::new(), - remediation: Some("Set BRAVE_SEARCH_API_KEY to enable web search".to_string()), + remediation: Some( + "Run `fabro secret set BRAVE_SEARCH_API_KEY ` to enable web search" + .to_string(), + ), }; }; diff --git a/lib/crates/fabro-util/src/check_report.rs b/lib/crates/fabro-util/src/check_report.rs index 4f07871b6..c20d307a3 100644 --- a/lib/crates/fabro-util/src/check_report.rs +++ b/lib/crates/fabro-util/src/check_report.rs @@ -4,6 +4,22 @@ use serde::Serialize; use crate::terminal::Styles; +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// Write `text` to `out`, rendering backtick-delimited segments with +/// `s.bold_cyan` (the conventional style for inline CLI commands). +fn write_styled_remediation(out: &mut String, text: &str, s: &Styles) { + for (i, segment) in text.split('`').enumerate() { + if i % 2 == 1 { + write!(out, "{}", s.bold_cyan.apply_to(segment)).unwrap(); + } else { + out.push_str(segment); + } + } +} + // --------------------------------------------------------------------------- // Core types // --------------------------------------------------------------------------- @@ -153,7 +169,8 @@ impl CheckReport { for check in &errors { write!(out, " • {}", check.name).unwrap(); if let Some(ref rem) = check.remediation { - write!(out, " — {rem}").unwrap(); + write!(out, " — ").unwrap(); + write_styled_remediation(&mut out, rem, s); } writeln!(out).unwrap(); } @@ -169,7 +186,8 @@ impl CheckReport { for check in &warnings { write!(out, " • {}", check.name).unwrap(); if let Some(ref rem) = check.remediation { - write!(out, " — {rem}").unwrap(); + write!(out, " — ").unwrap(); + write_styled_remediation(&mut out, rem, s); } writeln!(out).unwrap(); } @@ -483,4 +501,45 @@ mod tests { assert!(out.contains("\x1b[31m")); assert!(out.contains("Git clean: false")); } + + // -- render: backtick-styled remediation -- + + #[test] + fn render_remediation_backticks_no_color() { + let r = report(vec![CheckResult { + name: "Sandbox".into(), + status: CheckStatus::Warning, + summary: "not configured".into(), + details: Vec::new(), + remediation: Some("Run `fabro secret set KEY` to fix".into()), + }]); + let out = r.render(&Styles::new(false), false, None, None); + insta::assert_snapshot!(out, @r" + Test Report + + [!] Sandbox (not configured) + + Found issues in 1 category. + + Warnings: + • Sandbox — Run fabro secret set KEY to fix + "); + } + + #[test] + fn render_remediation_backticks_with_color() { + let r = report(vec![CheckResult { + name: "Sandbox".into(), + status: CheckStatus::Warning, + summary: "not configured".into(), + details: Vec::new(), + remediation: Some("Run `fabro secret set KEY` to fix".into()), + }]); + let out = r.render(&Styles::new(true), false, None, None); + // ANSI codes should wrap the command text + assert!(out.contains("\x1b[")); + assert!(out.contains("fabro secret set KEY")); + // backticks should not appear in the output + assert!(!out.contains('`')); + } }