Private
Public Access
1
0

feat: 重构 setup.ps1 为一站式安装配置脚本

- 新增包管理器检测(Node.js/npm 和 Bun)
- 新增 Bun 安装引导功能
- 新增工具安装功能(通过 npm/bun 安装 CLI 工具)
- 支持从远程下载并执行配置脚本
- 移除 Claude Code 配置中的默认 model 设置
This commit is contained in:
2025-12-05 18:38:34 +08:00
parent 13c6e92df6
commit badf8e6bb6
7 changed files with 294 additions and 85 deletions

297
setup.ps1
View File

@@ -1,92 +1,305 @@
# XCodeCLI Setup Launcher (Windows)
# Interactive script to configure Claude Code, Gemini CLI, or Codex
# 一站式安装和配置 Claude Code, Gemini CLI, Codex
param(
[string]$ApiKey,
[switch]$Help
)
# 支持一行命令传入 API Key: $key='xxx'; iwr ... | iex
if (-not $ApiKey -and (Test-Path Variable:key)) { $ApiKey = $key }
# ========== 颜色输出函数 ==========
function Write-Info { param([string]$Message); Write-Host "[INFO]" -ForegroundColor Blue -NoNewline; Write-Host " $Message" }
function Write-Success { param([string]$Message); Write-Host "[SUCCESS]" -ForegroundColor Green -NoNewline; Write-Host " $Message" }
function Write-Warning { param([string]$Message); Write-Host "[WARNING]" -ForegroundColor Yellow -NoNewline; Write-Host " $Message" }
function Write-Error { param([string]$Message); Write-Host "[ERROR]" -ForegroundColor Red -NoNewline; Write-Host " $Message" }
# ========== 工具配置表 ==========
$ToolsConfig = @{
1 = @{
Name = "Claude Code"
Command = "claude"
Package = "@anthropic-ai/claude-code"
SetupUrl = "https://gitea.sususu.cf/sususu/xcodecli-shells/raw/branch/main/ClaudeCode/setup-claude-code.ps1"
}
2 = @{
Name = "Gemini CLI"
Command = "gemini"
Package = "@google/gemini-cli@latest"
SetupUrl = "https://gitea.sususu.cf/sususu/xcodecli-shells/raw/branch/main/GeminiCLI/setup-gemini.ps1"
}
3 = @{
Name = "Codex"
Command = "codex"
Package = "@openai/codex"
SetupUrl = "https://gitea.sususu.cf/sususu/xcodecli-shells/raw/branch/main/codex/setup-codex.ps1"
}
}
# ========== 帮助信息 ==========
function Show-Help {
Write-Host @"
XCodeCLI Setup Launcher (Windows)
Claude Code, Gemini CLI, Codex
Usage: powershell -ExecutionPolicy Bypass -File setup.ps1 [OPTIONS]
Options:
-ApiKey <KEY> Pre-set the API key
-Help Show this help message
-ApiKey <KEY> API
-Help
使:
`$key='YOUR_API_KEY'; iwr -useb https://gitea.sususu.cf/sususu/xcodecli-shells/raw/branch/main/setup.ps1 | iex
"@
exit 0
}
function Test-Command { param([string]$Name); return [bool](Get-Command $Name -ErrorAction SilentlyContinue) }
# ========== 工具函数 ==========
function Test-Command {
param([string]$Name)
return [bool](Get-Command $Name -ErrorAction SilentlyContinue)
}
function Refresh-Path {
$env:Path = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine")
}
# ========== 包管理器检测 ==========
function Get-PackageManager {
# 优先检测 Node.js/npm
if (Test-Command "node") {
try {
$nodeVersion = (& node --version 2>$null) -replace 'v', ''
Write-Info "检测到 Node.js v$nodeVersion"
return @{ Type = "npm"; Cmd = "npm install -g" }
}
catch { }
}
# 其次检测 Bun
if (Test-Command "bun") {
try {
$bunVersion = & bun --version 2>$null
Write-Info "检测到 Bun v$bunVersion"
return @{ Type = "bun"; Cmd = "bun add -g" }
}
catch { }
}
return $null
}
# ========== Bun 安装引导 ==========
function Install-Bun {
Write-Host ""
Write-Warning "未检测到 Node.js 或 Bun"
Write-Info "推荐安装 Bun轻量级 JavaScript 运行时)"
Write-Host ""
Write-Host " 安装命令: " -NoNewline
Write-Host 'powershell -c "irm bun.sh/install.ps1|iex"' -ForegroundColor Cyan
Write-Host ""
Write-Host " 要求: Windows 10 version 1809 或更高" -ForegroundColor Gray
Write-Host ""
$install = Read-Host "是否立即安装 Bun? (Y/n)"
if ($install -eq "n" -or $install -eq "N") {
return $false
}
Write-Info "正在安装 Bun..."
try {
Invoke-Expression 'irm bun.sh/install.ps1 | iex'
Refresh-Path
if (Test-Command "bun") {
Write-Success "Bun 安装成功!"
return $true
}
else {
Write-Warning "Bun 可能已安装,但需要重新打开终端才能生效"
Write-Info "请重新打开 PowerShell 后再运行此脚本"
return $false
}
}
catch {
Write-Error "Bun 安装失败: $($_.Exception.Message)"
return $false
}
}
# ========== 工具安装 ==========
function Install-Tool {
param(
[hashtable]$Tool
)
# 获取包管理器
$pm = Get-PackageManager
if (-not $pm) {
if (-not (Install-Bun)) {
return $false
}
Refresh-Path
$pm = Get-PackageManager
if (-not $pm) {
Write-Error "仍未检测到可用的包管理器"
return $false
}
}
Write-Info "使用 $($pm.Type) 安装 $($Tool.Name)..."
$installCmd = "$($pm.Cmd) $($Tool.Package)"
Write-Host " 执行: $installCmd" -ForegroundColor Gray
try {
Invoke-Expression $installCmd
$exitCode = $LASTEXITCODE
Refresh-Path
# 检查安装命令退出码
if ($exitCode -ne 0) {
Write-Error "安装命令返回错误码: $exitCode"
return $false
}
if (Test-Command $Tool.Command) {
Write-Success "$($Tool.Name) 安装成功!"
return $true
}
else {
Write-Warning "$($Tool.Name) 可能已安装,但需要重新打开终端才能生效"
$continue = Read-Host "是否继续进行配置? (Y/n)"
return ($continue -ne "n" -and $continue -ne "N")
}
}
catch {
Write-Error "安装失败: $($_.Exception.Message)"
return $false
}
}
# ========== 远程配置脚本调用 ==========
function Invoke-RemoteSetup {
param(
[hashtable]$Tool,
[string]$ApiKey
)
Write-Host ""
Write-Info "下载并执行 $($Tool.Name) 配置脚本..."
Write-Host " URL: $($Tool.SetupUrl)" -ForegroundColor Gray
Write-Host ""
$tempFile = $null
try {
# 下载脚本到临时文件
$tempFile = [System.IO.Path]::ChangeExtension([System.IO.Path]::GetTempFileName(), ".ps1")
Invoke-WebRequest -Uri $Tool.SetupUrl -UseBasicParsing -OutFile $tempFile
# 执行脚本,正确传递参数
$LASTEXITCODE = 0
if ($ApiKey) {
& $tempFile -ApiKey $ApiKey
}
else {
& $tempFile
}
$scriptSucceeded = $?
$exitCode = $LASTEXITCODE
# 清理临时文件
Remove-Item $tempFile -ErrorAction SilentlyContinue
# 检查执行结果
if (-not $scriptSucceeded -or $exitCode -ne 0) {
Write-Error "配置脚本执行失败,退出码: $exitCode"
return $false
}
Write-Host ""
Write-Success "$($Tool.Name) 配置完成!"
return $true
}
catch {
if ($tempFile) { Remove-Item $tempFile -ErrorAction SilentlyContinue }
Write-Error "配置脚本执行失败: $($_.Exception.Message)"
return $false
}
}
# ========== 菜单显示 ==========
function Show-Menu {
$claudeStatus = if (Test-Command "claude") { "[已安装]" } else { "[未安装]" }
$geminiStatus = if (Test-Command "gemini") { "[已安装]" } else { "[未安装]" }
$codexStatus = if (Test-Command "codex") { "[已安装]" } else { "[未安装]" }
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " XCodeCLI Setup Launcher" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Select the tool to configure:" -ForegroundColor Yellow
Write-Host "选择要安装和配置的工具:" -ForegroundColor Yellow
Write-Host ""
$claudeColor = if (Test-Command "claude") { "Green" } else { "Red" }
$geminiColor = if (Test-Command "gemini") { "Green" } else { "Red" }
$codexColor = if (Test-Command "codex") { "Green" } else { "Red" }
Write-Host " [1] Claude Code " -NoNewline; Write-Host $claudeStatus -ForegroundColor $claudeColor
Write-Host " [2] Gemini CLI " -NoNewline; Write-Host $geminiStatus -ForegroundColor $geminiColor
Write-Host " [3] Codex " -NoNewline; Write-Host $codexStatus -ForegroundColor $codexColor
Write-Host ""
Write-Host " [0] Exit" -ForegroundColor Gray
Write-Host ""
}
function Get-ScriptPath {
param([int]$Choice)
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { "." }
switch ($Choice) {
1 { @("$scriptDir\ClaudeCode\setup-claude-code.ps1", "$scriptDir\setup-claude-code.ps1") | Where-Object { Test-Path $_ } | Select-Object -First 1 }
2 { "$scriptDir\GeminiCLI\setup-gemini.ps1" }
3 { "$scriptDir\codex\setup-codex.ps1" }
foreach ($key in ($ToolsConfig.Keys | Sort-Object)) {
$tool = $ToolsConfig[$key]
$installed = Test-Command $tool.Command
$status = if ($installed) { "[已安装]" } else { "[未安装]" }
$color = if ($installed) { "Green" } else { "Red" }
$label = " [$key] $($tool.Name.PadRight(12))"
Write-Host "$label " -NoNewline
Write-Host $status -ForegroundColor $color
}
Write-Host ""
Write-Host " [0] 退出" -ForegroundColor Gray
Write-Host ""
}
# ========== 主函数 ==========
function Main {
if ($Help) { Show-Help }
Show-Menu
$choice = Read-Host "Enter your choice (0-3)"
$choice = Read-Host "请选择 (0-3)"
if ($choice -eq "0") { Write-Info "Goodbye!"; exit 0 }
# 退出选项
if ($choice -eq "0") {
Write-Info "再见!"
exit 0
}
$choiceNum = [int]$choice
if ($choiceNum -lt 1 -or $choiceNum -gt 3) { Write-Error "Invalid choice."; exit 1 }
$scriptPath = Get-ScriptPath -Choice $choiceNum
if (-not $scriptPath -or -not (Test-Path $scriptPath)) {
$toolNames = @{ 1 = "Claude Code"; 2 = "Gemini CLI"; 3 = "Codex" }
Write-Error "Setup script for $($toolNames[$choiceNum]) not found."
# 验证选择
$choiceNum = 0
if (-not [int]::TryParse($choice, [ref]$choiceNum) -or $choiceNum -lt 1 -or $choiceNum -gt 3) {
Write-Error "无效的选择"
exit 1
}
Write-Host ""
Write-Info "Launching: $scriptPath"
Write-Host ""
$tool = $ToolsConfig[$choiceNum]
if ($ApiKey) { & $scriptPath -ApiKey $ApiKey } else { & $scriptPath }
# 检测是否已安装
if (-not (Test-Command $tool.Command)) {
Write-Host ""
Write-Warning "$($tool.Name) 未安装"
$install = Read-Host "是否立即安装? (Y/n)"
if ($install -eq "n" -or $install -eq "N") {
Write-Info "已取消"
exit 0
}
if (-not (Install-Tool -Tool $tool)) {
exit 1
}
}
else {
Write-Host ""
Write-Success "$($tool.Name) 已安装"
}
# 调用远程配置脚本
if (-not (Invoke-RemoteSetup -Tool $tool -ApiKey $ApiKey)) {
exit 1
}
}
Main