Files
u-claw/usb-release/启动 U-Claw.command
dongsheng123132 025bb62a5b feat(usb-release): 统一发布版,Mac + Windows 跨平台支持
基于 Pro 精简结构,去掉 app/ 中间层,core/runtime/data/ 直接在根目录。
- Mac: 启动 U-Claw.command + 重新配置.command(含 Config GUI 首次配置)
- Windows: Windows-Start.bat + Windows-Menu.bat(15 项功能菜单)
- setup.sh: --all-platforms 三平台 runtime, --with-toolkit 下载安装包
- 10 个中国优化技能 (skills/)
- toolkit/ 放 Node.js pkg/msi 供离线装机
2026-03-19 21:05:45 +08:00

184 lines
6.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# ============================================================
# U-Claw — 便携版启动器 (macOS)
# 双击此文件即可启动 OpenClaw
# ============================================================
DIR="$(cd "$(dirname "$0")" && pwd)"
ARCH=$(uname -m)
# --- Colors ---
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
echo ""
echo -e "${CYAN} 🦞 U-Claw — 便携版${NC}"
echo -e " ════════════════════════════════"
echo ""
# --- Find Node.js ---
if [ "$ARCH" = "arm64" ]; then
NODE_BIN="$DIR/runtime/node-mac-arm64/bin/node"
else
NODE_BIN="$DIR/runtime/node-mac-x64/bin/node"
fi
[ ! -f "$NODE_BIN" ] && NODE_BIN="$(which node 2>/dev/null)"
if [ -z "$NODE_BIN" ] || [ ! -f "$NODE_BIN" ]; then
echo -e "${RED} ✗ 未找到 Node.js请确保 runtime/ 目录完整${NC}"
echo " 按回车退出..."; read; exit 1
fi
NODE_VER=$("$NODE_BIN" --version 2>/dev/null)
echo -e " ${GREEN}${NC} Node.js: $NODE_VER ($ARCH)"
# --- Remove macOS quarantine ---
if xattr -l "$NODE_BIN" 2>/dev/null | grep -q "com.apple.quarantine"; then
echo -e " ${YELLOW}移除 macOS 安全限制...${NC}"
xattr -rd com.apple.quarantine "$DIR" 2>/dev/null || true
echo -e " ${GREEN}${NC} 已移除"
fi
# --- Find OpenClaw ---
CORE_DIR="$DIR/core"
OPENCLAW_MJS="$CORE_DIR/node_modules/openclaw/openclaw.mjs"
if [ ! -f "$OPENCLAW_MJS" ]; then
echo -e "${RED} ✗ 未找到 OpenClaw请确保 core/ 目录完整${NC}"
echo " 按回车退出..."; read; exit 1
fi
echo -e " ${GREEN}${NC} OpenClaw: 已就绪"
# --- Setup portable data dir ---
DATA_DIR="$DIR/data"
export OPENCLAW_HOME="$DATA_DIR"
export OPENCLAW_STATE_DIR="$DATA_DIR/.openclaw"
export OPENCLAW_CONFIG_PATH="$DATA_DIR/.openclaw/openclaw.json"
mkdir -p "$DATA_DIR/.openclaw" "$DATA_DIR/memory" "$DATA_DIR/backups" "$DATA_DIR/logs"
# --- Check if config needs setup (first run) ---
CONFIG_FILE="$DATA_DIR/.openclaw/openclaw.json"
NEEDS_CONFIG=false
if [ ! -f "$CONFIG_FILE" ]; then
NEEDS_CONFIG=true
else
if ! grep -qE '"apiKey"|"ZAI_API_KEY"|"providers"' "$CONFIG_FILE" 2>/dev/null; then
NEEDS_CONFIG=true
fi
fi
# --- If first run, open Config GUI first ---
if [ "$NEEDS_CONFIG" = "true" ]; then
echo ""
echo -e " ${YELLOW}⚡ 首次运行,请先配置模型和 API Key${NC}"
echo -e " ${YELLOW} 正在打开配置页面...${NC}"
echo ""
CONFIG_PORT=18780
while lsof -i :$CONFIG_PORT >/dev/null 2>&1; do
CONFIG_PORT=$((CONFIG_PORT + 1))
[ $CONFIG_PORT -gt 18785 ] && break
done
"$NODE_BIN" -e "
const http = require('http');
const fs = require('fs');
const path = require('path');
const configPath = '$CONFIG_FILE';
const htmlPath = path.join('$DIR', 'Config.html');
const server = http.createServer((req, res) => {
if (req.method === 'GET' && (req.url === '/' || req.url === '/index.html')) {
res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
res.end(fs.readFileSync(htmlPath, 'utf-8'));
} else if (req.method === 'GET' && req.url === '/api/config') {
try {
const cfg = fs.existsSync(configPath) ? JSON.parse(fs.readFileSync(configPath, 'utf-8')) : {};
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(cfg));
} catch(e) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end('{}');
}
} else if (req.method === 'POST' && req.url === '/api/config') {
let body = '';
req.on('data', c => body += c);
req.on('end', () => {
try {
const cfg = JSON.parse(body);
fs.mkdirSync(path.dirname(configPath), {recursive: true});
fs.writeFileSync(configPath, JSON.stringify(cfg, null, 2));
res.writeHead(200, {'Content-Type': 'application/json'});
res.end('{\"ok\":true}');
} catch(e) {
res.writeHead(400, {'Content-Type': 'application/json'});
res.end('{\"error\":\"' + e.message + '\"}');
}
});
} else if (req.method === 'POST' && req.url === '/api/done') {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end('{\"ok\":true}');
setTimeout(() => { server.close(); process.exit(0); }, 300);
} else {
res.writeHead(404); res.end('Not Found');
}
});
server.listen($CONFIG_PORT, '127.0.0.1', () => {
console.log('Config server: http://127.0.0.1:$CONFIG_PORT');
});
" &
CONFIG_PID=$!
sleep 1
open "http://127.0.0.1:$CONFIG_PORT/"
echo -e " ${CYAN}等待配置完成...${NC}"
echo -e " (在浏览器中选择模型、填写 API Key点击「保存并启动」"
echo ""
wait $CONFIG_PID 2>/dev/null
echo -e " ${GREEN}${NC} 配置已保存"
echo ""
fi
# --- Check dependencies ---
if [ ! -d "$CORE_DIR/node_modules" ]; then
echo -e " ${YELLOW}首次运行,安装依赖...${NC}"
NODE_DIR="$(dirname "$(dirname "$NODE_BIN")")"
cd "$CORE_DIR"
"$NODE_BIN" "$NODE_DIR/bin/npm" install --registry=https://registry.npmmirror.com 2>&1
echo -e " ${GREEN}${NC} 依赖安装完成"
echo ""
fi
# --- Find available port ---
PORT=18789
while lsof -i :$PORT >/dev/null 2>&1; do
PORT=$((PORT + 1))
[ $PORT -gt 18799 ] && echo -e "${RED} ✗ 没有可用端口 (18789-18799)${NC}" && exit 1
done
echo -e " ${CYAN}🚀 正在启动 OpenClaw...${NC}"
echo ""
# --- Start OpenClaw gateway ---
cd "$CORE_DIR"
"$NODE_BIN" "$OPENCLAW_MJS" gateway run --allow-unconfigured --force --port $PORT &
GW_PID=$!
# --- Wait for gateway, then open browser ---
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
TOKEN=$("$NODE_BIN" -e "try{const c=JSON.parse(require('fs').readFileSync('$CONFIG_FILE','utf8'));console.log(c.gateway?.auth?.token||'uclaw')}catch(e){console.log('uclaw')}" 2>/dev/null)
open "http://127.0.0.1:$PORT/#token=$TOKEN" 2>/dev/null || true
break
fi
done
TOKEN=$("$NODE_BIN" -e "try{const c=JSON.parse(require('fs').readFileSync('$CONFIG_FILE','utf8'));console.log(c.gateway?.auth?.token||'uclaw')}catch(e){console.log('uclaw')}" 2>/dev/null)
echo -e " ${GREEN}════════════════════════════════${NC}"
echo -e " ${GREEN}🦞 U-Claw 正在运行!${NC}"
echo -e " ${GREEN} 地址: http://127.0.0.1:$PORT/#token=$TOKEN${NC}"
echo ""
echo -e " ${YELLOW}按 Ctrl+C 停止服务${NC}"
echo -e " ${GREEN}════════════════════════════════${NC}"
echo ""
trap "kill $GW_PID 2>/dev/null; echo ''; echo ' 🦞 U-Claw 已停止'; exit 0" INT TERM
wait $GW_PID