- build-usb.sh: one-click USB drive builder (downloads Node.js + OpenClaw from China mirrors, packages into USB-ready directory) - Mac-Install.command: install from USB to Mac (~/.uclaw/), offline-first with China mirror fallback - Windows-Install.bat: same for Windows - README.md rewritten to position project as "USB drive builder toolkit"
258 lines
7.8 KiB
Bash
Executable File
258 lines
7.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# ============================================================
|
|
# U-Claw - Install to Mac (从 U 盘安装到电脑)
|
|
# 优先使用 U 盘内的离线资源,缺失时从国内镜像下载
|
|
# ============================================================
|
|
|
|
set -e
|
|
|
|
UCLAW_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
APP_DIR="$UCLAW_DIR/app"
|
|
INSTALL_TARGET="$HOME/.uclaw"
|
|
|
|
GREEN='\033[0;32m'
|
|
CYAN='\033[0;36m'
|
|
RED='\033[0;31m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
BOLD='\033[1m'
|
|
DIM='\033[2m'
|
|
|
|
NODE_VER="v22.14.0"
|
|
MIRROR="https://registry.npmmirror.com"
|
|
NODE_MIRROR="https://npmmirror.com/mirrors/node"
|
|
|
|
clear
|
|
echo ""
|
|
echo -e "${CYAN}${BOLD}"
|
|
echo " ╔══════════════════════════════════════╗"
|
|
echo " ║ U-Claw 安装到 Mac ║"
|
|
echo " ║ 从 U 盘离线安装 ║"
|
|
echo " ╚══════════════════════════════════════╝"
|
|
echo -e "${NC}"
|
|
echo ""
|
|
|
|
# ---- Check CPU ----
|
|
ARCH=$(uname -m)
|
|
if [ "$ARCH" = "arm64" ]; then
|
|
echo -e " ${GREEN}Apple Silicon (M 系列) ✓${NC}"
|
|
NODE_PLATFORM="node-mac-arm64"
|
|
else
|
|
echo -e " ${YELLOW}Intel Mac${NC}"
|
|
NODE_PLATFORM="node-mac-x64"
|
|
fi
|
|
echo ""
|
|
|
|
# ---- Check existing installation ----
|
|
if [ -d "$INSTALL_TARGET" ]; then
|
|
echo -e " ${YELLOW}检测到已有安装: $INSTALL_TARGET${NC}"
|
|
read -p " 覆盖安装?(y/n): " -n 1 OVERWRITE
|
|
echo ""
|
|
if [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "Y" ]; then
|
|
echo -e " ${DIM}已取消${NC}"
|
|
exit 0
|
|
fi
|
|
echo ""
|
|
fi
|
|
|
|
# ---- Step 1: Check environment ----
|
|
echo -e " ${BOLD}[1/4] 检查环境...${NC}"
|
|
|
|
NEED_DOWNLOAD_NODE=false
|
|
NEED_DOWNLOAD_OPENCLAW=false
|
|
|
|
# Check Node.js - prefer USB, then system, then download
|
|
USB_NODE="$APP_DIR/runtime/$NODE_PLATFORM/bin/node"
|
|
USB_NPM="$APP_DIR/runtime/$NODE_PLATFORM/bin/npm"
|
|
|
|
if [ -f "$USB_NODE" ]; then
|
|
echo -e " ${GREEN}Node.js: 使用 U 盘内的 ($("$USB_NODE" --version))${NC}"
|
|
USE_NODE="usb"
|
|
elif command -v node >/dev/null 2>&1; then
|
|
SYS_VER=$(node --version)
|
|
MAJOR=$(echo "$SYS_VER" | sed 's/v//' | cut -d. -f1)
|
|
if [ "$MAJOR" -ge 20 ] 2>/dev/null; then
|
|
echo -e " ${GREEN}Node.js: 使用系统的 ($SYS_VER)${NC}"
|
|
USE_NODE="system"
|
|
else
|
|
echo -e " ${YELLOW}Node.js: 系统版本太低 ($SYS_VER),需要 v20+${NC}"
|
|
NEED_DOWNLOAD_NODE=true
|
|
USE_NODE="download"
|
|
fi
|
|
else
|
|
echo -e " ${YELLOW}Node.js: 未安装${NC}"
|
|
NEED_DOWNLOAD_NODE=true
|
|
USE_NODE="download"
|
|
fi
|
|
|
|
# Check OpenClaw
|
|
USB_OPENCLAW="$APP_DIR/core/node_modules/openclaw/openclaw.mjs"
|
|
if [ -f "$USB_OPENCLAW" ]; then
|
|
echo -e " ${GREEN}OpenClaw: 使用 U 盘内的${NC}"
|
|
USE_OPENCLAW="usb"
|
|
else
|
|
echo -e " ${YELLOW}OpenClaw: U 盘内未找到,需要在线下载${NC}"
|
|
NEED_DOWNLOAD_OPENCLAW=true
|
|
USE_OPENCLAW="download"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# ---- Step 2: Create install directory ----
|
|
echo -e " ${BOLD}[2/4] 安装到 $INSTALL_TARGET ...${NC}"
|
|
|
|
mkdir -p "$INSTALL_TARGET"
|
|
mkdir -p "$INSTALL_TARGET/data/.openclaw"
|
|
mkdir -p "$INSTALL_TARGET/data/memory"
|
|
mkdir -p "$INSTALL_TARGET/data/backups"
|
|
|
|
# ---- Step 3: Copy/Download Node.js ----
|
|
echo -e " ${BOLD}[3/4] 安装 Node.js...${NC}"
|
|
|
|
NODE_INSTALL_DIR="$INSTALL_TARGET/runtime/$NODE_PLATFORM"
|
|
|
|
case $USE_NODE in
|
|
usb)
|
|
echo -e " ${CYAN}从 U 盘复制 Node.js...${NC}"
|
|
mkdir -p "$NODE_INSTALL_DIR"
|
|
cp -R "$APP_DIR/runtime/$NODE_PLATFORM/"* "$NODE_INSTALL_DIR/"
|
|
chmod +x "$NODE_INSTALL_DIR/bin/node"
|
|
INSTALL_NODE="$NODE_INSTALL_DIR/bin/node"
|
|
INSTALL_NPM="$NODE_INSTALL_DIR/bin/npm"
|
|
echo -e " ${GREEN}Node.js 安装完成 ✓${NC}"
|
|
;;
|
|
system)
|
|
INSTALL_NODE="$(which node)"
|
|
INSTALL_NPM="$(which npm)"
|
|
echo -e " ${GREEN}使用系统 Node.js ✓${NC}"
|
|
;;
|
|
download)
|
|
echo -e " ${CYAN}从国内镜像下载 Node.js $NODE_VER...${NC}"
|
|
PLATFORM_NAME="darwin-$ARCH"
|
|
TARBALL="node-${NODE_VER}-${PLATFORM_NAME}.tar.gz"
|
|
URL="${NODE_MIRROR}/${NODE_VER}/${TARBALL}"
|
|
|
|
mkdir -p "$NODE_INSTALL_DIR"
|
|
curl -# -L "$URL" -o "/tmp/$TARBALL"
|
|
tar -xzf "/tmp/$TARBALL" -C "$NODE_INSTALL_DIR" --strip-components=1
|
|
rm -f "/tmp/$TARBALL"
|
|
chmod +x "$NODE_INSTALL_DIR/bin/node"
|
|
INSTALL_NODE="$NODE_INSTALL_DIR/bin/node"
|
|
INSTALL_NPM="$NODE_INSTALL_DIR/bin/npm"
|
|
echo -e " ${GREEN}Node.js 下载安装完成 ✓${NC}"
|
|
;;
|
|
esac
|
|
|
|
echo ""
|
|
|
|
# ---- Step 4: Copy/Download OpenClaw ----
|
|
echo -e " ${BOLD}[4/4] 安装 OpenClaw...${NC}"
|
|
|
|
CORE_INSTALL_DIR="$INSTALL_TARGET/core"
|
|
|
|
case $USE_OPENCLAW in
|
|
usb)
|
|
echo -e " ${CYAN}从 U 盘复制 OpenClaw + 插件...${NC}"
|
|
mkdir -p "$CORE_INSTALL_DIR"
|
|
cp -R "$APP_DIR/core/"* "$CORE_INSTALL_DIR/"
|
|
echo -e " ${GREEN}OpenClaw 安装完成 ✓${NC}"
|
|
;;
|
|
download)
|
|
echo -e " ${CYAN}从国内镜像下载 OpenClaw...${NC}"
|
|
mkdir -p "$CORE_INSTALL_DIR"
|
|
cat > "$CORE_INSTALL_DIR/package.json" << 'PKGEOF'
|
|
{
|
|
"name": "u-claw-core",
|
|
"version": "1.0.0",
|
|
"private": true,
|
|
"dependencies": {
|
|
"openclaw": "latest"
|
|
}
|
|
}
|
|
PKGEOF
|
|
cd "$CORE_INSTALL_DIR"
|
|
"$INSTALL_NODE" "$INSTALL_NPM" install --registry="$MIRROR" 2>&1 | tail -3
|
|
"$INSTALL_NODE" "$INSTALL_NPM" install @sliverp/qqbot@latest --registry="$MIRROR" 2>&1 | tail -2
|
|
echo -e " ${GREEN}OpenClaw 下载安装完成 ✓${NC}"
|
|
;;
|
|
esac
|
|
|
|
# ---- Default config ----
|
|
CONFIG_PATH="$INSTALL_TARGET/data/.openclaw/openclaw.json"
|
|
if [ ! -f "$CONFIG_PATH" ]; then
|
|
cat > "$CONFIG_PATH" << 'CFGEOF'
|
|
{
|
|
"gateway": {
|
|
"mode": "local",
|
|
"auth": { "token": "uclaw" }
|
|
}
|
|
}
|
|
CFGEOF
|
|
fi
|
|
|
|
# ---- Copy launch scripts ----
|
|
for f in Config.html U-Claw.html; do
|
|
[ -f "$UCLAW_DIR/$f" ] && cp "$UCLAW_DIR/$f" "$INSTALL_TARGET/"
|
|
done
|
|
|
|
# ---- Create launch script ----
|
|
cat > "$INSTALL_TARGET/start.command" << 'STARTEOF'
|
|
#!/bin/bash
|
|
DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
ARCH=$(uname -m)
|
|
NODE_PLATFORM="node-mac-$( [ "$ARCH" = "arm64" ] && echo "arm64" || echo "x64" )"
|
|
|
|
NODE_BIN="$DIR/runtime/$NODE_PLATFORM/bin/node"
|
|
[ ! -f "$NODE_BIN" ] && NODE_BIN="$(which node)"
|
|
|
|
CORE_DIR="$DIR/core"
|
|
OPENCLAW_MJS="$CORE_DIR/node_modules/openclaw/openclaw.mjs"
|
|
|
|
export OPENCLAW_HOME="$DIR/data"
|
|
export OPENCLAW_STATE_DIR="$DIR/data/.openclaw"
|
|
export OPENCLAW_CONFIG_PATH="$DIR/data/.openclaw/openclaw.json"
|
|
|
|
PORT=18789
|
|
while lsof -i :$PORT >/dev/null 2>&1; do
|
|
PORT=$((PORT + 1))
|
|
[ $PORT -gt 18799 ] && echo "No available port" && exit 1
|
|
done
|
|
|
|
cd "$CORE_DIR"
|
|
"$NODE_BIN" "$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port $PORT &
|
|
PID=$!
|
|
|
|
for i in $(seq 1 30); do
|
|
sleep 0.5
|
|
if curl -s -o /dev/null "http://127.0.0.1:$PORT/" 2>/dev/null; then
|
|
open "http://127.0.0.1:$PORT/#token=uclaw"
|
|
break
|
|
fi
|
|
done
|
|
|
|
wait $PID
|
|
STARTEOF
|
|
chmod +x "$INSTALL_TARGET/start.command"
|
|
|
|
echo ""
|
|
|
|
# ---- Summary ----
|
|
INSTALL_SIZE=$(du -sh "$INSTALL_TARGET" | cut -f1)
|
|
|
|
echo -e " ${GREEN}${BOLD}╔══════════════════════════════════════╗"
|
|
echo -e " ║ ✅ 安装成功! ║"
|
|
echo -e " ╚══════════════════════════════════════╝${NC}"
|
|
echo ""
|
|
echo -e " ${BOLD}安装位置:${NC} $INSTALL_TARGET"
|
|
echo -e " ${BOLD}大小:${NC} $INSTALL_SIZE"
|
|
echo ""
|
|
echo -e " ${BOLD}启动方式:${NC}"
|
|
echo -e " 双击 ${CYAN}$INSTALL_TARGET/start.command${NC}"
|
|
echo -e " 或终端运行: ${CYAN}bash ~/.uclaw/start.command${NC}"
|
|
echo ""
|
|
echo -e " ${BOLD}首次使用:${NC}"
|
|
echo -e " 启动后浏览器自动打开配置页面"
|
|
echo -e " 选择 AI 模型 → 填写 API Key → 开始用"
|
|
echo ""
|
|
read -p " 按回车关闭..."
|