#!/usr/bin/env bash set -euo pipefail # Check which skills from the source repo are missing from the active Claude profile. DEFAULT_SKILLS_REPO="$HOME/dev/claude/projects/custom-claude-skills/skills" usage() { cat <<'EOF' Usage: check-skills [OPTIONS] [SKILLS_REPO] Check which skills from the custom-claude-skills repository are missing from the active Claude Code profile's skills directory. Arguments: SKILLS_REPO Path to skills source directory (default: ~/dev/claude/projects/custom-claude-skills/skills) Options: --profile DIR Override Claude profile directory (default: $CLAUDE_CONFIG_DIR or ~/.claude) --dryrun, -n Accepted for convention compliance (script is read-only) --help, -h Show this help EOF } # Colours GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' RED='\033[0;31m' BOLD='\033[1m' NC='\033[0m' # Parse args profile_dir="" skills_repo="" while [[ $# -gt 0 ]]; do case "$1" in --profile) profile_dir="$2"; shift 2 ;; --dryrun|-n) shift ;; --help|-h) usage; exit 0 ;; -*) echo "Unknown option: $1" >&2; usage >&2; exit 1 ;; *) skills_repo="$1"; shift ;; esac done skills_repo="${skills_repo:-$DEFAULT_SKILLS_REPO}" profile_dir="${profile_dir:-${CLAUDE_CONFIG_DIR:-$HOME/.claude}}" profile_skills="$profile_dir/skills" # Validate source if [[ ! -d "$skills_repo" ]]; then echo -e "${RED}ERROR${NC} Skills source directory not found: $skills_repo" >&2 exit 1 fi # Display paths (use ~ shorthand for readability) display_profile="${profile_skills/#$HOME/~}" display_source="${skills_repo/#$HOME/~}" echo -e "${BOLD}Profile:${NC} $display_profile" echo -e "${BOLD}Source:${NC} $display_source" echo "" linked=0 missing=0 stale=0 orphan=0 # Check each source skill for skill_dir in "$skills_repo"/*/; do [[ -d "$skill_dir" ]] || continue [[ -f "$skill_dir/SKILL.md" ]] || continue skill_name="$(basename "$skill_dir")" target="$profile_skills/$skill_name" if [[ -L "$target" ]]; then actual="$(readlink -f "$target" 2>/dev/null || echo "BROKEN")" expected="$(readlink -f "$skill_dir")" if [[ "$actual" == "$expected" ]]; then echo -e " ${GREEN}LINKED${NC} $skill_name" linked=$((linked + 1)) else echo -e " ${YELLOW}STALE${NC} $skill_name (points to $actual)" stale=$((stale + 1)) fi elif [[ -e "$target" ]]; then echo -e " ${YELLOW}STALE${NC} $skill_name (non-symlink exists)" stale=$((stale + 1)) else echo -e " ${YELLOW}MISSING${NC} $skill_name" missing=$((missing + 1)) fi done # Check for orphans in profile if [[ -d "$profile_skills" ]]; then for entry in "$profile_skills"/*/; do [[ -d "$entry" || -L "$entry" ]] || continue entry_name="$(basename "$entry")" if [[ ! -d "$skills_repo/$entry_name" ]]; then echo -e " ${CYAN}ORPHAN${NC} $entry_name (not in source repo)" orphan=$((orphan + 1)) fi done fi echo "" echo -e "Summary: ${GREEN}$linked linked${NC}, ${YELLOW}$missing missing${NC}, ${YELLOW}$stale stale${NC}, ${CYAN}$orphan orphan${NC}" if [[ $missing -gt 0 || $stale -gt 0 ]]; then echo "" echo "Run 'install.sh' from the custom-claude-skills repo to fix missing/stale skills." exit 1 fi exit 0