feat: Add installation tool, Claude.ai export, and skill standardization (#1)
## Summary - Add portable installation tool (`install.sh`) for cross-machine setup - Add Claude.ai export files with proper YAML frontmatter - Add multi-agent-guide v2.0 with consolidated framework template - Rename `00-claude-code-setting` → `00-our-settings-audit` (avoid reserved word) - Add YAML frontmatter to 25+ SKILL.md files for Claude Desktop compatibility ## Commits Included - `93f604a` feat: Add portable installation tool for cross-machine setup - `9b84104` feat: Add Claude.ai export for portable skill installation - `f7ab973` fix: Add YAML frontmatter to Claude.ai export files - `3fed49a` feat(multi-agent-guide): Add v2.0 with consolidated framework - `3be26ef` refactor: Rename settings-audit skill and add YAML frontmatter Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
415
custom-skills/_ourdigital-shared/install.sh
Executable file
415
custom-skills/_ourdigital-shared/install.sh
Executable file
@@ -0,0 +1,415 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# OurDigital Skills Installer
|
||||
# Portable installation tool for OurDigital Claude Skills package
|
||||
#
|
||||
# Usage:
|
||||
# ./install.sh # Interactive install
|
||||
# ./install.sh --update # Update existing installation
|
||||
# ./install.sh --uninstall # Remove installation
|
||||
# ./install.sh --help # Show help
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILLS_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ENV_FILE="$HOME/.env.ourdigital"
|
||||
CONFIG_DIR="$HOME/.ourdigital"
|
||||
VENV_DIR="$SKILLS_DIR/.venv-ourdigital"
|
||||
|
||||
# Print banner
|
||||
print_banner() {
|
||||
echo -e "${CYAN}"
|
||||
echo "╔═══════════════════════════════════════════════════════════╗"
|
||||
echo "║ ║"
|
||||
echo "║ OurDigital Skills Installer ║"
|
||||
echo "║ 사람, 디지털, 그리고 문화 ║"
|
||||
echo "║ ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════╝"
|
||||
echo -e "${NC}"
|
||||
}
|
||||
|
||||
# Print colored messages
|
||||
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# Check prerequisites
|
||||
check_prerequisites() {
|
||||
info "Checking prerequisites..."
|
||||
|
||||
local missing=()
|
||||
|
||||
# Check Python 3.11+
|
||||
if command -v python3 &> /dev/null; then
|
||||
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
|
||||
if [[ $(echo "$PYTHON_VERSION >= 3.11" | bc -l) -eq 1 ]]; then
|
||||
success "Python $PYTHON_VERSION"
|
||||
else
|
||||
warn "Python $PYTHON_VERSION (3.11+ recommended)"
|
||||
fi
|
||||
else
|
||||
missing+=("python3")
|
||||
fi
|
||||
|
||||
# Check git
|
||||
if command -v git &> /dev/null; then
|
||||
success "Git $(git --version | cut -d' ' -f3)"
|
||||
else
|
||||
missing+=("git")
|
||||
fi
|
||||
|
||||
# Check 1Password CLI (optional)
|
||||
if command -v op &> /dev/null; then
|
||||
success "1Password CLI available"
|
||||
HAS_1PASSWORD=true
|
||||
else
|
||||
warn "1Password CLI not found (credentials will need manual entry)"
|
||||
HAS_1PASSWORD=false
|
||||
fi
|
||||
|
||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||
error "Missing required tools: ${missing[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Create directory structure
|
||||
setup_directories() {
|
||||
info "Setting up directories..."
|
||||
|
||||
# Create config directory
|
||||
mkdir -p "$CONFIG_DIR/credentials"
|
||||
chmod 700 "$CONFIG_DIR"
|
||||
chmod 700 "$CONFIG_DIR/credentials"
|
||||
success "Created $CONFIG_DIR/"
|
||||
|
||||
# Create logs directory
|
||||
mkdir -p "$CONFIG_DIR/logs"
|
||||
success "Created $CONFIG_DIR/logs/"
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Setup environment file
|
||||
setup_environment() {
|
||||
info "Setting up environment file..."
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
warn "$ENV_FILE already exists"
|
||||
read -p "Overwrite? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
info "Keeping existing environment file"
|
||||
return
|
||||
fi
|
||||
cp "$ENV_FILE" "$ENV_FILE.backup.$(date +%Y%m%d%H%M%S)"
|
||||
success "Backed up existing file"
|
||||
fi
|
||||
|
||||
cp "$SCRIPT_DIR/.env.ourdigital.template" "$ENV_FILE"
|
||||
chmod 600 "$ENV_FILE"
|
||||
success "Created $ENV_FILE"
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Setup credentials from 1Password or manual
|
||||
setup_credentials() {
|
||||
info "Setting up credentials..."
|
||||
|
||||
if [[ "$HAS_1PASSWORD" == true ]]; then
|
||||
read -p "Fetch credentials from 1Password? (Y/n): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
||||
fetch_from_1password
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Manual credential setup required.${NC}"
|
||||
echo "Edit $ENV_FILE with your API keys:"
|
||||
echo " - NOTION_API_TOKEN"
|
||||
echo " - GHOST_BLOG_ADMIN_KEY"
|
||||
echo " - GHOST_JOURNAL_ADMIN_KEY"
|
||||
echo " - FIGMA_ACCESS_TOKEN"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Fetch credentials from 1Password
|
||||
fetch_from_1password() {
|
||||
info "Fetching credentials from 1Password..."
|
||||
|
||||
# Check if signed in
|
||||
if ! op account list &> /dev/null; then
|
||||
warn "Please sign in to 1Password CLI first"
|
||||
echo "Run: eval \$(op signin)"
|
||||
return
|
||||
fi
|
||||
|
||||
# Fetch each credential
|
||||
local credentials=(
|
||||
"NOTION_API_TOKEN:OurDigital Notion:api_token"
|
||||
"GHOST_BLOG_ADMIN_KEY:OurDigital Ghost Blog:api_key"
|
||||
"GHOST_JOURNAL_ADMIN_KEY:OurDigital Ghost Journal:api_key"
|
||||
"FIGMA_ACCESS_TOKEN:OurDigital Figma:api_token"
|
||||
)
|
||||
|
||||
for cred in "${credentials[@]}"; do
|
||||
IFS=':' read -r env_var item_name field <<< "$cred"
|
||||
|
||||
if value=$(op item get "$item_name" --fields "$field" 2>/dev/null); then
|
||||
sed -i '' "s|^$env_var=.*|$env_var=$value|" "$ENV_FILE" 2>/dev/null || \
|
||||
sed -i "s|^$env_var=.*|$env_var=$value|" "$ENV_FILE"
|
||||
success "Fetched $env_var"
|
||||
else
|
||||
warn "Could not fetch $env_var from 1Password"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Setup Python virtual environment
|
||||
setup_python_env() {
|
||||
info "Setting up Python virtual environment..."
|
||||
|
||||
if [[ -d "$VENV_DIR" ]]; then
|
||||
warn "Virtual environment already exists"
|
||||
read -p "Recreate? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
rm -rf "$VENV_DIR"
|
||||
else
|
||||
info "Using existing virtual environment"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
python3 -m venv "$VENV_DIR"
|
||||
success "Created virtual environment"
|
||||
|
||||
# Activate and install dependencies
|
||||
source "$VENV_DIR/bin/activate"
|
||||
pip install --upgrade pip -q
|
||||
pip install -r "$SCRIPT_DIR/requirements/base.txt" -q
|
||||
success "Installed base dependencies"
|
||||
|
||||
# Install code-specific if requested
|
||||
read -p "Install Claude Code dependencies? (Y/n): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
||||
pip install -r "$SCRIPT_DIR/requirements/code.txt" -q
|
||||
success "Installed Code dependencies"
|
||||
fi
|
||||
|
||||
deactivate
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Copy config file
|
||||
setup_config() {
|
||||
info "Setting up configuration..."
|
||||
|
||||
if [[ ! -f "$CONFIG_DIR/config.yaml" ]]; then
|
||||
cp "$SCRIPT_DIR/config/ourdigital.yaml" "$CONFIG_DIR/config.yaml"
|
||||
success "Created $CONFIG_DIR/config.yaml"
|
||||
else
|
||||
info "Config file already exists, skipping"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Validate installation
|
||||
validate_installation() {
|
||||
info "Validating installation..."
|
||||
|
||||
local checks_passed=0
|
||||
local checks_total=6
|
||||
|
||||
# Check directories
|
||||
[[ -d "$CONFIG_DIR" ]] && ((checks_passed++)) && success "Config directory exists" || warn "Config directory missing"
|
||||
[[ -d "$CONFIG_DIR/credentials" ]] && ((checks_passed++)) && success "Credentials directory exists" || warn "Credentials directory missing"
|
||||
|
||||
# Check files
|
||||
[[ -f "$ENV_FILE" ]] && ((checks_passed++)) && success "Environment file exists" || warn "Environment file missing"
|
||||
[[ -f "$CONFIG_DIR/config.yaml" ]] && ((checks_passed++)) && success "Config file exists" || warn "Config file missing"
|
||||
|
||||
# Check virtual environment
|
||||
[[ -d "$VENV_DIR" ]] && ((checks_passed++)) && success "Virtual environment exists" || warn "Virtual environment missing"
|
||||
|
||||
# Check skills directory
|
||||
[[ -d "$SKILLS_DIR/01-ourdigital-brand-guide" ]] && ((checks_passed++)) && success "Skills directory valid" || warn "Skills not found"
|
||||
|
||||
echo ""
|
||||
echo -e "${CYAN}Validation: $checks_passed/$checks_total checks passed${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Show installed skills
|
||||
show_skills() {
|
||||
info "Installed OurDigital Skills:"
|
||||
echo ""
|
||||
|
||||
for dir in "$SKILLS_DIR"/0{1,2,3,4,5,6,7,8,9}-ourdigital-* "$SKILLS_DIR"/10-ourdigital-*; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
name=$(basename "$dir")
|
||||
desc=$(grep -m1 "^name:" "$dir/desktop/SKILL.md" 2>/dev/null | cut -d':' -f2 | xargs || echo "")
|
||||
echo -e " ${GREEN}✓${NC} $name"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Print usage instructions
|
||||
print_usage() {
|
||||
echo -e "${CYAN}Usage Instructions:${NC}"
|
||||
echo ""
|
||||
echo "1. Activate the virtual environment:"
|
||||
echo " source $VENV_DIR/bin/activate"
|
||||
echo ""
|
||||
echo "2. Edit credentials if needed:"
|
||||
echo " nano $ENV_FILE"
|
||||
echo ""
|
||||
echo "3. Use skills with 'our' or 'ourdigital' prefix:"
|
||||
echo " - our blog [topic]"
|
||||
echo " - our research [topic]"
|
||||
echo " - our 견적서"
|
||||
echo ""
|
||||
echo "4. Documentation:"
|
||||
echo " $SKILLS_DIR/OUR_SKILL_PROJECT_PLAN_v1.1.md"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Uninstall
|
||||
uninstall() {
|
||||
warn "This will remove OurDigital configuration (not skills)."
|
||||
read -p "Continue? (y/N): " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
info "Cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Backup before removing
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
cp "$ENV_FILE" "$ENV_FILE.uninstall.backup"
|
||||
rm "$ENV_FILE"
|
||||
success "Removed $ENV_FILE (backup saved)"
|
||||
fi
|
||||
|
||||
if [[ -d "$VENV_DIR" ]]; then
|
||||
rm -rf "$VENV_DIR"
|
||||
success "Removed virtual environment"
|
||||
fi
|
||||
|
||||
info "Config directory preserved at $CONFIG_DIR"
|
||||
info "To fully remove: rm -rf $CONFIG_DIR"
|
||||
|
||||
success "Uninstall complete"
|
||||
}
|
||||
|
||||
# Show help
|
||||
show_help() {
|
||||
echo "OurDigital Skills Installer"
|
||||
echo ""
|
||||
echo "Usage: ./install.sh [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --help, -h Show this help message"
|
||||
echo " --update, -u Update existing installation"
|
||||
echo " --uninstall Remove installation (preserves skills)"
|
||||
echo " --validate Only run validation checks"
|
||||
echo " --skip-creds Skip credentials setup"
|
||||
echo " --skip-venv Skip virtual environment setup"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " ./install.sh # Full interactive install"
|
||||
echo " ./install.sh --update # Update existing setup"
|
||||
echo " ./install.sh --skip-creds # Install without credentials"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main installation flow
|
||||
main_install() {
|
||||
print_banner
|
||||
check_prerequisites
|
||||
setup_directories
|
||||
setup_environment
|
||||
|
||||
if [[ "$SKIP_CREDS" != true ]]; then
|
||||
setup_credentials
|
||||
fi
|
||||
|
||||
if [[ "$SKIP_VENV" != true ]]; then
|
||||
setup_python_env
|
||||
fi
|
||||
|
||||
setup_config
|
||||
validate_installation
|
||||
show_skills
|
||||
print_usage
|
||||
|
||||
echo -e "${GREEN}╔═══════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${GREEN}║ Installation Complete! ║${NC}"
|
||||
echo -e "${GREEN}╚═══════════════════════════════════════════════════════════╝${NC}"
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
SKIP_CREDS=false
|
||||
SKIP_VENV=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--help|-h)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
--uninstall)
|
||||
uninstall
|
||||
exit 0
|
||||
;;
|
||||
--validate)
|
||||
validate_installation
|
||||
exit 0
|
||||
;;
|
||||
--update|-u)
|
||||
info "Updating installation..."
|
||||
setup_python_env
|
||||
validate_installation
|
||||
exit 0
|
||||
;;
|
||||
--skip-creds)
|
||||
SKIP_CREDS=true
|
||||
shift
|
||||
;;
|
||||
--skip-venv)
|
||||
SKIP_VENV=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
error "Unknown option: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Run main install
|
||||
main_install
|
||||
Reference in New Issue
Block a user