Make the REPL feel more reliable and discoverable

This pass hardens the interactive UX instead of chasing feature breadth.
It preserves raw REPL input whitespace, honors the configured editorMode
for vim-oriented sessions, improves slash-command help readability, and
turns unknown slash commands into actionable guidance instead of noisy
stderr output.

Constraint: Keep the existing slash-command surface and avoid new dependencies
Rejected: Full TUI/input rewrite | too broad for a polish-and-reliability pass
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Preserve user prompt text exactly in the REPL path; do not reintroduce blanket trimming before runtime submission
Tested: cargo check
Tested: cargo test
Tested: Manual QA of /help, /status, /statu suggestion flow, and editorMode=vim banner/help/status behavior
Not-tested: Live network-backed assistant turns against a real provider
This commit is contained in:
Yeachan-Heo
2026-04-01 13:05:32 +00:00
parent 27e46d7ea6
commit a13b1c2825
5 changed files with 235 additions and 60 deletions

View File

@@ -389,34 +389,32 @@ pub fn resume_supported_slash_commands() -> Vec<&'static SlashCommandSpec> {
pub fn render_slash_command_help() -> String {
let mut lines = vec![
"Slash commands".to_string(),
" [resume] means the command also works with --resume SESSION.json".to_string(),
" [resume] = also available via claw --resume SESSION.json".to_string(),
];
for spec in slash_command_specs() {
let name = match spec.argument_hint {
Some(argument_hint) => format!("/{} {}", spec.name, argument_hint),
None => format!("/{}", spec.name),
};
let alias_suffix = if spec.aliases.is_empty() {
String::new()
} else {
format!(
" (aliases: {})",
spec.aliases
.iter()
.map(|alias| format!("/{alias}"))
.collect::<Vec<_>>()
.join(", ")
)
};
let resume = if spec.resume_supported {
" [resume]"
} else {
""
};
lines.push(format!(
" {name:<20} {}{alias_suffix}{resume}",
spec.summary
));
lines.push(format!(" {name}"));
lines.push(format!(" {}", spec.summary));
if !spec.aliases.is_empty() || spec.resume_supported {
let mut details = Vec::new();
if !spec.aliases.is_empty() {
details.push(format!(
"aliases: {}",
spec.aliases
.iter()
.map(|alias| format!("/{alias}"))
.collect::<Vec<_>>()
.join(", ")
));
}
if spec.resume_supported {
details.push("[resume]".to_string());
}
lines.push(format!(" {}", details.join(" · ")));
}
}
lines.join("\n")
}
@@ -1413,7 +1411,7 @@ mod tests {
#[test]
fn renders_help_from_shared_specs() {
let help = render_slash_command_help();
assert!(help.contains("works with --resume SESSION.json"));
assert!(help.contains("available via claw --resume SESSION.json"));
assert!(help.contains("/help"));
assert!(help.contains("/status"));
assert!(help.contains("/compact"));