269 lines
8.3 KiB
Bash
Executable File
269 lines
8.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# ============================================================================
|
||
# OpenClaw + Mem0 One-Click Setup
|
||
# ============================================================================
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
OPENCLAW_CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw}"
|
||
OPENCLAW_PORT="${OPENCLAW_PORT:-18789}"
|
||
|
||
# Colors (disabled if not a terminal)
|
||
if [ -t 1 ]; then
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
BOLD='\033[1m'
|
||
NC='\033[0m'
|
||
else
|
||
RED='' GREEN='' YELLOW='' BLUE='' BOLD='' NC=''
|
||
fi
|
||
|
||
info() { echo -e "${BLUE}ℹ${NC} $*"; }
|
||
ok() { echo -e "${GREEN}✔${NC} $*"; }
|
||
warn() { echo -e "${YELLOW}⚠${NC} $*"; }
|
||
error() { echo -e "${RED}✖${NC} $*" >&2; }
|
||
header() { echo -e "\n${BOLD}$*${NC}"; }
|
||
|
||
# ============================================================================
|
||
# Step 1: Check prerequisites
|
||
# ============================================================================
|
||
|
||
header "Checking prerequisites..."
|
||
|
||
if ! command -v docker &>/dev/null; then
|
||
error "Docker is not installed."
|
||
echo " Install Docker Desktop: https://www.docker.com/products/docker-desktop/"
|
||
echo " Or Docker Engine: https://docs.docker.com/engine/install/"
|
||
exit 1
|
||
fi
|
||
|
||
if ! docker compose version &>/dev/null; then
|
||
error "Docker Compose v2 is not available."
|
||
echo " Ensure you have Docker Compose v2 (comes with Docker Desktop)."
|
||
echo " Docs: https://docs.docker.com/compose/install/"
|
||
exit 1
|
||
fi
|
||
|
||
if ! docker info &>/dev/null 2>&1; then
|
||
error "Docker daemon is not running. Please start Docker and try again."
|
||
exit 1
|
||
fi
|
||
|
||
ok "Docker and Docker Compose are available."
|
||
|
||
# Check for port conflict
|
||
if command -v lsof &>/dev/null && lsof -i :"$OPENCLAW_PORT" &>/dev/null; then
|
||
warn "Port $OPENCLAW_PORT is already in use."
|
||
echo " Check what's using it: lsof -i :$OPENCLAW_PORT"
|
||
echo " Or set a different port: OPENCLAW_PORT=18790 ./setup.sh"
|
||
exit 1
|
||
fi
|
||
|
||
# ============================================================================
|
||
# Step 2: Check for existing config
|
||
# ============================================================================
|
||
|
||
if [ -f "$OPENCLAW_CONFIG_DIR/openclaw.json" ]; then
|
||
warn "Existing config found at $OPENCLAW_CONFIG_DIR/openclaw.json"
|
||
read -rp " Overwrite with new config? [y/N] " overwrite
|
||
if [[ ! "$overwrite" =~ ^[Yy]$ ]]; then
|
||
info "Keeping existing config. Skipping config generation."
|
||
SKIP_CONFIG=true
|
||
else
|
||
SKIP_CONFIG=false
|
||
fi
|
||
else
|
||
SKIP_CONFIG=false
|
||
fi
|
||
|
||
# ============================================================================
|
||
# Step 3: Choose mode
|
||
# ============================================================================
|
||
|
||
header "Choose your setup mode:"
|
||
echo ""
|
||
echo " 1) Platform — Uses Mem0 Cloud (managed storage, dashboard at app.mem0.ai)"
|
||
echo " 2) OSS — Self-hosted with local Qdrant (fully offline-capable)"
|
||
echo ""
|
||
|
||
while true; do
|
||
read -rp "Enter 1 or 2: " mode_choice
|
||
case "$mode_choice" in
|
||
1) MODE="platform"; break ;;
|
||
2) MODE="oss"; break ;;
|
||
*) echo " Please enter 1 or 2." ;;
|
||
esac
|
||
done
|
||
|
||
ok "Mode: $MODE"
|
||
|
||
# ============================================================================
|
||
# Step 4: Collect API keys
|
||
# ============================================================================
|
||
|
||
header "API Key Configuration"
|
||
|
||
MEM0_API_KEY=""
|
||
OPENAI_API_KEY=""
|
||
|
||
if [ "$MODE" = "platform" ]; then
|
||
echo " Platform mode requires a Mem0 API key from https://app.mem0.ai"
|
||
echo ""
|
||
while true; do
|
||
read -rp " Mem0 API Key: " MEM0_API_KEY
|
||
if [ -n "$MEM0_API_KEY" ]; then break; fi
|
||
warn "API key is required for platform mode."
|
||
done
|
||
|
||
echo ""
|
||
read -rp " OpenAI API Key (optional, for agent LLM — press Enter to skip): " OPENAI_API_KEY
|
||
else
|
||
echo " OSS mode requires an OpenAI API key for embeddings, LLM, and the agent."
|
||
echo ""
|
||
while true; do
|
||
read -rp " OpenAI API Key: " OPENAI_API_KEY
|
||
if [ -n "$OPENAI_API_KEY" ]; then break; fi
|
||
warn "API key is required for OSS mode."
|
||
done
|
||
fi
|
||
|
||
ok "API keys configured."
|
||
|
||
# ============================================================================
|
||
# Step 5: User ID
|
||
# ============================================================================
|
||
|
||
DEFAULT_USER_ID="$(whoami)"
|
||
read -rp " User ID for memory scoping [${DEFAULT_USER_ID}]: " MEM0_USER_ID
|
||
MEM0_USER_ID="${MEM0_USER_ID:-$DEFAULT_USER_ID}"
|
||
ok "User ID: $MEM0_USER_ID"
|
||
|
||
# ============================================================================
|
||
# Step 6: Generate .env
|
||
# ============================================================================
|
||
|
||
header "Generating configuration..."
|
||
|
||
cat > "$SCRIPT_DIR/.env" <<EOF
|
||
# Generated by setup.sh on $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||
MEM0_API_KEY=${MEM0_API_KEY}
|
||
OPENAI_API_KEY=${OPENAI_API_KEY}
|
||
MEM0_USER_ID=${MEM0_USER_ID}
|
||
OPENCLAW_PORT=${OPENCLAW_PORT}
|
||
OPENCLAW_CONFIG_DIR=${OPENCLAW_CONFIG_DIR}
|
||
TZ=${TZ:-UTC}
|
||
EOF
|
||
|
||
ok "Created .env"
|
||
|
||
# ============================================================================
|
||
# Step 7: Generate OpenClaw config
|
||
# ============================================================================
|
||
|
||
if [ "$SKIP_CONFIG" = false ]; then
|
||
mkdir -p "$OPENCLAW_CONFIG_DIR"
|
||
|
||
if [ "$MODE" = "platform" ]; then
|
||
TEMPLATE="$SCRIPT_DIR/config/openclaw.platform.json"
|
||
else
|
||
TEMPLATE="$SCRIPT_DIR/config/openclaw.oss.json"
|
||
fi
|
||
|
||
# Substitute the user ID placeholder (apiKey uses env var resolution at runtime)
|
||
sed "s/__MEM0_USER_ID__/${MEM0_USER_ID}/g" "$TEMPLATE" > "$OPENCLAW_CONFIG_DIR/openclaw.json"
|
||
|
||
ok "Created $OPENCLAW_CONFIG_DIR/openclaw.json"
|
||
fi
|
||
|
||
# ============================================================================
|
||
# Step 8: Install Mem0 plugin
|
||
# ============================================================================
|
||
|
||
header "Installing Mem0 plugin..."
|
||
|
||
COMPOSE_CMD="docker compose"
|
||
if [ "$MODE" = "oss" ]; then
|
||
COMPOSE_CMD="docker compose -f docker-compose.yml -f docker-compose.oss.yml"
|
||
fi
|
||
|
||
cd "$SCRIPT_DIR"
|
||
|
||
if $COMPOSE_CMD run --rm openclaw openclaw plugins install @mem0/openclaw-mem0 2>/dev/null; then
|
||
ok "Mem0 plugin installed."
|
||
else
|
||
warn "Plugin install via Docker failed. This may be normal on first run."
|
||
echo " You can install manually later:"
|
||
echo " $COMPOSE_CMD run --rm openclaw openclaw plugins install @mem0/openclaw-mem0"
|
||
fi
|
||
|
||
# ============================================================================
|
||
# Step 9: Copy onboarding skill
|
||
# ============================================================================
|
||
|
||
SKILL_DIR="$OPENCLAW_CONFIG_DIR/workspace/skills/mem0-onboarding"
|
||
mkdir -p "$SKILL_DIR"
|
||
cp "$SCRIPT_DIR/skills/mem0-onboarding/SKILL.md" "$SKILL_DIR/SKILL.md"
|
||
ok "Onboarding skill installed."
|
||
|
||
# ============================================================================
|
||
# Step 10: Start containers
|
||
# ============================================================================
|
||
|
||
header "Starting OpenClaw..."
|
||
|
||
$COMPOSE_CMD up -d
|
||
|
||
# ============================================================================
|
||
# Step 11: Health check
|
||
# ============================================================================
|
||
|
||
info "Waiting for OpenClaw to be ready..."
|
||
|
||
HEALTH_URL="http://127.0.0.1:${OPENCLAW_PORT}/healthz"
|
||
TIMEOUT=90
|
||
ELAPSED=0
|
||
INTERVAL=3
|
||
|
||
while [ $ELAPSED -lt $TIMEOUT ]; do
|
||
if curl -sf "$HEALTH_URL" &>/dev/null; then
|
||
echo ""
|
||
ok "OpenClaw is ready!"
|
||
break
|
||
fi
|
||
printf "."
|
||
sleep $INTERVAL
|
||
ELAPSED=$((ELAPSED + INTERVAL))
|
||
done
|
||
|
||
if [ $ELAPSED -ge $TIMEOUT ]; then
|
||
echo ""
|
||
warn "Health check timed out after ${TIMEOUT}s."
|
||
echo " OpenClaw may still be starting. Check logs:"
|
||
echo " cd $SCRIPT_DIR && $COMPOSE_CMD logs -f"
|
||
exit 1
|
||
fi
|
||
|
||
# ============================================================================
|
||
# Done!
|
||
# ============================================================================
|
||
|
||
echo ""
|
||
header "Setup complete!"
|
||
echo ""
|
||
echo " Open the web UI: ${BOLD}http://localhost:${OPENCLAW_PORT}${NC}"
|
||
echo " Mode: ${MODE}"
|
||
echo " User ID: ${MEM0_USER_ID}"
|
||
echo " Config: ${OPENCLAW_CONFIG_DIR}/openclaw.json"
|
||
echo ""
|
||
echo " ${BLUE}Tip:${NC} Your first chat will trigger the Mem0 onboarding skill."
|
||
echo " Try telling the agent something about yourself to test memory!"
|
||
echo ""
|
||
echo " Useful commands:"
|
||
echo " View logs: cd $SCRIPT_DIR && $COMPOSE_CMD logs -f"
|
||
echo " Stop: cd $SCRIPT_DIR && $COMPOSE_CMD down"
|
||
echo " Restart: cd $SCRIPT_DIR && $COMPOSE_CMD restart"
|
||
echo ""
|