Files
server-deploy/claude-dev-stack/wsl-setup.sh
Joywayer 1a29cab661 新增 claude-dev-stack 全栈一键部署脚本
WSL2 + Claude Code CLI (WSL2 原生) + Unity MCP Server (AnkleBreaker) + Rust Token Killer + v2rayN 代理自动配置

- deploy.ps1:8 步全自动部署,支持幂等重跑
- Invoke-WSL 改用 base64 编码规避 PowerShell→WSL CRLF 问题
- nvm 安装 Node.js,正确排除 Windows interop 路径
- claude mcp add --scope user 全局注册 Unity MCP
- .wslconfig networkingMode=mirrored,代理直连 127.0.0.1
- 摘要显示复用已检测变量,避免二次 WSL 调用
- .env.example 提供配置模板,.env 已加入 .gitignore

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-28 09:38:17 +08:00

272 lines
12 KiB
Bash
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.
#!/usr/bin/env bash
# =============================================================
# WSL2 内部环境检测 & 安装脚本
# 可单独在 WSL2 Ubuntu 中运行bash wsl-setup.sh
# 也会被 deploy.ps1 自动调用(通过 Invoke-WSL
# =============================================================
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; NC='\033[0m'
log() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
step() { echo -e "\n${CYAN}====== $* ======${NC}"; }
# ──────────────────────────────────────────────────────────────
# 加载 .env与脚本同目录
# ──────────────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/.env"
ENV_EXAMPLE="$SCRIPT_DIR/.env.example"
if [ ! -f "$ENV_FILE" ]; then
if [ -f "$ENV_EXAMPLE" ]; then
cp "$ENV_EXAMPLE" "$ENV_FILE"
warn "已从 .env.example 创建 .env请按需编辑后重新运行"
exit 0
fi
fi
if [ -f "$ENV_FILE" ]; then
sed -i 's/\r$//' "$ENV_FILE"
set -a; source "$ENV_FILE"; set +a
fi
ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-}"
ANTHROPIC_BASE_URL="${ANTHROPIC_BASE_URL:-https://api.anthropic.com}"
CLAUDE_MODEL="${CLAUDE_MODEL:-claude-opus-4-5}"
BRIDGE_PORT="${BRIDGE_PORT:-7890}"
# ──────────────────────────────────────────────────────────────
# Step 1: v2rayN 代理配置WSL2 侧)
# ──────────────────────────────────────────────────────────────
step "1/6 代理配置"
# 优先读取 deploy.ps1 写入的 ~/.mcp-proxy.env
if [ -f ~/.mcp-proxy.env ]; then
source ~/.mcp-proxy.env 2>/dev/null || true
if [ -n "${http_proxy:-}" ]; then
log "代理已从 ~/.mcp-proxy.env 加载: $http_proxy"
fi
fi
# 若代理未设置但提供了 PROXY_PORT则动态检测 Windows 主机 IP
PROXY_PORT="${PROXY_PORT:-0}"
if [ -z "${http_proxy:-}" ] && [ "$PROXY_PORT" -gt 0 ] 2>/dev/null; then
WIN_HOST=$(ip route 2>/dev/null | grep default | awk '{print $3}' | head -1)
[ -z "$WIN_HOST" ] && WIN_HOST=$(grep nameserver /etc/resolv.conf 2>/dev/null | awk '{print $2}' | head -1)
if [ -n "$WIN_HOST" ]; then
export http_proxy="http://${WIN_HOST}:${PROXY_PORT}"
export https_proxy="$http_proxy"
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$http_proxy"
export no_proxy="localhost,127.0.0.1,::1"
log "WSL2 代理已设置: $http_proxy (Windows 主机: $WIN_HOST)"
else
warn "无法获取 Windows 主机 IP代理未设置"
fi
fi
# 写入 ~/.mcp-proxy.env 并持久化到 ~/.bashrc
if [ -n "${http_proxy:-}" ] && [ -z "$(grep -s 'mcp-proxy.env' ~/.bashrc)" ]; then
cat >> ~/.bashrc << 'BASHRCBLOCK'
# Unity MCP WSL2 proxy (generated by wsl-setup.sh)
[ -f ~/.mcp-proxy.env ] && . ~/.mcp-proxy.env
BASHRCBLOCK
log "代理配置已写入 ~/.bashrc"
fi
# 写入 git 代理
if [ -n "${http_proxy:-}" ]; then
git config --global http.proxy "$http_proxy" 2>/dev/null || true
git config --global https.proxy "$https_proxy" 2>/dev/null || true
log "git 代理已配置"
fi
if [ -z "${http_proxy:-}" ]; then
warn "未配置代理,将使用直连网络(如下载失败请通过 PROXY_PORT=10809 重新运行)"
fi
# ──────────────────────────────────────────────────────────────
# Step 2: 系统依赖
# ──────────────────────────────────────────────────────────────
step "2/6 系统依赖"
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update -qq
sudo apt-get install -y -qq \
curl wget git build-essential pkg-config libssl-dev \
ca-certificates gnupg lsb-release unzip python3
log "系统依赖安装完成"
# ──────────────────────────────────────────────────────────────
# Step 3: Node.js LTS
# ──────────────────────────────────────────────────────────────
step "3/6 Node.js LTS"
if command -v node &>/dev/null; then
log "Node.js 已安装: $(node --version)"
else
log "通过 NodeSource 安装 Node.js LTS..."
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - > /dev/null 2>&1
sudo apt-get install -y -qq nodejs
log "Node.js 安装完成: $(node --version)"
fi
# 设置 npm 代理
if [ -n "${http_proxy:-}" ] && command -v npm &>/dev/null; then
npm config set proxy "$http_proxy" 2>/dev/null || true
npm config set https-proxy "$https_proxy" 2>/dev/null || true
log "npm 代理已配置"
fi
# ──────────────────────────────────────────────────────────────
# Step 4: Claude Code CLI
# ──────────────────────────────────────────────────────────────
step "4/6 Claude Code CLI"
if command -v claude &>/dev/null; then
log "Claude Code 已安装: $(claude --version 2>&1 | head -1)"
else
log "安装 @anthropic-ai/claude-code..."
sudo npm install -g @anthropic-ai/claude-code --quiet
log "Claude Code 安装完成: $(claude --version 2>&1 | head -1)"
fi
mkdir -p ~/.claude
cat > ~/.claude/settings.json << SETTINGS
{"model": "$CLAUDE_MODEL"}
SETTINGS
log "已写入 ~/.claude/settings.json"
PROFILE_BLOCK=""
[ -n "$ANTHROPIC_API_KEY" ] && PROFILE_BLOCK+="export ANTHROPIC_API_KEY='$ANTHROPIC_API_KEY'\n"
[ -n "$ANTHROPIC_BASE_URL" ] && PROFILE_BLOCK+="export ANTHROPIC_BASE_URL='$ANTHROPIC_BASE_URL'\n"
PROFILE_BLOCK+="export CLAUDE_MODEL='$CLAUDE_MODEL'\n"
for rc in ~/.bashrc ~/.profile; do
if ! grep -q "ANTHROPIC_API_KEY" "$rc" 2>/dev/null; then
printf "\n# Claude Code CLI\n${PROFILE_BLOCK}" >> "$rc"
log "已追加环境变量到 $rc"
fi
done
# ──────────────────────────────────────────────────────────────
# Step 5: Unity MCP Server
# ──────────────────────────────────────────────────────────────
step "5/6 Unity MCP Server (AnkleBreaker-Studio)"
MCP_SERVER_DIR="$HOME/.mcp-servers/unity-mcp-server"
mkdir -p "$HOME/.mcp-servers"
if [ -d "$MCP_SERVER_DIR/.git" ]; then
log "unity-mcp-server 已存在,更新至最新..."
git -C "$MCP_SERVER_DIR" pull --quiet
else
log "克隆 unity-mcp-server..."
git clone --quiet https://github.com/AnkleBreaker-Studio/unity-mcp-server.git "$MCP_SERVER_DIR"
fi
log "安装 npm 依赖..."
(cd "$MCP_SERVER_DIR" && npm install --prefer-offline --quiet 2>/dev/null || npm install --quiet)
# 确定入口文件
if [ -f "$MCP_SERVER_DIR/src/index.js" ]; then
SERVER_ENTRY="$MCP_SERVER_DIR/src/index.js"
elif [ -f "$MCP_SERVER_DIR/build/index.js" ]; then
SERVER_ENTRY="$MCP_SERVER_DIR/build/index.js"
else
SERVER_ENTRY="$MCP_SERVER_DIR/index.js"
fi
log "MCP Server 入口:$SERVER_ENTRY"
# 写入 Claude Code (WSL2) MCP 配置
MCP_CONFIG_DIR="$HOME/.config/Claude"
MCP_CONFIG_FILE="$MCP_CONFIG_DIR/claude_desktop_config.json"
mkdir -p "$MCP_CONFIG_DIR"
python3 - << PYEOF
import json, os
cfg_file = "$MCP_CONFIG_FILE"
try:
with open(cfg_file) as f:
cfg = json.load(f)
except:
cfg = {}
cfg.setdefault("mcpServers", {})
cfg["mcpServers"]["unity-mcp"] = {
"command": "node",
"args": ["$SERVER_ENTRY"],
"env": {"UNITY_BRIDGE_PORT": "$BRIDGE_PORT"}
}
with open(cfg_file, "w") as f:
json.dump(cfg, f, indent=2)
print("Claude Code (WSL2) MCP config written")
PYEOF
log "MCP 配置已写入 $MCP_CONFIG_FILE"
# ──────────────────────────────────────────────────────────────
# Step 6: Rust 工具链 & Token Killer
# ──────────────────────────────────────────────────────────────
step "6/6 Rust 工具链 & Token Killer"
[ -f "$HOME/.cargo/env" ] && source "$HOME/.cargo/env"
if command -v rustc &>/dev/null; then
log "Rust 已安装: $(rustc --version)"
else
log "通过 rustup 安装 Rust stable..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --default-toolchain stable --no-modify-path
source "$HOME/.cargo/env"
log "Rust 安装完成: $(rustc --version)"
fi
for rc in ~/.bashrc ~/.profile; do
grep -q 'cargo/env' "$rc" 2>/dev/null || echo 'source ~/.cargo/env 2>/dev/null || true' >> "$rc"
done
if command -v rtk &>/dev/null; then
log "rtk 已安装: $(rtk --version 2>/dev/null || echo ok)"
else
log "安装 rtk (Rust Token Killer)..."
sudo apt-get install -y -qq pkg-config libssl-dev 2>/dev/null || true
if cargo install --git https://github.com/rtk-ai/rtk 2>&1 | tail -3; then
log "rtk 安装成功"
else
warn "rtk 安装失败,请手动运行: cargo install --git https://github.com/rtk-ai/rtk"
fi
fi
# ──────────────────────────────────────────────────────────────
# 安装摘要
# ──────────────────────────────────────────────────────────────
echo ""
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
echo -e "${GREEN} ✅ WSL2 环境部署完成${NC}"
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
echo -e " Node.js $(node --version 2>/dev/null || echo 未安装)"
echo -e " npm $(npm --version 2>/dev/null || echo 未安装)"
echo -e " Claude Code $(claude --version 2>/dev/null | head -1 || echo 未安装)"
echo -e " Rust $(rustc --version 2>/dev/null || echo 未安装)"
echo -e " rtk $(rtk --version 2>/dev/null || echo 未安装)"
echo -e " MCP Server $SERVER_ENTRY"
if [ -n "${http_proxy:-}" ]; then
echo -e " Proxy $http_proxy"
fi
echo ""
echo -e " ${YELLOW}⚠ 后续步骤(手动):${NC}"
echo -e " 1. Unity Package Manager 安装插件:"
echo -e " ${CYAN}https://github.com/AnkleBreaker-Studio/unity-mcp-plugin.git${NC}"
echo -e " 2. 确认 Unity Bridge 在线: http://127.0.0.1:${BRIDGE_PORT}/api/ping"
echo -e " 3. 重启 AI 客户端Claude Desktop / Cursor / Windsurf"
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
echo ""
log "请重新加载 shell: source ~/.bashrc"