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) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-04-14 15:22:25 -04:00
parent e366e4e761
commit be748a880d
2 changed files with 69 additions and 4 deletions

View file

@ -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 <value>` 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 <value>` to enable web search"
.to_string(),
),
};
};

View file

@ -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('`'));
}
}