From dee7742a12dfa395cd39e2f650de773302ec6481 Mon Sep 17 00:00:00 2001 From: bookworm Date: Mon, 6 Apr 2026 19:48:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20pwsh7=E9=BB=98=E8=AE=A4=E7=BB=88?= =?UTF-8?q?=E7=AB=AF=20+=20Phase1=E4=BE=9D=E8=B5=96=E5=A2=9E=E5=BC=BA=20+?= =?UTF-8?q?=20Phase6=20MCP=E9=A2=84=E5=AE=89=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Phase 1: +PowerShell 7/Python 3.12/uv, pwsh升为核心依赖 - Phase 4: 修复缓存命中后仍弹密码框的逻辑缺陷 - Phase 5: 新增 {{PWSH_PATH}} 占位符渲染 - Phase 6: npm cache add + uv tool install 预缓存(超时保护) - Phase 7: Start-Process pwsh 独立窗口启动Claude - install.ps1: Render函数添加 {{PWSH_PATH}} + Start-Process启动 - OneClick.bat: 新增步骤4/8安装PowerShell 7 - 所有.bat: start pwsh新窗口模式 + CRLF修复 Co-Authored-By: Claude Opus 4.6 (1M context) --- Bookworm-AutoSetup.bat | 12 ++- Bookworm-OneClick.bat | 69 +++++++----- auto-setup.ps1 | 203 ++++++++++++++++++++++++++++++------ install.ps1 | 24 +++-- 启动Bookworm.bat | 19 ++-- 更新并启动Bookworm.bat | 20 ++-- 6 files changed, 260 insertions(+), 87 deletions(-) diff --git a/Bookworm-AutoSetup.bat b/Bookworm-AutoSetup.bat index 6ca9d51..fdf612e 100644 --- a/Bookworm-AutoSetup.bat +++ b/Bookworm-AutoSetup.bat @@ -58,16 +58,18 @@ echo. :: 更新到最新版本 git pull >nul 2>nul -:: 检测 PowerShell 7 (pwsh) 或退回 5.1 (powershell) +:: 检测 PowerShell 7 (pwsh): 新窗口启动, 退出 cmd where pwsh >nul 2>nul if %errorlevel% equ 0 ( echo [OK] 使用 PowerShell 7 - pwsh -ExecutionPolicy Bypass -File auto-setup.ps1 -) else ( - echo [..] 使用 PowerShell 5.1 - powershell -ExecutionPolicy Bypass -File auto-setup.ps1 + start "Bookworm 全自动安装" pwsh -NoLogo -ExecutionPolicy Bypass -File "%CD%\auto-setup.ps1" + exit ) +:: 回退 PowerShell 5.1 (auto-setup 会安装 pwsh7, Phase 7 再切换) +echo [..] PowerShell 7 未安装, 先用 5.1 执行安装 (将自动安装 pwsh7) +powershell -ExecutionPolicy Bypass -File auto-setup.ps1 + if %errorlevel% neq 0 ( echo. echo [!!] 安装过程中出现错误 diff --git a/Bookworm-OneClick.bat b/Bookworm-OneClick.bat index 305fe74..5b9f8ae 100644 --- a/Bookworm-OneClick.bat +++ b/Bookworm-OneClick.bat @@ -39,8 +39,8 @@ echo ^| ^| echo +============================================================+ echo. -:: ─── 步骤 1/7: winget 检测 ────────────────────────── -echo [1/7] 检测包管理器... +:: ─── 步骤 1/8: winget 检测 ────────────────────────── +echo [1/8] 检测包管理器... where winget >nul 2>nul if %errorlevel% neq 0 ( echo. @@ -58,8 +58,8 @@ if %errorlevel% neq 0 ( echo [OK] winget 可用 echo. -:: ─── 步骤 2/7: 安装 Git ──────────────────────────── -echo [2/7] 检查 Git... +:: ─── 步骤 2/8: 安装 Git ──────────────────────────── +echo [2/8] 检查 Git... where git >nul 2>nul if %errorlevel% neq 0 ( echo [..] Git 未安装, 正在通过 winget 安装... @@ -76,8 +76,8 @@ if %errorlevel% neq 0 ( ) echo. -:: ─── 步骤 3/7: 安装 Node.js ──────────────────────── -echo [3/7] 检查 Node.js... +:: ─── 步骤 3/8: 安装 Node.js ──────────────────────── +echo [3/8] 检查 Node.js... where node >nul 2>nul if %errorlevel% neq 0 ( echo [..] Node.js 未安装, 正在通过 winget 安装... @@ -94,6 +94,24 @@ if %errorlevel% neq 0 ( ) echo. +:: ─── 步骤 4/8: 安装 PowerShell 7 ──────────────────── +echo [4/8] 检查 PowerShell 7... +where pwsh >nul 2>nul +if %errorlevel% neq 0 ( + echo [..] PowerShell 7 未安装, 正在通过 winget 安装... + winget install Microsoft.PowerShell --accept-source-agreements --accept-package-agreements --silent + if !errorlevel! neq 0 ( + echo [!!] PowerShell 7 安装失败 + set /a ERRORS+=1 + ) else ( + echo [OK] PowerShell 7 安装成功 + set "NEED_PATH_REFRESH=1" + ) +) else ( + echo [OK] PowerShell 7 已安装 +) +echo. + :: ─── 刷新 PATH (新装软件需要) ──────────────────────── if "%NEED_PATH_REFRESH%"=="1" ( echo [..] 刷新系统 PATH... @@ -102,12 +120,12 @@ if "%NEED_PATH_REFRESH%"=="1" ( for /f "tokens=2*" %%a in ('reg query "HKCU\Environment" /v Path 2^>nul') do set "USR_PATH=%%b" set "PATH=!SYS_PATH!;!USR_PATH!" :: 同时添加常见 Node.js / Git 路径 - set "PATH=!PATH!;C:\Program Files\nodejs;C:\Program Files\Git\cmd;C:\Program Files\Git\usr\bin" + set "PATH=!PATH!;C:\Program Files\nodejs;C:\Program Files\Git\cmd;C:\Program Files\Git\usr\bin;C:\Program Files\PowerShell\7" echo [OK] PATH 已刷新 echo. ) -:: ─── 二次验证: Git + Node ──────────────────────────── +:: ─── 二次验证: Git + Node + pwsh ───────────────────── where git >nul 2>nul if %errorlevel% neq 0 ( echo [FATAL] Git 仍然不可用 @@ -122,9 +140,13 @@ if %errorlevel% neq 0 ( pause exit /b 1 ) +where pwsh >nul 2>nul +if %errorlevel% neq 0 ( + echo [WARN] PowerShell 7 未就绪, Claude Code 将使用 PowerShell 5.1 +) -:: ─── 步骤 4/7: 安装 Claude Code ───────────────────── -echo [4/7] 检查 Claude Code... +:: ─── 步骤 5/8: 安装 Claude Code ───────────────────── +echo [5/8] 检查 Claude Code... :: 国内 npm 镜像 - 淘宝源, 避免 npmjs.org 超时 call npm config set registry https://registry.npmmirror.com 2>nul where claude >nul 2>nul @@ -143,8 +165,8 @@ if %errorlevel% neq 0 ( ) echo. -:: ─── 步骤 5/7: 克隆/更新 Bookworm ────────────────── -echo [5/7] 同步 Bookworm 配置... +:: ─── 步骤 6/8: 克隆/更新 Bookworm ────────────────── +echo [6/8] 同步 Bookworm 配置... :: 配置 git credential helper (免重复输密码) git config --global credential.helper manager 2>nul @@ -175,8 +197,8 @@ if exist "%INSTALL_DIR%\.git" ( echo [OK] Bookworm 文件已就绪 echo. -:: ─── 步骤 6/7: 执行安装配置 ──────────────────────── -echo [6/7] 执行安装配置... +:: ─── 步骤 7/8: 执行安装配置 ──────────────────────── +echo [7/8] 执行安装配置... echo. if exist "%INSTALL_DIR%\install.ps1" ( @@ -192,8 +214,8 @@ if exist "%INSTALL_DIR%\install.ps1" ( ) echo. -:: ─── 步骤 7/7: 创建桌面快捷方式 + 完成 ────────────── -echo [7/7] 创建桌面快捷方式... +:: ─── 步骤 8/8: 创建桌面快捷方式 + 完成 ────────────── +echo [8/8] 创建桌面快捷方式... :: 用 PowerShell 创建快捷方式 powershell -ExecutionPolicy Bypass -Command ^ @@ -223,6 +245,7 @@ echo ^| ^| echo ^| 已安装: ^| echo ^| [v] Node.js LTS — JavaScript 运行时 ^| echo ^| [v] Git — 版本控制与配置同步 ^| +echo ^| [v] PowerShell 7 — 现代终端环境 ^| echo ^| [v] Claude Code — AI 编程助手 ^| echo ^| [v] Bookworm — 92 Skills / 18 Agents ^| echo ^| ^| @@ -243,17 +266,15 @@ if %ERRORS% gtr 0 ( echo 按任意键启动 Bookworm... pause > nul -:: 启动 +:: 启动 — 优先在 pwsh7 新窗口中运行 cd /d "%INSTALL_DIR%" -if exist "启动Bookworm.bat" ( +where pwsh >nul 2>nul +if !errorlevel! equ 0 ( + start "Bookworm Smart Assistant" pwsh -NoLogo -ExecutionPolicy Bypass -File "%INSTALL_DIR%\install.ps1" -StartOnly -AutoAccept +) else if exist "启动Bookworm.bat" ( call "启动Bookworm.bat" ) else ( - where pwsh >nul 2>nul - if !errorlevel! equ 0 ( - pwsh -NoLogo -ExecutionPolicy Bypass -File install.ps1 -StartOnly -AutoAccept - ) else ( - powershell -NoLogo -ExecutionPolicy Bypass -File install.ps1 -StartOnly -AutoAccept - ) + powershell -NoLogo -ExecutionPolicy Bypass -File "%INSTALL_DIR%\install.ps1" -StartOnly -AutoAccept ) endlocal diff --git a/auto-setup.ps1 b/auto-setup.ps1 index 6256448..3de8eaf 100644 --- a/auto-setup.ps1 +++ b/auto-setup.ps1 @@ -261,9 +261,11 @@ Log-Phase 1 "环境检测 + 依赖自动安装" $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") $deps = @( - @{ Name = "Node.js"; Cmd = "node"; WingetId = "OpenJS.NodeJS.LTS"; NpmPkg = $null } - @{ Name = "Git"; Cmd = "git"; WingetId = "Git.Git"; NpmPkg = $null } - @{ Name = "Claude Code"; Cmd = "claude"; WingetId = $null; NpmPkg = "@anthropic-ai/claude-code" } + @{ Name = "Node.js"; Cmd = "node"; WingetId = "OpenJS.NodeJS.LTS"; NpmPkg = $null; PipPkg = $null } + @{ Name = "Git"; Cmd = "git"; WingetId = "Git.Git"; NpmPkg = $null; PipPkg = $null } + @{ Name = "PowerShell 7"; Cmd = "pwsh"; WingetId = "Microsoft.PowerShell"; NpmPkg = $null; PipPkg = $null } + @{ Name = "Python 3.12"; Cmd = "python"; WingetId = "Python.Python.3.12"; NpmPkg = $null; PipPkg = $null } + @{ Name = "Claude Code"; Cmd = "claude"; WingetId = $null; NpmPkg = "@anthropic-ai/claude-code"; PipPkg = $null } ) $hasWinget = Test-Cmd "winget" @@ -318,20 +320,72 @@ if (-not (Test-Cmd "claude") -and (Test-Cmd "npm")) { if (Test-Cmd "claude") { Log-OK "Claude Code 安装成功" } else { Log-Fail "Claude Code 安装失败" } } +# uv 依赖 Python, 需要在 Python 安装后再检查 +if (Test-Cmd "python") { + if (Test-Cmd "uv") { + $uvVer = try { & uv --version 2>$null | Select-Object -First 1 } catch { "installed" } + Log-OK "uv $uvVer" + } else { + Log-Info "安装 uv (Python 包管理器)..." + try { + & python -m pip install uv --quiet 2>&1 | Select-Object -Last 2 | ForEach-Object { Write-Host " $_" -ForegroundColor Gray } + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") + # pip install 的 Scripts 目录可能不在 PATH, 追加 + $pyScripts = Join-Path (Split-Path (& python -c "import sys; print(sys.executable)") -Parent) "Scripts" + if (Test-Path $pyScripts) { $env:Path += ";$pyScripts" } + if (Test-Cmd "uv") { + Log-OK "uv 安装成功" + $installed += "uv" + } else { + Log-Warn "uv 安装后未找到, 尝试 uvx 替代检查..." + } + } catch { Log-Warn "uv 安装失败: $_" } + } +} else { + Log-Warn "Python 未安装, 跳过 uv (部分 MCP 不可用)" +} + # OpenSSL (随 Git 安装) $opensslCmd = Find-OpenSSL if ($opensslCmd) { Log-OK "OpenSSL: $opensslCmd" } else { Log-Warn "OpenSSL 未找到 (凭证解密可能失败)" } -# 最终检查 -if (-not (Test-Cmd "node") -or -not (Test-Cmd "git") -or -not (Test-Cmd "claude")) { +# 最终检查 (核心四件套必须) +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 "pwsh")) { $missing += "PowerShell 7" } if (-not (Test-Cmd "claude")) { $missing += "Claude Code" } - Show-MsgBox "以下依赖安装失败: $($missing -join ', ')`n`n请手动安装后重新运行。" "安装中断" "OK" "Error" + Show-MsgBox "以下核心依赖安装失败: $($missing -join ', ')`n`n请手动安装后重新运行。" "安装中断" "OK" "Error" exit 1 } +# 定位 pwsh.exe 完整路径 (供后续 settings.json 配置使用) +$PwshPath = (Get-Command pwsh -ErrorAction SilentlyContinue).Source +if (-not $PwshPath) { + # winget 默认安装路径 + $defaultPaths = @( + "$env:ProgramFiles\PowerShell\7\pwsh.exe", + "${env:ProgramFiles(x86)}\PowerShell\7\pwsh.exe", + "$env:LOCALAPPDATA\Microsoft\PowerShell\pwsh.exe" + ) + $PwshPath = $defaultPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 +} +if ($PwshPath) { + Log-OK "PowerShell 7 路径: $PwshPath" +} else { + Log-Warn "pwsh 可执行但无法定位完整路径, 使用 'pwsh'" + $PwshPath = "pwsh" +} + +# 可选依赖警告 (不阻断) +$optionalMissing = @() +if (-not (Test-Cmd "python")) { $optionalMissing += "Python 3.12" } +if (-not (Test-Cmd "uv")) { $optionalMissing += "uv" } +if ($optionalMissing.Count -gt 0) { + Log-Warn "可选依赖未就绪: $($optionalMissing -join ', ') (部分 MCP 不可用)" +} + if ($installed.Count -gt 0) { Log-OK "本次新安装: $($installed -join ', ')" } @@ -530,7 +584,8 @@ if (Get-CachedSecrets) { Log-OK "从本日缓存加载凭证 (免密)" $secretsDecrypted = $true } -# 再解密 +# 再解密 (缓存命中则跳过) +if (-not $secretsDecrypted) { $cryptoHelper = Join-Path $ScriptDir "crypto-helper.js" $useNode = (Test-Cmd "node") -and (Test-Path $cryptoHelper) if (-not $useNode -and -not $opensslCmd) { @@ -596,6 +651,7 @@ elseif (Test-Path $SecretsEnc) { elseif (-not (Test-Path $SecretsEnc)) { Log-Warn "secrets.enc 不存在, 跳过凭证解密" } +} # end if (-not $secretsDecrypted) # ======================================================================== # Phase 5: 配置渲染 @@ -608,13 +664,16 @@ $settingsFile = Join-Path $ClaudeDir "settings.json" if (Test-Path $templateFile) { $claudeRoot = $ClaudeDir.Replace('\', '/') $homeDir = $env:USERPROFILE + # pwsh 路径转正斜杠供 JSON 使用 (C:/Program Files/PowerShell/7/pwsh.exe) + $pwshJsonPath = if ($PwshPath) { $PwshPath.Replace('\', '/') } else { "pwsh" } $content = Get-Content $templateFile -Raw $content = $content -replace '\{\{CLAUDE_ROOT\}\}', $claudeRoot $content = $content -replace '\{\{HOME\}\}', ($homeDir -replace '\\', '\\') + $content = $content -replace '\{\{PWSH_PATH\}\}', ($pwshJsonPath -replace '\\', '\\') Set-Content $settingsFile -Value $content -Encoding UTF8 - Log-OK "settings.json 已渲染 (ROOT=$claudeRoot)" + Log-OK "settings.json 已渲染 (ROOT=$claudeRoot, SHELL=$pwshJsonPath)" # settings.local.template.json $localTpl = Join-Path $ClaudeDir "settings.local.template.json" @@ -624,6 +683,7 @@ if (Test-Path $templateFile) { $lc = $lc -replace '\{\{CLAUDE_ROOT\}\}', $claudeRoot $lc = $lc -replace '\{\{HOME\}\}', ($homeDir -replace '\\', '\\') $lc = $lc -replace '\{\{USERNAME\}\}', $env:USERNAME + $lc = $lc -replace '\{\{PWSH_PATH\}\}', ($pwshJsonPath -replace '\\', '\\') Set-Content $localSet -Value $lc -Encoding UTF8 Log-OK "settings.local.json 已渲染" } @@ -636,9 +696,9 @@ $env:CLAUDE_HOME = $ClaudeDir # ======================================================================== # Phase 6: MCP 验证 + 自动安装 # ======================================================================== -Log-Phase 6 "MCP 服务验证" +Log-Phase 6 "MCP 服务验证 + 预安装" -# Bookworm 完整性 +# ── 6a: Bookworm 完整性检查 ── $skillCount = 0; $hookCount = 0 $skillsDir = Join-Path $ClaudeDir "skills" $hooksDir = Join-Path $ClaudeDir "hooks" @@ -670,44 +730,114 @@ foreach ($c in $checks) { if ($c.OK) { Log-OK $c.Name } else { Log-Fail $c.Name; $allOK = $false } } -# API Key 检查 +# ── 6b: API 凭证检查 ── Write-Host "" Log-Info "API 凭证检查..." if ($env:ANTHROPIC_API_KEY) { Log-OK "ANTHROPIC_API_KEY 已配置" } else { Log-Fail "ANTHROPIC_API_KEY 未配置" } if ($env:ANTHROPIC_BASE_URL) { Log-OK "ANTHROPIC_BASE_URL 已配置" } else { Log-Warn "ANTHROPIC_BASE_URL 未配置 (将使用默认)" } -# MCP 依赖自动安装 +# ── 6c: MCP npx 包预缓存 ── Write-Host "" -Log-Info "MCP 依赖检查..." +Log-Info "MCP 预安装 (npx 包预缓存)..." -# Playwright -$hasPlaywright = $false -try { - $pwCheck = npm list -g @anthropic-ai/mcp-playwright 2>$null - if ($pwCheck -and $pwCheck -notmatch 'empty') { $hasPlaywright = $true } -} catch {} +# Tier 1: 纯 npx, 无需 Key +$npxPackages = @( + @{ Name = "context7"; Pkg = "@upstash/context7-mcp@2.1.1" } + @{ Name = "sequential-thinking"; Pkg = "@modelcontextprotocol/server-sequential-thinking@2025.12.18" } + @{ Name = "playwright"; Pkg = "@playwright/mcp@0.0.68" } + @{ Name = "session-continuity"; Pkg = "claude-session-continuity-mcp@1.13.0" } + @{ Name = "notebooklm"; Pkg = "notebooklm-mcp@latest" } + @{ Name = "cloudflare-docs"; Pkg = "mcp-remote" } + @{ Name = "chrome-devtools"; Pkg = "chrome-devtools-mcp@0.18.1" } + # Tier 2: npx + Key + @{ Name = "github"; Pkg = "@modelcontextprotocol/server-github" } + @{ Name = "slack"; Pkg = "@modelcontextprotocol/server-slack" } + @{ Name = "firecrawl"; Pkg = "firecrawl-mcp" } + @{ Name = "mcp-image"; Pkg = "mcp-image" } + @{ Name = "google-drive"; Pkg = "@piotr-agier/google-drive-mcp" } +) -if ($hasPlaywright) { - Log-OK "Playwright MCP 已安装" -} else { - Log-Info "安装 Playwright MCP..." +$mcpOK = 0; $mcpFail = 0 +foreach ($mcp in $npxPackages) { + $idx = $mcpOK + $mcpFail + 1 + Write-Host " [$idx/$($npxPackages.Count)] $($mcp.Name) " -NoNewline -ForegroundColor Gray try { - npm i -g @anthropic-ai/mcp-playwright 2>&1 | Select-Object -Last 2 | ForEach-Object { Write-Host " $_" -ForegroundColor Gray } - Log-OK "Playwright MCP 安装完成" - } catch { Log-Warn "Playwright MCP 安装失败 (不影响核心功能)" } + # npm cache add 只下载到缓存, 不执行 (MCP 是 stdio 长驻进程, 不能用 --help) + $proc = Start-Process npm.cmd -ArgumentList "cache", "add", $mcp.Pkg -NoNewWindow -PassThru -RedirectStandardOutput "NUL" -RedirectStandardError "NUL" + $exited = $proc.WaitForExit(60000) # 60 秒超时 + if (-not $exited) { $proc.Kill(); throw "timeout" } + if ($proc.ExitCode -eq 0) { + Write-Host "[cached]" -ForegroundColor Green + $mcpOK++ + } else { throw "exit $($proc.ExitCode)" } + } catch { + Write-Host "[FAIL: $_]" -ForegroundColor Red + $mcpFail++ + } +} +Log-OK "npx 预缓存: $mcpOK 成功, $mcpFail 失败 (共 $($npxPackages.Count))" + +# ── 6d: Playwright 浏览器安装 ── +Write-Host "" +Log-Info "Playwright 浏览器安装..." +try { + $pwBrowserPath = Join-Path $env:USERPROFILE "AppData\Local\ms-playwright" + if (Test-Path (Join-Path $pwBrowserPath "chromium-*")) { + Log-OK "Playwright Chromium 已存在" + } else { + Write-Host " 下载 Chromium (首次约 150MB, 最长等 5 分钟)..." -ForegroundColor Gray + $pwProc = Start-Process npx.cmd -ArgumentList "-y", "playwright", "install", "chromium" -NoNewWindow -PassThru + $pwExited = $pwProc.WaitForExit(300000) # 5 分钟超时 + if (-not $pwExited) { $pwProc.Kill(); Log-Warn "Playwright 下载超时, 跳过" } + elseif (Test-Path (Join-Path $pwBrowserPath "chromium-*")) { + Log-OK "Playwright Chromium 安装成功" + } else { + Log-Warn "Playwright Chromium 安装可能未完成" + } + } +} catch { Log-Warn "Playwright 浏览器安装失败: $_ (不影响核心功能)" } + +# ── 6e: Python MCP (uvx) 验证 ── +Write-Host "" +if (Test-Cmd "uvx") { + Log-Info "Python MCP 验证 (uvx)..." + + $uvxPackages = @( + @{ Name = "windows-mcp"; Args = @("--python", "3.13", "windows-mcp") } + @{ Name = "atlassian"; Args = @("mcp-atlassian") } + ) + + foreach ($pkg in $uvxPackages) { + Write-Host " $($pkg.Name) " -NoNewline -ForegroundColor Gray + try { + # uv tool install 只下载不启动 (MCP 是 stdio 长驻进程, --help 会挂起) + $installArgs = @("tool", "install") + $pkg.Args + $proc = Start-Process uv -ArgumentList $installArgs -NoNewWindow -PassThru -RedirectStandardOutput "NUL" -RedirectStandardError "NUL" + $exited = $proc.WaitForExit(90000) # 90 秒超时 (Python 包较大) + if (-not $exited) { $proc.Kill(); throw "timeout" } + Write-Host "[ready]" -ForegroundColor Green + } catch { + Write-Host "[skip: $_]" -ForegroundColor Yellow + } + } +} else { + Log-Warn "uvx 不可用, 跳过 Python MCP (windows-mcp, atlassian)" } -# 可选 API Key 提示 +# ── 6f: 可选 API Key 提示 ── $optional = @( @{ Key = "GITHUB_PERSONAL_ACCESS_TOKEN"; Name = "GitHub MCP" } @{ Key = "FIRECRAWL_API_KEY"; Name = "Firecrawl MCP" } @{ Key = "SLACK_BOT_TOKEN"; Name = "Slack MCP" } + @{ Key = "BROWSERBASE_API_KEY"; Name = "Browserbase MCP" } + @{ Key = "GEMINI_API_KEY"; Name = "MCP Image / Browserbase" } + @{ Key = "ATLASSIAN_API_TOKEN"; Name = "Atlassian MCP" } ) $missingOpt = $optional | Where-Object { -not [System.Environment]::GetEnvironmentVariable($_.Key, "Process") } if ($missingOpt.Count -gt 0) { Write-Host "" - Write-Host " 可选 MCP (未配置, 不影响核心功能):" -ForegroundColor DarkGray - foreach ($m in $missingOpt) { Write-Host " [-] $($m.Name)" -ForegroundColor DarkGray } + Write-Host " 可选 MCP (Key 未配置, 不影响核心功能):" -ForegroundColor DarkGray + foreach ($m in $missingOpt) { Write-Host " [-] $($m.Name) ($($m.Key))" -ForegroundColor DarkGray } } # ======================================================================== @@ -733,7 +863,13 @@ if ($allOK -and $env:ANTHROPIC_API_KEY) { Write-Host "" Log-Info "正在启动 Claude Code..." Write-Host "" - & claude + # 始终在独立 pwsh7 窗口中启动 (bat 调 pwsh 子进程时窗口仍属 cmd.exe) + $pwshCmd = Get-Command pwsh -ErrorAction SilentlyContinue + if ($pwshCmd) { + Start-Process $pwshCmd.Source -ArgumentList "-NoLogo", "-NoExit", "-Command", "& claude" -WorkingDirectory $env:USERPROFILE -WindowStyle Normal + } else { + & claude + } } } else { Write-Host " +---------------------------------------------------+" -ForegroundColor Yellow @@ -749,6 +885,11 @@ if ($allOK -and $env:ANTHROPIC_API_KEY) { $launchResult = Show-MsgBox "安装完成, 但存在以下问题:`n$issueText`n`n是否仍然启动 Claude Code?`n(将以受限模式运行)" "安装警告" "YesNo" "Warning" if ($launchResult -eq "Yes" -and -not $SkipLaunch) { - & claude + $pwshCmd = Get-Command pwsh -ErrorAction SilentlyContinue + if ($pwshCmd) { + Start-Process $pwshCmd.Source -ArgumentList "-NoLogo", "-NoExit", "-Command", "& claude" -WorkingDirectory $env:USERPROFILE -WindowStyle Normal + } else { + & claude + } } } diff --git a/install.ps1 b/install.ps1 index 1cedc82..baac3ca 100644 --- a/install.ps1 +++ b/install.ps1 @@ -257,22 +257,26 @@ function Render-SettingsTemplate { } $claudeRoot = $ClaudeTarget.Replace('\', '/') - # HOME 保留反斜杠格式,与 Claude Code 原始行为一致 - $homeDir = $env:USERPROFILE + $homeDir = $env:USERPROFILE.Replace('\', '/') + # 定位 pwsh 路径 (正斜杠供 JSON) + $pwshExe = (Get-Command pwsh -ErrorAction SilentlyContinue) + $pwshJsonPath = if ($pwshExe) { $pwshExe.Source.Replace('\', '/') } else { "pwsh" } $content = Get-Content $TemplateFile -Raw $content = $content -replace '\{\{CLAUDE_ROOT\}\}', $claudeRoot - $content = $content -replace '\{\{HOME\}\}', ($homeDir -replace '\\', '\\') + $content = $content -replace '\{\{HOME\}\}', $homeDir + $content = $content -replace '\{\{PWSH_PATH\}\}', $pwshJsonPath Set-Content $SettingsFile -Value $content -Encoding UTF8 - Write-Host " [OK] settings.json 已渲染 (ROOT=$claudeRoot)" -ForegroundColor Green + Write-Host " [OK] settings.json 已渲染 (ROOT=$claudeRoot, SHELL=$pwshJsonPath)" -ForegroundColor Green # 渲染 settings.local.template.json (如果存在) if (Test-Path $LocalTplFile) { $localContent = Get-Content $LocalTplFile -Raw $localContent = $localContent -replace '\{\{CLAUDE_ROOT\}\}', $claudeRoot - $localContent = $localContent -replace '\{\{HOME\}\}', ($homeDir -replace '\\', '\\') + $localContent = $localContent -replace '\{\{HOME\}\}', $homeDir $localContent = $localContent -replace '\{\{USERNAME\}\}', $env:USERNAME + $localContent = $localContent -replace '\{\{PWSH_PATH\}\}', $pwshJsonPath Set-Content $LocalSetFile -Value $localContent -Encoding UTF8 Write-Host " [OK] settings.local.json 已渲染" -ForegroundColor Green } @@ -723,4 +727,12 @@ if (-not $StartOnly) { } } -& claude +# 始终在独立 pwsh7 窗口中启动 Claude Code +# (bat 调 pwsh 子进程时窗口仍属 cmd.exe, 必须 Start-Process 新建窗口) +$pwshCmd = Get-Command pwsh -ErrorAction SilentlyContinue +if ($pwshCmd) { + Write-Host " [..] 正在启动 Claude Code (PowerShell 7)..." -ForegroundColor Cyan + Start-Process $pwshCmd.Source -ArgumentList "-NoLogo", "-NoExit", "-Command", "& claude" -WorkingDirectory $env:USERPROFILE -WindowStyle Normal +} else { + & claude +} diff --git a/启动Bookworm.bat b/启动Bookworm.bat index 082db7e..6add78d 100644 --- a/启动Bookworm.bat +++ b/启动Bookworm.bat @@ -1,25 +1,24 @@ @echo off chcp 65001 > nul -title Bookworm Portable - 启动 cd /d "%~dp0" :: 中转站在国内,不走代理 set NO_PROXY=bww.letcareme.com,code.letcareme.com,letcareme.com,localhost,127.0.0.1 set no_proxy=%NO_PROXY% -echo. -echo ==================================== -echo Bookworm Portable - 快速启动 -echo ==================================== -echo. - +:: 优先 pwsh7: 启动新 PowerShell 7 窗口, 退出 cmd where pwsh >nul 2>nul if %errorlevel% equ 0 ( - pwsh -ExecutionPolicy Bypass -File install.ps1 -StartOnly -AutoAccept -) else ( - powershell -ExecutionPolicy Bypass -File install.ps1 -StartOnly -AutoAccept + start "Bookworm Smart Assistant" pwsh -NoLogo -ExecutionPolicy Bypass -File "%~dp0install.ps1" -StartOnly -AutoAccept + exit ) +:: 回退 PowerShell 5.1 +title Bookworm Portable +echo. +echo [!] PowerShell 7 未安装, 使用 PowerShell 5.1 +echo. +powershell -ExecutionPolicy Bypass -File install.ps1 -StartOnly -AutoAccept if %errorlevel% neq 0 ( echo. echo 启动失败,按任意键退出... diff --git a/更新并启动Bookworm.bat b/更新并启动Bookworm.bat index de8ea0f..8fadce5 100644 --- a/更新并启动Bookworm.bat +++ b/更新并启动Bookworm.bat @@ -1,26 +1,24 @@ @echo off chcp 65001 > nul -title Bookworm Portable - 更新并启动 cd /d "%~dp0" :: 中转站在国内,不走代理 set NO_PROXY=bww.letcareme.com,code.letcareme.com,letcareme.com,localhost,127.0.0.1 set no_proxy=%NO_PROXY% -echo. -echo ==================================== -echo Bookworm Portable - 更新并启动 -echo (同步最新 Skills/Hooks 后启动) -echo ==================================== -echo. - +:: 优先 pwsh7: 启动新 PowerShell 7 窗口, 退出 cmd where pwsh >nul 2>nul if %errorlevel% equ 0 ( - pwsh -ExecutionPolicy Bypass -File install.ps1 -AutoAccept -) else ( - powershell -ExecutionPolicy Bypass -File install.ps1 -AutoAccept + start "Bookworm - 更新并启动" pwsh -NoLogo -ExecutionPolicy Bypass -File "%~dp0install.ps1" -AutoAccept + exit ) +:: 回退 PowerShell 5.1 +title Bookworm Portable - 更新并启动 +echo. +echo [!] PowerShell 7 未安装, 使用 PowerShell 5.1 +echo. +powershell -ExecutionPolicy Bypass -File install.ps1 -AutoAccept if %errorlevel% neq 0 ( echo. echo 启动失败,按任意键退出...