hotfix(v3.1.3): 卸载精准删除 + 体检凭证链路修正

W1: 卸载脚本改为只删 Bookworm 注入的 7 目录+3 文件,
    保留用户自有 CLAUDE.md/memory/projects (防误杀)
W2: bw-doctor [9] 改检 DPAPI→profile 注入链路,
    不再检查 User 持久环境变量 (逻辑反转修正)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
bookworm 2026-04-26 17:05:38 +08:00
parent 2d36862f38
commit 0b4402d417
4 changed files with 63 additions and 35 deletions

View File

@ -48,7 +48,7 @@ trap {
} }
# ─── 版本号 (每次更新递增, build.ps1 自动读取) ────── # ─── 版本号 (每次更新递增, build.ps1 自动读取) ──────
$BWVersion = "3.1.2" # 完整生命周期: 卸载脚本 + 体检工具 + nvm探测 + 镜像fallback + log rotation + 4桌面lnk (闭合 L9/L10/L11/L12) $BWVersion = "3.1.3" # hotfix: 卸载精准删除 (不删用户自有 ~/.claude) + 体检凭证链路检测修正
# DryRun 模式日志标记 # DryRun 模式日志标记
if ($DryRun) { $global:BWDryRun = $DryRun } else { $global:BWDryRun = $null } if ($DryRun) { $global:BWDryRun = $DryRun } else { $global:BWDryRun = $null }

View File

@ -1,6 +1,6 @@
<# <#
.SYNOPSIS .SYNOPSIS
Bookworm Portable 体检工具 (v3.1.2) Bookworm Portable 体检工具 (v3.1.3)
.DESCRIPTION .DESCRIPTION
13 维度自检, 覆盖 auto-setup.ps1 7 阶段所有安装产物. 13 维度自检, 覆盖 auto-setup.ps1 7 阶段所有安装产物.
@ -59,11 +59,11 @@ function Test-Cmd($name) { return [bool](Get-Command $name -EA SilentlyContinue)
# ── Banner ── # ── Banner ──
Write-Host "" Write-Host ""
Write-Host " +------------------------------------------+" -ForegroundColor Cyan Write-Host " +------------------------------------------+" -ForegroundColor Cyan
Write-Host " | Bookworm Doctor v3.1.2 |" -ForegroundColor Cyan Write-Host " | Bookworm Doctor v3.1.3 |" -ForegroundColor Cyan
Write-Host " | 13 维度健康体检 |" -ForegroundColor Cyan Write-Host " | 13 维度健康体检 |" -ForegroundColor Cyan
Write-Host " +------------------------------------------+" -ForegroundColor Cyan Write-Host " +------------------------------------------+" -ForegroundColor Cyan
Write-Host "" Write-Host ""
Log-Doctor "=== Bookworm Doctor v3.1.2 START ===" Log-Doctor "=== Bookworm Doctor v3.1.3 START ==="
# ══════════════════════════════════════════════════════ # ══════════════════════════════════════════════════════
# [1/13] PowerShell 7 # [1/13] PowerShell 7
@ -275,32 +275,43 @@ if (Test-Path $clipProfile) {
} }
# ══════════════════════════════════════════════════════ # ══════════════════════════════════════════════════════
# [9/13] 环境变量 # [9/13] 凭证注入链路 (DPAPI → profile → 运行时 Key)
# ══════════════════════════════════════════════════════ # ══════════════════════════════════════════════════════
Write-Host " [9/13] 环境变量" -ForegroundColor Cyan Write-Host " [9/13] 凭证注入链路" -ForegroundColor Cyan
$envChecks = @( # Bookworm 的设计: DPAPI 加密存 HKCU → profile.ps1 启动时解密 export → 运行时 env 可用
@{ Name = "ANTHROPIC_API_KEY"; Required = $true } # 不应检查 User 持久环境变量 (Key 明文存 User env 反而不安全)
@{ Name = "ANTHROPIC_BASE_URL"; Required = $false } $chainOK = $true; $chainDetail = @()
@{ Name = "ANTHROPIC_MODEL"; Required = $false }
) # 环节 1: DPAPI 存储有 Key
$envOK = @(); $envMissing = @(); $envOptMissing = @() $regPath = "HKCU:\Software\Bookworm\CachedEnv"
foreach ($e in $envChecks) { $dpapiHasKey = $false
$val = [Environment]::GetEnvironmentVariable($e.Name, 'User') if (Test-Path $regPath) {
if ($val) { try {
$masked = if ($e.Name -eq 'ANTHROPIC_API_KEY') { $val.Substring(0, [Math]::Min(7, $val.Length)) + '...' } else { $val } $props = Get-ItemProperty $regPath -EA SilentlyContinue
$envOK += "$($e.Name)=$masked" $apiKeyProp = $props.PSObject.Properties | Where-Object { $_.Name -eq 'ANTHROPIC_API_KEY' }
} elseif ($e.Required) { if ($apiKeyProp) { $dpapiHasKey = $true; $chainDetail += "DPAPI=OK" }
$envMissing += $e.Name } catch {}
} else {
$envOptMissing += $e.Name
} }
if (-not $dpapiHasKey) { $chainOK = $false; $chainDetail += "DPAPI=MISSING" }
# 环节 2: profile 有 BW_CRED 块
$ps7Profile = Join-Path $env:USERPROFILE "Documents\PowerShell\profile.ps1"
$profileHasCred = $false
if (Test-Path $ps7Profile) {
$c = Get-Content $ps7Profile -Raw -EA SilentlyContinue
if ($c -match 'BW_CRED_START') { $profileHasCred = $true; $chainDetail += "Profile=OK" }
} }
if ($envMissing.Count -eq 0) { if (-not $profileHasCred) { $chainOK = $false; $chainDetail += "Profile=MISSING" }
$detail = ($envOK -join '; ')
if ($envOptMissing.Count -gt 0) { $detail += " (可选未设: $($envOptMissing -join ', '))" } # 环节 3: BASE_URL (可选但推荐)
Report "[9] 环境变量" "PASS" $detail $baseUrl = [Environment]::GetEnvironmentVariable('ANTHROPIC_BASE_URL', 'User')
if (-not $baseUrl) { $baseUrl = $env:ANTHROPIC_BASE_URL }
if ($baseUrl) { $chainDetail += "BaseURL=$baseUrl" } else { $chainDetail += "BaseURL=default" }
if ($chainOK) {
Report "[9] 凭证注入链路" "PASS" ($chainDetail -join ' → ')
} else { } else {
Report "[9] 环境变量" "FAIL" "缺失: $($envMissing -join ', ')" Report "[9] 凭证注入链路" "FAIL" ($chainDetail -join ' → ') + " — 重跑 Bookworm-Setup.exe"
} }
# ══════════════════════════════════════════════════════ # ══════════════════════════════════════════════════════

View File

@ -1,6 +1,6 @@
<# <#
.SYNOPSIS .SYNOPSIS
v3.1.2: Bookworm 完整卸载实现脚本 v3.1.3: Bookworm 完整卸载实<EFBFBD><EFBFBD>脚本
.DESCRIPTION .DESCRIPTION
卸载Bookworm.bat 调用. 集中所有 PS 清理逻辑, 避免 cmd 多行 PS 转义. 卸载Bookworm.bat 调用. 集中所有 PS 清理逻辑, 避免 cmd 多行 PS 转义.
@ -25,12 +25,13 @@ Add-Type -AssemblyName System.Windows.Forms -EA SilentlyContinue
$msg = "确定要卸载 Bookworm 吗?`n`n" $msg = "确定要卸载 Bookworm 吗?`n`n"
$msg += "将删除:`n" $msg += "将删除:`n"
$msg += " - 桌面 4-5 个快捷方式`n" $msg += " - 桌面 4-5 个快捷方式`n"
$msg += " - ~/.claude 配置目录 (skills/hooks/agents)`n" $msg += " - ~/.claude 中 Bookworm 注入的内容 (skills/hooks/agents/scripts)`n"
$msg += " - HKCU DPAPI 凭证缓存`n" $msg += " - HKCU DPAPI 凭证缓存`n"
$msg += " - PowerShell profile (PS7+PS5.1) 中的 BW_* 块`n" $msg += " - PowerShell profile (PS7+PS5.1) 中的 BW_* 块`n"
$msg += " - 还原截图 Toast 默认设置`n" $msg += " - 还原截图 Toast 默认设置`n"
$msg += " - ANTHROPIC_* User 环境变量`n`n" $msg += " - ANTHROPIC_* User 环境变量`n`n"
$msg += "保留 (公共依赖, 不主动卸):`n" $msg += "保留:`n"
$msg += " - ~/.claude/CLAUDE.md, memory/, projects/ (用户自有内容)`n"
$msg += " - Node.js / Git / PowerShell 7 / Claude Code" $msg += " - Node.js / Git / PowerShell 7 / Claude Code"
$confirm = [System.Windows.Forms.MessageBox]::Show($msg, 'Bookworm 卸载二次确认', 'YesNo', 'Warning') $confirm = [System.Windows.Forms.MessageBox]::Show($msg, 'Bookworm 卸载二次确认', 'YesNo', 'Warning')
@ -53,12 +54,28 @@ foreach ($n in @('启动Bookworm.lnk','更新Bookworm.lnk','体检Bookworm.lnk',
} }
} }
# ── [2/7] ~/.claude 目录 ── # ── [2/7] ~/.claude Bookworm 注入内容 (精准删除, 保留用户自有配置) ──
Log "[2/7] 删 ~/.claude/ (配置 + 凭证 + skills/hooks/agents)" Log "[2/7] 清 ~/.claude/ 中 Bookworm 注入的文件"
$claudeDir = Join-Path $env:USERPROFILE '.claude' $claudeDir = Join-Path $env:USERPROFILE '.claude'
if (Test-Path $claudeDir) { if (Test-Path $claudeDir) {
try { Remove-Item $claudeDir -Recurse -Force -EA Stop; Log " ✓ 已删 $claudeDir" } # 只删 Bookworm 管理的子目录和文件, 不删用户自己的 CLAUDE.md / memory / projects
catch { Log " [!] 删除失败 (可能 claude 进程占用): $_" } $bwManagedDirs = @('skills', 'hooks', 'agents', 'scripts', 'constitution', 'patches', 'session-state')
foreach ($d in $bwManagedDirs) {
$dp = Join-Path $claudeDir $d
if (Test-Path $dp) {
try { Remove-Item $dp -Recurse -Force -EA Stop; Log " ✓ 删 $d/" }
catch { Log " [!] 删 $d/ 失败: $_" }
}
}
# 删 Bookworm 的配置文件 (settings.json 含 hooks 注册)
foreach ($f in @('settings.json', 'settings.local.json', 'stats-compiled.json')) {
$fp = Join-Path $claudeDir $f
if (Test-Path $fp) {
try { Remove-Item $fp -Force -EA Stop; Log " ✓ 删 $f" }
catch { Log " [!] 删 $f 失败: $_" }
}
}
Log " · 保留 ~/.claude/CLAUDE.md, memory/, projects/ (用户自有内容)"
} }
# ── [3/7] HKCU DPAPI 凭证 + Toast 备份元数据 ── # ── [3/7] HKCU DPAPI 凭证 + Toast 备份元数据 ──

View File

@ -1,6 +1,6 @@
@echo off @echo off
chcp 65001 > nul chcp 65001 > nul
:: v3.1.2: Bookworm 完整卸载脚本 :: v3.1.3: Bookworm 完整卸载脚本
:: 删除: 桌面 .lnk × 4 / ~/.claude / DPAPI HKCU 凭证 / :: 删除: 桌面 .lnk × 4 / ~/.claude / DPAPI HKCU 凭证 /
:: 双 profile (PS7+PS5.1) 的 BW_CRED + BW_CLIP 块 / Toast 备份还原 / :: 双 profile (PS7+PS5.1) 的 BW_CRED + BW_CLIP 块 / Toast 备份还原 /
:: ANTHROPIC_* User 环境变量 :: ANTHROPIC_* User 环境变量