#!/usr/bin/env bash set -euo pipefail # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' DARKGRAY='\033[0;90m' NC='\033[0m' # No Color # Detect OS OS="unknown" case "$(uname -s)" in Linux*) OS="linux";; Darwin*) OS="macos";; CYGWIN*|MINGW*|MSYS*) OS="windows";; esac # Config paths if [ "$OS" = "windows" ]; then CONFIG_DIR="$USERPROFILE/.config/opencode" else CONFIG_DIR="$HOME/.config/opencode" fi REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" echo -e "${CYAN}========================================${NC}" echo -e "${CYAN} Opencode Config Installer (Unix) ${NC}" echo -e "${CYAN} OS: $OS ${NC}" echo -e "${CYAN}========================================${NC}" echo "" # Check prerequisites echo -e "${YELLOW}[*] Checking prerequisites...${NC}" if ! command -v git &> /dev/null; then echo -e "${RED}[ERROR] Git not found. Install git first.${NC}" exit 1 fi if ! command -v npm &> /dev/null; then echo -e "${RED}[ERROR] npm not found. Install Node.js from https://nodejs.org/${NC}" exit 1 fi if ! command -v python3 &> /dev/null && ! command -v python &> /dev/null; then echo -e "${RED}[ERROR] Python not found. Install Python 3.${NC}" exit 1 fi echo -e "${GREEN}[OK] Prerequisites met${NC}" echo "" # Get or prompt for API keys get_env_or_prompt() { local name="$1" local prompt="$2" local required="${3:-false}" local val="" # Check environment val="${!name:-}" if [ -z "$val" ]; then if [ "$required" = "true" ]; then read -rp "$prompt (required): " val if [ -z "$val" ]; then echo -e "${RED}[ERROR] $name is required${NC}" exit 1 fi else read -rp "$prompt (optional, press Enter to skip): " val fi # Save to shell rc file if [ -n "$val" ]; then local shell_rc="" if [ -f "$HOME/.zshrc" ]; then shell_rc="$HOME/.zshrc" elif [ -f "$HOME/.bashrc" ]; then shell_rc="$HOME/.bashrc" fi if [ -n "$shell_rc" ]; then echo "export $name=\"$val\"" >> "$shell_rc" echo -e "${DARKGRAY} Saved $name to $shell_rc${NC}" fi fi else echo -e "${DARKGRAY} Found $name in environment${NC}" fi echo "$val" } echo -e "${YELLOW}[*] Configuring secrets...${NC}" API_KEY=$(get_env_or_prompt "OPENCODE_API_KEY" "Enter your OpenAI-compatible API key" "true") BRAVE_KEY=$(get_env_or_prompt "BRAVE_API_KEY" "Enter your Brave Search API key" "false") # Detect or prompt for projects path PROJECTS_PATH="${PROJECTS_PATH:-}" if [ -z "$PROJECTS_PATH" ]; then default_path="$HOME/projects" read -rp "Enter your projects directory path [default: $default_path]: " PROJECTS_PATH if [ -z "$PROJECTS_PATH" ]; then PROJECTS_PATH="$default_path" fi if [ ! -d "$PROJECTS_PATH" ]; then echo -e "${DARKGRAY} Creating projects directory: $PROJECTS_PATH${NC}" mkdir -p "$PROJECTS_PATH" fi fi echo -e "${GREEN}[OK] Projects path: $PROJECTS_PATH${NC}" echo "" # Backup existing config if [ -f "$CONFIG_DIR/opencode.json" ]; then backup="$CONFIG_DIR/opencode.json.backup.$(date +%Y%m%d%H%M%S)" cp "$CONFIG_DIR/opencode.json" "$backup" echo -e "${YELLOW}[*] Backed up existing config to: $backup${NC}" fi # Create config directory mkdir -p "$CONFIG_DIR" # Generate opencode.json from template echo -e "${YELLOW}[*] Generating opencode.json...${NC}" # Escape path for JSON (handle backslashes on Windows) PROJECTS_PATH_ESCAPED="$PROJECTS_PATH" if [ "$OS" = "windows" ]; then # Double backslashes for JSON PROJECTS_PATH_ESCAPED="${PROJECTS_PATH//\\//\\\\}" fi # Read template and substitute sed -e "s|\\\${OPENCODE_API_KEY}|$API_KEY|g" \ -e "s|\\\${BRAVE_API_KEY}|$BRAVE_KEY|g" \ -e "s|\\\${PROJECTS_PATH}|$PROJECTS_PATH_ESCAPED|g" \ "$REPO_DIR/opencode.json.template" > "$CONFIG_DIR/opencode.json" # Disable brave-search if no key if [ -z "$BRAVE_KEY" ]; then echo -e "${DARKGRAY} [!] No Brave API key - disabling brave-search MCP${NC}" # Use python to safely modify JSON python3 -c " import json with open('$CONFIG_DIR/opencode.json', 'r') as f: config = json.load(f) if 'brave-search' in config.get('mcp', {}): config['mcp']['brave-search']['enabled'] = False if 'env' in config['mcp']['brave-search']: del config['mcp']['brave-search']['env'] with open('$CONFIG_DIR/opencode.json', 'w') as f: json.dump(config, f, indent=2) " 2>/dev/null || python -c " import json with open('$CONFIG_DIR/opencode.json', 'r') as f: config = json.load(f) if 'brave-search' in config.get('mcp', {}): config['mcp']['brave-search']['enabled'] = False if 'env' in config['mcp']['brave-search']: del config['mcp']['brave-search']['env'] with open('$CONFIG_DIR/opencode.json', 'w') as f: json.dump(config, f, indent=2) " fi echo -e "${GREEN}[OK] Config written to $CONFIG_DIR/opencode.json${NC}" echo "" # Copy agents and skills echo -e "${YELLOW}[*] Syncing agents and skills...${NC}" # Remove old skills/agents to ensure clean sync rm -rf "$CONFIG_DIR/agents" "$CONFIG_DIR/skills" cp -r "$REPO_DIR/agents" "$CONFIG_DIR/" cp -r "$REPO_DIR/skills" "$CONFIG_DIR/" SKILL_COUNT=$(find "$CONFIG_DIR/skills" -maxdepth 1 -type d | wc -l) SKILL_COUNT=$((SKILL_COUNT - 1)) # Exclude skills dir itself echo -e "${GREEN}[OK] Copied 3 agents and $SKILL_COUNT skills${NC}" echo "" # Install global dependencies echo -e "${YELLOW}[*] Installing global dependencies...${NC}" GLOBAL_PACKAGES=( "@colbymchenry/codegraph" "@brave/brave-search-mcp-server" "@modelcontextprotocol/server-filesystem" "@modelcontextprotocol/server-github" "@modelcontextprotocol/server-memory" "@modelcontextprotocol/server-sequential-thinking" "@playwright/mcp" "@upstash/context7-mcp" "mcp-remote" ) for pkg in "${GLOBAL_PACKAGES[@]}"; do echo -e "${DARKGRAY} Installing $pkg...${NC}" -n if npm install -g "$pkg" 2>/dev/null; then echo -e "${GREEN} OK${NC}" else echo -e "${YELLOW} SKIP (may already be installed)${NC}" fi done # Install Python git MCP echo -e "${DARKGRAY} Installing Python git MCP...${NC}" -n if python3 -m pip install mcp-server-git 2>/dev/null || python -m pip install mcp-server-git 2>/dev/null; then echo -e "${GREEN} OK${NC}" else echo -e "${YELLOW} SKIP${NC}" fi echo "" echo -e "${CYAN}========================================${NC}" echo -e "${GREEN} Installation Complete! ${NC}" echo -e "${CYAN}========================================${NC}" echo "" echo -e "${WHITE}Next steps:${NC}" echo -e " 1. Restart opencode to load new config" echo -e " 2. Run 'opencode' in your project directory" echo -e " 3. Initialize CodeGraph: codegraph init" echo "" echo -e "${DARKGRAY}Config location: $CONFIG_DIR${NC}" echo "" # Verify config echo -e "${YELLOW}[*] Verifying config...${NC}" if python3 -c "import json; config=json.load(open('$CONFIG_DIR/opencode.json')); print(f'[OK] Config valid - {len(config.get(\"mcp\", {}))} MCP servers configured')" 2>/dev/null || \ python -c "import json; config=json.load(open('$CONFIG_DIR/opencode.json')); print(f'[OK] Config valid - {len(config.get(\"mcp\", {}))} MCP servers configured')" 2>/dev/null; then : else echo -e "${YELLOW}[WARN] Config may have syntax issues - please check $CONFIG_DIR/opencode.json${NC}" fi