refactor: 拆分 claude-dev-stack 为 windows-dev-stack 和 wsl-dev-stack

将原 claude-dev-stack 目录拆分为独立的 Windows 和 WSL 部署栈,便于分别维护和使用。

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-05-29 01:11:20 +08:00
parent e8693dad2a
commit dd3eb24d0f
488 changed files with 33927 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
# =============================================================
# Windows Dev Stack 配置文件
# 复制为 .env 并按需填写
# =============================================================
# ── Claude / API 配置 ────────────────────────────────────────
# 推荐:灵眸 AI国内直连无需代理https://docs.lmuai.com/docs/tools/claude-code
ANTHROPIC_AUTH_TOKEN=sk-你的灵眸API密钥
ANTHROPIC_BASE_URL=https://api.lmuai.com
# 备选Anthropic 官方 API Key海外直连
# ANTHROPIC_API_KEY=
# ANTHROPIC_BASE_URL=https://api.anthropic.com
# 备选DeepSeek 兼容接口
# ANTHROPIC_API_KEY=
# ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
# 默认使用的模型
# 灵眸可选claude-opus-4-7 | claude-sonnet-4-6 | claude-sonnet-4-5 | claude-haiku-4-5
CLAUDE_MODEL=claude-sonnet-4-6
# ── Godot MCP Pro ─────────────────────────────────────────────
# 本地包相对路径(相对于本脚本目录),默认引用 claude-dev-stack 中的包
# 通常无需修改
GODOT_MCP_VERSION=godot-mcp-pro-v1.14.1
GODOT_MCP_PACKAGE_DIR=.
# ── Unity MCP ─────────────────────────────────────────────────
# unity-mcp-server 安装目录Windows 侧)
# UNITY_MCP_INSTALL_DIR=%USERPROFILE%\unity-mcp-server
# Unity Hub 路径(写入 MCP 配置 env 供 unity-mcp 使用)
# UNITY_HUB_PATH=C:\Program Files\Unity Hub\Unity Hub.exe
# Unity MCP Bridge 端口
BRIDGE_PORT=7890
# ── Rust / Token Killer ──────────────────────────────────────
# 国内加速镜像(安装 Rust 缓慢时启用)
# RUSTUP_DIST_SERVER=https://rsproxy.cn
# RUSTUP_UPDATE_ROOT=https://rsproxy.cn/rustup

155
windows-dev-stack/README.md Normal file
View File

@@ -0,0 +1,155 @@
# Windows Dev Stack
**Windows 原生** Claude Code CLI + GitHub Copilot CLI + MCP + Rust Token Killer 一键部署方案。
不依赖 WSL2所有组件直接运行在 Windows 本机。
## 组件清单
| 组件 | 说明 | 安装位置 |
|------|------|---------|
| **Node.js LTS** | JS 运行时 | winget → 系统 |
| **Claude Code CLI** | `@anthropic-ai/claude-code` | npm global |
| **GitHub CLI + Copilot CLI** | `gh` + `github/gh-copilot` 扩展 | winget + gh extension |
| **Unity MCP Server** | AnkleBreaker-Studio — Claude ↔ Unity Editor | `%USERPROFILE%\unity-mcp-server\` |
| **Godot MCP Pro** | 本地包 v1.14.1 — Claude ↔ Godot Editor | `%USERPROFILE%\godot-mcp-pro\` |
| **Rust** | rustup stable 工具链 | winget → `%USERPROFILE%\.cargo\` |
| **RTK** | Rust Token Killer — LLM token 优化 | cargo install → `%USERPROFILE%\.cargo\bin\` |
## 目录结构
```
windows-dev-stack/
├── deploy.ps1 # Windows 一键部署PowerShell 5.1+
├── .env.example # 配置模板
└── README.md
```
> Godot MCP Pro 本地包位于 `../claude-dev-stack/godot-mcp-pro-v1.14.1/`
> 两个 stack 共用同一份本地包,无需重复存储。
---
## 快速开始
```powershell
# 1. 复制并填写配置
cd path\to\windows-dev-stack
cp .env.example .env
notepad .env
# 2. 运行部署(普通用户即可;防火墙步骤会弹 UAC 提权)
pwsh .\deploy.ps1
# 3. GitHub CLI 登录(首次使用前)
gh auth login
```
---
## 配置说明(`.env`
### 推荐:灵眸 AI国内直连无需代理
| 变量 | 说明 |
|------|------|
| `ANTHROPIC_AUTH_TOKEN` | 灵眸 API Key从 [lmuai.com](https://lmuai.com) 获取 |
| `ANTHROPIC_BASE_URL` | `https://api.lmuai.com`(默认) |
| `CLAUDE_MODEL` | `claude-sonnet-4-6`(默认) |
### 备选Anthropic 官方 API
| 变量 | 说明 |
|------|------|
| `ANTHROPIC_API_KEY` | 从 [console.anthropic.com](https://console.anthropic.com) 获取 |
| `ANTHROPIC_BASE_URL` | `https://api.anthropic.com` |
---
## 与 claude-dev-stack 的对比
| 特性 | `claude-dev-stack` | `windows-dev-stack` |
|------|--------------------|---------------------|
| 运行环境 | WSL2Linux | Windows 原生 |
| Claude Code CLI | WSL2 内 npm global | Windows npm global |
| GitHub Copilot CLI | WSL2 gh extension | Windows gh extension |
| Rust / RTK | WSL2 cargo | Windows cargo |
| MCP Servers | WSL2 node 进程 | Windows node 进程 |
| 适合场景 | Linux 工具链 / 命令行重度用户 | 纯 Windows 开发者 / 不想装 WSL2 |
两套 stack **可以共存**,各自写入独立配置,互不干扰。
---
## MCP 配置覆盖范围
`deploy.ps1` 自动写入以下客户端的 MCP 配置:
| 客户端 | 配置文件 |
|--------|---------|
| Claude Desktop | `%APPDATA%\Claude\claude_desktop_config.json` |
| Cursor | `%USERPROFILE%\.cursor\mcp.json` |
| Windsurf | `%APPDATA%\Windsurf\mcp_config.json` |
| VS Code | `%APPDATA%\Code\User\mcp.json` |
| Claude Code CLI | `claude mcp add --scope user`(写入用户级 MCP |
---
## RTK 使用
RTK 通过 Claude Code 的 PreToolUse hook 自动生效(`deploy.ps1` 运行 `rtk init -g` 注册)。
```powershell
# 查看 token 节省统计
rtk gain
rtk gain --history
# 手动使用
rtk git status
rtk cargo test
```
`.github/copilot-instructions.md` 已在仓库根目录配置GitHub Copilot (VS Code) 会自动读取并在终端命令前加 `rtk` 前缀。
---
## 故障排查
### Node.js 安装后找不到命令
```powershell
# 刷新当前会话 PATH
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" +
[System.Environment]::GetEnvironmentVariable("Path","User")
# 或直接重开 PowerShell
```
### Rust / cargo 安装后找不到命令
```powershell
# 手动加入 PATH当前会话
$env:Path = "$env:USERPROFILE\.cargo\bin;$env:Path"
# 或重开终端rustup installer 已写入用户 PATH
```
### rtk 安装失败(需要 Build Tools
```powershell
# 安装 Visual C++ Build ToolsRust Windows 编译器后端依赖)
winget install Microsoft.VisualStudio.2022.BuildTools
# 安装后重开终端,再运行:
cargo install --git https://github.com/rtk-ai/rtk
```
### gh copilot 找不到扩展
```powershell
# 确认已登录
gh auth status
# 重新安装扩展
gh extension install github/gh-copilot
```
### Unity MCP Bridge 连接失败
```powershell
# 检查 Bridge 端口
Invoke-WebRequest http://127.0.0.1:7890/api/ping
# 确认防火墙已放行
Get-NetFirewallRule -DisplayName "Unity MCP Bridge*" | Select-Object DisplayName, Enabled
```

View File

@@ -0,0 +1,741 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Windows 原生 Claude Code CLI + GitHub Copilot CLI + MCP + Rust Token Killer 一键部署脚本
.DESCRIPTION
不依赖 WSL2全部组件原生运行在 Windows 上。完成以下步骤:
1. Node.js LTS 检测 / 安装winget
2. Claude Code CLI (@anthropic-ai/claude-code) 安装
3. GitHub CLI + Copilot CLI 扩展安装winget + gh extension
4. Unity MCP Server 安装 & 写入各 AI 客户端 MCP 配置
5. Godot MCP Pro 安装(本地包)& 写入各 AI 客户端 MCP 配置
6. Rust 工具链 + RTK (Rust Token Killer) 安装
7. RTK hook 注册到 Claude Code + Copilot Instructions 生成
8. PowerShell Profile 快捷命令写入
.PARAMETER BridgePort
Unity MCP Bridge 端口,默认 7890
.PARAMETER SkipFirewall
跳过防火墙规则配置
.NOTES
防火墙规则需要管理员权限,其余步骤普通用户即可运行。
脚本可重复运行(幂等),已安装的组件自动跳过。
#>
param(
[int] $BridgePort = 7890,
[string]$GodotMcpVersion = "godot-mcp-pro-v1.14.1",
[switch]$SkipFirewall
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# ──────────────────────────────────────────────────────────────
# 颜色日志辅助
# ──────────────────────────────────────────────────────────────
function Write-Step { param($msg) Write-Host "`n==== $msg ====" -ForegroundColor Cyan }
function Write-OK { param($msg) Write-Host " [OK] $msg" -ForegroundColor Green }
function Write-Info { param($msg) Write-Host " [..] $msg" -ForegroundColor DarkGray }
function Write-Warn { param($msg) Write-Host " [!!] $msg" -ForegroundColor Yellow }
function Write-Fail { param($msg) Write-Host " [ERR] $msg" -ForegroundColor Red }
# ──────────────────────────────────────────────────────────────
# 加载 .env 配置
# ──────────────────────────────────────────────────────────────
$ScriptDir = $PSScriptRoot
$EnvFile = Join-Path $ScriptDir ".env"
$EnvExample = Join-Path $ScriptDir ".env.example"
if (-not (Test-Path $EnvFile)) {
if (Test-Path $EnvExample) {
Copy-Item $EnvExample $EnvFile
Write-Warn "已从 .env.example 创建 .env请按需填写后重新运行"
Write-Warn " notepad `"$EnvFile`""
exit 0
}
}
$Cfg = @{}
if (Test-Path $EnvFile) {
Get-Content $EnvFile | Where-Object { $_ -match "^\s*[^#].*=" } | ForEach-Object {
$parts = $_ -split "=", 2
$key = $parts[0].Trim()
$val = $parts[1].Trim().Trim('"').Trim("'")
$Cfg[$key] = $val
}
Write-Info "已加载配置:$EnvFile"
}
$ANTHROPIC_API_KEY = $Cfg["ANTHROPIC_API_KEY"] ?? ""
$ANTHROPIC_AUTH_TOKEN = $Cfg["ANTHROPIC_AUTH_TOKEN"] ?? ""
$ANTHROPIC_BASE_URL = $Cfg["ANTHROPIC_BASE_URL"] ?? "https://api.lmuai.com"
$CLAUDE_MODEL = $Cfg["CLAUDE_MODEL"] ?? "claude-sonnet-4-6"
$BRIDGE_PORT_CFG = $Cfg["BRIDGE_PORT"] ?? "$BridgePort"
$UnityHubPath = $Cfg["UNITY_HUB_PATH"] ?? "C:\Program Files\Unity Hub\Unity Hub.exe"
$UnityMcpInstallDir = $Cfg["UNITY_MCP_INSTALL_DIR"] ?? "$env:USERPROFILE\unity-mcp-server"
$GodotMcpPackageDir = $Cfg["GODOT_MCP_PACKAGE_DIR"] ?? "."
# 参数 BridgePort 优先于 .env
if ($BridgePort -eq 7890 -and $BRIDGE_PORT_CFG -ne "7890") { $BridgePort = [int]$BRIDGE_PORT_CFG }
# 判断认证方式
$UseLmuAuth = ($ANTHROPIC_AUTH_TOKEN -ne "" -and $ANTHROPIC_BASE_URL -ne "https://api.anthropic.com")
# ──────────────────────────────────────────────────────────────
# Banner
# ──────────────────────────────────────────────────────────────
Write-Host ""
Write-Host "╔══════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
Write-Host "║ Windows Native: Claude Code + Copilot CLI + MCP + RTK ║" -ForegroundColor Cyan
Write-Host "║ Unity MCP · Godot MCP Pro · Rust Token Killer ║" -ForegroundColor Cyan
Write-Host "╚══════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
Write-Host ""
# ──────────────────────────────────────────────────────────────
# 辅助:刷新当前进程 PATH
# ──────────────────────────────────────────────────────────────
function Refresh-Path {
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" +
[System.Environment]::GetEnvironmentVariable("Path", "User")
}
# ──────────────────────────────────────────────────────────────
# 辅助winget 安装(静默)
# ──────────────────────────────────────────────────────────────
function Install-Winget {
param([string]$Id, [string]$DisplayName)
$wg = Get-Command winget -ErrorAction SilentlyContinue
if (-not $wg) {
Write-Warn "未找到 winget请手动安装 $DisplayName"
return $false
}
Write-Info "winget install $Id ..."
winget install --id $Id --silent --accept-source-agreements --accept-package-agreements 2>&1 | Out-Null
Refresh-Path
return $true
}
# ──────────────────────────────────────────────────────────────
# 辅助:写入 / 合并 MCP 配置文件JSON
# ──────────────────────────────────────────────────────────────
function Merge-McpConfig {
param(
[string] $ConfigFile,
[hashtable] $Entry,
[string] $Label,
[string] $ServerName = "unity-mcp"
)
$dir = Split-Path $ConfigFile
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
function ConvertTo-Hashtable($obj) {
if ($obj -is [System.Management.Automation.PSCustomObject]) {
$h = @{}
foreach ($p in $obj.PSObject.Properties) { $h[$p.Name] = ConvertTo-Hashtable $p.Value }
return $h
} elseif ($obj -is [System.Collections.IEnumerable] -and $obj -isnot [string]) {
return @($obj | ForEach-Object { ConvertTo-Hashtable $_ })
}
return $obj
}
$cfg = @{ mcpServers = @{} }
if (Test-Path $ConfigFile) {
try {
$raw = Get-Content $ConfigFile -Raw | ConvertFrom-Json
$converted = ConvertTo-Hashtable $raw
if ($converted -is [hashtable]) { $cfg = $converted }
} catch {}
}
if (-not $cfg.ContainsKey("mcpServers")) { $cfg["mcpServers"] = @{} }
$cfg["mcpServers"][$ServerName] = $Entry
$cfg | ConvertTo-Json -Depth 10 | Set-Content $ConfigFile -Encoding UTF8
Write-OK "$Label -> $ConfigFile"
}
# ══════════════════════════════════════════════════════════════
# Step 1: Node.js LTS
# ══════════════════════════════════════════════════════════════
Write-Step "1/8 Node.js LTS"
$nodeCmd = Get-Command node -ErrorAction SilentlyContinue
if ($nodeCmd) {
Write-OK "Node.js 已安装: $(& node --version)"
} else {
Write-Info "通过 winget 安装 Node.js LTS..."
$ok = Install-Winget "OpenJS.NodeJS.LTS" "Node.js LTS"
$nodeCmd = Get-Command node -ErrorAction SilentlyContinue
if ($nodeCmd) {
Write-OK "Node.js 安装完成: $(& node --version)"
} else {
Write-Warn "未能自动安装 Node.js请手动安装后重新运行"
Write-Warn " https://nodejs.org/zh-cn/download 或 winget install OpenJS.NodeJS.LTS"
}
}
# ══════════════════════════════════════════════════════════════
# Step 2: Claude Code CLI
# ══════════════════════════════════════════════════════════════
Write-Step "2/8 Claude Code CLI"
$claudeCmd = Get-Command claude -ErrorAction SilentlyContinue
if ($claudeCmd) {
Write-OK "Claude Code 已安装: $(& claude --version 2>&1 | Select-Object -First 1)"
} else {
if (Get-Command node -ErrorAction SilentlyContinue) {
Write-Info "安装 @anthropic-ai/claude-code ..."
& npm install -g @anthropic-ai/claude-code --quiet 2>&1 | Out-Null
Refresh-Path
$claudeCmd = Get-Command claude -ErrorAction SilentlyContinue
if ($claudeCmd) {
Write-OK "Claude Code 安装完成: $(& claude --version 2>&1 | Select-Object -First 1)"
} else {
Write-Warn "安装后未找到 claude 命令,请重开终端后重试"
}
} else {
Write-Warn "Node.js 未就绪,跳过 Claude Code 安装"
}
}
# ── 写入 Claude Code 配置settings.json──────────────────
$mcpAllowedTools = @(
"Bash","Read","Write","Edit","MultiEdit","Glob","Grep","LS","WebFetch","TodoRead","TodoWrite",
# Unity MCP
"mcp__unity-mcp__unity_editor_ping","mcp__unity-mcp__unity_editor_state","mcp__unity-mcp__unity_project_info",
"mcp__unity-mcp__unity_scene_info","mcp__unity-mcp__unity_scene_open","mcp__unity-mcp__unity_scene_save",
"mcp__unity-mcp__unity_scene_new","mcp__unity-mcp__unity_scene_hierarchy","mcp__unity-mcp__unity_scene_stats",
"mcp__unity-mcp__unity_gameobject_create","mcp__unity-mcp__unity_gameobject_delete",
"mcp__unity-mcp__unity_gameobject_info","mcp__unity-mcp__unity_gameobject_set_transform",
"mcp__unity-mcp__unity_gameobject_duplicate","mcp__unity-mcp__unity_gameobject_set_active",
"mcp__unity-mcp__unity_gameobject_reparent",
"mcp__unity-mcp__unity_component_add","mcp__unity-mcp__unity_component_remove",
"mcp__unity-mcp__unity_component_get_properties","mcp__unity-mcp__unity_component_set_property",
"mcp__unity-mcp__unity_component_set_reference","mcp__unity-mcp__unity_component_batch_wire",
"mcp__unity-mcp__unity_component_get_referenceable",
"mcp__unity-mcp__unity_asset_list","mcp__unity-mcp__unity_asset_import",
"mcp__unity-mcp__unity_asset_delete","mcp__unity-mcp__unity_asset_create_prefab",
"mcp__unity-mcp__unity_asset_instantiate_prefab",
"mcp__unity-mcp__unity_script_create","mcp__unity-mcp__unity_script_read",
"mcp__unity-mcp__unity_script_update","mcp__unity-mcp__unity_execute_code",
"mcp__unity-mcp__unity_material_create","mcp__unity-mcp__unity_renderer_set_material",
"mcp__unity-mcp__unity_build","mcp__unity-mcp__unity_play_mode",
"mcp__unity-mcp__unity_console_log","mcp__unity-mcp__unity_console_clear",
"mcp__unity-mcp__unity_get_compilation_errors",
"mcp__unity-mcp__unity_execute_menu_item","mcp__unity-mcp__unity_undo",
"mcp__unity-mcp__unity_redo","mcp__unity-mcp__unity_undo_history",
"mcp__unity-mcp__unity_selection_get","mcp__unity-mcp__unity_selection_set",
"mcp__unity-mcp__unity_selection_focus_scene_view","mcp__unity-mcp__unity_selection_find_by_type",
"mcp__unity-mcp__unity_search_by_component","mcp__unity-mcp__unity_search_by_tag",
"mcp__unity-mcp__unity_search_by_layer","mcp__unity-mcp__unity_search_by_name",
"mcp__unity-mcp__unity_search_assets","mcp__unity-mcp__unity_search_missing_references",
"mcp__unity-mcp__unity_screenshot_game","mcp__unity-mcp__unity_screenshot_scene",
"mcp__unity-mcp__unity_graphics_scene_capture","mcp__unity-mcp__unity_graphics_game_capture",
"mcp__unity-mcp__unity_prefab_info","mcp__unity-mcp__unity_set_object_reference",
"mcp__unity-mcp__unity_packages_list","mcp__unity-mcp__unity_packages_add",
"mcp__unity-mcp__unity_packages_remove","mcp__unity-mcp__unity_packages_search",
"mcp__unity-mcp__unity_packages_info",
"mcp__unity-mcp__unity_queue_info","mcp__unity-mcp__unity_agents_list","mcp__unity-mcp__unity_agent_log",
"mcp__unity-mcp__unity_list_advanced_tools","mcp__unity-mcp__unity_advanced_tool",
"mcp__unity-mcp__unity_hub_list_editors","mcp__unity-mcp__unity_hub_available_releases",
"mcp__unity-mcp__unity_hub_install_editor","mcp__unity-mcp__unity_hub_install_modules",
"mcp__unity-mcp__unity_hub_get_install_path","mcp__unity-mcp__unity_hub_set_install_path",
"mcp__unity-mcp__unity_list_instances","mcp__unity-mcp__unity_select_instance",
"mcp__unity-mcp__unity_get_project_context",
# Godot MCP Pro
"mcp__godot-mcp-pro__get_project_info","mcp__godot-mcp-pro__get_filesystem_tree",
"mcp__godot-mcp-pro__search_files","mcp__godot-mcp-pro__search_in_files",
"mcp__godot-mcp-pro__get_project_settings","mcp__godot-mcp-pro__get_project_statistics",
"mcp__godot-mcp-pro__uid_to_project_path","mcp__godot-mcp-pro__project_path_to_uid",
"mcp__godot-mcp-pro__get_scene_tree","mcp__godot-mcp-pro__get_scene_file_content",
"mcp__godot-mcp-pro__get_scene_exports","mcp__godot-mcp-pro__get_scene_dependencies",
"mcp__godot-mcp-pro__create_scene","mcp__godot-mcp-pro__open_scene",
"mcp__godot-mcp-pro__save_scene","mcp__godot-mcp-pro__add_scene_instance",
"mcp__godot-mcp-pro__get_node_properties","mcp__godot-mcp-pro__get_node_groups",
"mcp__godot-mcp-pro__get_signals","mcp__godot-mcp-pro__find_nodes_in_group",
"mcp__godot-mcp-pro__find_nodes_by_type","mcp__godot-mcp-pro__find_signal_connections",
"mcp__godot-mcp-pro__find_node_references",
"mcp__godot-mcp-pro__add_node","mcp__godot-mcp-pro__duplicate_node",
"mcp__godot-mcp-pro__move_node","mcp__godot-mcp-pro__rename_node",
"mcp__godot-mcp-pro__update_property","mcp__godot-mcp-pro__add_resource",
"mcp__godot-mcp-pro__set_anchor_preset",
"mcp__godot-mcp-pro__connect_signal","mcp__godot-mcp-pro__disconnect_signal",
"mcp__godot-mcp-pro__set_node_groups",
"mcp__godot-mcp-pro__batch_set_property","mcp__godot-mcp-pro__cross_scene_set_property",
"mcp__godot-mcp-pro__list_scripts","mcp__godot-mcp-pro__read_script",
"mcp__godot-mcp-pro__get_open_scripts","mcp__godot-mcp-pro__validate_script",
"mcp__godot-mcp-pro__create_script","mcp__godot-mcp-pro__edit_script",
"mcp__godot-mcp-pro__attach_script",
"mcp__godot-mcp-pro__get_editor_errors","mcp__godot-mcp-pro__get_output_log",
"mcp__godot-mcp-pro__get_editor_screenshot","mcp__godot-mcp-pro__get_editor_performance",
"mcp__godot-mcp-pro__clear_output","mcp__godot-mcp-pro__reload_plugin",
"mcp__godot-mcp-pro__reload_project",
"mcp__godot-mcp-pro__read_resource","mcp__godot-mcp-pro__get_resource_preview",
"mcp__godot-mcp-pro__create_resource","mcp__godot-mcp-pro__edit_resource",
"mcp__godot-mcp-pro__read_shader","mcp__godot-mcp-pro__get_shader_params",
"mcp__godot-mcp-pro__create_shader","mcp__godot-mcp-pro__edit_shader",
"mcp__godot-mcp-pro__assign_shader_material","mcp__godot-mcp-pro__set_shader_param",
"mcp__godot-mcp-pro__list_animations","mcp__godot-mcp-pro__get_animation_info",
"mcp__godot-mcp-pro__create_animation","mcp__godot-mcp-pro__add_animation_track",
"mcp__godot-mcp-pro__set_animation_keyframe",
"mcp__godot-mcp-pro__get_animation_tree_structure",
"mcp__godot-mcp-pro__create_animation_tree","mcp__godot-mcp-pro__add_state_machine_state",
"mcp__godot-mcp-pro__add_state_machine_transition",
"mcp__godot-mcp-pro__set_blend_tree_node","mcp__godot-mcp-pro__set_tree_parameter",
"mcp__godot-mcp-pro__get_audio_bus_layout","mcp__godot-mcp-pro__get_audio_info",
"mcp__godot-mcp-pro__add_audio_bus","mcp__godot-mcp-pro__set_audio_bus",
"mcp__godot-mcp-pro__add_audio_bus_effect","mcp__godot-mcp-pro__add_audio_player",
"mcp__godot-mcp-pro__get_input_actions","mcp__godot-mcp-pro__set_input_action",
"mcp__godot-mcp-pro__get_physics_layers","mcp__godot-mcp-pro__get_collision_info",
"mcp__godot-mcp-pro__set_physics_layers",
"mcp__godot-mcp-pro__add_mesh_instance","mcp__godot-mcp-pro__setup_lighting",
"mcp__godot-mcp-pro__set_material_3d","mcp__godot-mcp-pro__setup_environment",
"mcp__godot-mcp-pro__setup_camera_3d","mcp__godot-mcp-pro__add_gridmap",
"mcp__godot-mcp-pro__setup_collision","mcp__godot-mcp-pro__add_raycast",
"mcp__godot-mcp-pro__setup_physics_body",
"mcp__godot-mcp-pro__get_navigation_info",
"mcp__godot-mcp-pro__setup_navigation_region","mcp__godot-mcp-pro__bake_navigation_mesh",
"mcp__godot-mcp-pro__setup_navigation_agent","mcp__godot-mcp-pro__set_navigation_layers",
"mcp__godot-mcp-pro__get_particle_info",
"mcp__godot-mcp-pro__create_particles","mcp__godot-mcp-pro__set_particle_material",
"mcp__godot-mcp-pro__set_particle_color_gradient","mcp__godot-mcp-pro__apply_particle_preset",
"mcp__godot-mcp-pro__get_theme_info",
"mcp__godot-mcp-pro__create_theme","mcp__godot-mcp-pro__set_theme_color",
"mcp__godot-mcp-pro__set_theme_constant","mcp__godot-mcp-pro__set_theme_font_size",
"mcp__godot-mcp-pro__set_theme_stylebox",
"mcp__godot-mcp-pro__tilemap_get_cell","mcp__godot-mcp-pro__tilemap_get_info",
"mcp__godot-mcp-pro__tilemap_get_used_cells",
"mcp__godot-mcp-pro__tilemap_set_cell","mcp__godot-mcp-pro__tilemap_fill_rect",
"mcp__godot-mcp-pro__get_autoload","mcp__godot-mcp-pro__add_autoload",
"mcp__godot-mcp-pro__set_project_setting",
"mcp__godot-mcp-pro__find_unused_resources","mcp__godot-mcp-pro__analyze_signal_flow",
"mcp__godot-mcp-pro__analyze_scene_complexity","mcp__godot-mcp-pro__find_script_references",
"mcp__godot-mcp-pro__detect_circular_dependencies",
"mcp__godot-mcp-pro__get_performance_monitors",
"mcp__godot-mcp-pro__get_export_info","mcp__godot-mcp-pro__list_export_presets",
"mcp__godot-mcp-pro__play_scene","mcp__godot-mcp-pro__stop_scene",
"mcp__godot-mcp-pro__get_game_scene_tree","mcp__godot-mcp-pro__get_game_node_properties",
"mcp__godot-mcp-pro__get_game_screenshot","mcp__godot-mcp-pro__set_game_node_property",
"mcp__godot-mcp-pro__find_nodes_by_script",
"mcp__godot-mcp-pro__simulate_key","mcp__godot-mcp-pro__simulate_mouse_click",
"mcp__godot-mcp-pro__simulate_mouse_move","mcp__godot-mcp-pro__simulate_action",
"mcp__godot-mcp-pro__simulate_sequence",
"mcp__godot-mcp-pro__capture_frames","mcp__godot-mcp-pro__record_frames",
"mcp__godot-mcp-pro__monitor_properties","mcp__godot-mcp-pro__batch_get_properties",
"mcp__godot-mcp-pro__start_recording","mcp__godot-mcp-pro__stop_recording",
"mcp__godot-mcp-pro__replay_recording",
"mcp__godot-mcp-pro__find_ui_elements","mcp__godot-mcp-pro__click_button_by_text",
"mcp__godot-mcp-pro__wait_for_node","mcp__godot-mcp-pro__find_nearby_nodes",
"mcp__godot-mcp-pro__navigate_to","mcp__godot-mcp-pro__move_to",
"mcp__godot-mcp-pro__run_test_scenario","mcp__godot-mcp-pro__assert_node_state",
"mcp__godot-mcp-pro__assert_screen_text","mcp__godot-mcp-pro__run_stress_test",
"mcp__godot-mcp-pro__get_test_report","mcp__godot-mcp-pro__compare_screenshots"
)
$claudeSettingsJson = if ($UseLmuAuth) {
[ordered]@{
env = [ordered]@{
ANTHROPIC_BASE_URL = $ANTHROPIC_BASE_URL
ANTHROPIC_AUTH_TOKEN = $ANTHROPIC_AUTH_TOKEN
API_TIMEOUT_MS = "3000000"
CLAUDE_CODE_ATTRIBUTION_HEADER = "0"
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1"
}
model = $CLAUDE_MODEL
allowedTools = $mcpAllowedTools
} | ConvertTo-Json -Depth 4
} else {
[ordered]@{ model = $CLAUDE_MODEL; allowedTools = $mcpAllowedTools } | ConvertTo-Json -Depth 3
}
$claudeDir = "$env:USERPROFILE\.claude"
if (-not (Test-Path $claudeDir)) { New-Item -ItemType Directory -Path $claudeDir | Out-Null }
$claudeSettingsJson | Set-Content "$claudeDir\settings.json" -Encoding UTF8
if ($UseLmuAuth) {
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $null, "User")
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", $null, "User")
[System.Environment]::SetEnvironmentVariable("CLAUDE_MODEL", $null, "User")
} elseif ($ANTHROPIC_API_KEY) {
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $ANTHROPIC_API_KEY, "User")
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", $ANTHROPIC_BASE_URL, "User")
[System.Environment]::SetEnvironmentVariable("CLAUDE_MODEL", $CLAUDE_MODEL, "User")
}
Write-OK "Claude Code 配置已写入 $claudeDir\settings.json"
# ══════════════════════════════════════════════════════════════
# Step 3: GitHub CLI + Copilot CLI 扩展
# ══════════════════════════════════════════════════════════════
Write-Step "3/8 GitHub CLI + Copilot CLI"
$ghCmd = Get-Command gh -ErrorAction SilentlyContinue
if ($ghCmd) {
Write-OK "GitHub CLI 已安装: $(& gh --version 2>&1 | Select-Object -First 1)"
} else {
Write-Info "通过 winget 安装 GitHub CLI..."
$ok = Install-Winget "GitHub.cli" "GitHub CLI"
$ghCmd = Get-Command gh -ErrorAction SilentlyContinue
if ($ghCmd) {
Write-OK "GitHub CLI 安装完成: $(& gh --version 2>&1 | Select-Object -First 1)"
} else {
Write-Warn "GitHub CLI 安装后未找到请重开终端或手动安装winget install GitHub.cli"
}
}
if ($ghCmd) {
$extList = & gh extension list 2>&1 | Out-String
if ($extList -match "github/gh-copilot") {
Write-OK "GitHub Copilot CLI 扩展已安装"
} else {
Write-Info "安装 GitHub Copilot CLI 扩展..."
try {
& gh extension install github/gh-copilot 2>&1 | Out-Null
Write-OK "GitHub Copilot CLI 扩展安装完成入口gh copilot"
} catch {
Write-Warn "安装失败(可能需要先 gh auth login请手动运行gh extension install github/gh-copilot"
}
}
}
# ══════════════════════════════════════════════════════════════
# Step 4: Unity MCP Server
# ══════════════════════════════════════════════════════════════
Write-Step "4/8 Unity MCP Server"
Write-Info "安装目录: $UnityMcpInstallDir"
$gitCmd = Get-Command git -ErrorAction SilentlyContinue
if (-not $gitCmd) {
Write-Warn "未找到 git跳过 Unity MCP Server 安装"
Write-Warn "请安装 Git for Windowswinget install Git.Git"
$UnityMcpReady = $false
} else {
if (Test-Path "$UnityMcpInstallDir\.git") {
Write-Info "已存在,更新至最新..."
Push-Location $UnityMcpInstallDir
try { & git pull --quiet 2>&1 | Out-Null } finally { Pop-Location }
} else {
if (Test-Path $UnityMcpInstallDir) { Remove-Item $UnityMcpInstallDir -Recurse -Force }
& git clone --quiet --depth 1 https://github.com/AnkleBreaker-Studio/unity-mcp-server.git $UnityMcpInstallDir
}
if (Get-Command node -ErrorAction SilentlyContinue) {
Push-Location $UnityMcpInstallDir
try { & npm install --prefer-offline --quiet 2>&1 | Out-Null } finally { Pop-Location }
Write-OK "Unity MCP Server 就绪"
$UnityMcpReady = $true
} else {
Write-Warn "Node.js 未就绪,跳过 npm install"
$UnityMcpReady = $false
}
}
# ── 确定入口文件 ──────────────────────────────────────────────
$unityEntry = ""
if ($UnityMcpReady) {
foreach ($f in @("src/index.js","build/index.js","index.js")) {
$fp = Join-Path $UnityMcpInstallDir $f
if (Test-Path $fp) { $unityEntry = $fp -replace "\\","/"; break }
}
}
# ── 写入 MCP 配置(四大 AI 客户端 + Claude Code CLI─────────
if ($unityEntry) {
$unityMcpEntry = @{
command = "node"
args = @($unityEntry)
env = @{ UNITY_HUB_PATH = $UnityHubPath; UNITY_BRIDGE_PORT = "$BridgePort" }
}
Merge-McpConfig "$env:APPDATA\Claude\claude_desktop_config.json" $unityMcpEntry "Claude Desktop"
Merge-McpConfig "$env:USERPROFILE\.cursor\mcp.json" $unityMcpEntry "Cursor"
$wsDirC = if (Test-Path "$env:APPDATA\Windsurf") { "$env:APPDATA\Windsurf" } else { "$env:USERPROFILE\.codeium\windsurf" }
Merge-McpConfig "$wsDirC\mcp_config.json" $unityMcpEntry "Windsurf"
Merge-McpConfig "$env:APPDATA\Code\User\mcp.json" $unityMcpEntry "VS Code"
# Claude Code CLIWindows
if (Get-Command claude -ErrorAction SilentlyContinue) {
& claude mcp remove unity-mcp --scope user 2>&1 | Out-Null
& claude mcp add --scope user unity-mcp node $unityEntry -e "UNITY_BRIDGE_PORT=$BridgePort" 2>&1 | Out-Null
Write-OK "Claude Code CLI MCP -> unity-mcp"
}
}
# ══════════════════════════════════════════════════════════════
# Step 5: Godot MCP Pro
# ══════════════════════════════════════════════════════════════
Write-Step "5/8 Godot MCP Pro"
# 解析 Godot MCP Pro 本地包路径(相对于本脚本目录)
$godotPkgBase = if ([System.IO.Path]::IsPathRooted($GodotMcpPackageDir)) {
$GodotMcpPackageDir
} else {
[System.IO.Path]::GetFullPath((Join-Path $ScriptDir $GodotMcpPackageDir))
}
$godotSrcDir = Join-Path $godotPkgBase "$GodotMcpVersion\server"
$godotWinDir = "$env:USERPROFILE\godot-mcp-pro"
if (-not (Test-Path $godotSrcDir)) {
Write-Warn "未找到 Godot MCP Pro 源目录: $godotSrcDir"
Write-Warn "请确认 .env 中 GODOT_MCP_PACKAGE_DIR 指向包含 $GodotMcpVersion\ 的目录"
$godotEntry = ""
} else {
Write-Info "同步 server/ -> $godotWinDir"
$rcArgs = @($godotSrcDir, $godotWinDir, "/E", "/XD", "node_modules",
"/NFL", "/NDL", "/NJH", "/NJS", "/nc", "/ns", "/np")
& robocopy @rcArgs 2>&1 | Out-Null
if (Get-Command node -ErrorAction SilentlyContinue) {
Push-Location $godotWinDir
try { & node build/setup.js install 2>&1 | Out-Null } finally { Pop-Location }
Write-OK "Godot MCP Pro 就绪: $godotWinDir"
} else {
Write-Warn "Node.js 未就绪,跳过 Godot MCP Pro setup"
}
$godotEntry = ($godotWinDir -replace "\\","/") + "/build/index.js"
$godotMcpEntry = @{ command = "node"; args = @($godotEntry) }
Merge-McpConfig "$env:APPDATA\Claude\claude_desktop_config.json" $godotMcpEntry "Claude Desktop (Godot)" "godot-mcp-pro"
Merge-McpConfig "$env:USERPROFILE\.cursor\mcp.json" $godotMcpEntry "Cursor (Godot)" "godot-mcp-pro"
$wsDirG = if (Test-Path "$env:APPDATA\Windsurf") { "$env:APPDATA\Windsurf" } else { "$env:USERPROFILE\.codeium\windsurf" }
Merge-McpConfig "$wsDirG\mcp_config.json" $godotMcpEntry "Windsurf (Godot)" "godot-mcp-pro"
Merge-McpConfig "$env:APPDATA\Code\User\mcp.json" $godotMcpEntry "VS Code (Godot)" "godot-mcp-pro"
if (Get-Command claude -ErrorAction SilentlyContinue) {
& claude mcp remove godot-mcp-pro --scope user 2>&1 | Out-Null
& claude mcp add --scope user godot-mcp-pro node $godotEntry 2>&1 | Out-Null
Write-OK "Claude Code CLI MCP -> godot-mcp-pro"
}
}
# ══════════════════════════════════════════════════════════════
# Step 6: 防火墙放行 MCP Bridge 端口
# ══════════════════════════════════════════════════════════════
Write-Step "6/8 Windows 防火墙规则"
if ($SkipFirewall) {
Write-Warn "已跳过防火墙配置(-SkipFirewall"
} else {
$portRange = "$BridgePort-$($BridgePort + 9)"
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if ($isAdmin) {
foreach ($dir in @("Inbound","Outbound")) {
$name = "Unity MCP Bridge $dir"
Get-NetFirewallRule -DisplayName $name -ErrorAction SilentlyContinue |
Remove-NetFirewallRule -ErrorAction SilentlyContinue
New-NetFirewallRule -DisplayName $name -Direction $dir `
-LocalPort $portRange -Protocol TCP -Action Allow -Profile Any | Out-Null
Write-OK "防火墙规则: $name (TCP $portRange)"
}
} else {
Write-Warn "非管理员权限,尝试以提升权限添加防火墙规则..."
$fwCmd = @"
`$p = '$portRange'
foreach (`$d in @('Inbound','Outbound')) {
`$n = "Unity MCP Bridge `$d"
Get-NetFirewallRule -DisplayName `$n -ErrorAction SilentlyContinue | Remove-NetFirewallRule -ErrorAction SilentlyContinue
New-NetFirewallRule -DisplayName `$n -Direction `$d -LocalPort `$p -Protocol TCP -Action Allow -Profile Any | Out-Null
Write-Host "OK: `$n"
}
Start-Sleep 1
"@
$enc = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($fwCmd))
$proc = Start-Process powershell.exe -ArgumentList "-NoProfile -EncodedCommand $enc" `
-Verb RunAs -Wait -PassThru -ErrorAction SilentlyContinue
if ($proc -and $proc.ExitCode -eq 0) {
Write-OK "防火墙规则已添加 (TCP $portRange)"
} else {
Write-Warn "防火墙配置未成功请手动以管理员运行New-NetFirewallRule ... -LocalPort $portRange"
}
}
}
# ══════════════════════════════════════════════════════════════
# Step 7: Rust 工具链 & RTK
# ══════════════════════════════════════════════════════════════
Write-Step "7/8 Rust 工具链 & Token Killer"
# 若 .env 配置了国内镜像,提前注入环境变量
$rustupMirror = $Cfg["RUSTUP_DIST_SERVER"] ?? ""
$rustupRoot = $Cfg["RUSTUP_UPDATE_ROOT"] ?? ""
if ($rustupMirror) { $env:RUSTUP_DIST_SERVER = $rustupMirror }
if ($rustupRoot) { $env:RUSTUP_UPDATE_ROOT = $rustupRoot }
# 先把 cargo\bin 加入 PATHrustup 通过 winget 安装后 PATH 需刷新)
$cargoBin = "$env:USERPROFILE\.cargo\bin"
if (Test-Path $cargoBin) { $env:Path = "$cargoBin;$env:Path" }
Refresh-Path
$cargoCmd = Get-Command cargo -ErrorAction SilentlyContinue
if ($cargoCmd) {
# 检查是否有默认 toolchain若没有则安装 stable
$rustcVer = & rustc --version 2>&1 | Out-String
if ($rustcVer -match "no default is configured" -or $rustcVer -match "error:") {
Write-Info "rustup 无默认 toolchain安装 stable..."
& rustup toolchain install stable 2>&1 | Select-Object -Last 3
& rustup default stable 2>&1 | Out-Null
Refresh-Path
if (Test-Path $cargoBin) { $env:Path = "$cargoBin;$env:Path" }
$rustcVer = & rustc --version 2>&1 | Out-String
}
Write-OK "Rust 已安装: $($rustcVer.Trim())"
} else {
# 检查 winget 是否已记录安装(避免重复安装时阻塞)
$wgList = winget list --id Rustlang.Rustup --accept-source-agreements 2>&1 | Out-String
if ($wgList -match "Rustlang.Rustup") {
Write-Info "rustup 已安装,但当前会话 PATH 未更新。已将 $cargoBin 加入 PATH"
# rustup 首次运行会初始化 stable 工具链
if (Test-Path "$cargoBin\rustup.exe") { & "$cargoBin\rustup.exe" show 2>&1 | Out-Null }
$cargoCmd = Get-Command cargo -ErrorAction SilentlyContinue
if ($cargoCmd) { Write-OK "Rust: $(& rustc --version 2>&1)" }
} else {
Write-Info "通过 winget 安装 Rust (rustup)..."
$ok = Install-Winget "Rustlang.Rustup" "Rustup"
if (Test-Path $cargoBin) { $env:Path = "$cargoBin;$env:Path" }
Refresh-Path
$cargoCmd = Get-Command cargo -ErrorAction SilentlyContinue
if ($cargoCmd) {
Write-OK "Rust 安装完成: $(& rustc --version 2>&1)"
} else {
Write-Warn "Rust 安装后未找到 cargo请关闭并重开终端后继续"
Write-Warn " 或手动安装https://rustup.rs"
}
}
}
# 先把 ~/.local/bin 加入 PATH预编译包安装目录
$localBin = "$env:USERPROFILE\.local\bin"
if (Test-Path $localBin) { $env:Path = "$localBin;$env:Path" }
$rtkCmd = Get-Command rtk -ErrorAction SilentlyContinue
if ($rtkCmd) {
Write-OK "rtk 已安装: $(& rtk --version 2>&1)"
} else {
# 从 GitHub Releases 下载预编译包(比 cargo install 快得多,且无需编译环境)
Write-Info "安装 rtk (Rust Token Killer) - 下载预编译包..."
try {
$rtkVer = "v0.42.0"
$rtkUrl = "https://github.com/rtk-ai/rtk/releases/download/$rtkVer/rtk-x86_64-pc-windows-msvc.zip"
New-Item -ItemType Directory -Force -Path $localBin | Out-Null
$rtkZip = "$env:TEMP\rtk-windows.zip"
Invoke-WebRequest -Uri $rtkUrl -OutFile $rtkZip -UseBasicParsing
Expand-Archive -Path $rtkZip -DestinationPath $localBin -Force
Remove-Item $rtkZip -ErrorAction SilentlyContinue
$env:Path = "$localBin;$env:Path"
$rtkCmd = Get-Command rtk -ErrorAction SilentlyContinue
if ($rtkCmd) {
Write-OK "rtk 安装完成: $(& rtk --version 2>&1)"
} else {
Write-Warn "rtk 安装失败可手动运行cargo install --git https://github.com/rtk-ai/rtk"
}
} catch {
Write-Warn "rtk 下载失败: $_"
Write-Warn "可手动运行cargo install --git https://github.com/rtk-ai/rtk"
}
}
# ── rtk init -g注册 Claude Code PreToolUse hook ─────────────
if (Get-Command rtk -ErrorAction SilentlyContinue) {
Write-Info "注册 rtk hook 到 Claude Code..."
# 先禁用遥测,避免交互式确认提示阻塞管道
$prevEAP = $ErrorActionPreference
$ErrorActionPreference = "Continue"
& rtk telemetry disable 2>&1 | Out-Null
try {
& rtk init -g --auto-patch 2>&1 | Out-Null
Write-OK "rtk hook 已注册(重启 Claude Code 后生效)"
} catch {
Write-Warn "rtk init 异常hook 可能已注册): $_"
} finally {
$ErrorActionPreference = $prevEAP
}
# ── rtk Copilot Instructions写入 .github/copilot-instructions.md ──
# 使用已有的(位于仓库根 .github/),仅在缺失时生成
$copilotDir = Join-Path $ScriptDir ".." ".github"
$copilotInst = Join-Path $copilotDir "copilot-instructions.md"
if (-not (Test-Path $copilotInst)) {
Write-Info "生成 .github/copilot-instructions.md ..."
if (-not (Test-Path $copilotDir)) { New-Item -ItemType Directory -Path $copilotDir | Out-Null }
& rtk init -g --copilot 2>&1 | Out-Null
Write-OK "Copilot Instructions 已生成"
} else {
Write-OK "Copilot Instructions 已存在,跳过生成"
}
}
# ══════════════════════════════════════════════════════════════
# Step 8: PowerShell Profile 快捷命令
# ══════════════════════════════════════════════════════════════
Write-Step "8/8 PowerShell Profile"
$pwshProfile = "$env:USERPROFILE\Documents\PowerShell\Microsoft.PowerShell_profile.ps1"
$profileDir = Split-Path $pwshProfile
if (-not (Test-Path $profileDir)) { New-Item -ItemType Directory -Path $profileDir | Out-Null }
$profileBlock = @"
# Windows Dev Stack (generated by windows-dev-stack\deploy.ps1)
`$env:ANTHROPIC_BASE_URL = "$ANTHROPIC_BASE_URL"
$(if ($ANTHROPIC_API_KEY) { "`$env:ANTHROPIC_API_KEY = `"$ANTHROPIC_API_KEY`"" } else { "# ANTHROPIC_API_KEY= (配置 .env 后重新运行)" })
`$env:CLAUDE_MODEL = "$CLAUDE_MODEL"
# rtk / cargo PATH PATH
`$_localBin = "`$env:USERPROFILE\.local\bin"
if ((Test-Path `$_localBin) -and `$env:Path -notlike "*.local\bin*") { `$env:Path = "`$_localBin;`$env:Path" }
`$_cargoBin = "`$env:USERPROFILE\.cargo\bin"
if ((Test-Path `$_cargoBin) -and `$env:Path -notlike "*cargo\bin*") { `$env:Path = "`$_cargoBin;`$env:Path" }
function unity-mcp-status { Invoke-RestMethod http://127.0.0.1:$BridgePort/api/ping -ErrorAction SilentlyContinue }
#
"@
$existing = if (Test-Path $pwshProfile) { Get-Content $pwshProfile -Raw } else { "" }
if ($existing -match "Windows Dev Stack") {
# 注意:直接用 -replace 会将 $_ 等解释为正则反向引用导致内容爆炸
# 使用 MatchEvaluator scriptblock 让替换字符串按字面量处理
$blockCapture = $profileBlock
$existing = [regex]::Replace($existing, '(?ms)# ── Windows Dev Stack.*?# ─+', { $blockCapture })
Set-Content $pwshProfile $existing -Encoding UTF8
} else {
Add-Content $pwshProfile $profileBlock -Encoding UTF8
}
$policy = Get-ExecutionPolicy -Scope CurrentUser
if ($policy -in @("Restricted","Undefined")) {
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force
}
Write-OK "PowerShell Profile 已配置: $pwshProfile"
# ══════════════════════════════════════════════════════════════
# 安装总结
# ══════════════════════════════════════════════════════════════
Write-Host ""
Write-Host "╔══════════════════════════════════════════════════════════════╗" -ForegroundColor Green
Write-Host "║ ✅ Windows 原生全栈部署完成 ║" -ForegroundColor Green
Write-Host "╚══════════════════════════════════════════════════════════════╝" -ForegroundColor Green
Write-Host ""
$nodeVer = if (Get-Command node -ErrorAction SilentlyContinue) { & node --version 2>&1 } else { "(未安装)" }
$claudeVer = if (Get-Command claude -ErrorAction SilentlyContinue) { & claude --version 2>&1 | Select-Object -First 1 } else { "(未安装)" }
$ghVer = if (Get-Command gh -ErrorAction SilentlyContinue) { & gh --version 2>&1 | Select-Object -First 1 } else { "(未安装)" }
$rustVer = if (Get-Command rustc -ErrorAction SilentlyContinue) { & rustc --version 2>&1 } else { "(未安装)" }
$rtkVer = if (Get-Command rtk -ErrorAction SilentlyContinue) { & rtk --version 2>&1 } else { "(未安装)" }
$items = @(
@("Node.js", $nodeVer),
@("Claude Code", $claudeVer),
@("GitHub CLI", $ghVer),
@("Rust", $rustVer),
@("rtk", $rtkVer),
@("Unity MCP", $(if ($unityEntry) { $unityEntry } else { "(未安装)" })),
@("Godot MCP Pro", $(if ($godotEntry) { $godotEntry } else { "(未安装)" })),
@("Bridge Port", "TCP $BridgePort (防火墙已放行 $BridgePort-$($BridgePort+9))")
)
foreach ($item in $items) {
$label = $item[0].PadRight(14)
Write-Host " $label $($item[1])" -ForegroundColor White
}
Write-Host ""
Write-Host " 后续手动步骤:" -ForegroundColor Yellow
Write-Host " 1. gh auth login # GitHub CLI 登录(首次)" -ForegroundColor DarkGray
Write-Host " 2. Unity Editor 安装 unity-mcp-plugin" -ForegroundColor DarkGray
Write-Host " https://github.com/AnkleBreaker-Studio/unity-mcp-plugin.git" -ForegroundColor DarkGray
Write-Host " 3. Godot 项目:复制 addons/godot_mcp/ 并在 Plugins 中启用" -ForegroundColor DarkGray
Write-Host " 源:$(Join-Path $godotPkgBase "$GodotMcpVersion\addons\godot_mcp")" -ForegroundColor DarkGray
Write-Host " 4. 重启 AI 客户端Claude Desktop / Cursor / Windsurf / VS Code" -ForegroundColor DarkGray
Write-Host ""

Some files were not shown because too many files have changed in this diff Show More