Add beautiful unified installer with Local/Cloud support
✨ New Features: - Beautiful CLI installer (setup-claude-os.sh) with ASCII art, progress bars, spinners, and styled prompts - Choose between Local (Ollama) or Cloud (OpenAI) providers - Lite model (llama3.2:3b) as default - faster download, works on more machines - Full model (llama3.1:8b) option for users who want better quality - OpenAI API support for users who prefer cloud 🔧 Changes: - setup.sh and install.sh now redirect to setup-claude-os.sh - config.py updated with provider support and new defaults - Works on both macOS and Linux 📦 Default Model Change: - Before: llama3.1:latest (8B, 4.7GB download) - After: llama3.2:3b (3B, 2GB download) This makes Claude OS accessible to more users with smaller machines while still offering the full experience for power users. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
61a9ad8f00
commit
e98ecbcf14
4 changed files with 820 additions and 792 deletions
|
|
@ -1,11 +1,15 @@
|
||||||
"""
|
"""
|
||||||
Configuration management for Claude OS.
|
Configuration management for Claude OS.
|
||||||
Centralizes all application settings with environment variable support.
|
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
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Any
|
from typing import Dict, List, Any, Optional
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
|
@ -24,14 +28,33 @@ class ConfigMeta(type):
|
||||||
class Config(metaclass=ConfigMeta):
|
class Config(metaclass=ConfigMeta):
|
||||||
"""Central configuration for Claude OS application."""
|
"""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_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")
|
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")
|
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
|
# Context and Retrieval Configuration
|
||||||
MAX_CONTEXT_LENGTH: int = int(os.getenv("MAX_CONTEXT_LENGTH", "4096"))
|
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."""
|
"""Get the full MCP server URL."""
|
||||||
return f"http://{cls.MCP_SERVER_HOST}:{cls.MCP_SERVER_PORT}"
|
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
|
@classmethod
|
||||||
def is_supported_file(cls, filename: str) -> bool:
|
def is_supported_file(cls, filename: str) -> bool:
|
||||||
"""Check if a file type is supported."""
|
"""Check if a file type is supported."""
|
||||||
|
|
|
||||||
448
install.sh
448
install.sh
|
|
@ -1,437 +1,23 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Claude OS Installation Script
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
# Sets up Claude OS for a new user/machine
|
# DEPRECATED: This script now redirects to setup-claude-os.sh
|
||||||
# This script ALWAYS completes and provides detailed feedback
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
#
|
||||||
|
# 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
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
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
|
|
||||||
# ════════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "════════════════════════════════════════"
|
echo "┌────────────────────────────────────────────────────────────────┐"
|
||||||
if [ "$INSTALL_STATUS" = "SUCCESS" ]; then
|
echo "│ ℹ️ install.sh is now setup-claude-os.sh │"
|
||||||
echo -e "${GREEN}✨ Installation completed successfully!${NC}"
|
echo "│ │"
|
||||||
elif [ "$INSTALL_STATUS" = "PARTIAL" ]; then
|
echo "│ Redirecting to the new unified installer... │"
|
||||||
echo -e "${YELLOW}⚠️ Installation completed with warnings${NC}"
|
echo "└────────────────────────────────────────────────────────────────┘"
|
||||||
else
|
|
||||||
echo -e "${RED}❌ Installation failed${NC}"
|
|
||||||
fi
|
|
||||||
echo "════════════════════════════════════════"
|
|
||||||
echo ""
|
echo ""
|
||||||
|
sleep 1
|
||||||
|
|
||||||
# Show error/warning counts
|
exec "${SCRIPT_DIR}/setup-claude-os.sh" "$@"
|
||||||
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
|
|
||||||
|
|
|
||||||
682
setup-claude-os.sh
Executable file
682
setup-claude-os.sh
Executable file
|
|
@ -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 "$@"
|
||||||
373
setup.sh
373
setup.sh
|
|
@ -1,362 +1,23 @@
|
||||||
#!/bin/bash
|
#!/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
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
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
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
echo "┌────────────────────────────────────────────────────────────────┐"
|
||||||
# Step 2: Create virtual environment
|
echo "│ ℹ️ setup.sh is now setup-claude-os.sh │"
|
||||||
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
|
echo "│ │"
|
||||||
echo -e "${BLUE}Step 2: Setting Up Python Environment${NC}"
|
echo "│ Redirecting to the new unified installer... │"
|
||||||
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n"
|
echo "└────────────────────────────────────────────────────────────────┘"
|
||||||
|
|
||||||
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 ""
|
||||||
|
sleep 1
|
||||||
|
|
||||||
# Step 3: Install Python dependencies
|
exec "${SCRIPT_DIR}/setup-claude-os.sh" "$@"
|
||||||
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"
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue