generated from nhcarrigan/template
feat: list available skills when running /skill with no args
- Add list_skills Tauri command to scan ~/.claude/skills/ - Only lists directories containing a SKILL.md file - Show helpful message when no skills are found - Display bullet-point list of available skills with usage hint
This commit is contained in:
@@ -180,3 +180,45 @@ pub async fn answer_question(
|
|||||||
let mut manager = bridge_manager.lock();
|
let mut manager = bridge_manager.lock();
|
||||||
manager.send_tool_result(&conversation_id, &tool_use_id, answers)
|
manager.send_tool_result(&conversation_id, &tool_use_id, answers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn list_skills() -> Result<Vec<String>, String> {
|
||||||
|
use std::path::Path;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
// Get the home directory
|
||||||
|
let home = std::env::var_os("HOME")
|
||||||
|
.ok_or_else(|| "Could not determine home directory".to_string())?;
|
||||||
|
|
||||||
|
let skills_dir = Path::new(&home).join(".claude").join("skills");
|
||||||
|
|
||||||
|
// If the skills directory doesn't exist, return empty list
|
||||||
|
if !skills_dir.exists() {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the directory and collect skill names
|
||||||
|
let mut skills = Vec::new();
|
||||||
|
let entries = fs::read_dir(&skills_dir)
|
||||||
|
.map_err(|e| format!("Failed to read skills directory: {}", e))?;
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?;
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
// Only include directories that contain a SKILL.md file
|
||||||
|
if path.is_dir() {
|
||||||
|
let skill_file = path.join("SKILL.md");
|
||||||
|
if skill_file.exists() {
|
||||||
|
if let Some(name) = path.file_name() {
|
||||||
|
skills.push(name.to_string_lossy().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort alphabetically
|
||||||
|
skills.sort();
|
||||||
|
|
||||||
|
Ok(skills)
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ pub fn run() {
|
|||||||
send_wsl_notification,
|
send_wsl_notification,
|
||||||
send_vbs_notification,
|
send_vbs_notification,
|
||||||
validate_directory,
|
validate_directory,
|
||||||
|
list_skills,
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export const slashCommands: SlashCommand[] = [
|
|||||||
{
|
{
|
||||||
name: "skill",
|
name: "skill",
|
||||||
description: "Invoke a Claude Code skill from ~/.claude/skills/",
|
description: "Invoke a Claude Code skill from ~/.claude/skills/",
|
||||||
usage: "/skill <name> <data>",
|
usage: "/skill [name] [data]",
|
||||||
execute: async (args: string) => {
|
execute: async (args: string) => {
|
||||||
const conversationId = get(claudeStore.activeConversationId);
|
const conversationId = get(claudeStore.activeConversationId);
|
||||||
if (!conversationId) {
|
if (!conversationId) {
|
||||||
@@ -198,11 +198,25 @@ export const slashCommands: SlashCommand[] = [
|
|||||||
const skillName = parts[0];
|
const skillName = parts[0];
|
||||||
const skillData = parts.slice(1).join(" ");
|
const skillData = parts.slice(1).join(" ");
|
||||||
|
|
||||||
|
// If no skill name provided, list available skills
|
||||||
if (!skillName) {
|
if (!skillName) {
|
||||||
claudeStore.addLine(
|
try {
|
||||||
"error",
|
const skills = await invoke<string[]>("list_skills");
|
||||||
"Usage: /skill <skill-name> [data]\nSkills are loaded from ~/.claude/skills/<skill-name>/SKILL.md\nExample: /skill onboard-mentee Discord ID: 123, GitHub: username"
|
if (skills.length === 0) {
|
||||||
);
|
claudeStore.addLine(
|
||||||
|
"system",
|
||||||
|
"No skills found in ~/.claude/skills/\nCreate a skill by adding a folder with a SKILL.md file."
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const skillList = skills.map((s) => ` • ${s}`).join("\n");
|
||||||
|
claudeStore.addLine(
|
||||||
|
"system",
|
||||||
|
`Available skills:\n${skillList}\n\nUsage: /skill <skill-name> [data]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
claudeStore.addLine("error", `Failed to list skills: ${error}`);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user