From 8d0308eecbab87d24d4d72575054a5c1d60bd109 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 9 Apr 2026 16:01:18 +0900 Subject: [PATCH] =?UTF-8?q?fix(cli):=20dispatch=20bare=20skill=20names=20t?= =?UTF-8?q?o=20skill=20invoker=20in=20REPL=20=E2=80=94=20ROADMAP=20#36?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users were typing skill names (e.g. 'caveman', 'find-skills') directly in the REPL and getting LLM responses instead of skill invocation. Only '/skills ' triggered dispatch; bare names fell through to run_turn. Fix: after slash-command parse returns None (bare text), check if the first token looks like a skill name (alphanumeric/dash/underscore, no slash). If resolve_skill_invocation() confirms the skill exists, dispatch the full input as a skill prompt. Unknown words fall through unchanged. 156 CLI tests pass, fmt clean. --- rust/crates/rusty-claude-cli/src/main.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/rust/crates/rusty-claude-cli/src/main.rs b/rust/crates/rusty-claude-cli/src/main.rs index 052b565..ee974e4 100644 --- a/rust/crates/rusty-claude-cli/src/main.rs +++ b/rust/crates/rusty-claude-cli/src/main.rs @@ -35,8 +35,8 @@ use commands::{ 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_skills_slash_command, handle_skills_slash_command_json, render_slash_command_help, - render_slash_command_help_filtered, resume_supported_slash_commands, slash_command_specs, - validate_slash_command_input, SkillSlashDispatch, SlashCommand, + render_slash_command_help_filtered, resolve_skill_invocation, resume_supported_slash_commands, + slash_command_specs, validate_slash_command_input, SkillSlashDispatch, SlashCommand, }; use compat_harness::{extract_manifest, UpstreamPaths}; use init::initialize_repo; @@ -2862,6 +2862,26 @@ fn run_repl( continue; } } + // Bare-word skill dispatch: if the first token of the input + // matches a known skill name, invoke it as `/skills ` + // rather than forwarding raw text to the LLM (ROADMAP #36). + let bare_first_token = trimmed.split_whitespace().next().unwrap_or_default(); + let looks_like_skill_name = !bare_first_token.is_empty() + && !bare_first_token.starts_with('/') + && bare_first_token + .chars() + .all(|c| c.is_alphanumeric() || c == '-' || c == '_'); + if looks_like_skill_name { + let cwd = std::env::current_dir().unwrap_or_default(); + if let Ok(SkillSlashDispatch::Invoke(prompt)) = + resolve_skill_invocation(&cwd, Some(&trimmed)) + { + editor.push_history(input); + cli.record_prompt_history(&trimmed); + cli.run_turn(&prompt)?; + continue; + } + } editor.push_history(input); cli.record_prompt_history(&trimmed); cli.run_turn(&trimmed)?;