fix(cli): JSON parity for /help and /diff in resume mode

/help now emits: {kind:help, text:<full 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.
This commit is contained in:
YeonGyu-Kim
2026-04-10 03:02:00 +09:00
parent ece48c7174
commit 316864227c

View File

@@ -2662,7 +2662,7 @@ fn run_resume_command(
SlashCommand::Help => Ok(ResumeCommandOutcome { SlashCommand::Help => Ok(ResumeCommandOutcome {
session: session.clone(), session: session.clone(),
message: Some(render_repl_help()), message: Some(render_repl_help()),
json: None, json: Some(serde_json::json!({ "kind": "help", "text": render_repl_help() })),
}), }),
SlashCommand::Compact => { SlashCommand::Compact => {
let result = runtime::compact_session( let result = runtime::compact_session(
@@ -2817,13 +2817,16 @@ fn run_resume_command(
json: Some(init_json_value(&message)), json: Some(init_json_value(&message)),
}) })
} }
SlashCommand::Diff => Ok(ResumeCommandOutcome { 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(), session: session.clone(),
message: Some(render_diff_report_for( message: Some(message),
&std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), json: Some(json),
)?), })
json: None, }
}),
SlashCommand::Version => Ok(ResumeCommandOutcome { SlashCommand::Version => Ok(ResumeCommandOutcome {
session: session.clone(), session: session.clone(),
message: Some(render_version_report()), message: Some(render_version_report()),
@@ -5554,6 +5557,30 @@ fn render_diff_report_for(cwd: &Path) -> Result<String, Box<dyn std::error::Erro
Ok(format!("Diff\n\n{}", sections.join("\n\n"))) Ok(format!("Diff\n\n{}", sections.join("\n\n")))
} }
fn render_diff_json_for(cwd: &Path) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
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( fn run_git_diff_command_in(
cwd: &Path, cwd: &Path,
args: &[&str], args: &[&str],