#!/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