From badf8e6bb6bd3a918ce264ad6e6c3935c0c7a497 Mon Sep 17 00:00:00 2001 From: sususu Date: Fri, 5 Dec 2025 18:38:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=20setup.ps1=20?= =?UTF-8?q?=E4=B8=BA=E4=B8=80=E7=AB=99=E5=BC=8F=E5=AE=89=E8=A3=85=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增包管理器检测(Node.js/npm 和 Bun) - 新增 Bun 安装引导功能 - 新增工具安装功能(通过 npm/bun 安装 CLI 工具) - 支持从远程下载并执行配置脚本 - 移除 Claude Code 配置中的默认 model 设置 --- ClaudeCode/setup-claude-code.ps1 | 1 - ClaudeCode/setup-claude-code.sh | 3 +- codex/setup-codex.ps1 | 24 +-- codex/setup-codex.sh | 50 +++--- setup-claude-code.ps1 | 1 - setup-claude-code.sh | 3 +- setup.ps1 | 297 ++++++++++++++++++++++++++----- 7 files changed, 294 insertions(+), 85 deletions(-) diff --git a/ClaudeCode/setup-claude-code.ps1 b/ClaudeCode/setup-claude-code.ps1 index 7802a96..e839536 100644 --- a/ClaudeCode/setup-claude-code.ps1 +++ b/ClaudeCode/setup-claude-code.ps1 @@ -167,7 +167,6 @@ function New-Settings { DISABLE_ERROR_REPORTING = 1 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = 1 } - model = "sonnet" } try { diff --git a/ClaudeCode/setup-claude-code.sh b/ClaudeCode/setup-claude-code.sh index a68bc0d..9a6dfa7 100644 --- a/ClaudeCode/setup-claude-code.sh +++ b/ClaudeCode/setup-claude-code.sh @@ -141,8 +141,7 @@ create_settings() { "DISABLE_TELEMETRY": 1, "DISABLE_ERROR_REPORTING": 1, "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1 - }, - "model": "sonnet" + } }') # Validate JSON diff --git a/codex/setup-codex.ps1 b/codex/setup-codex.ps1 index 8c8303d..c864933 100644 --- a/codex/setup-codex.ps1 +++ b/codex/setup-codex.ps1 @@ -163,15 +163,15 @@ function New-Settings { ) $config = @" -model_provider = "apirouter" -model = "gpt-5-codex" +model_provider = "xcodecli" +model = "gpt-5.1-codex" model_reasoning_effort = "high" -[model_providers.apirouter] -name = "apirouter" +[model_providers.xcodecli] +name = "xcodecli" base_url = "$BaseUrl/v1" wire_api = "responses" -env_key = "APIROUTER_API_KEY" +env_key = "XCODECLI_API_KEY" "@ try { @@ -199,7 +199,7 @@ function Show-Settings { Write-Host "" Write-Info "Current environment variables:" Write-Host "----------------------------------------" - $apirouterKey = [Environment]::GetEnvironmentVariable("APIROUTER_API_KEY", [EnvironmentVariableTarget]::User) + $apirouterKey = [Environment]::GetEnvironmentVariable("XCODECLI_API_KEY", [EnvironmentVariableTarget]::User) if ($apirouterKey) { $maskedKey = if ($apirouterKey.Length -gt 12) { @@ -207,9 +207,9 @@ function Show-Settings { } else { "$($apirouterKey.Substring(0, [Math]::Min(4, $apirouterKey.Length)))..." } - Write-Info "APIROUTER_API_KEY: $maskedKey" + Write-Info "XCODECLI_API_KEY: $maskedKey" } else { - Write-Info "APIROUTER_API_KEY: (not set)" + Write-Info "XCODECLI_API_KEY: (not set)" } Write-Host "----------------------------------------" } @@ -307,17 +307,17 @@ function Main { Write-Info "Setting environment variables..." try { # Set user environment variables (persistent across sessions) - [Environment]::SetEnvironmentVariable("APIROUTER_API_KEY", $ApiKey, [EnvironmentVariableTarget]::User) + [Environment]::SetEnvironmentVariable("XCODECLI_API_KEY", $ApiKey, [EnvironmentVariableTarget]::User) # Also set for current session - $env:APIROUTER_API_KEY = $ApiKey + $env:XCODECLI_API_KEY = $ApiKey Write-Success "Environment variables set successfully" } catch { Write-Warning "Failed to set environment variables: $($_.Exception.Message)" Write-Info "You may need to set them manually:" - Write-Info " APIROUTER_API_KEY=$ApiKey" + Write-Info " XCODECLI_API_KEY=$ApiKey" } Write-Host "" @@ -325,7 +325,7 @@ function Main { Write-Info "You can now use Codex with your XCodeCLI API router." Write-Info "" Write-Info "Configuration file location: $CodexConfigFile" - Write-Info "Environment variable APIROUTER_API_KEY has been set" + Write-Info "Environment variable XCODECLI_API_KEY has been set" if (Test-Path $CodexConfigFile) { Write-Host "" diff --git a/codex/setup-codex.sh b/codex/setup-codex.sh index 7f1b851..03f61ad 100644 --- a/codex/setup-codex.sh +++ b/codex/setup-codex.sh @@ -174,21 +174,21 @@ create_codex_config() { # Create config.toml cat > "$HOME/.codex/config.toml" << EOF -model_provider = "apirouter" +model_provider = "xcodecli" model = "gpt-5-codex" model_reasoning_effort = "high" -[model_providers.apirouter] -name = "apirouter" +[model_providers.xcodecli] +name = "xcodecli" base_url = "${base_url}/v1" wire_api = "responses" -env_key = "APIROUTER_API_KEY" +env_key = "XCODECLI_API_KEY" EOF cat > "$HOME/.codex/auth.json" << EOF { "OPENAI_API_KEY": "$api_key", - "APIROUTER_API_KEY": "$api_key" + "XCODECLI_API_KEY": "$api_key" } EOF @@ -202,7 +202,7 @@ set_environment_variable() { local api_key="$1" # Export for current session - export APIROUTER_API_KEY="$api_key" + export XCODECLI_API_KEY="$api_key" # Detect shell and add to appropriate config file local shell_config="" @@ -244,40 +244,40 @@ set_environment_variable() { # Handle Fish shell differently (uses 'set -x' instead of 'export') if [ "$shell_name" = "fish" ] || [[ "$shell_config" == *"fish"* ]]; then # Fish shell syntax - if [ -f "$shell_config" ] && grep -q "set -x APIROUTER_API_KEY" "$shell_config"; then + if [ -f "$shell_config" ] && grep -q "set -x XCODECLI_API_KEY" "$shell_config"; then # Update existing if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' "s/set -x APIROUTER_API_KEY.*/set -x APIROUTER_API_KEY \"$api_key\"/" "$shell_config" + sed -i '' "s/set -x XCODECLI_API_KEY.*/set -x XCODECLI_API_KEY \"$api_key\"/" "$shell_config" else - sed -i "s/set -x APIROUTER_API_KEY.*/set -x APIROUTER_API_KEY \"$api_key\"/" "$shell_config" + sed -i "s/set -x XCODECLI_API_KEY.*/set -x XCODECLI_API_KEY \"$api_key\"/" "$shell_config" fi - print_info "Updated APIROUTER_API_KEY in $shell_config" + print_info "Updated XCODECLI_API_KEY in $shell_config" else # Add new mkdir -p "$(dirname "$shell_config")" echo "" >> "$shell_config" echo "# API Router API key for Codex" >> "$shell_config" - echo "set -x APIROUTER_API_KEY \"$api_key\"" >> "$shell_config" - print_info "Added APIROUTER_API_KEY to $shell_config" + echo "set -x XCODECLI_API_KEY \"$api_key\"" >> "$shell_config" + print_info "Added XCODECLI_API_KEY to $shell_config" fi else # Bash/Zsh/sh syntax - if [ -f "$shell_config" ] && grep -q "export APIROUTER_API_KEY=" "$shell_config"; then + if [ -f "$shell_config" ] && grep -q "export XCODECLI_API_KEY=" "$shell_config"; then # Update existing if [[ "$OSTYPE" == "darwin"* ]]; then # macOS - sed -i '' "s/export APIROUTER_API_KEY=.*/export APIROUTER_API_KEY=\"$api_key\"/" "$shell_config" + sed -i '' "s/export XCODECLI_API_KEY=.*/export XCODECLI_API_KEY=\"$api_key\"/" "$shell_config" else # Linux - sed -i "s/export APIROUTER_API_KEY=.*/export APIROUTER_API_KEY=\"$api_key\"/" "$shell_config" + sed -i "s/export XCODECLI_API_KEY=.*/export XCODECLI_API_KEY=\"$api_key\"/" "$shell_config" fi - print_info "Updated APIROUTER_API_KEY in $shell_config" + print_info "Updated XCODECLI_API_KEY in $shell_config" else # Add new echo "" >> "$shell_config" echo "# API Router API key for Codex" >> "$shell_config" - echo "export APIROUTER_API_KEY=\"$api_key\"" >> "$shell_config" - print_info "Added APIROUTER_API_KEY to $shell_config" + echo "export XCODECLI_API_KEY=\"$api_key\"" >> "$shell_config" + print_info "Added XCODECLI_API_KEY to $shell_config" fi fi @@ -301,11 +301,11 @@ show_current_settings() { echo "----------------------------------------" print_info "Environment variable:" - if [ ! -z "$APIROUTER_API_KEY" ]; then - local masked_key="${APIROUTER_API_KEY:0:8}...${APIROUTER_API_KEY: -4}" - print_info "APIROUTER_API_KEY: $masked_key" + if [ ! -z "$XCODECLI_API_KEY" ]; then + local masked_key="${XCODECLI_API_KEY:0:8}...${XCODECLI_API_KEY: -4}" + print_info "XCODECLI_API_KEY: $masked_key" else - print_info "APIROUTER_API_KEY: (not set)" + print_info "XCODECLI_API_KEY: (not set)" fi echo "----------------------------------------" @@ -393,7 +393,7 @@ main() { # Set environment variable if ! set_environment_variable "$API_KEY"; then print_warning "Failed to set environment variable automatically" - print_info "Please set manually: export APIROUTER_API_KEY=\"$API_KEY\"" + print_info "Please set manually: export XCODECLI_API_KEY=\"$API_KEY\"" fi echo "" @@ -405,9 +405,9 @@ main() { # Provide correct command based on detected shell local current_shell=$(basename "$SHELL" 2>/dev/null || echo "bash") if [ "$current_shell" = "fish" ]; then - print_info " set -x APIROUTER_API_KEY \"$API_KEY\"" + print_info " set -x XCODECLI_API_KEY \"$API_KEY\"" else - print_info " export APIROUTER_API_KEY=\"$API_KEY\"" + print_info " export XCODECLI_API_KEY=\"$API_KEY\"" fi print_info "Or restart your terminal." print_info "" diff --git a/setup-claude-code.ps1 b/setup-claude-code.ps1 index 7802a96..e839536 100644 --- a/setup-claude-code.ps1 +++ b/setup-claude-code.ps1 @@ -167,7 +167,6 @@ function New-Settings { DISABLE_ERROR_REPORTING = 1 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = 1 } - model = "sonnet" } try { diff --git a/setup-claude-code.sh b/setup-claude-code.sh index a68bc0d..9a6dfa7 100644 --- a/setup-claude-code.sh +++ b/setup-claude-code.sh @@ -141,8 +141,7 @@ create_settings() { "DISABLE_TELEMETRY": 1, "DISABLE_ERROR_REPORTING": 1, "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1 - }, - "model": "sonnet" + } }') # Validate JSON diff --git a/setup.ps1 b/setup.ps1 index 1e89b95..77be9e4 100644 --- a/setup.ps1 +++ b/setup.ps1 @@ -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 Pre-set the API key - -Help Show this help message + -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 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