From 9fc7f1c9fafabb4fbff60c3cc3ceff063eba7aa6 Mon Sep 17 00:00:00 2001 From: bookworm Date: Fri, 24 Apr 2026 22:13:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(v3.0.8):=20Phase=201=20=E5=BC=95=E5=AF=BC?= =?UTF-8?q?=E6=80=A7=E5=A4=A7=E5=8D=87=E7=BA=A7=20(PS7=20=E7=A1=AC?= =?UTF-8?q?=E6=A0=B8+per-dep=20=E5=BC=B9=E7=AA=97+=E6=80=BB=E7=BB=93+Claud?= =?UTF-8?q?e=20=E8=AF=8A=E6=96=AD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户反馈: v3.0.7 EXE 安装没有检测和引导 PS7/Claude Code. 根因: B1: PS7 标记为'可选', 装失败只 Log-Info, 用户滚动错过. 但启动器 bat 强依赖 pwsh, 降级 5.1 体验差 (粘贴多行命令被拆/Base64 截断). B2: Core 依赖装失败只 Log-Fail 到 GUI, 末尾才一次 manualGuide. B3: Claude Code 失败没具体诊断 ('npm 安装失败' 模糊无法报障). 修复: F1: PS7 升硬核 (最终检查含 pwsh, 缺失 exit 1 + manualGuide 含 winget+MSI) F2: foreach 内 Core 失败立即弹 Warning 专属窗 (winget/MSI/EXE/npm 全方案) F3: Phase 1 末尾总结 MessageBox (就绪/新装/失败分组, 只在有动作时弹) F4: Claude 失败写诊断到 bw-crash.log (node -v/npm -v/npm prefix/PATH) EXE 212480 → 217088 bytes (+4608) UX 对比: v3.0.7 用户滚动错过关键信息; v3.0.8 每步都有专属弹窗或总结 --- auto-setup.ps1 | 98 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 8 deletions(-) diff --git a/auto-setup.ps1 b/auto-setup.ps1 index 4d55d9d..0aab117 100644 --- a/auto-setup.ps1 +++ b/auto-setup.ps1 @@ -48,7 +48,7 @@ trap { } # ─── 版本号 (每次更新递增, build.ps1 自动读取) ────── -$BWVersion = "3.0.7" # hotfix: 顶层 trap 防闪退 + Phase 5.5 regex 字面替换 + 可选步骤 try-catch 降级 +$BWVersion = "3.0.8" # UX: PS7 升硬核 + per-dep 失败弹窗 + Phase 1 总结 + Claude 诊断增强 # DryRun 模式日志标记 if ($DryRun) { $global:BWDryRun = $DryRun } else { $global:BWDryRun = $null } @@ -939,11 +939,35 @@ foreach ($dep in $deps) { elseif (-not $hasWinget) { if ($dep.Core) { Log-Fail "$($dep.Name) 需要手动安装 (winget 不可用)" - Show-MsgBox "$($dep.Name) 未安装且 winget 不可用。`n请手动安装后重新运行。`n`nNode.js: https://nodejs.org`nGit: https://git-scm.com" "缺少依赖" "OK" "Error" + # 失败专属弹窗由下面统一的 per-dep 失败检查处理 } else { Log-Info "$($dep.Name) 未安装 (可选, 不影响核心功能)" } } + + # v3.0.8: per-dep 失败立即弹专属 Warning (不阻断继续下一个 dep, Phase 1 末尾统一判断 exit) + # 场景: 3 种安装路径全挂 + Core=true → 给用户**具体**该 dep 的手动方案, 而非等到末尾总弹窗 + if ($dep.Core -and -not (Test-Cmd $dep.Cmd)) { + $depFailMsg = "[$($dep.Name)] 自动安装失败`n`n" + $depFailMsg += "请手动安装 (任选一种):`n" + if ($dep.WingetId) { + $depFailMsg += "`n方式 A (winget): `n winget install --id $($dep.WingetId) --accept-source-agreements --accept-package-agreements`n" + } + if ($dep.MsiUrl) { + $depFailMsg += "`n方式 B (MSI 直链):`n 浏览器打开: $($dep.MsiUrl)`n 下载后双击安装, 全部选默认`n" + } + if ($dep.ExeUrl) { + $depFailMsg += "`n方式 B (EXE 直链):`n 浏览器打开: $($dep.ExeUrl)`n 下载后双击安装, 全部选默认`n" + } + if ($dep.NpmPkg) { + $depFailMsg += "`n方式 A (需 Node.js 就绪):`n 命令行: npm i -g $($dep.NpmPkg)`n" + } + if ($dep.ManualUrl) { + $depFailMsg += "`n参考下载页: $($dep.ManualUrl)`n" + } + $depFailMsg += "`n【装完后】重新双击 Bookworm-Setup.exe 即可继续 (已装的依赖会自动跳过)" + Show-MsgBox $depFailMsg "[$($dep.Name)] 需手动安装" "OK" "Warning" + } } } @@ -973,11 +997,33 @@ if ((Test-Cmd "git") -and -not (Test-Cmd "bash")) { } # Claude Code 依赖 npm, 需要在 Node.js 安装后再检查 +# v3.0.8: 失败时写诊断到 bw-crash.log (node -v / npm -v / npm prefix / PATH 片段) if (-not (Test-Cmd "claude") -and (Test-Cmd "npm")) { Log-Info "安装 Claude Code..." $r = Run-CmdWithUI "npm" @("i", "-g", "@anthropic-ai/claude-code") "安装 Claude Code (首次约 2 分钟)" 180000 $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") - if (Test-Cmd "claude") { Log-OK "Claude Code 安装成功" } else { Log-Fail "Claude Code 安装失败" } + # 补 npm 全局路径到 PATH (Windows 默认 %APPDATA%\npm) + $npmGlobal = "$env:APPDATA\npm" + if ((Test-Path $npmGlobal) -and ($env:Path -notlike "*$npmGlobal*")) { $env:Path = "$npmGlobal;$env:Path" } + if (Test-Cmd "claude") { + Log-OK "Claude Code 安装成功" + } else { + Log-Fail "Claude Code 安装失败" + # v3.0.8: 写具体诊断到 crash log, 便于用户报障 (不走 Show-MsgBox 避免双重打扰, 由 Phase 1 末尾统一弹) + try { + $nodeV = try { (& node --version 2>$null) } catch { "(node 不可用)" } + $npmV = try { (& npm --version 2>$null) } catch { "(npm 不可用)" } + $npmPrefix = try { (& npm config get prefix 2>$null) } catch { "(获取失败)" } + $pathNpm = ($env:Path -split ';') | Where-Object { $_ -match 'npm|nodejs' } | Out-String + $diag = "[$([DateTime]::Now.ToString('s'))] CLAUDE_INSTALL_FAIL`n" + $diag += " node -v : $nodeV`n" + $diag += " npm -v : $npmV`n" + $diag += " npm prefix : $npmPrefix`n" + $diag += " PATH (npm 相关):`n$pathNpm`n" + $diag | Out-File -FilePath $global:BWCrashLog -Append -Encoding UTF8 -EA SilentlyContinue + Bw-Log "INFO" "Claude Code 诊断已写入: $global:BWCrashLog" + } catch {} + } } # uv (Python 包管理器, 可选依赖) - 完全静默, 失败不阻断不弹窗 @@ -1050,12 +1096,45 @@ if (Test-Cmd "uv") { $opensslCmd = Find-OpenSSL if ($opensslCmd) { Log-OK "OpenSSL: $opensslCmd" } else { Log-Warn "OpenSSL 未找到 (凭证解密可能失败)" } -# 最终检查 (仅 Node.js + Git + Claude Code 为硬性依赖, PowerShell 7 可选) -if (-not (Test-Cmd "node") -or -not (Test-Cmd "git") -or -not (Test-Cmd "claude")) { +# v3.0.8: Phase 1 总结弹窗 — 让用户一眼看懂全局, 避免 GUI 进度条滚动中遗漏关键信息 +$coreList = @("Node.js", "Git", "PowerShell 7", "Claude Code") +$coreCmds = @{ "Node.js" = "node"; "Git" = "git"; "PowerShell 7" = "pwsh"; "Claude Code" = "claude" } +$summaryReady = @() # 已就绪 (本次未重装) +$summaryNew = @() # 本次自动安装成功 +$summaryFail = @() # 本次自动安装失败 +foreach ($name in $coreList) { + $cmd = $coreCmds[$name] + if (Test-Cmd $cmd) { + if ($installed -contains $name) { $summaryNew += $name } + else { $summaryReady += $name } + } else { + $summaryFail += $name + } +} +# 只在发生过自动安装时弹总结 (纯就绪无新动作不打扰用户) +if ($summaryNew.Count -gt 0 -or $summaryFail.Count -gt 0) { + $sum = "[Phase 1] 依赖环境检查完成`n`n" + if ($summaryReady.Count -gt 0) { $sum += "[OK] 已就绪: $($summaryReady -join ', ')`n" } + if ($summaryNew.Count -gt 0) { $sum += "[INSTALLED] 本次自动安装: $($summaryNew -join ', ')`n" } + if ($summaryFail.Count -gt 0) { + $sum += "[FAIL] 需手动处理: $($summaryFail -join ', ')`n" + $sum += "`n失败项已在前面弹窗给出手动方案; 装完重跑 EXE 即可继续." + } else { + $sum += "`n所有核心依赖就绪, 即将进入 Phase 2 网络诊断." + } + $icon = if ($summaryFail.Count -gt 0) { "Warning" } else { "Information" } + Show-MsgBox $sum "Phase 1 总结 — v$BWVersion" "OK" $icon +} + +# v3.0.8: PS7 升为硬核依赖 (启动器 bat 强依赖 pwsh 的 -EncodedCommand + STA runspace 正确性, +# PS5.1 降级路径体验差: 粘贴多行命令被拆分 / Base64 可能被截断 / WinForms 兼容不一致) +# 最终检查 (Node.js + Git + Claude Code + PowerShell 7 全部为硬性依赖) +if (-not (Test-Cmd "node") -or -not (Test-Cmd "git") -or -not (Test-Cmd "claude") -or -not (Test-Cmd "pwsh")) { $missing = @() if (-not (Test-Cmd "node")) { $missing += "Node.js" } if (-not (Test-Cmd "git")) { $missing += "Git" } if (-not (Test-Cmd "claude")) { $missing += "Claude Code" } + if (-not (Test-Cmd "pwsh")) { $missing += "PowerShell 7" } # v3.0.5: 清除桌面僵尸快捷方式, 防用户点击空快捷方式触发 'claude.exe not found' try { @@ -1086,6 +1165,12 @@ if (-not (Test-Cmd "node") -or -not (Test-Cmd "git") -or -not (Test-Cmd "claude" $manualGuide += "3. Claude Code (需先装好 Node.js)`n" $manualGuide += " 命令行执行: npm i -g @anthropic-ai/claude-code`n`n" } + if ($missing -contains "PowerShell 7") { + $manualGuide += "4. PowerShell 7 (启动器 bat + Base64 启动链路必需)`n" + $manualGuide += " 方式 A: winget install --id Microsoft.PowerShell`n" + $manualGuide += " 方式 B: 下载 MSI https://github.com/PowerShell/PowerShell/releases/latest`n" + $manualGuide += " 选 PowerShell-7.x.x-win-x64.msi → 双击安装`n`n" + } $manualGuide += "【完成后】`n" $manualGuide += " 重新双击 Bookworm-Setup.exe 即可继续安装`n" $manualGuide += " (已装成功的依赖会被自动跳过)`n`n" @@ -1097,9 +1182,6 @@ if (-not (Test-Cmd "node") -or -not (Test-Cmd "git") -or -not (Test-Cmd "claude" Show-MsgBox $manualGuide "安装中断 — 手动安装指引" "OK" "Error" exit 1 } -if (-not (Test-Cmd "pwsh")) { - Log-Info "PowerShell 7 未安装 (可选, 用系统 PowerShell 5.1 替代)" -} # 定位 pwsh.exe 完整路径 (供后续 settings.json 配置使用) $PwshPath = (Get-Command pwsh -ErrorAction SilentlyContinue).Source