diff --git a/app/core/config.py b/app/core/config.py index a3c86a9..0c07fbd 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -1,11 +1,15 @@ """ Configuration management for Claude OS. Centralizes all application settings with environment variable support. + +Supports two providers: +- local: Uses Ollama for embeddings and LLM (free, private) +- openai: Uses OpenAI API for embeddings and LLM (requires API key) """ import os from pathlib import Path -from typing import Dict, List, Any +from typing import Dict, List, Any, Optional from dotenv import load_dotenv @@ -24,14 +28,33 @@ class ConfigMeta(type): class Config(metaclass=ConfigMeta): """Central configuration for Claude OS application.""" - # Ollama Configuration + # ═══════════════════════════════════════════════════════════════════════ + # PROVIDER CONFIGURATION + # ═══════════════════════════════════════════════════════════════════════ + # Provider: "local" (Ollama) or "openai" (OpenAI API) + PROVIDER: str = os.getenv("CLAUDE_OS_PROVIDER", "local") + + # ═══════════════════════════════════════════════════════════════════════ + # OLLAMA CONFIGURATION (for local provider) + # ═══════════════════════════════════════════════════════════════════════ OLLAMA_HOST: str = os.getenv("OLLAMA_HOST", "http://localhost:11434") - OLLAMA_MODEL: str = os.getenv("OLLAMA_MODEL", "llama3.1:latest") # Upgraded to faster 8B model + OLLAMA_MODEL: str = os.getenv("OLLAMA_MODEL", "llama3.2:3b") # Lite model - faster, works on most machines OLLAMA_EMBED_MODEL: str = os.getenv("OLLAMA_EMBED_MODEL", "nomic-embed-text") - # Model Configuration + # ═══════════════════════════════════════════════════════════════════════ + # OPENAI CONFIGURATION (for openai provider) + # ═══════════════════════════════════════════════════════════════════════ + OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "") + OPENAI_LLM_MODEL: str = os.getenv("OPENAI_LLM_MODEL", "gpt-4o-mini") + OPENAI_EMBED_MODEL: str = os.getenv("OPENAI_EMBED_MODEL", "text-embedding-3-small") + OPENAI_EMBED_DIMENSIONS: int = 1536 # OpenAI text-embedding-3-small dimensions + + # ═══════════════════════════════════════════════════════════════════════ + # MODEL CONFIGURATION (auto-selected based on provider) + # ═══════════════════════════════════════════════════════════════════════ + # These are the "active" models - set based on provider or overridden via env EMBEDDING_MODEL: str = os.getenv("EMBEDDING_MODEL", "nomic-embed-text") - LLM_MODEL: str = os.getenv("LLM_MODEL", "llama3.1") + LLM_MODEL: str = os.getenv("LLM_MODEL", "llama3.2:3b") # Default to lite model # Context and Retrieval Configuration MAX_CONTEXT_LENGTH: int = int(os.getenv("MAX_CONTEXT_LENGTH", "4096")) @@ -188,6 +211,82 @@ class Config(metaclass=ConfigMeta): """Get the full MCP server URL.""" return f"http://{cls.MCP_SERVER_HOST}:{cls.MCP_SERVER_PORT}" + # ═══════════════════════════════════════════════════════════════════════ + # PROVIDER HELPER METHODS + # ═══════════════════════════════════════════════════════════════════════ + + @classmethod + def get_provider(cls) -> str: + """Get the active provider (local or openai).""" + provider = os.getenv("CLAUDE_OS_PROVIDER", "local").lower() + if provider not in ("local", "openai", "custom"): + return "local" + return provider + + @classmethod + def is_local_provider(cls) -> bool: + """Check if using local (Ollama) provider.""" + return cls.get_provider() == "local" + + @classmethod + def is_openai_provider(cls) -> bool: + """Check if using OpenAI provider.""" + return cls.get_provider() == "openai" + + @classmethod + def get_active_llm_model(cls) -> str: + """Get the active LLM model based on provider.""" + # Allow explicit override via LLM_MODEL env var + explicit_model = os.getenv("LLM_MODEL") + if explicit_model: + return explicit_model + + if cls.is_openai_provider(): + return cls.OPENAI_LLM_MODEL + return cls.OLLAMA_MODEL + + @classmethod + def get_active_embed_model(cls) -> str: + """Get the active embedding model based on provider.""" + # Allow explicit override via EMBEDDING_MODEL env var + explicit_model = os.getenv("EMBEDDING_MODEL") + if explicit_model: + return explicit_model + + if cls.is_openai_provider(): + return cls.OPENAI_EMBED_MODEL + return cls.OLLAMA_EMBED_MODEL + + @classmethod + def get_embedding_dimensions(cls) -> int: + """Get the embedding dimensions based on provider/model.""" + if cls.is_openai_provider(): + return cls.OPENAI_EMBED_DIMENSIONS # 1536 for text-embedding-3-small + # nomic-embed-text uses 768 dimensions + return 768 + + @classmethod + def get_openai_api_key(cls) -> Optional[str]: + """Get the OpenAI API key if configured.""" + key = os.getenv("OPENAI_API_KEY", "") + return key if key else None + + @classmethod + def validate_provider_config(cls) -> List[str]: + """Validate provider-specific configuration. Returns list of errors.""" + errors = [] + provider = cls.get_provider() + + if provider == "openai": + if not cls.get_openai_api_key(): + errors.append("OPENAI_API_KEY is required when using OpenAI provider") + + elif provider == "local": + # Could add Ollama connectivity check here + pass + + return errors + @classmethod def is_supported_file(cls, filename: str) -> bool: """Check if a file type is supported.""" diff --git a/install.sh b/install.sh index 1274272..55bbdba 100755 --- a/install.sh +++ b/install.sh @@ -1,437 +1,23 @@ #!/bin/bash -# Claude OS Installation Script -# Sets up Claude OS for a new user/machine -# This script ALWAYS completes and provides detailed feedback +# ═══════════════════════════════════════════════════════════════════════════ +# DEPRECATED: This script now redirects to setup-claude-os.sh +# ═══════════════════════════════════════════════════════════════════════════ +# +# For the best experience, run: +# ./setup-claude-os.sh +# +# This alias exists for backwards compatibility with existing documentation. +# ═══════════════════════════════════════════════════════════════════════════ -# DON'T exit on error - we want to handle all errors gracefully -set +e - -# Initialize error tracking -ERROR_COUNT=0 -WARNING_COUNT=0 -ERROR_LOG="" -INSTALL_STATUS="IN_PROGRESS" - -# Directories -CLAUDE_OS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -USER_CLAUDE_DIR="${HOME}/.claude" -TEMPLATES_DIR="${CLAUDE_OS_DIR}/templates" - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' - -# Helper functions -log_error() { - ERROR_COUNT=$((ERROR_COUNT + 1)) - ERROR_LOG="${ERROR_LOG}ERROR: $1\n" - echo -e "${RED}❌ ERROR: $1${NC}" >&2 -} - -log_warning() { - WARNING_COUNT=$((WARNING_COUNT + 1)) - ERROR_LOG="${ERROR_LOG}WARNING: $1\n" - echo -e "${YELLOW}⚠️ WARNING: $1${NC}" -} - -log_success() { - echo -e "${GREEN}✅ $1${NC}" -} - -echo "🚀 Claude OS Installation" -echo "=========================" -echo "" -echo "Claude OS Directory: ${CLAUDE_OS_DIR}" -echo "User Claude Directory: ${USER_CLAUDE_DIR}" -echo "" - -# Find compatible Python version (3.11 or 3.12 only) -echo "🔍 Looking for compatible Python version (3.11 or 3.12)..." - -PYTHON_CMD="" -PYTHON_VERSION="" - -# Check for Python 3.12 first (preferred) -if command -v python3.12 &> /dev/null; then - PYTHON_CMD="python3.12" - PYTHON_VERSION=$(python3.12 --version | cut -d' ' -f2) - log_success "Found Python 3.12: ${PYTHON_VERSION}" -# Then check for Python 3.11 -elif command -v python3.11 &> /dev/null; then - PYTHON_CMD="python3.11" - PYTHON_VERSION=$(python3.11 --version | cut -d' ' -f2) - log_success "Found Python 3.11: ${PYTHON_VERSION}" -# Check if default python3 is 3.11 or 3.12 -elif command -v python3 &> /dev/null; then - DEFAULT_VERSION=$(python3 --version 2>&1 | cut -d' ' -f2 | cut -d'.' -f1,2) - if [ "$DEFAULT_VERSION" = "3.11" ] || [ "$DEFAULT_VERSION" = "3.12" ]; then - PYTHON_CMD="python3" - PYTHON_VERSION=$(python3 --version | cut -d' ' -f2) - log_success "Found Python ${DEFAULT_VERSION}: ${PYTHON_VERSION}" - else - log_error "Python ${DEFAULT_VERSION} found, but Claude OS requires Python 3.11 or 3.12" - echo "" - echo "Your system has Python ${DEFAULT_VERSION}, but some dependencies (like tree-sitter-languages)" - echo "don't yet support Python 3.13+." - echo "" - echo "Please install Python 3.11 or 3.12:" - echo " • macOS with Homebrew: brew install python@3.12" - echo " • Ubuntu/Debian: sudo apt install python3.12" - echo " • Fedora/RHEL: sudo dnf install python3.12" - echo " • Arch Linux: sudo pacman -S python" - echo " • Or download from: https://www.python.org/downloads/" - echo "" - INSTALL_STATUS="FAILED" - # Jump to summary section - skip_to_summary=true - fi -else - log_error "Python 3 is not installed" - echo "" - echo "Please install Python 3.11 or 3.12:" - echo " • macOS with Homebrew: brew install python@3.12" - echo " • Ubuntu/Debian: sudo apt install python3.12" - echo " • Fedora/RHEL: sudo dnf install python3.12" - echo " • Arch Linux: sudo pacman -S python" - echo " • Or download from: https://www.python.org/downloads/" - echo "" - INSTALL_STATUS="FAILED" - skip_to_summary=true -fi - -# Skip rest of installation if Python check failed -if [ "$skip_to_summary" != "true" ]; then - -# Create user .claude directory if it doesn't exist -if [ ! -d "$USER_CLAUDE_DIR" ]; then - echo "📁 Creating ${USER_CLAUDE_DIR}..." - mkdir -p "${USER_CLAUDE_DIR}/commands" - mkdir -p "${USER_CLAUDE_DIR}/skills" -else - echo "✅ ${USER_CLAUDE_DIR} already exists" -fi - -# Ensure commands and skills subdirectories exist (even if .claude already existed) -mkdir -p "${USER_CLAUDE_DIR}/commands" -mkdir -p "${USER_CLAUDE_DIR}/skills" - -# Create symlinks for commands -echo "" -echo "🔗 Setting up command symlinks..." -for cmd_file in "${TEMPLATES_DIR}"/commands/*.md; do - if [ -f "$cmd_file" ]; then - cmd_name=$(basename "$cmd_file") - dest="${USER_CLAUDE_DIR}/commands/${cmd_name}" - - # Remove existing file/link - if [ -e "$dest" ] || [ -L "$dest" ]; then - rm -f "$dest" - fi - - # Create symlink - ln -s "$cmd_file" "$dest" - echo " ✅ Linked: ${cmd_name}" - fi -done - -# Create symlinks for skills -echo "" -echo "🔗 Setting up skill symlinks..." -for skill_dir in "${TEMPLATES_DIR}"/skills/*/; do - if [ -d "$skill_dir" ]; then - skill_name=$(basename "$skill_dir") - dest="${USER_CLAUDE_DIR}/skills/${skill_name}" - - # Remove existing directory/link - if [ -e "$dest" ] || [ -L "$dest" ]; then - rm -rf "$dest" - fi - - # Create symlink - ln -s "$skill_dir" "$dest" - echo " ✅ Linked: ${skill_name}/" - fi -done - -# Set up Python virtual environment -echo "" -echo "🐍 Setting up Python environment..." -if [ ! -d "${CLAUDE_OS_DIR}/venv" ]; then - echo " Creating virtual environment with ${PYTHON_CMD}..." - ${PYTHON_CMD} -m venv "${CLAUDE_OS_DIR}/venv" -fi - -echo " Installing dependencies..." -source "${CLAUDE_OS_DIR}/venv/bin/activate" -pip install --quiet --upgrade pip -pip install --quiet -r "${CLAUDE_OS_DIR}/requirements.txt" -echo " ✅ Dependencies installed" - -# Installation complete - move to config creation -echo "" - -# Create config file -echo "⚙️ Creating configuration..." -CONFIG_FILE="${CLAUDE_OS_DIR}/claude-os-config.json" -if [ ! -f "$CONFIG_FILE" ]; then - cat > "$CONFIG_FILE" << EOF -{ - "server": { - "host": "0.0.0.0", - "port": 8051 - }, - "database": { - "path": "./data/claude-os.db" - }, - "embeddings": { - "model": "all-MiniLM-L6-v2", - "device": "cpu" - }, - "installed_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", - "version": "2.0.0" -} -EOF - echo " ✅ Created ${CONFIG_FILE}" -else - echo " ✅ Config already exists" -fi - -# Update MCP server configuration in settings.json -echo "" -echo "📡 Configuring MCP server for Claude Code..." - -SETTINGS_FILE="${USER_CLAUDE_DIR}/settings.json" - -# Create settings.json if it doesn't exist -if [ ! -f "$SETTINGS_FILE" ]; then - echo "{}" > "$SETTINGS_FILE" -fi - -# Add MCP server configuration using Python for proper JSON handling -python3 << EOF -import json -import os - -settings_file = "$SETTINGS_FILE" -claude_os_dir = "$CLAUDE_OS_DIR" - -# Read existing settings -try: - with open(settings_file, 'r') as f: - settings = json.load(f) -except (json.JSONDecodeError, FileNotFoundError): - settings = {} - -# Ensure mcpServers exists -if 'mcpServers' not in settings: - settings['mcpServers'] = {} - -# Add code-forge MCP server configuration -settings['mcpServers']['code-forge'] = { - "command": os.path.join(claude_os_dir, "venv", "bin", "python3"), - "args": [os.path.join(claude_os_dir, "mcp_server", "claude_code_mcp.py")], - "env": { - "CLAUDE_OS_API": "http://localhost:8051" - } -} - -# Write updated settings -with open(settings_file, 'w') as f: - json.dump(settings, f, indent=2) - -print(" ✅ MCP server configured in settings.json") -print(f" Server: code-forge") -print(f" Tools will appear as: mcp__code-forge__*") -EOF - -# Also keep the legacy config file for reference -MCP_CONFIG="${USER_CLAUDE_DIR}/mcp-servers/code-forge.json" -MCP_DIR=$(dirname "$MCP_CONFIG") -if [ ! -d "$MCP_DIR" ]; then - mkdir -p "$MCP_DIR" -fi -cat > "$MCP_CONFIG" << EOF -{ - "name": "code-forge", - "description": "Claude OS - AI Memory & Knowledge Base System (Legacy config - actual config in settings.json)", - "url": "http://localhost:8051", - "enabled": true, - "claude_os_dir": "${CLAUDE_OS_DIR}" -} -EOF - -# Create start script -echo "" -echo "🎬 Creating start script..." -START_SCRIPT="${CLAUDE_OS_DIR}/start.sh" -cat > "$START_SCRIPT" << 'EOF' -#!/bin/bash -# Start Claude OS services - -CLAUDE_OS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$CLAUDE_OS_DIR" - -echo "🚀 Starting Claude OS..." -echo "" - -# Activate virtual environment -source venv/bin/activate - -# Start the MCP server -echo "📡 Starting MCP server on http://localhost:8051" -python3 mcp_server/server.py & -MCP_PID=$! - -echo "✅ Claude OS MCP Server is running!" -echo "" -echo " 📡 MCP Server: http://localhost:8051" -echo " (For Claude Code integration - do NOT open in browser)" -echo "" -echo "To stop MCP server: kill \$MCP_PID or press Ctrl+C" -echo "" -echo "════════════════════════════════════════" -echo "💡 Want the full experience?" -echo "════════════════════════════════════════" -echo "" -echo "This script only starts the MCP server." -echo "" -echo "To start ALL services (MCP + Frontend + Workers):" -echo " ./start_all_services.sh" -echo "" -echo "This will give you:" -echo " • MCP Server (port 8051) - For Claude Code" -echo " • Web UI (port 5173) - Visual interface" -echo " • Redis + Workers - Real-time learning" -echo " • Ollama - Local AI models" -echo "" - -# Wait for server to exit -wait $MCP_PID -EOF - -chmod +x "$START_SCRIPT" -log_success "Created start script" - -fi # End of main installation (if skip_to_summary != true) - -# Mark installation as successful if we got here with no errors -if [ "$ERROR_COUNT" -eq 0 ]; then - INSTALL_STATUS="SUCCESS" -elif [ "$ERROR_COUNT" -gt 0 ] && [ -f "$START_SCRIPT" ]; then - INSTALL_STATUS="PARTIAL" -else - INSTALL_STATUS="FAILED" -fi - -# ════════════════════════════════════════════════════════════════ -# INSTALLATION SUMMARY -# ════════════════════════════════════════════════════════════════ +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" echo "" -echo "════════════════════════════════════════" -if [ "$INSTALL_STATUS" = "SUCCESS" ]; then - echo -e "${GREEN}✨ Installation completed successfully!${NC}" -elif [ "$INSTALL_STATUS" = "PARTIAL" ]; then - echo -e "${YELLOW}⚠️ Installation completed with warnings${NC}" -else - echo -e "${RED}❌ Installation failed${NC}" -fi -echo "════════════════════════════════════════" +echo "┌────────────────────────────────────────────────────────────────┐" +echo "│ ℹ️ install.sh is now setup-claude-os.sh │" +echo "│ │" +echo "│ Redirecting to the new unified installer... │" +echo "└────────────────────────────────────────────────────────────────┘" echo "" +sleep 1 -# Show error/warning counts -if [ "$ERROR_COUNT" -gt 0 ] || [ "$WARNING_COUNT" -gt 0 ]; then - echo "📊 Summary:" - [ "$ERROR_COUNT" -gt 0 ] && echo -e " ${RED}Errors: $ERROR_COUNT${NC}" - [ "$WARNING_COUNT" -gt 0 ] && echo -e " ${YELLOW}Warnings: $WARNING_COUNT${NC}" - echo "" -fi - -# Show what was set up -echo "📋 What was set up:" -[ -d "${USER_CLAUDE_DIR}/commands" ] && echo " ✅ Commands: $(ls -1 ${USER_CLAUDE_DIR}/commands/claude-os-*.md 2>/dev/null | wc -l | xargs) symlinks" -[ -d "${USER_CLAUDE_DIR}/skills" ] && echo " ✅ Skills: 3 symlinks" -[ -n "$PYTHON_VERSION" ] && echo " ✅ Python ${PYTHON_VERSION} virtual environment" -[ -d "${CLAUDE_OS_DIR}/venv" ] && echo " ✅ Dependencies installed" -[ -f "${USER_CLAUDE_DIR}/mcp-servers/code-forge.json" ] && echo " ✅ MCP server configured" -[ -f "$START_SCRIPT" ] && echo " ✅ Start script created" - -# If there were errors, show them -if [ "$ERROR_COUNT" -gt 0 ]; then - echo "" - echo -e "${RED}Errors encountered:${NC}" - echo -e "$ERROR_LOG" | head -10 -fi - -echo "" - -# Next steps (only if installation succeeded or partially succeeded) -if [ "$INSTALL_STATUS" != "FAILED" ]; then - echo "════════════════════════════════════════" - echo "🎯 Next steps:" - echo "════════════════════════════════════════" - echo "" - echo "1️⃣ Start Claude OS:" - echo "" - echo " Option A - MCP Server only (minimal):" - echo " ./start.sh" - echo "" - echo " Option B - Full experience (recommended):" - echo " ./start_all_services.sh" - echo "" - echo "2️⃣ In Claude Code, go to your project:" - echo " cd /path/to/your/project" - echo "" - echo "3️⃣ Initialize your project:" - echo " /claude-os-init" - echo "" - echo "4️⃣ Start coding with AI memory! 🚀" - echo "" -fi - -echo "════════════════════════════════════════" -echo "📚 Documentation:" -echo "════════════════════════════════════════" -echo " • README.md - Full documentation" -echo " • BACKUP_RESTORE_GUIDE.md - Backup & restore" -echo " • /claude-os-search - Search memories" -echo " • /claude-os-remember - Save insights" -echo "" - -# ════════════════════════════════════════════════════════════════ -# ERROR REPORTING -# ════════════════════════════════════════════════════════════════ - -if [ "$ERROR_COUNT" -gt 0 ] || [ "$INSTALL_STATUS" = "FAILED" ]; then - echo "════════════════════════════════════════" - echo "🐛 Need help?" - echo "════════════════════════════════════════" - echo "" - echo "Please report this issue on GitHub:" - echo " https://github.com/brobertsaz/claude-os/issues/new" - echo "" - echo "Include this information:" - echo " • Your OS: $(uname -s) $(uname -r)" - echo " • Python version: ${PYTHON_VERSION:-unknown}" - echo " • Error count: $ERROR_COUNT" - echo "" - if [ -n "$ERROR_LOG" ]; then - echo "Error details:" - echo -e "$ERROR_LOG" | head -5 - echo "" - fi - echo "We'll help you get it working! 🚀" - echo "" -fi - -# Exit with appropriate code -if [ "$INSTALL_STATUS" = "SUCCESS" ]; then - exit 0 -elif [ "$INSTALL_STATUS" = "PARTIAL" ]; then - exit 0 # Still consider it success if key components work -else - exit 1 -fi +exec "${SCRIPT_DIR}/setup-claude-os.sh" "$@" diff --git a/setup-claude-os.sh b/setup-claude-os.sh new file mode 100755 index 0000000..32fc559 --- /dev/null +++ b/setup-claude-os.sh @@ -0,0 +1,682 @@ +#!/bin/bash +# ╔═══════════════════════════════════════════════════════════════════════════╗ +# ║ Claude OS Installer ║ +# ║ ║ +# ║ Beautiful, unified setup for Claude's AI memory system ║ +# ║ Works on macOS and Linux ║ +# ╚═══════════════════════════════════════════════════════════════════════════╝ + +set -e + +# ═══════════════════════════════════════════════════════════════════════════ +# CONFIGURATION +# ═══════════════════════════════════════════════════════════════════════════ + +VERSION="2.1.0" +CLAUDE_OS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +USER_CLAUDE_DIR="${HOME}/.claude" +TEMPLATES_DIR="${CLAUDE_OS_DIR}/templates" + +# Default model choices +DEFAULT_LLM_MODEL="llama3.2:3b" # Lite model - faster download, works on most machines +DEFAULT_EMBED_MODEL="nomic-embed-text" # Best local embedding model +FULL_LLM_MODEL="llama3.1:8b" # Full model - better quality + +# ═══════════════════════════════════════════════════════════════════════════ +# COLORS & STYLING +# ═══════════════════════════════════════════════════════════════════════════ + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +MAGENTA='\033[0;35m' +WHITE='\033[1;37m' +DIM='\033[2m' +BOLD='\033[1m' +NC='\033[0m' + +# Box drawing characters +BOX_TL="╭" +BOX_TR="╮" +BOX_BL="╰" +BOX_BR="╯" +BOX_H="─" +BOX_V="│" + +# ═══════════════════════════════════════════════════════════════════════════ +# HELPER FUNCTIONS +# ═══════════════════════════════════════════════════════════════════════════ + +# Print a styled box +print_box() { + local title="$1" + local width=60 + local padding=$(( (width - ${#title} - 2) / 2 )) + + echo "" + echo -e "${CYAN}${BOX_TL}$(printf '%*s' "$width" | tr ' ' "$BOX_H")${BOX_TR}${NC}" + echo -e "${CYAN}${BOX_V}${NC}$(printf '%*s' "$padding")${BOLD}${WHITE}$title${NC}$(printf '%*s' "$((width - padding - ${#title}))") ${CYAN}${BOX_V}${NC}" + echo -e "${CYAN}${BOX_BL}$(printf '%*s' "$width" | tr ' ' "$BOX_H")${BOX_BR}${NC}" + echo "" +} + +# Print a section header +print_section() { + echo "" + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${BLUE} $1${NC}" + echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" +} + +# Animated spinner +spinner() { + local pid=$1 + local message=$2 + local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' + local i=0 + + while kill -0 $pid 2>/dev/null; do + i=$(( (i + 1) % 10 )) + printf "\r${CYAN} ${spin:$i:1}${NC} ${message}" + sleep 0.1 + done + printf "\r" +} + +# Success message +success() { + echo -e "${GREEN} ✓${NC} $1" +} + +# Warning message +warn() { + echo -e "${YELLOW} ⚠${NC} $1" +} + +# Error message +error() { + echo -e "${RED} ✗${NC} $1" +} + +# Info message +info() { + echo -e "${CYAN} ℹ${NC} $1" +} + +# Progress bar +progress_bar() { + local current=$1 + local total=$2 + local width=40 + local percentage=$((current * 100 / total)) + local filled=$((current * width / total)) + local empty=$((width - filled)) + + printf "\r ${CYAN}[" + printf "%${filled}s" | tr ' ' '█' + printf "%${empty}s" | tr ' ' '░' + printf "]${NC} ${percentage}%%" +} + +# Detect OS +detect_os() { + if [[ "$OSTYPE" == "darwin"* ]]; then + OS="macos" + PKG_MANAGER="brew" + elif [[ "$OSTYPE" == "linux-gnu"* ]]; then + OS="linux" + if command -v apt-get &> /dev/null; then + PKG_MANAGER="apt" + elif command -v dnf &> /dev/null; then + PKG_MANAGER="dnf" + elif command -v yum &> /dev/null; then + PKG_MANAGER="yum" + elif command -v pacman &> /dev/null; then + PKG_MANAGER="pacman" + else + PKG_MANAGER="unknown" + fi + else + OS="unknown" + PKG_MANAGER="unknown" + fi +} + +# ═══════════════════════════════════════════════════════════════════════════ +# BANNER +# ═══════════════════════════════════════════════════════════════════════════ + +show_banner() { + clear + echo "" + echo -e "${CYAN}" + cat << 'EOF' + ██████╗██╗ █████╗ ██╗ ██╗██████╗ ███████╗ ██████╗ ███████╗ + ██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██╔════╝ ██╔═══██╗██╔════╝ + ██║ ██║ ███████║██║ ██║██║ ██║█████╗ ██║ ██║███████╗ + ██║ ██║ ██╔══██║██║ ██║██║ ██║██╔══╝ ██║ ██║╚════██║ + ╚██████╗███████╗██║ ██║╚██████╔╝██████╔╝███████╗ ╚██████╔╝███████║ + ╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝ +EOF + echo -e "${NC}" + echo -e "${DIM} Your AI Memory System • v${VERSION}${NC}" + echo "" + echo -e "${WHITE} Claude CLI + Claude OS = Invincible! 🚀${NC}" + echo "" +} + +# ═══════════════════════════════════════════════════════════════════════════ +# PROVIDER SELECTION +# ═══════════════════════════════════════════════════════════════════════════ + +select_provider() { + print_box "Choose Your Setup" + + echo -e " ${WHITE}How would you like to power Claude OS?${NC}" + echo "" + echo -e " ${CYAN}[1]${NC} ${GREEN}🏠 Local (Ollama)${NC}" + echo -e " ${DIM}Free, private, runs on your machine${NC}" + echo -e " ${DIM}Best for: Privacy-focused users, offline use${NC}" + echo "" + echo -e " ${CYAN}[2]${NC} ${BLUE}☁️ Cloud (OpenAI)${NC}" + echo -e " ${DIM}Fast, no local resources needed${NC}" + echo -e " ${DIM}Best for: Quick setup, Linux servers${NC}" + echo "" + echo -e " ${CYAN}[3]${NC} ${MAGENTA}🔧 Custom${NC}" + echo -e " ${DIM}I'll configure it myself${NC}" + echo "" + + while true; do + echo -ne " ${WHITE}Enter choice [1-3]:${NC} " + read -r choice + case $choice in + 1) PROVIDER="local"; break ;; + 2) PROVIDER="openai"; break ;; + 3) PROVIDER="custom"; break ;; + *) echo -e " ${RED}Please enter 1, 2, or 3${NC}" ;; + esac + done +} + +# ═══════════════════════════════════════════════════════════════════════════ +# MODEL SIZE SELECTION (for local installs) +# ═══════════════════════════════════════════════════════════════════════════ + +select_model_size() { + print_box "Choose Model Size" + + echo -e " ${WHITE}Select your local model:${NC}" + echo "" + echo -e " ${CYAN}[1]${NC} ${GREEN}💨 Lite${NC} ${DIM}(Recommended)${NC}" + echo -e " ${WHITE}llama3.2:3b${NC} - 2GB download, ~4GB RAM" + echo -e " ${DIM}Fast download, works on most machines${NC}" + echo "" + echo -e " ${CYAN}[2]${NC} ${BLUE}🚀 Full${NC}" + echo -e " ${WHITE}llama3.1:8b${NC} - 4.7GB download, ~8GB RAM" + echo -e " ${DIM}Better quality, needs more resources${NC}" + echo "" + + while true; do + echo -ne " ${WHITE}Enter choice [1-2]:${NC} " + read -r choice + case $choice in + 1) LLM_MODEL="$DEFAULT_LLM_MODEL"; break ;; + 2) LLM_MODEL="$FULL_LLM_MODEL"; break ;; + *) echo -e " ${RED}Please enter 1 or 2${NC}" ;; + esac + done + + EMBED_MODEL="$DEFAULT_EMBED_MODEL" +} + +# ═══════════════════════════════════════════════════════════════════════════ +# OPENAI CONFIGURATION +# ═══════════════════════════════════════════════════════════════════════════ + +configure_openai() { + print_box "OpenAI Configuration" + + echo -e " ${WHITE}Enter your OpenAI API key:${NC}" + echo -e " ${DIM}(Get one at https://platform.openai.com/api-keys)${NC}" + echo "" + echo -ne " ${WHITE}API Key:${NC} " + read -rs OPENAI_API_KEY + echo "" + + if [[ -z "$OPENAI_API_KEY" ]]; then + error "API key cannot be empty" + exit 1 + fi + + # Validate key format + if [[ ! "$OPENAI_API_KEY" =~ ^sk- ]]; then + warn "API key doesn't start with 'sk-' - are you sure it's correct?" + fi + + echo "" + success "API key saved" +} + +# ═══════════════════════════════════════════════════════════════════════════ +# PYTHON SETUP +# ═══════════════════════════════════════════════════════════════════════════ + +setup_python() { + print_section "Setting Up Python Environment" + + # Find compatible Python + PYTHON_CMD="" + + if command -v python3.12 &> /dev/null; then + PYTHON_CMD="python3.12" + elif command -v python3.11 &> /dev/null; then + PYTHON_CMD="python3.11" + elif command -v python3 &> /dev/null; then + local ver=$(python3 --version 2>&1 | cut -d' ' -f2 | cut -d'.' -f1,2) + if [[ "$ver" == "3.11" || "$ver" == "3.12" ]]; then + PYTHON_CMD="python3" + fi + fi + + if [[ -z "$PYTHON_CMD" ]]; then + error "Python 3.11 or 3.12 required" + echo "" + echo -e " ${WHITE}Install Python:${NC}" + echo -e " macOS: ${CYAN}brew install python@3.12${NC}" + echo -e " Ubuntu: ${CYAN}sudo apt install python3.12${NC}" + echo -e " Fedora: ${CYAN}sudo dnf install python3.12${NC}" + exit 1 + fi + + local py_version=$($PYTHON_CMD --version | cut -d' ' -f2) + success "Found Python $py_version" + + # Create virtual environment + if [[ ! -d "${CLAUDE_OS_DIR}/venv" ]]; then + info "Creating virtual environment..." + $PYTHON_CMD -m venv "${CLAUDE_OS_DIR}/venv" & + spinner $! "Creating virtual environment..." + success "Virtual environment created" + else + success "Virtual environment exists" + fi + + # Activate and install dependencies + source "${CLAUDE_OS_DIR}/venv/bin/activate" + + info "Installing dependencies..." + pip install --quiet --upgrade pip setuptools wheel 2>/dev/null & + spinner $! "Upgrading pip..." + + pip install --quiet -r "${CLAUDE_OS_DIR}/requirements.txt" 2>/dev/null & + spinner $! "Installing dependencies (this may take a minute)..." + success "Dependencies installed" +} + +# ═══════════════════════════════════════════════════════════════════════════ +# OLLAMA SETUP +# ═══════════════════════════════════════════════════════════════════════════ + +setup_ollama() { + print_section "Setting Up Ollama" + + # Check if Ollama is installed + if command -v ollama &> /dev/null; then + success "Ollama already installed" + else + info "Installing Ollama..." + + if [[ "$OS" == "macos" ]]; then + if command -v brew &> /dev/null; then + brew install ollama &>/dev/null & + spinner $! "Installing via Homebrew..." + else + error "Homebrew required. Install from https://brew.sh" + exit 1 + fi + elif [[ "$OS" == "linux" ]]; then + curl -fsSL https://ollama.ai/install.sh | sh &>/dev/null & + spinner $! "Installing Ollama..." + fi + + success "Ollama installed" + fi + + # Start Ollama if not running + if ! curl -s http://localhost:11434/api/tags &>/dev/null; then + info "Starting Ollama..." + + if [[ "$OS" == "macos" ]]; then + brew services start ollama &>/dev/null || ollama serve &>/dev/null & + else + ollama serve &>/dev/null & + fi + + sleep 3 + + if curl -s http://localhost:11434/api/tags &>/dev/null; then + success "Ollama started" + else + warn "Ollama may need manual start: ollama serve" + fi + else + success "Ollama is running" + fi + + # Download models + echo "" + info "Downloading AI models..." + echo "" + + # Download LLM model + if curl -s http://localhost:11434/api/tags | grep -q "\"name\":\"${LLM_MODEL}\""; then + success "Model ${LLM_MODEL} ready" + else + echo -e " ${CYAN}Downloading ${LLM_MODEL}...${NC}" + echo -e " ${DIM}(This may take a few minutes on first install)${NC}" + ollama pull "$LLM_MODEL" 2>&1 | while read line; do + if [[ "$line" =~ ([0-9]+)% ]]; then + progress_bar "${BASH_REMATCH[1]}" 100 + fi + done + echo "" + success "Model ${LLM_MODEL} downloaded" + fi + + # Download embedding model + if curl -s http://localhost:11434/api/tags | grep -q "\"name\":\"${EMBED_MODEL}\""; then + success "Model ${EMBED_MODEL} ready" + else + echo -e " ${CYAN}Downloading ${EMBED_MODEL}...${NC}" + ollama pull "$EMBED_MODEL" 2>&1 | while read line; do + if [[ "$line" =~ ([0-9]+)% ]]; then + progress_bar "${BASH_REMATCH[1]}" 100 + fi + done + echo "" + success "Model ${EMBED_MODEL} downloaded" + fi +} + +# ═══════════════════════════════════════════════════════════════════════════ +# REDIS SETUP +# ═══════════════════════════════════════════════════════════════════════════ + +setup_redis() { + print_section "Setting Up Redis" + + if command -v redis-cli &> /dev/null; then + success "Redis already installed" + else + info "Installing Redis..." + + if [[ "$OS" == "macos" ]]; then + brew install redis &>/dev/null & + spinner $! "Installing via Homebrew..." + elif [[ "$OS" == "linux" ]]; then + case "$PKG_MANAGER" in + apt) sudo apt-get update -qq && sudo apt-get install -y -qq redis-server &>/dev/null & ;; + dnf) sudo dnf install -y -q redis &>/dev/null & ;; + yum) sudo yum install -y -q redis &>/dev/null & ;; + pacman) sudo pacman -S --noconfirm --quiet redis &>/dev/null & ;; + esac + spinner $! "Installing Redis..." + fi + + success "Redis installed" + fi + + # Start Redis if not running + if redis-cli ping &>/dev/null; then + success "Redis is running" + else + info "Starting Redis..." + + if [[ "$OS" == "macos" ]]; then + brew services start redis &>/dev/null || true + else + redis-server --daemonize yes &>/dev/null || true + fi + + sleep 1 + + if redis-cli ping &>/dev/null; then + success "Redis started" + else + warn "Redis may need manual start" + fi + fi +} + +# ═══════════════════════════════════════════════════════════════════════════ +# CLAUDE CODE INTEGRATION +# ═══════════════════════════════════════════════════════════════════════════ + +setup_claude_integration() { + print_section "Integrating with Claude Code" + + # Create directories + mkdir -p "${USER_CLAUDE_DIR}/commands" + mkdir -p "${USER_CLAUDE_DIR}/skills" + mkdir -p "${USER_CLAUDE_DIR}/mcp-servers" + mkdir -p "${CLAUDE_OS_DIR}/data" + mkdir -p "${CLAUDE_OS_DIR}/logs" + + success "Created directories" + + # Symlink commands + local cmd_count=0 + for cmd_file in "${TEMPLATES_DIR}"/commands/*.md; do + if [[ -f "$cmd_file" ]]; then + local cmd_name=$(basename "$cmd_file") + local dest="${USER_CLAUDE_DIR}/commands/${cmd_name}" + rm -f "$dest" 2>/dev/null + ln -s "$cmd_file" "$dest" + ((cmd_count++)) + fi + done + success "Linked ${cmd_count} commands" + + # Symlink skills + local skill_count=0 + for skill_dir in "${TEMPLATES_DIR}"/skills/*/; do + if [[ -d "$skill_dir" ]]; then + local skill_name=$(basename "$skill_dir") + local dest="${USER_CLAUDE_DIR}/skills/${skill_name}" + rm -rf "$dest" 2>/dev/null + ln -s "$skill_dir" "$dest" + ((skill_count++)) + fi + done + success "Linked ${skill_count} skills" + + # Configure MCP server in settings.json + local settings_file="${USER_CLAUDE_DIR}/settings.json" + + if [[ ! -f "$settings_file" ]]; then + echo "{}" > "$settings_file" + fi + + python3 << EOF +import json +import os + +settings_file = "$settings_file" +claude_os_dir = "$CLAUDE_OS_DIR" + +try: + with open(settings_file, 'r') as f: + settings = json.load(f) +except: + settings = {} + +if 'mcpServers' not in settings: + settings['mcpServers'] = {} + +settings['mcpServers']['code-forge'] = { + "command": os.path.join(claude_os_dir, "venv", "bin", "python3"), + "args": [os.path.join(claude_os_dir, "mcp_server", "claude_code_mcp.py")], + "env": { + "CLAUDE_OS_API": "http://localhost:8051" + } +} + +with open(settings_file, 'w') as f: + json.dump(settings, f, indent=2) +EOF + + success "Configured MCP server" +} + +# ═══════════════════════════════════════════════════════════════════════════ +# CREATE CONFIGURATION FILE +# ═══════════════════════════════════════════════════════════════════════════ + +create_config() { + print_section "Creating Configuration" + + local config_file="${CLAUDE_OS_DIR}/.env" + + cat > "$config_file" << EOF +# Claude OS Configuration +# Generated by setup-claude-os.sh on $(date) + +# Provider: local or openai +CLAUDE_OS_PROVIDER=${PROVIDER} + +# LLM Settings +LLM_MODEL=${LLM_MODEL:-gpt-4o-mini} +EMBEDDING_MODEL=${EMBED_MODEL:-text-embedding-3-small} + +# Ollama Settings (for local provider) +OLLAMA_HOST=http://localhost:11434 + +# OpenAI Settings (for cloud provider) +OPENAI_API_KEY=${OPENAI_API_KEY:-} + +# Server Settings +CLAUDE_OS_HOST=0.0.0.0 +CLAUDE_OS_PORT=8051 + +# Database +CLAUDE_OS_DB_PATH=./data/claude-os.db +EOF + + success "Created configuration file" + + # Also create the JSON config for backwards compatibility + cat > "${CLAUDE_OS_DIR}/claude-os-config.json" << EOF +{ + "provider": "${PROVIDER}", + "llm_model": "${LLM_MODEL:-gpt-4o-mini}", + "embed_model": "${EMBED_MODEL:-text-embedding-3-small}", + "version": "${VERSION}", + "installed_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" +} +EOF +} + +# ═══════════════════════════════════════════════════════════════════════════ +# COMPLETION +# ═══════════════════════════════════════════════════════════════════════════ + +show_completion() { + echo "" + echo -e "${GREEN}" + cat << 'EOF' + ╔═══════════════════════════════════════════════════════════════════╗ + ║ ║ + ║ ✨ Claude OS is ready! ✨ ║ + ║ ║ + ╚═══════════════════════════════════════════════════════════════════╝ +EOF + echo -e "${NC}" + + echo -e " ${WHITE}What was set up:${NC}" + echo "" + [[ -d "${CLAUDE_OS_DIR}/venv" ]] && echo -e " ${GREEN}✓${NC} Python environment" + [[ "$PROVIDER" == "local" ]] && echo -e " ${GREEN}✓${NC} Ollama with ${LLM_MODEL}" + [[ "$PROVIDER" == "local" ]] && echo -e " ${GREEN}✓${NC} Embedding model (${EMBED_MODEL})" + [[ "$PROVIDER" == "openai" ]] && echo -e " ${GREEN}✓${NC} OpenAI API configured" + command -v redis-cli &>/dev/null && echo -e " ${GREEN}✓${NC} Redis cache" + [[ -d "${USER_CLAUDE_DIR}/commands" ]] && echo -e " ${GREEN}✓${NC} Claude Code commands" + [[ -d "${USER_CLAUDE_DIR}/skills" ]] && echo -e " ${GREEN}✓${NC} Claude Code skills" + [[ -f "${USER_CLAUDE_DIR}/settings.json" ]] && echo -e " ${GREEN}✓${NC} MCP server configured" + + echo "" + echo -e " ${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" + echo -e " ${WHITE}Next Steps:${NC}" + echo "" + echo -e " ${CYAN}1.${NC} Start Claude OS:" + echo -e " ${DIM}./start_all_services.sh${NC}" + echo "" + echo -e " ${CYAN}2.${NC} In your project, initialize Claude OS:" + echo -e " ${DIM}/claude-os-init${NC}" + echo "" + echo -e " ${CYAN}3.${NC} Start a session:" + echo -e " ${DIM}/claude-os-session start \"working on feature X\"${NC}" + echo "" + echo -e " ${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" + echo -e " ${DIM}Documentation: README.md${NC}" + echo -e " ${DIM}Issues: https://github.com/brobertsaz/claude-os/issues${NC}" + echo "" + echo -e " ${WHITE}Happy coding! 🚀${NC}" + echo "" +} + +# ═══════════════════════════════════════════════════════════════════════════ +# MAIN +# ═══════════════════════════════════════════════════════════════════════════ + +main() { + # Detect OS first + detect_os + + # Show banner + show_banner + + # Provider selection + select_provider + + # Provider-specific setup + if [[ "$PROVIDER" == "local" ]]; then + select_model_size + elif [[ "$PROVIDER" == "openai" ]]; then + configure_openai + LLM_MODEL="gpt-4o-mini" + EMBED_MODEL="text-embedding-3-small" + elif [[ "$PROVIDER" == "custom" ]]; then + info "Custom setup - you'll need to configure .env manually" + LLM_MODEL="" + EMBED_MODEL="" + fi + + # Common setup + setup_python + + # Provider-specific dependencies + if [[ "$PROVIDER" == "local" ]]; then + setup_ollama + fi + + # Optional: Redis (useful for caching) + setup_redis + + # Claude Code integration + setup_claude_integration + + # Create configuration + create_config + + # Show completion + show_completion +} + +# Run main +main "$@" diff --git a/setup.sh b/setup.sh index b39cf83..e9f676c 100755 --- a/setup.sh +++ b/setup.sh @@ -1,362 +1,23 @@ #!/bin/bash -set -e +# ═══════════════════════════════════════════════════════════════════════════ +# DEPRECATED: This script now redirects to setup-claude-os.sh +# ═══════════════════════════════════════════════════════════════════════════ +# +# For the best experience, run: +# ./setup-claude-os.sh +# +# This alias exists for backwards compatibility with existing documentation. +# ═══════════════════════════════════════════════════════════════════════════ -# 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 - -# Detect OS and package manager -detect_os() { - if [[ "$OSTYPE" == "darwin"* ]]; then - OS="macos" - PKG_MANAGER="brew" - elif [[ "$OSTYPE" == "linux-gnu"* ]]; then - OS="linux" - if command -v apt-get &> /dev/null; then - PKG_MANAGER="apt" - elif command -v dnf &> /dev/null; then - PKG_MANAGER="dnf" - elif command -v yum &> /dev/null; then - PKG_MANAGER="yum" - elif command -v pacman &> /dev/null; then - PKG_MANAGER="pacman" - else - PKG_MANAGER="unknown" - fi - else - OS="unknown" - PKG_MANAGER="unknown" - fi -} - -detect_os - -# Banner -clear -echo -e "${CYAN}" -echo "╔════════════════════════════════════════════════════════════════╗" -echo "║ 🚀 Claude OS Setup Script ║" -echo "║ ║" -echo "║ This script will set up Claude OS with all dependencies ║" -echo "║ and prepare it for development ║" -echo "╚════════════════════════════════════════════════════════════════╝" -echo -e "${NC}\n" - -PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$PROJECT_DIR" - -# Step 1: Check prerequisites -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE}Step 1: Checking Prerequisites${NC}" -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" - -# Check Python -if ! command -v python3 &> /dev/null; then - echo -e "${RED}❌ Python 3 is not installed${NC}" - echo "Install Python 3 from https://www.python.org/downloads/" - exit 1 -fi -PYTHON_VERSION=$(python3 --version | awk '{print $2}') -echo -e "${GREEN}✅ Python ${PYTHON_VERSION} found${NC}" - -# Check Git -if ! command -v git &> /dev/null; then - echo -e "${RED}❌ Git is not installed${NC}" - echo "Install Git from https://git-scm.com/" - exit 1 -fi -echo -e "${GREEN}✅ Git found${NC}" - -# Check if in git repo -if ! git rev-parse --git-dir > /dev/null 2>&1; then - echo -e "${YELLOW}⚠️ Not in a git repository${NC}" - echo "Make sure to run this from the Claude OS project directory" -else - echo -e "${GREEN}✅ In Claude OS git repository${NC}" -fi +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" echo "" - -# Step 2: Create virtual environment -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE}Step 2: Setting Up Python Environment${NC}" -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" - -if [ ! -d "venv" ]; then - echo "Creating virtual environment..." - python3 -m venv venv - echo -e "${GREEN}✅ Virtual environment created${NC}" -else - echo -e "${YELLOW}⚠️ Virtual environment already exists${NC}" -fi - -echo "Activating virtual environment..." -source venv/bin/activate -echo -e "${GREEN}✅ Virtual environment activated${NC}" - -echo "Upgrading pip, setuptools, and wheel..." -pip install -q --upgrade pip setuptools wheel -echo -e "${GREEN}✅ Pip upgraded${NC}" - +echo "┌────────────────────────────────────────────────────────────────┐" +echo "│ ℹ️ setup.sh is now setup-claude-os.sh │" +echo "│ │" +echo "│ Redirecting to the new unified installer... │" +echo "└────────────────────────────────────────────────────────────────┘" echo "" +sleep 1 -# Step 3: Install Python dependencies -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE}Step 3: Installing Python Dependencies${NC}" -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" - -if [ -f "requirements.txt" ]; then - echo "Installing requirements from requirements.txt..." - pip install -q -r requirements.txt - echo -e "${GREEN}✅ Python dependencies installed${NC}" -else - echo -e "${RED}❌ requirements.txt not found${NC}" - exit 1 -fi - -echo "" - -# Step 4: Check Ollama -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE}Step 4: Setting Up Ollama (LLM Engine)${NC}" -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" - -if command -v ollama &> /dev/null; then - echo -e "${GREEN}✅ Ollama already installed${NC}" -else - echo -e "${YELLOW}⚠️ Ollama not found${NC}" - echo "Installing Ollama..." - - if [[ "$OS" == "macos" ]]; then - # macOS - if ! command -v brew &> /dev/null; then - echo -e "${RED}❌ Homebrew not found (required for macOS)${NC}" - echo "Install from https://brew.sh" - exit 1 - fi - brew install ollama - elif [[ "$OS" == "linux" ]]; then - # Linux - use universal installer (works on all distros) - curl -fsSL https://ollama.ai/install.sh | sh - else - echo -e "${RED}❌ Unsupported OS${NC}" - echo "Please install Ollama manually from https://ollama.ai" - exit 1 - fi - echo -e "${GREEN}✅ Ollama installed${NC}" -fi - -echo "Checking if Ollama is running..." -if curl -s http://localhost:11434/api/tags &> /dev/null; then - echo -e "${GREEN}✅ Ollama is running${NC}" -else - echo -e "${YELLOW}⚠️ Ollama is not running${NC}" - echo "Starting Ollama..." - if [[ "$OS" == "macos" ]]; then - brew services start ollama &> /dev/null || true - elif [[ "$OS" == "linux" ]]; then - # Start ollama directly (no sudo needed) - ollama serve &> /dev/null & - else - ollama serve &> /dev/null & - fi - echo "Waiting for Ollama to start..." - sleep 5 - - if ! curl -s http://localhost:11434/api/tags &> /dev/null; then - echo -e "${YELLOW}⚠️ Could not verify Ollama is running${NC}" - echo "You may need to start it manually" - else - echo -e "${GREEN}✅ Ollama started successfully${NC}" - fi -fi - -echo "Ensuring required models are available..." -for model in llama3.1:latest nomic-embed-text:latest; do - if curl -s http://localhost:11434/api/tags | grep -q "\"name\":\"$model\""; then - echo -e "${GREEN}✅ Model $model is installed${NC}" - else - echo "Downloading model $model (this may take a few minutes)..." - ollama pull $model > /dev/null 2>&1 || true - echo -e "${GREEN}✅ Model $model downloaded${NC}" - fi -done - -echo "" - -# Step 5: Check Redis -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE}Step 5: Setting Up Redis (Cache & Queue System)${NC}" -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" - -if command -v redis-cli &> /dev/null; then - echo -e "${GREEN}✅ Redis already installed${NC}" -else - echo -e "${YELLOW}⚠️ Redis not found${NC}" - echo "Installing Redis..." - - if [[ "$OS" == "macos" ]]; then - brew install redis - elif [[ "$OS" == "linux" ]]; then - case "$PKG_MANAGER" in - apt) - sudo apt-get update && sudo apt-get install -y redis-server - ;; - dnf) - sudo dnf install -y redis - ;; - yum) - sudo yum install -y redis - ;; - pacman) - sudo pacman -S --noconfirm redis - ;; - *) - echo -e "${RED}❌ Unknown package manager${NC}" - echo "Please install Redis manually from https://redis.io" - exit 1 - ;; - esac - else - echo -e "${RED}❌ Unsupported OS${NC}" - echo "Please install Redis manually from https://redis.io" - exit 1 - fi - echo -e "${GREEN}✅ Redis installed${NC}" -fi - -echo "Checking if Redis is running..." -if redis-cli ping &> /dev/null; then - echo -e "${GREEN}✅ Redis is running${NC}" -else - echo -e "${YELLOW}⚠️ Redis is not running${NC}" - echo "Starting Redis..." - if [[ "$OS" == "macos" ]]; then - brew services start redis > /dev/null 2>&1 || true - elif [[ "$OS" == "linux" ]]; then - # Start redis directly (no sudo needed) - redis-server --daemonize yes > /dev/null 2>&1 || true - else - redis-server --daemonize yes > /dev/null 2>&1 || true - fi - sleep 2 - - if redis-cli ping &> /dev/null; then - echo -e "${GREEN}✅ Redis started successfully${NC}" - else - echo -e "${YELLOW}⚠️ Could not verify Redis is running${NC}" - echo "You may need to start it manually" - fi -fi - -echo "" - -# Step 6: Create directories -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE}Step 6: Creating Required Directories${NC}" -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" - -mkdir -p data -mkdir -p logs -mkdir -p frontend - -echo -e "${GREEN}✅ Directories created:${NC}" -echo " • data/ (SQLite database)" -echo " • logs/ (Service logs)" -echo " • frontend/ (React UI)" - -echo "" - -# Step 7: Install Node/npm if needed -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE}Step 7: Checking Frontend Dependencies${NC}" -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" - -if [ -f "frontend/package.json" ]; then - if ! command -v npm &> /dev/null; then - echo -e "${RED}❌ npm not found (required for frontend)${NC}" - echo "Install Node.js from https://nodejs.org/" - exit 1 - fi - - echo "Installing frontend dependencies..." - cd frontend - npm install -q - cd .. - echo -e "${GREEN}✅ Frontend dependencies installed${NC}" -else - echo -e "${YELLOW}⚠️ frontend/package.json not found${NC}" -fi - -echo "" - -# Step 8: Initialize database -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE}Step 8: Initializing Database${NC}" -echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" - -if [ ! -f "data/claude-os.db" ]; then - echo "Creating SQLite database..." - python3 << 'EOF' -from app.core.sqlite_manager import get_sqlite_manager -db = get_sqlite_manager() -print("✅ Database initialized") -EOF - echo -e "${GREEN}✅ Database created${NC}" -else - echo -e "${GREEN}✅ Database already exists${NC}" -fi - -echo "" - -# Step 9: Summary and next steps -echo -e "${CYAN}" -echo "╔════════════════════════════════════════════════════════════════╗" -echo "║ ✨ Claude OS Setup Complete! ✨ ║" -echo "╚════════════════════════════════════════════════════════════════╝" -echo -e "${NC}\n" - -echo -e "${GREEN}✅ All components are ready:${NC}" -echo " ✓ Python environment" -echo " ✓ Dependencies installed" -echo " ✓ Ollama (LLM engine)" -echo " ✓ Redis (cache & queues)" -echo " ✓ Database" -echo " ✓ Directories" -echo "" - -echo -e "${BLUE}Next Steps:${NC}" -echo "" -echo "1. Start all services:" -echo -e " ${CYAN}./start_all_services.sh${NC}" -echo "" -echo "2. Access the services:" -echo -e " ${CYAN}Frontend: http://localhost:5173${NC}" -echo -e " ${CYAN}MCP API: http://localhost:8051${NC}" -echo -e " ${CYAN}API Docs: http://localhost:8051/docs${NC}" -echo "" -echo "3. Initialize your first project:" -echo -e " ${CYAN}Create a project in the UI, then run:${NC}" -echo -e " ${CYAN}/initialize-project [project-id]${NC}" -echo "" -echo "4. Register MCPs with Claude Code:" -echo -e " ${CYAN}claude mcp add --transport http [mcp-name] http://localhost:8051/mcp/kb/[KB-name]${NC}" -echo "" - -echo -e "${YELLOW}💡 Tips:${NC}" -echo " • Run './start_all_services.sh' to start everything" -echo " • Run './stop_all_services.sh' to stop everything" -echo " • Run './restart_services.sh' to restart everything" -echo " • Check logs with: tail -f logs/mcp_server.log" -echo "" - -echo -e "${CYAN}Documentation:${NC}" -echo " • WHAT_IS_CLAUDE_OS.md (learn what Claude OS does)" -echo " • CLAUDE_OS_DEVELOPER_GUIDE.md (detailed development guide)" -echo "" - -echo -e "${GREEN}Ready to get started! 🚀${NC}\n" +exec "${SCRIPT_DIR}/setup-claude-os.sh" "$@"