mirror of
https://github.com/instructkr/claude-code.git
synced 2026-05-30 09:16:44 +00:00
Keep doctor help machine-discoverable locally (#3184)
Doctor help was already on the local help path in current source, but the exact #702 dogfood surface lacked a focused guard and the JSON help envelope was still too prose-oriented for wrappers. Strengthen the JSON contract while preserving text help.\n\nConstraint: Preserve unrelated dirty rust/Cargo.lock from prior #701 work.\nRejected: Starting runtime/provider/session to inspect doctor semantics | help must be local and credential-free.\nConfidence: high\nScope-risk: narrow\nDirective: Keep doctor help routed through parse_local_help_action and print_help_topic; do not call run_doctor for --help.\nTested: cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --test output_format_contract doctor_help -- --nocapture; cargo test --manifest-path rust/Cargo.toml -p rusty-claude-cli --test output_format_contract help -- --nocapture; cargo fmt --manifest-path rust/Cargo.toml --all -- --check; cargo check --manifest-path rust/Cargo.toml -p rusty-claude-cli; timeout 5s cargo run -q --bin claw -- --output-format json doctor --help; timeout 5s cargo run -q --bin claw -- doctor --help.\nNot-tested: full workspace test suite.
This commit is contained in:
@@ -7885,10 +7885,51 @@ fn render_export_help_json() -> serde_json::Value {
|
||||
})
|
||||
}
|
||||
|
||||
fn render_doctor_help_json() -> serde_json::Value {
|
||||
json!({
|
||||
"kind": "help",
|
||||
"action": "help",
|
||||
"status": "ok",
|
||||
"topic": "doctor",
|
||||
"command": "doctor",
|
||||
"schema_version": "1.0",
|
||||
"usage": "claw doctor [--output-format <format>]",
|
||||
"purpose": "diagnose local auth, config, workspace, sandbox, boot preflight, and build metadata",
|
||||
"formats": ["text", "json"],
|
||||
"local_only": true,
|
||||
"requires_credentials": false,
|
||||
"requires_provider_request": false,
|
||||
"requires_session_resume": false,
|
||||
"mutates_workspace": false,
|
||||
"output_fields": ["kind", "action", "status", "message", "report", "has_failures", "summary", "checks"],
|
||||
"check_names": ["auth", "config", "install source", "workspace", "boot preflight", "sandbox", "system"],
|
||||
"status_values": ["ok", "warn", "fail"],
|
||||
"options": [
|
||||
{
|
||||
"name": "--output-format",
|
||||
"value": "<format>",
|
||||
"values": ["text", "json"],
|
||||
"default": "text",
|
||||
"description": "format for the doctor report or help envelope"
|
||||
},
|
||||
{
|
||||
"name": "--help",
|
||||
"aliases": ["-h"],
|
||||
"description": "show help for the doctor command without running diagnostics"
|
||||
}
|
||||
],
|
||||
"related": ["/doctor", "claw --resume latest /doctor"],
|
||||
"message": render_help_topic(LocalHelpTopic::Doctor),
|
||||
})
|
||||
}
|
||||
|
||||
fn render_help_topic_json(topic: LocalHelpTopic) -> serde_json::Value {
|
||||
if topic == LocalHelpTopic::Export {
|
||||
return render_export_help_json();
|
||||
}
|
||||
if topic == LocalHelpTopic::Doctor {
|
||||
return render_doctor_help_json();
|
||||
}
|
||||
|
||||
json!({
|
||||
"kind": "help",
|
||||
|
||||
@@ -66,6 +66,52 @@ fn export_help_preserves_plaintext_in_text_mode_384() {
|
||||
serde_json::from_str::<Value>(&stdout).expect_err("text help should remain plaintext");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctor_help_json_is_local_structured_and_bounded_702() {
|
||||
let root = unique_temp_dir("doctor-help-json-702");
|
||||
fs::create_dir_all(&root).expect("temp dir should exist");
|
||||
|
||||
let parsed = assert_json_command(&root, &["--output-format", "json", "doctor", "--help"]);
|
||||
assert_eq!(parsed["kind"], "help");
|
||||
assert_eq!(parsed["action"], "help");
|
||||
assert_eq!(parsed["status"], "ok");
|
||||
assert_eq!(parsed["topic"], "doctor");
|
||||
assert_eq!(parsed["command"], "doctor");
|
||||
assert_eq!(parsed["usage"], "claw doctor [--output-format <format>]");
|
||||
assert_eq!(parsed["local_only"], true);
|
||||
assert_eq!(parsed["requires_credentials"], false);
|
||||
assert_eq!(parsed["requires_provider_request"], false);
|
||||
assert_eq!(parsed["requires_session_resume"], false);
|
||||
assert_eq!(parsed["mutates_workspace"], false);
|
||||
|
||||
let fields = parsed["output_fields"].as_array().expect("output_fields");
|
||||
assert!(fields.iter().any(|field| field == "checks"));
|
||||
let statuses = parsed["status_values"].as_array().expect("status_values");
|
||||
assert!(statuses.iter().any(|status| status == "warn"));
|
||||
let checks = parsed["check_names"].as_array().expect("check_names");
|
||||
assert!(checks.iter().any(|check| check == "auth"));
|
||||
assert!(checks.iter().any(|check| check == "boot preflight"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctor_help_text_stays_plaintext_and_local_702() {
|
||||
let root = unique_temp_dir("doctor-help-text-702");
|
||||
fs::create_dir_all(&root).expect("temp dir should exist");
|
||||
|
||||
let output = run_claw(&root, &["doctor", "--help"], &[]);
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"stdout:\n{}\n\nstderr:\n{}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
let stdout = String::from_utf8(output.stdout).expect("stdout utf8");
|
||||
assert!(stdout.starts_with("Doctor\n"));
|
||||
assert!(stdout.contains("Usage claw doctor"));
|
||||
assert!(stdout.contains("no provider request or session resume required"));
|
||||
serde_json::from_str::<Value>(&stdout).expect_err("text help should remain plaintext");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn version_emits_json_when_requested() {
|
||||
let root = unique_temp_dir("version-json");
|
||||
|
||||
Reference in New Issue
Block a user