#!/bin/bash # ============================================ # ClawPortal 一键安装脚本 # 版本: v1.0 # 支持: OrbStack / Docker Desktop # 架构: macOS + Apple Silicon (arm64) # ============================================ set -e # ============================================ # 配置 # ============================================ PORTAL_URL="https://portal.conaeon.ai" INSTALL_DIR="$HOME/clawportal" DOCKER_COMPOSE="$INSTALL_DIR/docker-compose.yml" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # ============================================ # 辅助函数 # ============================================ print_header() { echo "" echo "======================================" echo " $1" echo "======================================" echo "" } print_step() { echo -e "${GREEN}[$1]${NC} $2" } print_error() { echo -e "${RED}错误:${NC} $1" } print_warning() { echo -e "${YELLOW}警告:${NC} $1" } # ============================================ # 主流程 # ============================================ print_header "ClawPortal AI一体机 一键安装" # -------------------------------------------- # 1. 检测系统 # -------------------------------------------- print_step "1/7" "检测系统环境..." # 检测操作系统 if [[ "$OSTYPE" != "darwin"* ]]; then print_error "当前仅支持 macOS" echo "Linux 支持即将推出,敬请期待" exit 1 fi # 检测架构 ARCH=$(uname -m) if [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then ARCH_SUFFIX="arm64" echo " ✓ Apple Silicon (arm64)" elif [ "$ARCH" = "x86_64" ]; then print_warning "检测到 Intel 架构" echo " 当前仅支持 Apple Silicon,Intel 版本即将推出" echo " 请联系客服: support@conaeon.ai" exit 1 else print_error "不支持的架构: $ARCH" exit 1 fi # -------------------------------------------- # 2. 检测容器运行时 # -------------------------------------------- print_step "2/7" "检测容器运行时..." RUNTIME="" RUNTIME_CMD="" if command -v orb &> /dev/null; then RUNTIME="OrbStack" RUNTIME_CMD="orb" echo " ✓ OrbStack 已安装" elif command -v docker &> /dev/null; then RUNTIME="Docker" RUNTIME_CMD="docker" echo " ✓ Docker 已安装" else print_error "未检测到容器运行时" echo "" echo "请先安装容器运行时:" echo "" echo "推荐: OrbStack (更快、更轻)" echo " 下载: https://orbstack.dev/download" echo "" echo "备选: Docker Desktop" echo " 下载: https://www.docker.com/products/docker-desktop/" exit 1 fi # 检查运行时是否运行 if ! $RUNTIME_CMD ps &> /dev/null; then print_error "$RUNTIME 未运行,请先启动 $RUNTIME" exit 1 fi # -------------------------------------------- # 3. 获取授权码 # -------------------------------------------- print_step "3/7" "获取授权码..." # 尝试从 URL 提取授权码(如果通过专属链接安装) AUTH_CODE="" # 检查是否通过专属链接调用 if [[ -n "$REQUEST_URI" ]]; then AUTH_CODE=$(echo "$REQUEST_URI" | grep -o 'XLK-[^/&]*' || true) fi # 如果 URL 中没有,提示用户输入 if [ -z "$AUTH_CODE" ]; then echo "" echo "请输入授权码 (格式: XLK-XXX-XXX-XXX):" read -r AUTH_CODE fi # 验证授权码格式 if [[ ! "$AUTH_CODE" =~ ^XLK-[A-Z0-9]{3}-[A-Z0-9]{3}-[A-Z0-9]{3}$ ]]; then print_error "授权码格式无效" echo " 正确格式: XLK-XXX-XXX-XXX" echo " 请联系客服获取授权码: support@conaeon.ai" exit 1 fi echo " 授权码: $AUTH_CODE" # -------------------------------------------- # 4. 验证授权码 # -------------------------------------------- print_step "4/7" "验证授权码..." VERIFY_URL="${PORTAL_URL}/verify?code=${AUTH_CODE}" if command -v jq &> /dev/null; then # 有 jq,使用 JSON 解析 VERIFY_RESULT=$(curl -s "$VERIFY_URL") VALID=$(echo "$VERIFY_RESULT" | jq -r '.valid // false') if [ "$VALID" != "true" ]; then ERROR=$(echo "$VERIFY_RESULT" | jq -r '.error // "Unknown error"') print_error "授权码验证失败: $ERROR" echo " 请联系客服: support@conaeon.ai" exit 1 fi # 获取配置 IMAGE=$(echo "$VERIFY_RESULT" | jq -r '.image') CUSTOMER=$(echo "$VERIFY_RESULT" | jq -r '.customer') VERSION=$(echo "$VERIFY_RESULT" | jq -r '.version') else # 无 jq,使用 grep 简单验证 VERIFY_RESULT=$(curl -s "$VERIFY_URL") if ! echo "$VERIFY_RESULT" | grep -q '"valid":true'; then print_error "授权码验证失败" echo " 请联系客服: support@conaeon.ai" exit 1 fi # 从结果中提取镜像地址(简化版) IMAGE=$(echo "$VERIFY_RESULT" | grep -o '"image":"[^"]*"' | cut -d'"' -f4) CUSTOMER="客户" VERSION="v1.0.0" fi echo " ✓ 授权验证通过" echo " 客户: $CUSTOMER" echo " 版本: $VERSION" # -------------------------------------------- # 5. 创建安装目录 # -------------------------------------------- print_step "5/7" "创建安装目录..." mkdir -p "$INSTALL_DIR" mkdir -p "$INSTALL_DIR/data" mkdir -p "$INSTALL_DIR/logs" echo " ✓ 目录: $INSTALL_DIR" # -------------------------------------------- # 6. 拉取镜像 # -------------------------------------------- print_step "6/7" "拉取 Docker 镜像..." echo " 镜像: $IMAGE" echo " 正在拉取,请稍候..." if ! $RUNTIME_CMD pull "$IMAGE"; then print_error "镜像拉取失败" echo " 请检查网络连接" echo " 或联系客服: support@conaeon.ai" exit 1 fi echo " ✓ 镜像拉取完成" # -------------------------------------------- # 7. 生成配置并启动服务 # -------------------------------------------- print_step "7/7" "生成配置并启动服务..." # 生成 docker-compose.yml cat > "$DOCKER_COMPOSE" </dev/null || echo "") else STATUS=$($RUNTIME_CMD ps --filter "name=clawportal" --format "{{.Status}}" 2>/dev/null || echo "") fi if echo "$STATUS" | grep -q "Up"; then # 检查健康状态 if curl -sf http://localhost:3000/health &> /dev/null; then echo " ✓ 服务启动成功" break fi fi echo " 等待中... (${WAIT_COUNT}s)" done if [ $WAIT_COUNT -ge $MAX_WAIT ]; then print_warning "服务启动超时,请检查日志" fi # -------------------------------------------- # 安装完成 # -------------------------------------------- print_header "安装完成!" echo "访问地址: http://localhost:3000" echo "安装目录: $INSTALL_DIR" echo "运行时: $RUNTIME" echo "" echo "常用命令:" if [ "$RUNTIME_CMD" = "orb" ]; then echo " 查看日志: orb logs -f clawportal" echo " 停止服务: cd $INSTALL_DIR && orb-compose down" echo " 重启服务: cd $INSTALL_DIR && orb-compose restart" echo " 查看状态: orb ps" else echo " 查看日志: docker logs -f clawportal" echo " 停止服务: cd $INSTALL_DIR && docker-compose down" echo " 重启服务: cd $INSTALL_DIR && docker-compose restart" echo " 查看状态: docker ps" fi echo "" echo "技术支持: support@conaeon.ai" echo "文档: https://github.com/conaeon-ai/clawportal" echo ""