#!/bin/bash # OpenCode Skills Installer # Simple, bash 3 compatible script set -e # Config REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" SKILLS_DIR="${REPO_ROOT}/skills" GLOBAL_DIR="${HOME}/.config/opencode" GLOBAL_SKILLS_DIR="${GLOBAL_DIR}/skills" UNIFIED_ENV="${GLOBAL_DIR}/.env" REPO_UNIFIED_ENV="${REPO_ROOT}/.env" # Colors INFO='\033[0;34m' SUCCESS='\033[0;32m' WARNING='\033[1;33m' ERROR='\033[0;31m' NC='\033[0m' print_info() { echo -e "${INFO}[INFO]${NC} $1"; } print_success() { echo -e "${SUCCESS}[OK]${NC} $1"; } print_warning() { echo -e "${WARNING}[WARN]${NC} $1"; } print_error() { echo -e "${ERROR}[ERR]${NC} $1"; } line() { echo "=========================================="; } # Get list of skills get_skills() { local found="" for dir in "$SKILLS_DIR"/*/; do [ -d "$dir" ] || continue name=$(basename "$dir") [ -f "$dir/SKILL.md" ] && found="$found $name" done echo $found } # Get env vars from .env.example get_env_vars() { local file="$1" [ -f "$file" ] || return grep -v '^#' "$file" | grep -v '^$' | grep '=' | cut -d'=' -f1 } # Setup unified .env setup_unified_env() { local env_example="${REPO_ROOT}/.env.example" local env_file="${REPO_ROOT}/.env" [ -f "$env_example" ] || return line print_info "Unified Configuration Setup" line echo "" print_info "Found unified .env.example" echo "This file contains credentials for ALL skills." echo "" # Get all env vars ENV_VARS=$(get_env_vars "$env_example") if [ -n "$ENV_VARS" ]; then print_info "Environment variables needed:" for v in $ENV_VARS; do echo " - $v" done line echo "" echo "Please enter values below:" echo "(Press Enter to skip optional values)" echo "" VALUES_FILE="/tmp/opencode_values_$$" > "$VALUES_FILE" for var in $ENV_VARS; do val="" confirm="" matched=0 # Check if it's optional or per-website is_optional=0 is_per_website=0 case "$var" in UMAMI_WEBSITE_ID) is_per_website=1 ;; CHUTES_*) is_optional=1 ;; esac if [ $is_per_website -eq 1 ]; then print_info "Skipping $var (configured per-website)" continue fi while [ $matched -eq 0 ]; do val="" printf "Enter %s: " "$var" read val # Allow empty for optional vars if [ -z "$val" ] && [ $is_optional -eq 1 ]; then matched=1 continue fi [ -z "$val" ] && print_error "Cannot be empty (or type 'skip' for optional)" && continue # Confirm required values if [ $is_optional -eq 0 ]; then printf "Confirm %s: " "$var" read confirm if [ "$val" = "$confirm" ]; then matched=1 else print_error "Values don't match, try again" fi else matched=1 fi done [ -n "$val" ] && [ "$val" != "skip" ] && echo "${var}=${val}" >> "$VALUES_FILE" [ -n "$val" ] && [ "$val" != "skip" ] && print_success "Set $var" [ "$val" = "skip" ] && print_info "Skipped $var (optional)" done echo "" # Create unified .env print_info "Creating unified .env file..." while IFS= read -r line_content; do if echo "$line_content" | grep -q '^#'; then echo "$line_content" >> "$env_file" elif echo "$line_content" | grep -q '^[A-Z_]*='; then varname=$(echo "$line_content" | cut -d'=' -f1) val=$(grep "^${varname}=" "$VALUES_FILE" 2>/dev/null | cut -d'=' -f2-) [ -n "$val" ] && echo "${varname}=${val}" >> "$env_file" || echo "${varname}=" >> "$env_file" elif [ -n "$line_content" ]; then echo "$line_content" >> "$env_file" fi done < "$env_example" chmod 600 "$env_file" print_success "Created: ${env_file}" rm -f "$VALUES_FILE" echo "" fi } # Copy unified .env to global location copy_unified_env() { local source_env="${REPO_ROOT}/.env" local target_env="${GLOBAL_DIR}/.env" if [ -f "$source_env" ]; then print_info "Copying unified .env to global location..." mkdir -p "$GLOBAL_DIR" cp "$source_env" "$target_env" chmod 600 "$target_env" print_success "Created: ${target_env}" echo "" fi } # Main main() { line echo "OpenCode Skills Installer" line echo "" # Check skills directory if [ ! -d "$SKILLS_DIR" ]; then print_error "Skills directory not found: $SKILLS_DIR" exit 1 fi # Setup unified .env FIRST setup_unified_env # Find skills print_info "Finding skills..." SKILLS=$(get_skills) if [ -z "$SKILLS" ]; then print_error "No skills found" exit 1 fi for s in $SKILLS; do print_info "Found: $s" done echo "" # Choose install location line print_info "Install location:" echo " 1) Global (~/.config/opencode/skills)" echo " 2) Project (./.opencode/skills)" line echo -n "Choice [1]: " read choice if [ "$choice" = "2" ]; then TARGET="${REPO_ROOT}/.opencode/skills" else TARGET="$GLOBAL_SKILLS_DIR" fi mkdir -p "$TARGET" echo "" # Install skills print_info "Installing to $TARGET..." for skill in $SKILLS; do dest="${TARGET}/${skill}" if [ -d "$dest" ]; then echo -n "$skill exists. Overwrite? [y/N]: " read ow if [ "$ow" != "y" ] && [ "$ow" != "Y" ]; then print_warning "Skipped $skill" continue fi rm -rf "$dest" fi cp -r "${SKILLS_DIR}/${skill}" "$dest" print_success "$skill" # If skill has install.sh, run it if [ -f "${SKILLS_DIR}/${skill}/scripts/install.sh" ]; then print_info "Running install script for $skill..." chmod +x "${SKILLS_DIR}/${skill}/scripts/install.sh" "${SKILLS_DIR}/${skill}/scripts/install.sh" 2>/dev/null || print_warning "Install failed for $skill (continuing...)" fi done echo "" # Install deps print_info "Installing dependencies..." PIP="" if command -v pip3 >/dev/null 2>&1; then PIP="pip3" elif command -v pip >/dev/null 2>&1; then PIP="pip" fi if [ -n "$PIP" ]; then for skill in $SKILLS; do req="${SKILLS_DIR}/${skill}/scripts/requirements.txt" if [ -f "$req" ]; then $PIP install -r "$req" -q 2>/dev/null && print_success "deps for $skill" fi done fi echo "" # Copy unified .env to global location copy_unified_env # Create skill-specific .env files that reference unified .env print_info "Creating skill configuration files..." for skill in $SKILLS; do dest="${TARGET}/${skill}" scripts_dir="${dest}/scripts" [ -d "$scripts_dir" ] || continue # Create .env file that tells script where to find unified .env cat > "${scripts_dir}/.env" << EOF # AUTO-GENERATED - DO NOT EDIT # This skill uses the unified .env file # Location: ${GLOBAL_DIR}/.env # # Edit that file instead to update credentials. # This file is overwritten on each install. EOF chmod 600 "${scripts_dir}/.env" done print_success "All skills configured" echo "" # Done line print_success "Installation complete!" line echo "" echo "Installed skills:" for skill in $SKILLS; do echo " - $skill" done echo "" echo "Location: $TARGET" echo "" echo "Unified .env: ${GLOBAL_DIR}/.env" echo "" print_info "IMPORTANT: Edit ${GLOBAL_DIR}/.env to update credentials" } main "$@"