fix(cli): exclude stub slash commands from help output — ROADMAP #39

The --help slash-command section was listing ~35 unimplemented commands
alongside working ones. Combined with the completions fix (c55c510), the
discovery surface now consistently shows only implemented commands.

Changes:
- commands crate: add render_slash_command_help_filtered(exclude: &[&str])
- move STUB_COMMANDS to module-level const in main.rs (reused by both
  completions and help rendering)
- replace render_slash_command_help() with filtered variant at all
  help-rendering call sites

156 CLI tests pass, fmt clean.
This commit is contained in:
YeonGyu-Kim
2026-04-09 14:36:00 +09:00
parent 2a2e205414
commit 414526c1bd
2 changed files with 85 additions and 49 deletions

View File

@@ -1938,6 +1938,42 @@ pub fn suggest_slash_commands(input: &str, limit: usize) -> Vec<String> {
} }
#[must_use] #[must_use]
/// Render the slash-command help section, optionally excluding stub commands
/// (commands that are registered in the spec list but not yet implemented).
/// Pass an empty slice to include all commands.
pub fn render_slash_command_help_filtered(exclude: &[&str]) -> String {
let mut lines = vec![
"Slash commands".to_string(),
" Start here /status, /diff, /agents, /skills, /commit".to_string(),
" [resume] also works with --resume SESSION.jsonl".to_string(),
String::new(),
];
let categories = ["Session", "Tools", "Config", "Debug"];
for category in categories {
lines.push(category.to_string());
for spec in slash_command_specs()
.iter()
.filter(|spec| slash_command_category(spec.name) == category)
.filter(|spec| !exclude.contains(&spec.name))
{
lines.push(format_slash_command_help_line(spec));
}
lines.push(String::new());
}
lines
.into_iter()
.rev()
.skip_while(String::is_empty)
.collect::<Vec<_>>()
.into_iter()
.rev()
.collect::<Vec<_>>()
.join("\n")
}
pub fn render_slash_command_help() -> String { pub fn render_slash_command_help() -> String {
let mut lines = vec![ let mut lines = vec![
"Slash commands".to_string(), "Slash commands".to_string(),

View File

@@ -35,8 +35,8 @@ use commands::{
classify_skills_slash_command, handle_agents_slash_command, handle_agents_slash_command_json, classify_skills_slash_command, handle_agents_slash_command, handle_agents_slash_command_json,
handle_mcp_slash_command, handle_mcp_slash_command_json, handle_plugins_slash_command, handle_mcp_slash_command, handle_mcp_slash_command_json, handle_plugins_slash_command,
handle_skills_slash_command, handle_skills_slash_command_json, render_slash_command_help, handle_skills_slash_command, handle_skills_slash_command_json, render_slash_command_help,
resume_supported_slash_commands, slash_command_specs, validate_slash_command_input, render_slash_command_help_filtered, resume_supported_slash_commands, slash_command_specs,
SkillSlashDispatch, SlashCommand, validate_slash_command_input, SkillSlashDispatch, SlashCommand,
}; };
use compat_harness::{extract_manifest, UpstreamPaths}; use compat_harness::{extract_manifest, UpstreamPaths};
use init::initialize_repo; use init::initialize_repo;
@@ -4711,7 +4711,7 @@ fn render_repl_help() -> String {
" Browse sessions /session list".to_string(), " Browse sessions /session list".to_string(),
" Show prompt history /history [count]".to_string(), " Show prompt history /history [count]".to_string(),
String::new(), String::new(),
render_slash_command_help(), render_slash_command_help_filtered(STUB_COMMANDS),
] ]
.join( .join(
" "
@@ -6925,6 +6925,51 @@ fn collect_prompt_cache_events(summary: &runtime::TurnSummary) -> Vec<serde_json
.collect() .collect()
} }
/// Slash commands that are registered in the spec list but not yet implemented
/// in this build. Used to filter both REPL completions and help output so the
/// discovery surface only shows commands that actually work (ROADMAP #39).
const STUB_COMMANDS: &[&str] = &[
"login",
"logout",
"vim",
"upgrade",
"stats",
"share",
"feedback",
"files",
"fast",
"exit",
"summary",
"desktop",
"brief",
"advisor",
"stickers",
"insights",
"thinkback",
"release-notes",
"security-review",
"keybindings",
"privacy-settings",
"plan",
"review",
"tasks",
"theme",
"voice",
"usage",
"rename",
"copy",
"hooks",
"context",
"color",
"effort",
"branch",
"rewind",
"ide",
"tag",
"output-style",
"add-dir",
];
fn slash_command_completion_candidates_with_sessions( fn slash_command_completion_candidates_with_sessions(
model: &str, model: &str,
active_session_id: Option<&str>, active_session_id: Option<&str>,
@@ -6932,51 +6977,6 @@ fn slash_command_completion_candidates_with_sessions(
) -> Vec<String> { ) -> Vec<String> {
let mut completions = BTreeSet::new(); let mut completions = BTreeSet::new();
// Commands that are registered in the spec list but not yet implemented
// in this build. Exclude them from completions so the discovery surface
// matches what actually works (ROADMAP #39).
const STUB_COMMANDS: &[&str] = &[
"login",
"logout",
"vim",
"upgrade",
"stats",
"share",
"feedback",
"files",
"fast",
"exit",
"summary",
"desktop",
"brief",
"advisor",
"stickers",
"insights",
"thinkback",
"release-notes",
"security-review",
"keybindings",
"privacy-settings",
"plan",
"review",
"tasks",
"theme",
"voice",
"usage",
"rename",
"copy",
"hooks",
"context",
"color",
"effort",
"branch",
"rewind",
"ide",
"tag",
"output-style",
"add-dir",
];
for spec in slash_command_specs() { for spec in slash_command_specs() {
if STUB_COMMANDS.contains(&spec.name) { if STUB_COMMANDS.contains(&spec.name) {
continue; continue;
@@ -7874,7 +7874,7 @@ fn print_help_to(out: &mut impl Write) -> io::Result<()> {
)?; )?;
writeln!(out)?; writeln!(out)?;
writeln!(out, "Interactive slash commands:")?; writeln!(out, "Interactive slash commands:")?;
writeln!(out, "{}", render_slash_command_help())?; writeln!(out, "{}", render_slash_command_help_filtered(STUB_COMMANDS))?;
writeln!(out)?; writeln!(out)?;
let resume_commands = resume_supported_slash_commands() let resume_commands = resume_supported_slash_commands()
.into_iter() .into_iter()