From 316864227c76cf5f22c0fcdcdb6da60f78634400 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 10 Apr 2026 03:02:00 +0900 Subject: [PATCH] fix(cli): JSON parity for /help and /diff in resume mode /help now emits: {kind:help, text:} /diff now emits: - no git repo: {kind:diff, result:no_git_repo, detail:...} - clean tree: {kind:diff, result:clean, staged:'', unstaged:''} - changes: {kind:diff, result:changes, staged:..., unstaged:...} Previously both returned json:None and fell through to prose output even in --output-format json --resume mode. 159 CLI tests pass. --- rust/crates/rusty-claude-cli/src/main.rs | 43 +++++++++++++++++++----- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index df90e57..d8ce69b 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -2662,7 +2662,7 @@ fn run_resume_command( SlashCommand::Help => Ok(ResumeCommandOutcome { session: session.clone(), message: Some(render_repl_help()), - json: None, + json: Some(serde_json::json!({ "kind": "help", "text": render_repl_help() })), }), SlashCommand::Compact => { let result = runtime::compact_session( @@ -2817,13 +2817,16 @@ fn run_resume_command( json: Some(init_json_value(&message)), }) } - SlashCommand::Diff => Ok(ResumeCommandOutcome { - session: session.clone(), - message: Some(render_diff_report_for( - &std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), - )?), - json: None, - }), + SlashCommand::Diff => { + let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); + let message = render_diff_report_for(&cwd)?; + let json = render_diff_json_for(&cwd)?; + Ok(ResumeCommandOutcome { + session: session.clone(), + message: Some(message), + json: Some(json), + }) + } SlashCommand::Version => Ok(ResumeCommandOutcome { session: session.clone(), message: Some(render_version_report()), @@ -5554,6 +5557,30 @@ fn render_diff_report_for(cwd: &Path) -> Result Result> { + let in_git_repo = std::process::Command::new("git") + .args(["rev-parse", "--is-inside-work-tree"]) + .current_dir(cwd) + .output() + .map(|o| o.status.success()) + .unwrap_or(false); + if !in_git_repo { + return Ok(serde_json::json!({ + "kind": "diff", + "result": "no_git_repo", + "detail": format!("{} is not inside a git project", cwd.display()), + })); + } + let staged = run_git_diff_command_in(cwd, &["diff", "--cached"])?; + let unstaged = run_git_diff_command_in(cwd, &["diff"])?; + Ok(serde_json::json!({ + "kind": "diff", + "result": if staged.trim().is_empty() && unstaged.trim().is_empty() { "clean" } else { "changes" }, + "staged": staged.trim(), + "unstaged": unstaged.trim(), + })) +} + fn run_git_diff_command_in( cwd: &Path, args: &[&str],