fix: v2.2.0 - 彻底修复 git pull 失败 + MCP 注入鲁棒化
4 个根因全修: 1. Phase 3 凭证缓存: clone 后 git credential approve 写入 Credential Manager 2. Phase 3 冲突清理: pull 前 reset --hard 清除运行时文件冲突 3. Phase 3 认证重试: pull 失败时弹窗重输凭证 + 缓存 4. Phase 5 fallback: inject-mcp.js 不存在时用内嵌 22 MCP 脚本 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
15449c86d8
commit
50d3ef0377
100
auto-setup.ps1
100
auto-setup.ps1
@ -16,7 +16,7 @@ param(
|
|||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
# ─── 版本号 (每次更新递增, build.ps1 自动读取) ──────
|
# ─── 版本号 (每次更新递增, build.ps1 自动读取) ──────
|
||||||
$BWVersion = "2.1.0"
|
$BWVersion = "2.2.0"
|
||||||
|
|
||||||
# ─── B4: 单实例保护 (防止双击两次导致竞态) ─────────
|
# ─── B4: 单实例保护 (防止双击两次导致竞态) ─────────
|
||||||
$mutexCreated = $false
|
$mutexCreated = $false
|
||||||
@ -881,14 +881,39 @@ Log-Phase 3 "同步 Bookworm 配置"
|
|||||||
git config --global credential.helper manager 2>$null
|
git config --global credential.helper manager 2>$null
|
||||||
|
|
||||||
# 克隆/更新 config 仓库 (.claude/) — 使用 Run-CmdWithUI 防止 UI 冻结
|
# 克隆/更新 config 仓库 (.claude/) — 使用 Run-CmdWithUI 防止 UI 冻结
|
||||||
|
# 辅助函数: clone 后缓存凭证到 Windows Credential Manager
|
||||||
|
function Cache-GitCredentials($credObj) {
|
||||||
|
if (-not $credObj) { return }
|
||||||
|
try {
|
||||||
|
$approveInput = "protocol=https`nhost=code.letcareme.com`nusername=$($credObj.User)`npassword=$($credObj.Pass)`n`n"
|
||||||
|
$approveInput | & git credential approve 2>$null
|
||||||
|
Bw-Log "OK" "Gitea 凭证已缓存到 Windows Credential Manager"
|
||||||
|
} catch { Bw-Log "WARN" "凭证缓存失败: $_" }
|
||||||
|
}
|
||||||
|
|
||||||
if (Test-Path (Join-Path $ClaudeDir ".git")) {
|
if (Test-Path (Join-Path $ClaudeDir ".git")) {
|
||||||
Log-Info "配置仓库已存在, 更新中..."
|
Log-Info "配置仓库已存在, 更新中..."
|
||||||
|
# 设置 git 身份 (auto-resolve commit 需要)
|
||||||
|
& git -C $ClaudeDir config user.email "bookworm@auto.local" 2>$null
|
||||||
|
& git -C $ClaudeDir config user.name "Bookworm" 2>$null
|
||||||
try {
|
try {
|
||||||
Run-CmdWithUI "git" @("-C", $ClaudeDir, "stash") "git stash" 15000 | Out-Null
|
# 强制清除冲突状态 (运行时文件不重要, Phase 5 会重新渲染)
|
||||||
$r = Run-CmdWithUI "git" @("-C", $ClaudeDir, "pull", "--rebase") "同步配置仓库" 120000
|
& git -C $ClaudeDir reset --hard HEAD 2>&1 | Out-Null
|
||||||
if ($r.OK) { Log-OK "配置仓库已更新" } else { Log-Warn "git pull 失败, 使用本地版本" }
|
$r = Run-CmdWithUI "git" @("-C", $ClaudeDir, "pull", "--rebase", "--autostash") "同步配置仓库" 120000
|
||||||
Run-CmdWithUI "git" @("-C", $ClaudeDir, "stash", "pop") "git stash pop" 15000 | Out-Null
|
if ($r.OK) {
|
||||||
} catch { Log-Warn "git pull 失败, 使用本地版本" }
|
Log-OK "配置仓库已更新"
|
||||||
|
} else {
|
||||||
|
# pull 失败可能是认证问题, 尝试重新输入凭证
|
||||||
|
Log-Warn "git pull 失败, 尝试重新认证..."
|
||||||
|
$cred = Show-GiteaCredentialDialog
|
||||||
|
if ($cred) {
|
||||||
|
Cache-GitCredentials $cred
|
||||||
|
$r2 = Run-CmdWithUI "git" @("-C", $ClaudeDir, "pull", "--rebase", "--autostash") "重试同步" 120000
|
||||||
|
if ($r2.OK) { Log-OK "配置仓库已更新 (重新认证成功)" }
|
||||||
|
else { Log-Warn "git pull 仍失败, 使用本地版本" }
|
||||||
|
} else { Log-Warn "用户取消认证, 使用本地版本" }
|
||||||
|
}
|
||||||
|
} catch { Log-Warn "git pull 异常: $_, 使用本地版本" }
|
||||||
}
|
}
|
||||||
elseif (Test-Path $ClaudeDir) {
|
elseif (Test-Path $ClaudeDir) {
|
||||||
Log-Info "备份现有 .claude/ 并克隆..."
|
Log-Info "备份现有 .claude/ 并克隆..."
|
||||||
@ -900,6 +925,7 @@ elseif (Test-Path $ClaudeDir) {
|
|||||||
$r = Run-CmdWithUI "git" @("clone", "--depth", "1", $cloneUrl, $ClaudeDir) "克隆配置仓库" 180000
|
$r = Run-CmdWithUI "git" @("clone", "--depth", "1", $cloneUrl, $ClaudeDir) "克隆配置仓库" 180000
|
||||||
if (Test-Path (Join-Path $ClaudeDir "CLAUDE.md")) {
|
if (Test-Path (Join-Path $ClaudeDir "CLAUDE.md")) {
|
||||||
Log-OK "配置仓库克隆成功 (旧目录已备份)"
|
Log-OK "配置仓库克隆成功 (旧目录已备份)"
|
||||||
|
Cache-GitCredentials $cred
|
||||||
} else {
|
} else {
|
||||||
Log-Fail "克隆失败"
|
Log-Fail "克隆失败"
|
||||||
if (Test-Path $BackupDir) { Rename-Item $BackupDir $ClaudeDir }
|
if (Test-Path $BackupDir) { Rename-Item $BackupDir $ClaudeDir }
|
||||||
@ -914,6 +940,7 @@ else {
|
|||||||
$r = Run-CmdWithUI "git" @("clone", "--depth", "1", $cloneUrl, $ClaudeDir) "克隆配置仓库" 180000
|
$r = Run-CmdWithUI "git" @("clone", "--depth", "1", $cloneUrl, $ClaudeDir) "克隆配置仓库" 180000
|
||||||
if (Test-Path (Join-Path $ClaudeDir "CLAUDE.md")) {
|
if (Test-Path (Join-Path $ClaudeDir "CLAUDE.md")) {
|
||||||
Log-OK "配置仓库克隆成功"
|
Log-OK "配置仓库克隆成功"
|
||||||
|
Cache-GitCredentials $cred
|
||||||
} else {
|
} else {
|
||||||
Log-Fail "克隆失败"
|
Log-Fail "克隆失败"
|
||||||
Show-MsgBox "配置仓库克隆失败。`n请检查网络连接和 Gitea 账号。" "克隆失败" "OK" "Error"
|
Show-MsgBox "配置仓库克隆失败。`n请检查网络连接和 Gitea 账号。" "克隆失败" "OK" "Error"
|
||||||
@ -1103,18 +1130,63 @@ if (Test-Path $templateFile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ── ~/.claude.json (Claude Code v2.1+ MCP 服务器配置的正确位置) ──
|
# ── ~/.claude.json (Claude Code v2.1+ MCP 服务器配置的正确位置) ──
|
||||||
# 直接调用 config 仓库里的 inject-mcp.js (包含全部 22 个 portable MCP)
|
# 优先用 config 仓库的 inject-mcp.js, 如果 git pull 失败则内嵌 fallback
|
||||||
$injectScript = Join-Path $ClaudeDir "inject-mcp.js"
|
$injectScript = Join-Path $ClaudeDir "inject-mcp.js"
|
||||||
try {
|
$mcpInjected = $false
|
||||||
if (Test-Path $injectScript) {
|
# 方案 A: 调用 config 仓库里的 inject-mcp.js
|
||||||
|
if (Test-Path $injectScript) {
|
||||||
|
try {
|
||||||
$nodeOut = & node $injectScript 2>&1
|
$nodeOut = & node $injectScript 2>&1
|
||||||
$firstLine = ($nodeOut | Select-Object -First 1).ToString().Trim()
|
$firstLine = ($nodeOut | Select-Object -First 1).ToString().Trim()
|
||||||
Log-OK $firstLine
|
Log-OK $firstLine
|
||||||
} else {
|
$mcpInjected = $true
|
||||||
Bw-Log "WARN" "inject-mcp.js 不存在, 跳过 MCP 注入"
|
} catch { Bw-Log "WARN" "inject-mcp.js 执行失败: $_" }
|
||||||
}
|
}
|
||||||
} catch {
|
# 方案 B: 内嵌 fallback (git pull 失败时 inject-mcp.js 不存在)
|
||||||
Bw-Log "WARN" ".claude.json 生成失败: $_"
|
if (-not $mcpInjected) {
|
||||||
|
Log-Info "inject-mcp.js 不可用, 使用内嵌 MCP 注入..."
|
||||||
|
$fallbackJs = Join-Path $env:TEMP "bw-mcp-fallback.js"
|
||||||
|
try {
|
||||||
|
$fbLines = @(
|
||||||
|
'var fs=require("fs"),p=require("path");'
|
||||||
|
'var H=process.env.USERPROFILE;'
|
||||||
|
'var f=p.join(H,".claude.json");'
|
||||||
|
'var d={};'
|
||||||
|
'try{d=JSON.parse(fs.readFileSync(f,"utf8"))}catch(e){}'
|
||||||
|
'var N="npx.cmd",Y="--yes";'
|
||||||
|
'var S={};'
|
||||||
|
'S.context7={command:N,args:[Y,"@upstash/context7-mcp@2.1.1"],type:"stdio"};'
|
||||||
|
'S.playwright={command:N,args:[Y,"@playwright/mcp@0.0.68","--headless"],type:"stdio"};'
|
||||||
|
'S["session-continuity"]={command:N,args:[Y,"claude-session-continuity-mcp@1.13.0"],type:"stdio"};'
|
||||||
|
'S["browser-mcp"]={command:N,args:[Y,"@browsermcp/mcp@latest"],type:"stdio"};'
|
||||||
|
'S["desktop-commander"]={command:N,args:[Y,"@wonderwhy-er/desktop-commander@latest"],type:"stdio"};'
|
||||||
|
'S["chrome-devtools"]={command:N,args:[Y,"chrome-devtools-mcp@0.18.1"],type:"stdio"};'
|
||||||
|
'S.github={command:N,args:[Y,"@modelcontextprotocol/server-github"],type:"stdio"};'
|
||||||
|
'S.slack={command:N,args:[Y,"@modelcontextprotocol/server-slack"],type:"stdio"};'
|
||||||
|
'S.firecrawl={command:N,args:[Y,"firecrawl-mcp"],type:"stdio"};'
|
||||||
|
'S["mcp-image"]={command:N,args:[Y,"mcp-image"],type:"stdio"};'
|
||||||
|
'S["google-drive"]={command:N,args:[Y,"@piotr-agier/google-drive-mcp"],type:"stdio"};'
|
||||||
|
'S.browserbase={command:N,args:[Y,"@anthropic-ai/browserbase-mcp"],type:"stdio"};'
|
||||||
|
'S.notebooklm={command:N,args:[Y,"notebooklm-mcp@latest"],type:"stdio"};'
|
||||||
|
'S.cloudflare={command:N,args:[Y,"mcp-remote","https://docs.mcp.cloudflare.com/sse"],type:"stdio"};'
|
||||||
|
'S.mobile={command:N,args:[Y,"@mobilenext/mobile-mcp@0.0.35"],type:"stdio"};'
|
||||||
|
'var K="@modelcontextprotocol/server-sequential-thinking";'
|
||||||
|
'S["sequential-thinking"]={command:N,args:[Y,K+"@2025.12.18"],type:"stdio"};'
|
||||||
|
'S.linear={type:"http",url:"https://mcp.linear.app/mcp"};'
|
||||||
|
'S.figma={type:"http",url:"https://mcp.figma.com/mcp"};'
|
||||||
|
'S["windows-mcp"]={command:"uvx",args:["--python","3.13","windows-mcp"],type:"stdio"};'
|
||||||
|
'S.atlassian={command:"uvx",args:["mcp-atlassian"],type:"stdio"};'
|
||||||
|
'S["computer-control-mcp"]={command:"uvx",args:["computer-control-mcp@latest"],type:"stdio"};'
|
||||||
|
'd.mcpServers=S;'
|
||||||
|
'fs.writeFileSync(f,JSON.stringify(d,null,2));'
|
||||||
|
'console.log("OK: "+Object.keys(S).length+" MCP servers (fallback)");'
|
||||||
|
)
|
||||||
|
$fbLines -join "`n" | Set-Content $fallbackJs -Encoding UTF8
|
||||||
|
$nodeOut = & node $fallbackJs 2>&1
|
||||||
|
$firstLine = ($nodeOut | Select-Object -First 1).ToString().Trim()
|
||||||
|
Remove-Item $fallbackJs -Force -ErrorAction SilentlyContinue
|
||||||
|
Log-OK $firstLine
|
||||||
|
} catch { Bw-Log "WARN" "MCP fallback 注入失败: $_" }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log-Warn "settings.template.json 不存在, 跳过渲染"
|
Log-Warn "settings.template.json 不存在, 跳过渲染"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user