diff --git a/install.ps1 b/install.ps1 index 7623efc..a22fd84 100644 --- a/install.ps1 +++ b/install.ps1 @@ -68,42 +68,51 @@ function Decrypt-Secrets { return } - $password = Read-Host " 输入主密码解密凭证" -AsSecureString - $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password) - $plainPwd = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) + $maxRetries = 3 + for ($attempt = 1; $attempt -le $maxRetries; $attempt++) { + $label = if ($attempt -gt 1) { " 重新输入主密码 (第 $attempt/$maxRetries 次)" } else { " 输入主密码解密凭证" } + $password = Read-Host $label -AsSecureString + $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password) + $plainPwd = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) - try { - # 通过 stdin 传入密码,避免进程列表泄露 + $prevEAP = $ErrorActionPreference + $ErrorActionPreference = "Continue" $decrypted = $plainPwd | & $opensslCmd enc -aes-256-cbc -d -pbkdf2 -iter 600000 -in $SecretsEnc -pass stdin 2>&1 - if ($LASTEXITCODE -ne 0) { - throw "解密失败,密码错误?" - } + $decExit = $LASTEXITCODE + $ErrorActionPreference = $prevEAP - # 使用 IndexOf 正确分割 key=value (value 中可能含 = 号) - $decrypted -split "`n" | ForEach-Object { - $line = $_.Trim() - if ($line -and $line.Contains('=')) { - $eqIdx = $line.IndexOf('=') - $key = $line.Substring(0, $eqIdx).Trim() - $val = $line.Substring($eqIdx + 1).Trim() - [System.Environment]::SetEnvironmentVariable($key, $val, "Process") - Write-Host " [OK] 已注入: $key" -ForegroundColor Green - } - } - } - catch { - Write-Host " [ERROR] 凭证解密失败: $_" -ForegroundColor Red - # 检查关键凭证是否存在 - if (-not $env:ANTHROPIC_API_KEY) { - Write-Host " [WARN] ANTHROPIC_API_KEY 未设置,Claude Code 可能无法使用中转站" -ForegroundColor Yellow - $continue = Read-Host " 继续启动? (y/n)" - if ($continue -ne 'y') { exit 1 } - } - } - finally { + # 清除内存中的密码 $plainPwd = $null [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) + + if ($decExit -eq 0 -and $decrypted) { + # 解密成功,注入环境变量 + $decrypted -split "`n" | ForEach-Object { + $line = $_.Trim() + if ($line -and $line.Contains('=')) { + $eqIdx = $line.IndexOf('=') + $key = $line.Substring(0, $eqIdx).Trim() + $val = $line.Substring($eqIdx + 1).Trim() + [System.Environment]::SetEnvironmentVariable($key, $val, "Process") + Write-Host " [OK] 已注入: $key" -ForegroundColor Green + } + } + return + } + + # 解密失败 + $remaining = $maxRetries - $attempt + if ($remaining -gt 0) { + Write-Host " [!!] 密码错误,剩余重试: $remaining 次" -ForegroundColor Red + } } + + # 3次全部失败 + Write-Host "" + Write-Host " [ABORT] 3 次密码均错误" -ForegroundColor Red + Write-Host " 请确认主密码是否正确 (区分大小写,至少12位)" -ForegroundColor Yellow + Write-Host " 如忘记密码,请联系管理员重新生成 secrets.enc" -ForegroundColor Yellow + exit 1 } function Render-SettingsTemplate { @@ -202,7 +211,7 @@ function Detect-SystemProxy { Write-Banner # 步骤 0: 前置检查 -Write-Host "[0/7] 前置检查..." -ForegroundColor White +Write-Host "[1/6] 前置检查..." -ForegroundColor White $checks = @( @{ Name = "Claude Code"; OK = (Test-Command "claude") } @{ Name = "Node.js"; OK = (Test-Command "node") } @@ -222,17 +231,23 @@ if (-not (Test-Command "node")) { exit 1 } -# 步骤 0.5: 代理检测 (国内必须) -Write-Host "`n[0.5/7] 代理检测..." -ForegroundColor White +# 步骤 2: 代理检测 (国内必须) +Write-Host "`n[2/6] 代理检测..." -ForegroundColor White Detect-SystemProxy -# 步骤 1: 解密凭证 (进程级环境变量,不写磁盘) -Write-Host "`n[1/7] 解密凭证..." -ForegroundColor White +# 步骤 3: 解密凭证 (进程级环境变量,不写磁盘) +Write-Host "`n[3/6] 解密凭证..." -ForegroundColor White Decrypt-Secrets +# 自动配置 git credential helper (避免 clone 时反复要密码) +$prevEAP = $ErrorActionPreference +$ErrorActionPreference = "Continue" +git config --global credential.helper store 2>$null +$ErrorActionPreference = $prevEAP + # 步骤 2: 克隆/更新仓库 if (-not $StartOnly) { - Write-Host "`n[2/7] 同步 Bookworm 配置..." -ForegroundColor White + Write-Host "`n[4/6] 同步 Bookworm 配置..." -ForegroundColor White if (Test-Path $ClaudeTarget) { $isGit = Test-Path (Join-Path $ClaudeTarget ".git") @@ -303,13 +318,26 @@ if (-not $StartOnly) { } } else { - Write-Host "`n[2/7] StartOnly 模式,跳过同步" -ForegroundColor Gray + Write-Host "`n[4/6] StartOnly 模式,跳过同步" -ForegroundColor Gray + # 静默检测远程更新 + $configDir = Join-Path $env:USERPROFILE ".claude" + if (Test-Path (Join-Path $configDir ".git")) { + $prevEAP2 = $ErrorActionPreference + $ErrorActionPreference = "Continue" + git -C $configDir fetch --quiet 2>$null + $behind = git -C $configDir rev-list "HEAD..origin/main" --count 2>$null + $ErrorActionPreference = $prevEAP2 + if ($behind -and [int]$behind -gt 0) { + Write-Host " [!] Bookworm 有 $behind 个新更新可用" -ForegroundColor Yellow + Write-Host " 双击 '更新并启动Bookworm.bat' 可同步最新版本" -ForegroundColor Yellow + } + } } # 步骤 3: 完整性校验 $integrityFile = Join-Path $ClaudeTarget "integrity.sha256" if (Test-Path $integrityFile) { - Write-Host "`n[4/7] 完整性校验..." -ForegroundColor White + Write-Host "`n[5/6] 完整性校验..." -ForegroundColor White $failures = @() Get-Content $integrityFile | ForEach-Object { if ($_ -match '^([a-f0-9]{64})\s+(.+)$') { @@ -333,15 +361,15 @@ if (Test-Path $integrityFile) { Write-Host " [OK] 所有文件完整性校验通过" -ForegroundColor Green } } else { - Write-Host "`n[4/7] 跳过完整性校验 (无 integrity.sha256)" -ForegroundColor Gray + Write-Host "`n[5/6] 跳过完整性校验 (无 integrity.sha256)" -ForegroundColor Gray } # 步骤 4: 渲染 settings.json -Write-Host "`n[5/7] 渲染配置模板..." -ForegroundColor White +Write-Host "`n[5/6] 渲染配置模板..." -ForegroundColor White Render-SettingsTemplate # 步骤 5: 确保必要目录存在 -Write-Host "`n[6/7] 初始化本地目录..." -ForegroundColor White +Write-Host "`n[5/6] 初始化本地目录..." -ForegroundColor White $localDirs = @("debug", "sessions", "cache", "backups", "telemetry", "shell-snapshots", "projects", "memory") foreach ($d in $localDirs) { $dirPath = Join-Path $ClaudeTarget $d @@ -364,7 +392,7 @@ if ($nodeCheck -eq $ClaudeTarget) { } # 步骤 6: Bookworm 完整性验证 + MCP 检查 -Write-Host "`n[7/8] Bookworm 系统验证..." -ForegroundColor White +Write-Host "`n[5/6] Bookworm 系统验证..." -ForegroundColor White # --- Bookworm vs 原生 Claude Code 检测 --- $bwChecks = @() @@ -495,7 +523,7 @@ if ($mcpWarnings.Count -eq 0) { } # 步骤 7: 启动 Claude Code -Write-Host "`n[8/8] 启动 Claude Code..." -ForegroundColor White +Write-Host "`n[6/6] 启动 Claude Code..." -ForegroundColor White Write-Host "" if ($allOK) { Write-Host " ╔══════════════════════════════════════════╗" -ForegroundColor Green diff --git a/quick-reference.txt b/quick-reference.txt index 589c232..b342502 100644 --- a/quick-reference.txt +++ b/quick-reference.txt @@ -5,10 +5,10 @@ ================================================================================ Gitea 地址: https://code.letcareme.com - 管理员账号: bookworm - 管理员密码: [REDACTED_OLD_PASSWORD] - 中转站地址: https://bww.letcareme.com/v1 - ECS 服务器: 8.138.11.105 (Gitea 端口 3300, 仅本地) + 管理员账号: [由管理员提供] + 管理员密码: [由管理员提供] + 中转站地址: [由管理员提供] + ECS 服务器: [由管理员提供] ================================================================================ 一、首次安装 (目标机) @@ -109,7 +109,7 @@ ---- 5.1 部署 Gitea (仅首次) ---- scp C:\Users\leesu\Desktop\bookworm-portable\deploy-gitea.sh root@8.138.11.105:/tmp/ - ssh root@8.138.11.105 "GITEA_ADMIN_PASS='[REDACTED_OLD_PASSWORD]' bash /tmp/deploy-gitea.sh" + ssh root@8.138.11.105 "GITEA_ADMIN_PASS='[密码]' bash /tmp/deploy-gitea.sh" ---- 5.2 配置 HTTPS (仅首次) ---- @@ -126,7 +126,7 @@ cd C:\Users\leesu\.claude git add -A git commit -m "update bookworm config" - git push https://bookworm:[REDACTED_OLD_PASSWORD]@code.letcareme.com/bookworm/bookworm-config.git main + git push https://bookworm:[密码]@code.letcareme.com/bookworm/bookworm-config.git main ---- 5.5 更新 boot 仓库脚本 ---- @@ -137,7 +137,7 @@ cp C:\Users\leesu\Desktop\bookworm-portable\secrets.enc . git add -A git commit -m "update boot scripts" - git push https://bookworm:[REDACTED_OLD_PASSWORD]@code.letcareme.com/bookworm/bookworm-boot.git main + git push https://bookworm:[密码]@code.letcareme.com/bookworm/bookworm-boot.git main ---- 5.6 重新加密凭证 (更换 API Key 后) ---- diff --git a/启动Bookworm.bat b/启动Bookworm.bat new file mode 100644 index 0000000..428cb32 --- /dev/null +++ b/启动Bookworm.bat @@ -0,0 +1,23 @@ +@echo off +chcp 65001 > nul +title Bookworm Portable - 启动 +cd /d "%~dp0" + +echo. +echo ==================================== +echo Bookworm Portable - 快速启动 +echo ==================================== +echo. + +where pwsh >nul 2>nul +if %errorlevel% equ 0 ( + pwsh -ExecutionPolicy Bypass -File install.ps1 -StartOnly +) else ( + powershell -ExecutionPolicy Bypass -File install.ps1 -StartOnly +) + +if %errorlevel% neq 0 ( + echo. + echo 启动失败,按任意键退出... + pause > nul +) diff --git a/更新并启动Bookworm.bat b/更新并启动Bookworm.bat new file mode 100644 index 0000000..6a586e9 --- /dev/null +++ b/更新并启动Bookworm.bat @@ -0,0 +1,24 @@ +@echo off +chcp 65001 > nul +title Bookworm Portable - 更新并启动 +cd /d "%~dp0" + +echo. +echo ==================================== +echo Bookworm Portable - 更新并启动 +echo (同步最新 Skills/Hooks 后启动) +echo ==================================== +echo. + +where pwsh >nul 2>nul +if %errorlevel% equ 0 ( + pwsh -ExecutionPolicy Bypass -File install.ps1 +) else ( + powershell -ExecutionPolicy Bypass -File install.ps1 +) + +if %errorlevel% neq 0 ( + echo. + echo 启动失败,按任意键退出... + pause > nul +)