# XCodeCLI Setup Launcher (Windows) # 一站式安装和配置 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 预设 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 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 { Write-Host "" Write-Host "========================================" -ForegroundColor Cyan Write-Host " XCodeCLI Setup Launcher" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" Write-Host "选择要安装和配置的工具:" -ForegroundColor Yellow Write-Host "" 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 "请选择 (0-3)" # 退出选项 if ($choice -eq "0") { Write-Info "再见!" exit 0 } # 验证选择 $choiceNum = 0 if (-not [int]::TryParse($choice, [ref]$choiceNum) -or $choiceNum -lt 1 -or $choiceNum -gt 3) { Write-Error "无效的选择" exit 1 } $tool = $ToolsConfig[$choiceNum] # 检测是否已安装 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