From b452ebe6ea27738a1f5db46371fc78c2e581c33d Mon Sep 17 00:00:00 2001 From: kevin9327 <5299031+kevin9327@users.noreply.github.com> Date: Mon, 5 Oct 2026 16:21:48 +0900 Subject: [PATCH] fix(doctor): put keep-local before the destructive restore hint When automatic skill updates pause for local changes, doctor listed both actions on one line with the overwrite option last. Put the recommended keep-local command first, label the restore path as destructive, and separate the two lines so the overwrite is harder to run by accident. Fixes #396 --- crates/bsk-cli/src/cli/doctor.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/bsk-cli/src/cli/doctor.rs b/crates/bsk-cli/src/cli/doctor.rs index f50e63d4..9436432c 100644 --- a/crates/bsk-cli/src/cli/doctor.rs +++ b/crates/bsk-cli/src/cli/doctor.rs @@ -268,7 +268,7 @@ fn auto_update_check( if hints.is_empty() { CheckResult::ok(name, detail) } else { - CheckResult::warn(name, detail, hints.join("; ")) + CheckResult::warn(name, detail, hints.join("\n")) } } @@ -472,7 +472,7 @@ fn skill_check_from_report(report: &crate::skill_install::sync::SyncReport) -> C details.extend(conflicts.iter().cloned()); } hints.push(format!( - "{id}: keep your instructions with `bsk install-skill --harness {id} --source --force`, or restore the bundled skill with `bsk install-skill --harness {id} --force` (overwrites existing instructions)" + "{id}: keep local changes (recommended): `bsk install-skill --harness {id} --source --force`\n{id}: discard local changes (overwrites existing instructions): `bsk install-skill --harness {id} --force`" )); } for (harness, message) in &report.errors { @@ -488,9 +488,9 @@ fn skill_check_from_report(report: &crate::skill_install::sync::SyncReport) -> C 0, "check filesystem access for the failing harness, then re-run `bsk doctor`".into(), ); - CheckResult::fail(name, detail, hints.join("; ")) + CheckResult::fail(name, detail, hints.join("\n")) } else if !report.paused.is_empty() { - CheckResult::warn(name, detail, hints.join("; ")) + CheckResult::warn(name, detail, hints.join("\n")) } else if !report.updated.is_empty() || !report.up_to_date.is_empty() { CheckResult::ok(name, detail) } else if !details.is_empty() { @@ -1061,7 +1061,12 @@ mod m2_tests { hint.contains("--harness cursor --source --force") ); assert!(hint.contains("--harness cursor --force")); - assert!(hint.contains("overwrites existing instructions")); + assert!(hint.contains("keep local changes (recommended)")); + assert!(hint.contains("discard local changes (overwrites existing instructions)")); + let keep = hint.find("keep local changes").expect("keep"); + let discard = hint.find("discard local changes").expect("discard"); + assert!(keep < discard, "recommended keep must come before destructive discard"); + assert!(hint.contains('\n'), "hint options must be on separate lines"); // An I/O failure takes precedence without hiding paused installations. report .errors