fix: direct-slash resume-safe commands route to CliAction instead of interactive_only (#831)

`claw /status`, `claw /diff`, `claw /version`, `claw /doctor`,
`claw /sandbox` all returned interactive_only because the direct-slash
handler only had explicit arms for /help, /agents, /mcp, /skills.
Other resume-safe slash commands fell through to the generic
`Ok(Some(command)) => Err(interactive_only...)` arm.

Fix: add explicit routing arms for SlashCommand::Status, ::Diff,
::Version, ::Doctor, ::Sandbox in `parse_direct_slash_command`.

One new integration test: direct_slash_resume_safe_commands_route_correctly
(covers /version, /sandbox, /diff)

572+ tests pass.
This commit is contained in:
YeonGyu-Kim
2026-05-29 17:11:00 +09:00
parent 63931c74fb
commit 892d8f9ea6
3 changed files with 52 additions and 0 deletions

View File

@@ -1741,6 +1741,21 @@ fn parse_direct_slash_cli_action(
}),
}
}
// #831: resume-safe slash commands invoked directly (claw /status,
// claw /diff, claw /version, claw /doctor, claw /sandbox) should
// route to the same CliAction as their subcommand equivalents.
// Previously they fell through to the generic interactive_only arm.
Ok(Some(SlashCommand::Status)) => Ok(CliAction::Status {
model: model.to_string(),
model_flag_raw: None,
permission_mode: permission_mode_override.unwrap_or_else(default_permission_mode),
output_format,
allowed_tools,
}),
Ok(Some(SlashCommand::Diff)) => Ok(CliAction::Diff { output_format }),
Ok(Some(SlashCommand::Version)) => Ok(CliAction::Version { output_format }),
Ok(Some(SlashCommand::Doctor)) => Ok(CliAction::Doctor { output_format }),
Ok(Some(SlashCommand::Sandbox)) => Ok(CliAction::Sandbox { output_format }),
Ok(Some(SlashCommand::Unknown(name))) => {
// #828: /approve and /deny are valid REPL-only slash commands that
// are not SlashCommand enum variants (they require an active tool

View File

@@ -4084,3 +4084,34 @@ fn mcp_show_missing_server_name_emits_missing_argument() {
"mcp show (no name) JSON must have empty stderr (#830): {stderr:?}"
);
}
// #831: direct-slash resume-safe commands must route to their CliAction equivalents
#[test]
fn direct_slash_resume_safe_commands_route_correctly() {
let root = unique_temp_dir("direct-slash-resume-831");
std::fs::create_dir_all(&root).expect("create temp dir");
// /version, /doctor, /sandbox, /diff all work without --resume
for (cmd, expected_kind) in &[
("/version", "version"),
("/sandbox", "sandbox"),
("/diff", "diff"),
] {
let output = run_claw(&root, &["--output-format", "json", cmd], &[]);
let stdout = String::from_utf8_lossy(&output.stdout);
let j: serde_json::Value = serde_json::from_str(stdout.trim())
.unwrap_or_else(|_| panic!("{cmd} must emit JSON (#831), got: {stdout:?}"));
assert_eq!(
j["status"], "ok",
"{cmd} direct slash must exit ok (#831): {j}"
);
assert_ne!(
j["error_kind"], "interactive_only",
"{cmd} direct slash must not emit interactive_only (#831): {j}"
);
let kind = j["kind"].as_str().unwrap_or("");
assert_eq!(
kind, *expected_kind,
"{cmd} direct slash must emit kind={expected_kind} (#831): {j}"
);
}
}