Files
gh-tenequm-claude-plugins-s…/skills/skill/references/installation-workflow.md
2025-11-30 09:01:22 +08:00

548 lines
13 KiB
Markdown

# Installation Workflow for Claude Skills
Complete guide to previewing, downloading, and installing Claude skills from GitHub.
## Installation Process Overview
1. **Preview** - Show skill details and requirements
2. **Confirm** - Get user approval
3. **Download** - Fetch skill files from GitHub
4. **Install** - Place in correct directory structure
5. **Verify** - Confirm installation success
6. **Setup** - Run any required setup steps
## Step 1: Preview Skill
### Fetch SKILL.md Content
```bash
# Get direct link to SKILL.md
skill_url="https://github.com/OWNER/REPO/blob/main/PATH/SKILL.md"
skill_path="PATH/SKILL.md"
# Fetch content (first 50 lines for preview)
gh api repos/OWNER/REPO/contents/$skill_path | \
jq -r '.content' | base64 -d | head -50
```
### Extract Key Information
```bash
# Parse SKILL.md for important details
skill_content=$(gh api repos/OWNER/REPO/contents/$skill_path | jq -r '.content' | base64 -d)
# Extract name (first # heading)
skill_name=$(echo "$skill_content" | grep -m1 '^# ' | sed 's/^# //')
# Extract description (first paragraph after title)
description=$(echo "$skill_content" | sed -n '/^# /,/^$/p' | grep -v '^#' | head -1)
# Extract dependencies
dependencies=$(echo "$skill_content" | grep -A10 -i "dependencies\|requirements\|prerequisites" | head -10)
# Extract usage examples
examples=$(echo "$skill_content" | grep -A10 -i "usage\|example\|quick start" | head -15)
```
### Display Preview
```bash
cat <<EOF
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📦 Skill Preview: $skill_name
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📝 Description:
$description
⭐ Repository: $repo_full_name
🌟 Stars: $stars
🔄 Last Updated: $days_ago days ago
📋 Dependencies:
$dependencies
💡 Usage Example:
$examples
📎 Full Documentation:
$skill_url
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EOF
```
## Step 2: Confirm Installation
### Check Existing Installation
```bash
# Determine skill directory name
skill_dir_name=$(echo "$skill_name" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
skill_dir=".claude/skills/$skill_dir_name"
# Check if already installed
if [ -d "$skill_dir" ]; then
echo "⚠️ Skill '$skill_name' is already installed at: $skill_dir"
echo ""
echo "Options:"
echo " [U] Update (overwrite existing)"
echo " [K] Keep existing (cancel)"
echo " [B] Backup and install new"
echo ""
read -p "Choose option [U/K/B]: " choice
case $choice in
[Uu])
echo "Overwriting existing installation..."
;;
[Kk])
echo "Keeping existing installation. Cancelled."
exit 0
;;
[Bb])
backup_dir="${skill_dir}.backup.$(date +%s)"
mv "$skill_dir" "$backup_dir"
echo "✅ Backed up to: $backup_dir"
;;
*)
echo "Invalid option. Cancelled."
exit 1
;;
esac
fi
```
### Get User Confirmation
```bash
echo ""
echo "Install '$skill_name' to $skill_dir?"
echo ""
read -p "Continue? [y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy] ]]; then
echo "Installation cancelled."
exit 0
fi
```
## Step 3: Download Skill Files
### Determine Skill Structure
Skills can have different structures:
1. **Simple** - Single SKILL.md file
2. **Standard** - SKILL.md + reference files
3. **Plugin** - Nested in `skills/` subdirectory
4. **Complex** - Multiple files, scripts, dependencies
```bash
# Detect structure type
structure_type=$(detect_skill_structure "$repo" "$skill_path")
case $structure_type in
"simple")
download_simple_skill "$repo" "$skill_path" "$skill_dir"
;;
"standard")
download_standard_skill "$repo" "$skill_path" "$skill_dir"
;;
"plugin")
download_plugin_skill "$repo" "$skill_path" "$skill_dir"
;;
"complex")
download_complex_skill "$repo" "$skill_path" "$skill_dir"
;;
esac
```
### Download Simple Skill (SKILL.md only)
```bash
download_simple_skill() {
local repo=$1
local skill_path=$2
local dest_dir=$3
echo "📥 Downloading simple skill..."
# Create destination directory
mkdir -p "$dest_dir"
# Download SKILL.md
gh api "repos/$repo/contents/$skill_path" | \
jq -r '.content' | base64 -d > "$dest_dir/SKILL.md"
if [ -f "$dest_dir/SKILL.md" ]; then
echo "✅ Downloaded SKILL.md"
else
echo "❌ Failed to download SKILL.md"
return 1
fi
}
```
### Download Standard Skill (with references)
```bash
download_standard_skill() {
local repo=$1
local skill_path=$2
local dest_dir=$3
echo "📥 Downloading standard skill..."
# Get skill directory path from SKILL.md path
skill_dir_path=$(dirname "$skill_path")
# Get all files in skill directory
gh api "repos/$repo/contents/$skill_dir_path?recursive=1" | \
jq -r '.tree[] | select(.type == "blob") | .path' | \
while read file_path; do
# Calculate relative path
rel_path=${file_path#$skill_dir_path/}
dest_file="$dest_dir/$rel_path"
# Create subdirectories
mkdir -p "$(dirname "$dest_file")"
# Download file
gh api "repos/$repo/contents/$file_path" | \
jq -r '.content' | base64 -d > "$dest_file"
echo "$rel_path"
done
echo "✅ Downloaded all skill files"
}
```
### Download Plugin Skill (nested structure)
```bash
download_plugin_skill() {
local repo=$1
local skill_path=$2
local dest_dir=$3
echo "📥 Downloading plugin skill..."
echo " (This may take a moment...)"
# Clone repository to temporary location
temp_dir=$(mktemp -d)
gh repo clone "$repo" "$temp_dir" -- --depth 1 --quiet
# Extract skill directory from SKILL.md path
# Example: skills/playwright-skill/SKILL.md -> skills/playwright-skill
skill_subdir=$(dirname "$skill_path")
# Copy skill directory to destination
if [ -d "$temp_dir/$skill_subdir" ]; then
cp -r "$temp_dir/$skill_subdir/"* "$dest_dir/"
echo "✅ Copied skill from $skill_subdir"
else
echo "❌ Skill directory not found: $skill_subdir"
rm -rf "$temp_dir"
return 1
fi
# Cleanup
rm -rf "$temp_dir"
}
```
### Download Complex Skill (with setup)
```bash
download_complex_skill() {
local repo=$1
local skill_path=$2
local dest_dir=$3
echo "📥 Downloading complex skill..."
# Use plugin download method
download_plugin_skill "$repo" "$skill_path" "$dest_dir"
# Check for dependencies
if [ -f "$dest_dir/package.json" ]; then
echo ""
echo "📦 This skill has npm dependencies."
echo " Run: cd $dest_dir && npm install"
fi
if [ -f "$dest_dir/requirements.txt" ]; then
echo ""
echo "🐍 This skill has Python dependencies."
echo " Run: cd $dest_dir && pip install -r requirements.txt"
fi
if [ -f "$dest_dir/setup.sh" ]; then
echo ""
echo "🔧 This skill has a setup script."
read -p " Run setup.sh now? [y/N]: " run_setup
if [[ "$run_setup" =~ ^[Yy] ]]; then
(cd "$dest_dir" && bash setup.sh)
fi
fi
}
```
## Step 4: Verify Installation
### Check Required Files
```bash
verify_installation() {
local skill_dir=$1
local errors=0
echo ""
echo "🔍 Verifying installation..."
# Check SKILL.md exists
if [ ! -f "$skill_dir/SKILL.md" ]; then
echo " ❌ Missing SKILL.md"
((errors++))
else
echo " ✅ SKILL.md present"
fi
# Check file permissions
if [ ! -r "$skill_dir/SKILL.md" ]; then
echo " ❌ SKILL.md not readable"
((errors++))
else
echo " ✅ File permissions OK"
fi
# Check for reference files (optional but good)
if [ -d "$skill_dir/references" ]; then
ref_count=$(find "$skill_dir/references" -type f | wc -l)
echo " ✅ Found $ref_count reference files"
fi
# Check for examples (optional)
if [ -d "$skill_dir/examples" ]; then
example_count=$(find "$skill_dir/examples" -type f | wc -l)
echo " ✅ Found $example_count example files"
fi
return $errors
}
```
### Validate SKILL.md Content
```bash
validate_skill_content() {
local skill_file=$1
# Check for required sections
local has_title=$(grep -q '^# ' "$skill_file" && echo "yes" || echo "no")
local has_description=$(grep -qi 'description\|what.*does' "$skill_file" && echo "yes" || echo "no")
local has_usage=$(grep -qi 'usage\|example\|how.*use' "$skill_file" && echo "yes" || echo "no")
if [ "$has_title" = "yes" ] && [ "$has_description" = "yes" ]; then
echo " ✅ SKILL.md structure valid"
return 0
else
echo " ⚠️ SKILL.md may be incomplete (missing title or description)"
return 1
fi
}
```
## Step 5: Post-Installation
### Run Setup Scripts
```bash
# Check for and run setup
if [ -f "$skill_dir/setup.sh" ]; then
echo ""
echo "🔧 Running setup script..."
(cd "$skill_dir" && bash setup.sh)
if [ $? -eq 0 ]; then
echo "✅ Setup completed successfully"
else
echo "⚠️ Setup script had warnings (check above)"
fi
fi
```
### Install Dependencies
```bash
# npm dependencies
if [ -f "$skill_dir/package.json" ]; then
echo ""
echo "📦 Installing npm dependencies..."
(cd "$skill_dir" && npm install --silent)
echo "✅ npm dependencies installed"
fi
# Python dependencies
if [ -f "$skill_dir/requirements.txt" ]; then
echo ""
echo "🐍 Installing Python dependencies..."
pip install -q -r "$skill_dir/requirements.txt"
echo "✅ Python dependencies installed"
fi
```
### Create Usage Instructions
```bash
cat <<EOF
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Installation Complete!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📁 Installed to: $skill_dir
🚀 Usage:
Invoke the skill by typing: /$skill_dir_name
Or let Claude auto-invoke when relevant
📖 Documentation:
Read: $skill_dir/SKILL.md
Examples: $skill_dir/examples/ (if available)
🔄 Update:
Re-run installation to update to latest version
❌ Uninstall:
rm -rf $skill_dir
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EOF
```
## Complete Installation Script
```bash
#!/bin/bash
install_skill() {
local repo=$1
local skill_path=$2
local skill_name=$3
# 1. Determine destination
skill_dir_name=$(echo "$skill_name" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
skill_dir=".claude/skills/$skill_dir_name"
# 2. Preview
echo "Fetching skill preview..."
skill_content=$(gh api "repos/$repo/contents/$skill_path" | jq -r '.content' | base64 -d)
description=$(echo "$skill_content" | sed -n '/^# /,/^$/p' | grep -v '^#' | head -1)
echo ""
echo "📦 $skill_name"
echo "📝 $description"
echo "📁 Will install to: $skill_dir"
echo ""
# 3. Confirm
read -p "Install this skill? [y/N]: " confirm
[[ ! "$confirm" =~ ^[Yy] ]] && { echo "Cancelled."; return 1; }
# 4. Check existing
if [ -d "$skill_dir" ]; then
read -p "Skill exists. Overwrite? [y/N]: " overwrite
[[ ! "$overwrite" =~ ^[Yy] ]] && { echo "Cancelled."; return 1; }
rm -rf "$skill_dir"
fi
# 5. Download
mkdir -p "$skill_dir"
# Detect if plugin format or simple
if [[ "$skill_path" == *"/skills/"* ]]; then
# Plugin format - clone and extract
temp_dir=$(mktemp -d)
gh repo clone "$repo" "$temp_dir" -- --depth 1 --quiet
skill_subdir=$(dirname "$skill_path")
cp -r "$temp_dir/$skill_subdir/"* "$skill_dir/"
rm -rf "$temp_dir"
else
# Simple format - direct download
gh api "repos/$repo/contents/$skill_path" | \
jq -r '.content' | base64 -d > "$skill_dir/SKILL.md"
fi
# 6. Verify
if [ -f "$skill_dir/SKILL.md" ]; then
echo "✅ Installation successful!"
echo "📁 Location: $skill_dir"
echo "🚀 Use: /$skill_dir_name"
else
echo "❌ Installation failed"
return 1
fi
}
# Usage:
# install_skill "lackeyjb/playwright-skill" "skills/playwright-skill/SKILL.md" "playwright-skill"
```
## Error Handling
### Common Issues
**Issue: Repository not found**
```bash
if ! gh api "repos/$repo" &>/dev/null; then
echo "❌ Repository not found or not accessible: $repo"
echo " Check if the repository exists and is public"
exit 1
fi
```
**Issue: SKILL.md not found**
```bash
if ! gh api "repos/$repo/contents/$skill_path" &>/dev/null; then
echo "❌ SKILL.md not found at: $skill_path"
echo " Searching for SKILL.md in repository..."
# Try to find it
found_paths=$(gh api "repos/$repo/git/trees/main?recursive=1" | \
jq -r '.tree[] | select(.path | contains("SKILL.md")) | .path')
if [ -n "$found_paths" ]; then
echo " Found SKILL.md at:"
echo "$found_paths" | sed 's/^/ /'
else
echo " No SKILL.md found in repository"
fi
exit 1
fi
```
**Issue: Permission denied**
```bash
if [ ! -w ".claude/skills" ]; then
echo "❌ Cannot write to .claude/skills directory"
echo " Check permissions: ls -la .claude/skills"
exit 1
fi
```
**Issue: Network/API error**
```bash
if ! ping -c 1 api.github.com &>/dev/null; then
echo "❌ Cannot reach GitHub API"
echo " Check your internet connection"
exit 1
fi
```
---
**Summary:** The installation workflow ensures safe, verified installation of Claude skills with proper error handling, user confirmation, and post-installation setup.