diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 43677ef..d43fa01 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -180,3 +180,45 @@ pub async fn answer_question( let mut manager = bridge_manager.lock(); manager.send_tool_result(&conversation_id, &tool_use_id, answers) } + +#[tauri::command] +pub async fn list_skills() -> Result, 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) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 5655334..61bbfba 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -55,6 +55,7 @@ pub fn run() { send_wsl_notification, send_vbs_notification, validate_directory, + list_skills, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/lib/commands/slashCommands.ts b/src/lib/commands/slashCommands.ts index d2d6dcd..04bdd97 100644 --- a/src/lib/commands/slashCommands.ts +++ b/src/lib/commands/slashCommands.ts @@ -186,7 +186,7 @@ export const slashCommands: SlashCommand[] = [ { name: "skill", description: "Invoke a Claude Code skill from ~/.claude/skills/", - usage: "/skill ", + usage: "/skill [name] [data]", execute: async (args: string) => { const conversationId = get(claudeStore.activeConversationId); if (!conversationId) { @@ -198,11 +198,25 @@ export const slashCommands: SlashCommand[] = [ const skillName = parts[0]; const skillData = parts.slice(1).join(" "); + // If no skill name provided, list available skills if (!skillName) { - claudeStore.addLine( - "error", - "Usage: /skill [data]\nSkills are loaded from ~/.claude/skills//SKILL.md\nExample: /skill onboard-mentee Discord ID: 123, GitHub: username" - ); + try { + const skills = await invoke("list_skills"); + 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 [data]` + ); + } + } catch (error) { + claudeStore.addLine("error", `Failed to list skills: ${error}`); + } return; }