mirror of
https://github.com/instructkr/claw-code.git
synced 2026-04-07 00:24:50 +08:00
Let /skills invocations reach the prompt skill path
The CLI still treated every /skills payload other than list/install/help as local usage text, so skills that appeared in /skills could not actually be invoked. This restores prompt dispatch for /skills <skill> [args], keeps list/install on the local path, and shares skill resolution with the Skill tool so project-local and legacy /commands entries resolve consistently. Constraint: --resume local slash execution still only supports local commands without provider turns Rejected: Implement full resumed prompt-turn execution for /skills | larger behavior change outside this bugfix Rejected: Keep separate skill lookups in tools and commands | drift already caused listing/invocation mismatches Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep /skills discovery, CLI prompt dispatch, and Tool Skill resolution on the same registry semantics Tested: cargo fmt --all; cargo clippy -p commands -p tools -p rusty-claude-cli --all-targets -- -D warnings; cargo test --workspace -- --nocapture Not-tested: Live provider-backed /skills invocation against external skill packs in an interactive REPL
This commit is contained in:
@@ -31,10 +31,11 @@ use api::{
|
||||
};
|
||||
|
||||
use commands::{
|
||||
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, resume_supported_slash_commands,
|
||||
slash_command_specs, validate_slash_command_input, SlashCommand,
|
||||
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,
|
||||
resume_supported_slash_commands, slash_command_specs, validate_slash_command_input,
|
||||
SkillSlashDispatch, SlashCommand,
|
||||
};
|
||||
use compat_harness::{extract_manifest, UpstreamPaths};
|
||||
use init::initialize_repo;
|
||||
@@ -419,10 +420,22 @@ fn parse_args(args: &[String]) -> Result<CliAction, String> {
|
||||
args: join_optional_args(&rest[1..]),
|
||||
output_format,
|
||||
}),
|
||||
"skills" => Ok(CliAction::Skills {
|
||||
args: join_optional_args(&rest[1..]),
|
||||
output_format,
|
||||
}),
|
||||
"skills" => {
|
||||
let args = join_optional_args(&rest[1..]);
|
||||
match classify_skills_slash_command(args.as_deref()) {
|
||||
SkillSlashDispatch::Invoke(prompt) => Ok(CliAction::Prompt {
|
||||
prompt,
|
||||
model,
|
||||
output_format,
|
||||
allowed_tools,
|
||||
permission_mode,
|
||||
}),
|
||||
SkillSlashDispatch::Local => Ok(CliAction::Skills {
|
||||
args,
|
||||
output_format,
|
||||
}),
|
||||
}
|
||||
}
|
||||
"system-prompt" => parse_system_prompt_args(&rest[1..], output_format),
|
||||
"login" => Ok(CliAction::Login { output_format }),
|
||||
"logout" => Ok(CliAction::Logout { output_format }),
|
||||
@@ -440,7 +453,13 @@ fn parse_args(args: &[String]) -> Result<CliAction, String> {
|
||||
permission_mode,
|
||||
})
|
||||
}
|
||||
other if other.starts_with('/') => parse_direct_slash_cli_action(&rest, output_format),
|
||||
other if other.starts_with('/') => parse_direct_slash_cli_action(
|
||||
&rest,
|
||||
model,
|
||||
output_format,
|
||||
allowed_tools,
|
||||
permission_mode,
|
||||
),
|
||||
_other => Ok(CliAction::Prompt {
|
||||
prompt: rest.join(" "),
|
||||
model,
|
||||
@@ -532,7 +551,10 @@ fn join_optional_args(args: &[String]) -> Option<String> {
|
||||
|
||||
fn parse_direct_slash_cli_action(
|
||||
rest: &[String],
|
||||
model: String,
|
||||
output_format: CliOutputFormat,
|
||||
allowed_tools: Option<AllowedToolSet>,
|
||||
permission_mode: PermissionMode,
|
||||
) -> Result<CliAction, String> {
|
||||
let raw = rest.join(" ");
|
||||
match SlashCommand::parse(&raw) {
|
||||
@@ -550,10 +572,21 @@ fn parse_direct_slash_cli_action(
|
||||
},
|
||||
output_format,
|
||||
}),
|
||||
Ok(Some(SlashCommand::Skills { args })) => Ok(CliAction::Skills {
|
||||
args,
|
||||
output_format,
|
||||
}),
|
||||
Ok(Some(SlashCommand::Skills { args })) => {
|
||||
match classify_skills_slash_command(args.as_deref()) {
|
||||
SkillSlashDispatch::Invoke(prompt) => Ok(CliAction::Prompt {
|
||||
prompt,
|
||||
model,
|
||||
output_format,
|
||||
allowed_tools,
|
||||
permission_mode,
|
||||
}),
|
||||
SkillSlashDispatch::Local => Ok(CliAction::Skills {
|
||||
args,
|
||||
output_format,
|
||||
}),
|
||||
}
|
||||
}
|
||||
Ok(Some(SlashCommand::Unknown(name))) => Err(format_unknown_direct_slash_command(&name)),
|
||||
Ok(Some(command)) => Err({
|
||||
let _ = command;
|
||||
@@ -2281,6 +2314,11 @@ fn run_resume_command(
|
||||
})
|
||||
}
|
||||
SlashCommand::Skills { args } => {
|
||||
if let SkillSlashDispatch::Invoke(_) = classify_skills_slash_command(args.as_deref()) {
|
||||
return Err(
|
||||
"resumed /skills invocations are interactive-only; start `claw` and run `/skills <skill>` in the REPL".into(),
|
||||
);
|
||||
}
|
||||
let cwd = env::current_dir()?;
|
||||
Ok(ResumeCommandOutcome {
|
||||
session: session.clone(),
|
||||
@@ -3203,7 +3241,12 @@ impl LiveCli {
|
||||
false
|
||||
}
|
||||
SlashCommand::Skills { args } => {
|
||||
Self::print_skills(args.as_deref(), CliOutputFormat::Text)?;
|
||||
match classify_skills_slash_command(args.as_deref()) {
|
||||
SkillSlashDispatch::Invoke(prompt) => self.run_turn(&prompt)?,
|
||||
SkillSlashDispatch::Local => {
|
||||
Self::print_skills(args.as_deref(), CliOutputFormat::Text)?;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
SlashCommand::Doctor => {
|
||||
@@ -7123,6 +7166,21 @@ mod tests {
|
||||
output_format: CliOutputFormat::Text,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_args(&[
|
||||
"skills".to_string(),
|
||||
"help".to_string(),
|
||||
"overview".to_string()
|
||||
])
|
||||
.expect("skills help overview should invoke"),
|
||||
CliAction::Prompt {
|
||||
prompt: "$help overview".to_string(),
|
||||
model: DEFAULT_MODEL.to_string(),
|
||||
output_format: CliOutputFormat::Text,
|
||||
allowed_tools: None,
|
||||
permission_mode: crate::default_permission_mode(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_args(&["agents".to_string(), "--help".to_string()])
|
||||
.expect("agents help should parse"),
|
||||
@@ -7264,6 +7322,21 @@ mod tests {
|
||||
output_format: CliOutputFormat::Text,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_args(&[
|
||||
"/skills".to_string(),
|
||||
"help".to_string(),
|
||||
"overview".to_string()
|
||||
])
|
||||
.expect("/skills help overview should invoke"),
|
||||
CliAction::Prompt {
|
||||
prompt: "$help overview".to_string(),
|
||||
model: DEFAULT_MODEL.to_string(),
|
||||
output_format: CliOutputFormat::Text,
|
||||
allowed_tools: None,
|
||||
permission_mode: crate::default_permission_mode(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_args(&[
|
||||
"/skills".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user