From 13c6e92df67cd9a781ded82b573ee62fb002bdbd Mon Sep 17 00:00:00 2001 From: sususu98 Date: Fri, 5 Dec 2025 16:27:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Claude=20Code?= =?UTF-8?q?=E3=80=81Gemini=20CLI=E3=80=81Codex=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ClaudeCode/: Claude Code 配置脚本 - GeminiCLI/: Gemini CLI 配置脚本 - codex/: Codex 配置脚本 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ClaudeCode/setup-claude-code.ps1 | 354 ++++++++++++++++++++++++++ ClaudeCode/setup-claude-code.sh | 334 ++++++++++++++++++++++++ GeminiCLI/setup-gemini.ps1 | 303 ++++++++++++++++++++++ GeminiCLI/setup-gemini.sh | 298 ++++++++++++++++++++++ codex/setup-codex.ps1 | 342 +++++++++++++++++++++++++ codex/setup-codex.sh | 422 +++++++++++++++++++++++++++++++ 6 files changed, 2053 insertions(+) create mode 100644 ClaudeCode/setup-claude-code.ps1 create mode 100644 ClaudeCode/setup-claude-code.sh create mode 100644 GeminiCLI/setup-gemini.ps1 create mode 100644 GeminiCLI/setup-gemini.sh create mode 100644 codex/setup-codex.ps1 create mode 100644 codex/setup-codex.sh diff --git a/ClaudeCode/setup-claude-code.ps1 b/ClaudeCode/setup-claude-code.ps1 new file mode 100644 index 0000000..7802a96 --- /dev/null +++ b/ClaudeCode/setup-claude-code.ps1 @@ -0,0 +1,354 @@ +# Claude Code Configuration Script for XCodeCLI (Windows) +# This script configures Claude Code to use your XCodeCLI instance +# Run with: powershell -ExecutionPolicy Bypass -File setup-claude-code.ps1 -ApiKey YOUR_KEY +# Or via one-liner: & { $key='YOUR_KEY'; iwr -useb https://api.xcodecli.com/setup-claude-code.ps1 | iex } + +param( + [string]$ApiKey, + [switch]$Test, + [switch]$Show, + [switch]$Help +) + +# Check for pre-set variables from one-liner command (use different names to avoid conflict) +if (-not $ApiKey -and (Test-Path Variable:key)) { $ApiKey = $key } + +# Configuration +$DefaultBaseUrl = "https://api2.xcodecli.com" +$ClaudeConfigDir = "$env:USERPROFILE\.claude" +$ClaudeSettingsFile = "$ClaudeConfigDir\settings.json" + +# Color functions for output +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" +} + +# Function to show help +function Show-Help { + Write-Host @" +Claude Code Configuration Script for XCodeCLI (Windows) + +Usage: powershell -ExecutionPolicy Bypass -File setup-claude-code.ps1 [OPTIONS] + +This script automatically tests multiple API endpoints and selects the working one: + - https://api2.xcodecli.com + - https://api.xcodecli.com + +Options: + -ApiKey Set the API key + -Test Test API connections only (requires -ApiKey) + -Show Show current settings and exit + -Help Show this help message + +Examples: + .\setup-claude-code.ps1 -ApiKey your-api-key-here + .\setup-claude-code.ps1 -Test -ApiKey your-api-key-here + .\setup-claude-code.ps1 -Show + +Interactive mode (no arguments): + .\setup-claude-code.ps1 + +PowerShell Execution Policy: + If you get an execution policy error, run: + powershell -ExecutionPolicy Bypass -File setup-claude-code.ps1 +"@ + exit 0 +} + +# Function to backup existing settings +function Backup-Settings { + if (Test-Path $ClaudeSettingsFile) { + $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" + $backupFile = "$ClaudeSettingsFile.backup.$timestamp" + Copy-Item -Path $ClaudeSettingsFile -Destination $backupFile + Write-Info "Backed up existing settings to: $backupFile" + } +} + +# Function to create settings directory +function New-SettingsDirectory { + if (-not (Test-Path $ClaudeConfigDir)) { + New-Item -ItemType Directory -Path $ClaudeConfigDir -Force | Out-Null + Write-Info "Created Claude configuration directory: $ClaudeConfigDir" + } +} + +# Function to validate API key format +function Test-ApiKey { + param([string]$ApiKey) + + if ($ApiKey -match '^[A-Za-z0-9_-]+$') { + return $true + } else { + Write-Error "Invalid API key format. API key should contain only alphanumeric characters, hyphens, and underscores." + return $false + } +} + +# Function to test API connection and return working base URL +function Test-ApiConnection { + param( + [string]$ApiKey + ) + + $testUrls = @( + "https://api2.xcodecli.com", + "https://api.xcodecli.com" + ) + + Write-Info "Testing API connections..." + + foreach ($baseUrl in $testUrls) { + Write-Info "Testing $baseUrl..." + + try { + $headers = @{ + "Content-Type" = "application/json" + "Authorization" = "Bearer $ApiKey" + } + + $uri = "$baseUrl/v1/models" + $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers -ErrorAction Stop + + if ($response.data -and $response.data.Count -gt 0) { + Write-Success "API connection successful! Found $($response.data.Count) models at $baseUrl" + return $baseUrl + } else { + Write-Warning "API responded but no models found at $baseUrl" + } + } + catch { + if ($_.Exception.Response -and $_.Exception.Response.StatusCode -eq 401) { + Write-Warning "API key authentication failed for $baseUrl" + } elseif ($_.Exception.Message -like "*Unable to connect*" -or $_.Exception.Message -like "*could not be resolved*") { + Write-Warning "Cannot connect to $baseUrl" + } else { + Write-Warning "API test failed for $baseUrl`: $($_.Exception.Message)" + } + } + } + + Write-Error "All API connections failed. Please check your API key and internet connection." + return $null +} + +# Function to create Claude Code settings +function New-Settings { + param( + [string]$BaseUrl, + [string]$ApiKey + ) + + $settings = @{ + env = @{ + ANTHROPIC_BASE_URL = $BaseUrl + ANTHROPIC_AUTH_TOKEN = $ApiKey + DISABLE_TELEMETRY = 1 + DISABLE_ERROR_REPORTING = 1 + CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = 1 + } + model = "sonnet" + } + + try { + $json = $settings | ConvertTo-Json -Depth 10 + Set-Content -Path $ClaudeSettingsFile -Value $json -Encoding UTF8 + Write-Success "Claude Code settings written to: $ClaudeSettingsFile" + return $true + } + catch { + Write-Error "Failed to create settings file: $($_.Exception.Message)" + return $false + } +} + +# Function to display current settings +function Show-Settings { + if (Test-Path $ClaudeSettingsFile) { + Write-Info "Current Claude Code settings:" + Write-Host "----------------------------------------" + $settings = Get-Content $ClaudeSettingsFile -Raw | ConvertFrom-Json + $settings | ConvertTo-Json -Depth 10 + Write-Host "----------------------------------------" + } else { + Write-Info "No existing Claude Code settings found." + } + + Write-Host "" + Write-Info "Current environment variables:" + Write-Host "----------------------------------------" + $baseUrl = [Environment]::GetEnvironmentVariable("ANTHROPIC_BASE_URL", [EnvironmentVariableTarget]::User) + $authToken = [Environment]::GetEnvironmentVariable("ANTHROPIC_AUTH_TOKEN", [EnvironmentVariableTarget]::User) + + if ($baseUrl) { + Write-Info "ANTHROPIC_BASE_URL: $baseUrl" + } else { + Write-Info "ANTHROPIC_BASE_URL: (not set)" + } + + if ($authToken) { + $maskedToken = if ($authToken.Length -gt 12) { + "$($authToken.Substring(0, 8))...$($authToken.Substring($authToken.Length - 4))" + } else { + "$($authToken.Substring(0, [Math]::Min(4, $authToken.Length)))..." + } + Write-Info "ANTHROPIC_AUTH_TOKEN: $maskedToken" + } else { + Write-Info "ANTHROPIC_AUTH_TOKEN: (not set)" + } + Write-Host "----------------------------------------" +} + +# Main function +function Main { + Write-Info "Claude Code Configuration Script for XCodeCLI" + Write-Host "=======================================================" + Write-Host "" + + # Handle command line arguments + if ($Help) { + Show-Help + } + + if ($Show) { + Show-Settings + exit 0 + } + + # Interactive mode if no Key provided + if (-not $ApiKey) { + Write-Info "Interactive setup mode" + Write-Host "" + + # Get API key + while ([string]::IsNullOrWhiteSpace($ApiKey)) { + $ApiKey = Read-Host "Enter your API key" + if ([string]::IsNullOrWhiteSpace($ApiKey)) { + Write-Warning "API key is required" + } elseif (-not (Test-ApiKey $ApiKey)) { + $ApiKey = "" + } + } + } + + # Validate inputs + if ([string]::IsNullOrWhiteSpace($ApiKey)) { + Write-Error "API key is required" + Write-Info "Use -Help for usage information" + exit 1 + } + + # Validate API key + if (-not (Test-ApiKey $ApiKey)) { + exit 1 + } + + $maskedKey = if ($ApiKey.Length -gt 12) { + "$($ApiKey.Substring(0, 8))...$($ApiKey.Substring($ApiKey.Length - 4))" + } else { + "$($ApiKey.Substring(0, [Math]::Min(4, $ApiKey.Length)))..." + } + Write-Info "API Key: $maskedKey" + Write-Host "" + + # Test API connection and get working base URL + $BaseUrl = Test-ApiConnection -ApiKey $ApiKey + + if ([string]::IsNullOrWhiteSpace($BaseUrl)) { + if ($Test) { + exit 1 + } + + $continue = Read-Host "All API tests failed. Continue anyway? (y/N)" + if ($continue -notmatch '^[Yy]$') { + Write-Info "Setup cancelled" + exit 1 + } + + # If user chooses to continue anyway, use default URL + $BaseUrl = $DefaultBaseUrl + Write-Warning "Using default URL: $BaseUrl" + } else { + Write-Info "Selected working base URL: $BaseUrl" + } + + # Exit if test only + if ($Test) { + Write-Success "API test completed successfully" + exit 0 + } + + # Create settings directory + New-SettingsDirectory + + # Backup existing settings + Backup-Settings + + # Create new settings + if (New-Settings -BaseUrl $BaseUrl -ApiKey $ApiKey) { + Write-Host "" + + # Also set environment variables for Windows + Write-Info "Setting environment variables..." + try { + # Set user environment variables (persistent across sessions) + [Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", $BaseUrl, [EnvironmentVariableTarget]::User) + [Environment]::SetEnvironmentVariable("ANTHROPIC_AUTH_TOKEN", $ApiKey, [EnvironmentVariableTarget]::User) + + # Also set for current session + $env:ANTHROPIC_BASE_URL = $BaseUrl + $env:ANTHROPIC_AUTH_TOKEN = $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 " ANTHROPIC_BASE_URL=$BaseUrl" + Write-Info " ANTHROPIC_AUTH_TOKEN=$ApiKey" + } + + Write-Host "" + Write-Success "Claude Code has been configured successfully!" + Write-Info "You can now use Claude Code with your API router." + Write-Info "" + Write-Info "To verify the setup, run:" + Write-Info " claude --version" + Write-Info "" + Write-Info "Configuration file location: $ClaudeSettingsFile" + Write-Info "Environment variables have been set for ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN" + + if (Test-Path $ClaudeSettingsFile) { + Write-Host "" + Write-Info "Current settings:" + $settings = Get-Content $ClaudeSettingsFile -Raw | ConvertFrom-Json + $settings | ConvertTo-Json -Depth 10 + } + } else { + Write-Error "Failed to create Claude Code settings" + exit 1 + } +} + +# Run main function +Main diff --git a/ClaudeCode/setup-claude-code.sh b/ClaudeCode/setup-claude-code.sh new file mode 100644 index 0000000..a68bc0d --- /dev/null +++ b/ClaudeCode/setup-claude-code.sh @@ -0,0 +1,334 @@ +#!/bin/bash + +# Claude Code Configuration Script for XCodeCLI +# This script configures Claude Code to use your XCodeCLI instance +# Automatically tests multiple API endpoints and selects the working one + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +DEFAULT_BASE_URL="https://api2.xcodecli.com" +CLAUDE_CONFIG_DIR="$HOME/.claude" +CLAUDE_SETTINGS_FILE="$CLAUDE_CONFIG_DIR/settings.json" + +# Function to print colored output +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to check if jq is installed +check_jq() { + if ! command -v jq &> /dev/null; then + print_error "jq is required but not installed." + print_info "Please install jq:" + print_info " macOS: brew install jq" + print_info " Ubuntu/Debian: sudo apt-get install jq" + print_info " CentOS/RHEL: sudo yum install jq" + exit 1 + fi +} + +# Function to backup existing settings +backup_settings() { + if [ -f "$CLAUDE_SETTINGS_FILE" ]; then + local backup_file="${CLAUDE_SETTINGS_FILE}.backup.$(date +%Y%m%d_%H%M%S)" + cp "$CLAUDE_SETTINGS_FILE" "$backup_file" + print_info "Backed up existing settings to: $backup_file" + fi +} + +# Function to create settings directory +create_settings_dir() { + if [ ! -d "$CLAUDE_CONFIG_DIR" ]; then + mkdir -p "$CLAUDE_CONFIG_DIR" + print_info "Created Claude configuration directory: $CLAUDE_CONFIG_DIR" + fi +} + +# Function to validate API key format +validate_api_key() { + local api_key="$1" + if [[ ! "$api_key" =~ ^[A-Za-z0-9_-]+$ ]]; then + print_error "Invalid API key format. API key should contain only alphanumeric characters, hyphens, and underscores." + return 1 + fi + return 0 +} + +# Function to test API connection and return working base URL +test_api_connection() { + local api_key="$1" + + local test_urls=( + "https://api2.xcodecli.com" + "https://api.xcodecli.com" + ) + + print_info "Testing API connections..." >&2 + + for base_url in "${test_urls[@]}"; do + print_info "Testing $base_url..." >&2 + + local test_endpoint="$base_url/v1/models" + + # Test a simple request to the API + local response + response=$(curl -s -w "%{http_code}" -o /tmp/claude_test_response \ + -X GET "$test_endpoint" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $api_key" \ + 2>/dev/null || echo "000") + + if [ "$response" = "200" ]; then + local model_count + model_count=$(cat /tmp/claude_test_response | jq -r '.data | length' 2>/dev/null || echo "0") + if [ "$model_count" -gt "0" ]; then + print_success "API connection successful! Found $model_count models at $base_url" >&2 + rm -f /tmp/claude_test_response + echo "$base_url" + return 0 + else + print_warning "API responded but no models found at $base_url" >&2 + fi + elif [ "$response" = "401" ]; then + print_warning "API key authentication failed for $base_url" >&2 + elif [ "$response" = "000" ]; then + print_warning "Cannot connect to $base_url" >&2 + else + print_warning "API test failed for $base_url with HTTP status: $response" >&2 + fi + + rm -f /tmp/claude_test_response + done + + print_error "All API connections failed. Please check your API key and internet connection." >&2 + return 1 +} + +# Function to create Claude Code settings +create_settings() { + local base_url="$1" + local api_key="$2" + + # Create JSON using jq to ensure proper escaping + local settings_json + settings_json=$(jq -n \ + --arg base_url "$base_url" \ + --arg api_key "$api_key" \ + '{ + "env": { + "ANTHROPIC_BASE_URL": $base_url, + "ANTHROPIC_AUTH_TOKEN": $api_key, + "DISABLE_TELEMETRY": 1, + "DISABLE_ERROR_REPORTING": 1, + "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1 + }, + "model": "sonnet" + }') + + # Validate JSON + if ! echo "$settings_json" | jq . > /dev/null 2>&1; then + print_error "Generated settings JSON is invalid" + return 1 + fi + + # Write settings file + echo "$settings_json" > "$CLAUDE_SETTINGS_FILE" + print_success "Claude Code settings written to: $CLAUDE_SETTINGS_FILE" +} + +# Function to display current settings +display_settings() { + if [ -f "$CLAUDE_SETTINGS_FILE" ]; then + print_info "Current Claude Code settings:" + echo "----------------------------------------" + cat "$CLAUDE_SETTINGS_FILE" | jq . + echo "----------------------------------------" + else + print_info "No existing Claude Code settings found." + fi +} + +# Main function +main() { + print_info "Claude Code Configuration Script for XCodeCLI" + echo "=======================================================" + echo + + # Check dependencies + check_jq + + # Parse command line arguments + local api_key="" + local test_only=false + local show_settings=false + + # Check for environment variable API_KEY + if [ -n "$API_KEY" ]; then + api_key="$API_KEY" + fi + + while [[ $# -gt 0 ]]; do + case $1 in + -k|--key) + api_key="$2" + shift 2 + ;; + -t|--test) + test_only=true + shift + ;; + -s|--show) + show_settings=true + shift + ;; + -h|--help) + cat < Set the API key + -Test Test API connections only (requires -ApiKey) + -Show Show current settings and exit + -Help Show this help message + +Examples: + .\setup-gemini.ps1 -ApiKey your-api-key-here + .\setup-gemini.ps1 -Test -ApiKey your-api-key-here + .\setup-gemini.ps1 -Show + +Interactive mode (no arguments): + .\setup-gemini.ps1 + +One-liner: + `$key='YOUR_API_KEY'; iwr -useb https://your-domain.tld/setup-gemini.ps1 | iex + +PowerShell Execution Policy: + If you get an execution policy error, run: + powershell -ExecutionPolicy Bypass -File setup-gemini.ps1 +"@ + exit 0 +} + +# Function to backup existing settings +function Backup-Settings { + if (Test-Path $GeminiEnvFile) { + $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" + $backupFile = "$GeminiEnvFile.backup.$timestamp" + Copy-Item -Path $GeminiEnvFile -Destination $backupFile + Write-Info "Backed up existing settings to: $backupFile" + } +} + +# Function to create settings directory +function New-SettingsDirectory { + if (-not (Test-Path $GeminiConfigDir)) { + New-Item -ItemType Directory -Path $GeminiConfigDir -Force | Out-Null + Write-Info "Created Gemini configuration directory: $GeminiConfigDir" + } +} + +# Function to validate API key format +function Test-ApiKey { + param([string]$ApiKey) + + if ($ApiKey -match '^[A-Za-z0-9_-]+$') { + return $true + } else { + Write-Error "Invalid API key format. API key should contain only alphanumeric characters, hyphens, and underscores." + return $false + } +} + +# Function to test API connection and return working base URL +function Test-ApiConnection { + param([string]$ApiKey) + + $testUrls = @( + "https://api2.xcodecli.com", + "https://api.xcodecli.com" + ) + + Write-Info "Testing API connections..." + + foreach ($baseUrl in $testUrls) { + Write-Info "Testing $baseUrl..." + + try { + $headers = @{ + "Content-Type" = "application/json" + "x-goog-api-key" = $ApiKey + } + + $testEndpoint = "$baseUrl/v1/models" + $response = Invoke-RestMethod -Uri $testEndpoint -Method Get -Headers $headers -ErrorAction Stop + + # Check if response contains models + if ($response.models) { + $modelCount = $response.models.Count + Write-Success "API connection successful! Found $modelCount models at $baseUrl" + return $baseUrl + } else { + Write-Warning "API responded but no models found at $baseUrl" + } + } + catch { + if ($_.Exception.Response -and $_.Exception.Response.StatusCode -eq 401) { + Write-Warning "API key authentication failed for $baseUrl" + } elseif ($_.Exception.Message -like "*Unable to connect*" -or $_.Exception.Message -like "*could not be resolved*") { + Write-Warning "Cannot connect to $baseUrl" + } else { + Write-Warning "API test failed for $baseUrl`: $($_.Exception.Message)" + } + } + } + + Write-Error "All API connections failed. Please check your API key and internet connection." + return $null +} + +# Function to create Gemini CLI settings +function New-Settings { + param( + [string]$BaseUrl, + [string]$ApiKey + ) + + $envContent = @" +GOOGLE_GEMINI_BASE_URL="$BaseUrl" +GEMINI_API_KEY="$ApiKey" +"@ + + try { + Set-Content -Path $GeminiEnvFile -Value $envContent -Encoding UTF8 + Write-Success "Gemini CLI settings written to: $GeminiEnvFile" + return $true + } + catch { + Write-Error "Failed to create .env file: $($_.Exception.Message)" + return $false + } +} + +# Function to display current settings +function Show-Settings { + if (Test-Path $GeminiEnvFile) { + Write-Info "Current Gemini CLI settings file ($GeminiEnvFile):" + Write-Host "----------------------------------------" + Get-Content $GeminiEnvFile + Write-Host "----------------------------------------" + } else { + Write-Info "No existing Gemini CLI .env file found." + } + + +} + +# Main function +function Main { + Write-Info "Gemini CLI Configuration Script for XCodeCLI" + Write-Host "=======================================================" + Write-Host "" + + # Handle command line arguments + if ($Help) { + Show-Help + } + + if ($Show) { + Show-Settings + exit 0 + } + + # Interactive mode if no API key provided + if ([string]::IsNullOrWhiteSpace($ApiKey)) { + Write-Info "Interactive setup mode" + Write-Host "" + + # Get API key + while ([string]::IsNullOrWhiteSpace($ApiKey)) { + $ApiKey = Read-Host "Enter your API key" + if ([string]::IsNullOrWhiteSpace($ApiKey)) { + Write-Warning "API key is required" + } elseif (-not (Test-ApiKey $ApiKey)) { + $ApiKey = "" + } + } + } + + # Validate inputs + if ([string]::IsNullOrWhiteSpace($ApiKey)) { + Write-Error "API key is required" + Write-Info "Use -Help for usage information" + exit 1 + } + + # Validate API key + if (-not (Test-ApiKey $ApiKey)) { + exit 1 + } + + $maskedKey = if ($ApiKey.Length -gt 12) { + "$($ApiKey.Substring(0, 8))...$($ApiKey.Substring($ApiKey.Length - 4))" + } else { + "$($ApiKey.Substring(0, [Math]::Min(4, $ApiKey.Length)))..." + } + Write-Info "API Key: $maskedKey" + Write-Host "" + + # Test API connection and get working base URL + $BaseUrl = Test-ApiConnection -ApiKey $ApiKey + + if (-not $BaseUrl) { + if ($Test) { + exit 1 + } + + $continue = Read-Host "All API tests failed. Continue anyway? (y/N)" + if ($continue -notmatch '^[Yy]$') { + Write-Info "Setup cancelled" + exit 1 + } + + # If user chooses to continue anyway, use default URL + $BaseUrl = $DefaultBaseUrl + Write-Warning "Using default URL: $BaseUrl" + } else { + Write-Info "Selected working base URL: $BaseUrl" + } + + # Exit if test only + if ($Test) { + Write-Success "API test completed successfully" + exit 0 + } + + # Create settings directory + New-SettingsDirectory + + # Backup existing settings + Backup-Settings + + # Create new settings + if (New-Settings -BaseUrl $BaseUrl -ApiKey $ApiKey) { + Write-Host "" + Write-Success "Gemini CLI has been configured successfully!" + Write-Info "You can now use Gemini CLI with your API router." + Write-Info "" + Write-Info "To verify the setup, run:" + Write-Info " gemini --version" + Write-Info "" + Write-Info "Configuration file location: $GeminiEnvFile" + + if (Test-Path $GeminiEnvFile) { + Write-Host "" + Write-Info "Current settings:" + Get-Content $GeminiEnvFile + } + } else { + Write-Error "Failed to create Gemini CLI settings" + exit 1 + } +} + +# Run main function +Main diff --git a/GeminiCLI/setup-gemini.sh b/GeminiCLI/setup-gemini.sh new file mode 100644 index 0000000..77f3503 --- /dev/null +++ b/GeminiCLI/setup-gemini.sh @@ -0,0 +1,298 @@ +#!/bin/bash + +# Gemini CLI Configuration Script for XCodeCLI +# This script configures Gemini CLI to use your XCodeCLI instance +# Automatically tests multiple API endpoints and selects the working one + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +DEFAULT_BASE_URL="https://api2.xcodecli.com" +GEMINI_CONFIG_DIR="$HOME/.gemini" +GEMINI_ENV_FILE="$GEMINI_CONFIG_DIR/.env" + +# Function to print colored output +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to backup existing settings +backup_settings() { + if [ -f "$GEMINI_ENV_FILE" ]; then + local backup_file="${GEMINI_ENV_FILE}.backup.$(date +%Y%m%d_%H%M%S)" + cp "$GEMINI_ENV_FILE" "$backup_file" + print_info "Backed up existing settings to: $backup_file" + fi +} + +# Function to create settings directory +create_settings_dir() { + if [ ! -d "$GEMINI_CONFIG_DIR" ]; then + mkdir -p "$GEMINI_CONFIG_DIR" + print_info "Created Gemini configuration directory: $GEMINI_CONFIG_DIR" + fi +} + +# Function to validate API key format +validate_api_key() { + local api_key="$1" + if [[ ! "$api_key" =~ ^[A-Za-z0-9_-]+$ ]]; then + print_error "Invalid API key format. API key should contain only alphanumeric characters, hyphens, and underscores." + return 1 + fi + return 0 +} + +# Function to test API connection and return working base URL +test_api_connection() { + local api_key="$1" + + local test_urls=( + "https://api2.xcodecli.com" + "https://api.xcodecli.com" + ) + + print_info "Testing API connections..." >&2 + + for base_url in "${test_urls[@]}"; do + print_info "Testing $base_url..." >&2 + + local test_endpoint="$base_url/v1/models" + + # Test with x-goog-api-key header (Gemini API style) + local response + response=$(curl -s -w "%{http_code}" -o /tmp/gemini_test_response \ + -X GET "$test_endpoint" \ + -H "Content-Type: application/json" \ + -H "x-goog-api-key: $api_key" \ + 2>/dev/null || echo "000") + + if [ "$response" = "200" ]; then + # Check if response contains models + if grep -q '"models"' /tmp/gemini_test_response 2>/dev/null; then + local model_count + model_count=$(grep -oE '"name"[[:space:]]*:' /tmp/gemini_test_response | wc -l | tr -d ' ') + print_success "API connection successful! Found $model_count models at $base_url" >&2 + rm -f /tmp/gemini_test_response + echo "$base_url" + return 0 + else + print_warning "API responded but no models found at $base_url" >&2 + fi + elif [ "$response" = "401" ]; then + print_warning "API key authentication failed for $base_url" >&2 + elif [ "$response" = "000" ]; then + print_warning "Cannot connect to $base_url" >&2 + else + print_warning "API test failed for $base_url with HTTP status: $response" >&2 + fi + + rm -f /tmp/gemini_test_response + done + + print_error "All API connections failed. Please check your API key and internet connection." >&2 + return 1 +} + +# Function to create Gemini CLI settings file +create_settings_file() { + local base_url="$1" + local api_key="$2" + + # Write to .env file + cat < "$GEMINI_ENV_FILE" +GOOGLE_GEMINI_BASE_URL="$base_url" +GEMINI_API_KEY="$api_key" +EOF + print_success "Gemini CLI settings written to: $GEMINI_ENV_FILE" +} + +# Function to display current settings +display_settings() { + if [ -f "$GEMINI_ENV_FILE" ]; then + print_info "Current Gemini CLI settings file ($GEMINI_ENV_FILE):" + echo "----------------------------------------" + cat "$GEMINI_ENV_FILE" + echo "----------------------------------------" + else + print_info "No existing Gemini CLI .env file found." + fi +} + +# Main function +main() { + print_info "Gemini CLI Configuration Script for XCodeCLI" + echo "=======================================================" + echo + + # Parse command line arguments + local api_key="" + local test_only=false + local show_settings=false + + # Check for environment variable API_KEY + if [ -n "$API_KEY" ]; then + api_key="$API_KEY" + fi + + while [[ $# -gt 0 ]]; do + case $1 in + -k|--key) + api_key="$2" + shift 2 + ;; + -t|--test) + test_only=true + shift + ;; + -s|--show) + show_settings=true + shift + ;; + -h|--help) + cat < Set the API key + -Test Test API connections only (requires -ApiKey) + -Show Show current settings and exit + -Help Show this help message + +Examples: + .\setup-codex.ps1 -ApiKey your-api-key-here + .\setup-codex.ps1 -Test -ApiKey your-api-key-here + .\setup-codex.ps1 -Show + +Interactive mode (no arguments): + .\setup-codex.ps1 + +One-liner: + `$key='YOUR_API_KEY'; iwr -useb https://your-domain.tld/setup-codex.ps1 | iex + +PowerShell Execution Policy: + If you get an execution policy error, run: + powershell -ExecutionPolicy Bypass -File setup-codex.ps1 +"@ + exit 0 +} + +# Function to backup existing settings +function Backup-Settings { + if (Test-Path $CodexConfigFile) { + $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" + $backupFile = "$CodexConfigFile.backup.$timestamp" + Copy-Item -Path $CodexConfigFile -Destination $backupFile + Write-Info "Backed up existing settings to: $backupFile" + } +} + +# Function to create settings directory +function New-SettingsDirectory { + if (-not (Test-Path $CodexConfigDir)) { + New-Item -ItemType Directory -Path $CodexConfigDir -Force | Out-Null + Write-Info "Created Codex configuration directory: $CodexConfigDir" + } +} + +# Function to validate API key format +function Test-ApiKey { + param([string]$ApiKey) + + if ($ApiKey -match '^[A-Za-z0-9_-]+$') { + return $true + } else { + Write-Error "Invalid API key format. API key should contain only alphanumeric characters, hyphens, and underscores." + return $false + } +} + +# Function to test API connection and return working base URL +function Test-ApiConnection { + param([string]$ApiKey) + + $testUrls = @( + "https://api2.xcodecli.com", + "https://api.xcodecli.com" + ) + + Write-Info "Testing API connections..." + + foreach ($baseUrl in $testUrls) { + Write-Info "Testing $baseUrl..." + + try { + $headers = @{ + "Content-Type" = "application/json" + "Authorization" = "Bearer $ApiKey" + } + + $testEndpoint = "$baseUrl/v1/models" + $response = Invoke-RestMethod -Uri $testEndpoint -Method Get -Headers $headers -ErrorAction Stop + + # Check if response contains models data + if ($response.data) { + $modelCount = $response.data.Count + Write-Success "API connection successful! Found $modelCount models at $baseUrl" + return $baseUrl + } else { + Write-Warning "API responded but no models found at $baseUrl" + } + } + catch { + if ($_.Exception.Response -and $_.Exception.Response.StatusCode -eq 401) { + Write-Warning "API key authentication failed for $baseUrl" + } elseif ($_.Exception.Message -like "*Unable to connect*" -or $_.Exception.Message -like "*could not be resolved*") { + Write-Warning "Cannot connect to $baseUrl" + } else { + Write-Warning "API test failed for $baseUrl`: $($_.Exception.Message)" + } + } + } + + Write-Error "All API connections failed. Please check your API key and internet connection." + return $null +} + +# Function to create Codex configuration +function New-Settings { + param( + [string]$BaseUrl, + [string]$ApiKey + ) + + $config = @" +model_provider = "apirouter" +model = "gpt-5-codex" +model_reasoning_effort = "high" + +[model_providers.apirouter] +name = "apirouter" +base_url = "$BaseUrl/v1" +wire_api = "responses" +env_key = "APIROUTER_API_KEY" +"@ + + try { + Set-Content -Path $CodexConfigFile -Value $config -Encoding UTF8 + Write-Success "Codex configuration written to: $CodexConfigFile" + return $true + } + catch { + Write-Error "Failed to create configuration file: $($_.Exception.Message)" + return $false + } +} + +# Function to display current settings +function Show-Settings { + if (Test-Path $CodexConfigFile) { + Write-Info "Current Codex settings:" + Write-Host "----------------------------------------" + Get-Content $CodexConfigFile + Write-Host "----------------------------------------" + } else { + Write-Info "No existing Codex configuration found." + } + + Write-Host "" + Write-Info "Current environment variables:" + Write-Host "----------------------------------------" + $apirouterKey = [Environment]::GetEnvironmentVariable("APIROUTER_API_KEY", [EnvironmentVariableTarget]::User) + + if ($apirouterKey) { + $maskedKey = if ($apirouterKey.Length -gt 12) { + "$($apirouterKey.Substring(0, 8))...$($apirouterKey.Substring($apirouterKey.Length - 4))" + } else { + "$($apirouterKey.Substring(0, [Math]::Min(4, $apirouterKey.Length)))..." + } + Write-Info "APIROUTER_API_KEY: $maskedKey" + } else { + Write-Info "APIROUTER_API_KEY: (not set)" + } + Write-Host "----------------------------------------" +} + +# Main function +function Main { + Write-Info "Codex Configuration Script for XCodeCLI" + Write-Host "=======================================" + Write-Host "" + + # Handle command line arguments + if ($Help) { + Show-Help + } + + if ($Show) { + Show-Settings + exit 0 + } + + # Interactive mode if no API key provided + if ([string]::IsNullOrWhiteSpace($ApiKey)) { + Write-Info "Interactive setup mode" + Write-Host "" + + # Get API key + while ([string]::IsNullOrWhiteSpace($ApiKey)) { + $ApiKey = Read-Host "Enter your API key" + if ([string]::IsNullOrWhiteSpace($ApiKey)) { + Write-Warning "API key is required" + } elseif (-not (Test-ApiKey $ApiKey)) { + $ApiKey = "" + } + } + } + + # Validate inputs + if ([string]::IsNullOrWhiteSpace($ApiKey)) { + Write-Error "API key is required" + Write-Info "Use -Help for usage information" + exit 1 + } + + # Validate API key + if (-not (Test-ApiKey $ApiKey)) { + exit 1 + } + + $maskedKey = if ($ApiKey.Length -gt 12) { + "$($ApiKey.Substring(0, 8))...$($ApiKey.Substring($ApiKey.Length - 4))" + } else { + "$($ApiKey.Substring(0, [Math]::Min(4, $ApiKey.Length)))..." + } + Write-Info "API Key: $maskedKey" + Write-Host "" + + # Test API connection and get working base URL + $BaseUrl = Test-ApiConnection -ApiKey $ApiKey + + if (-not $BaseUrl) { + if ($Test) { + exit 1 + } + + $continue = Read-Host "All API tests failed. Continue anyway? (y/N)" + if ($continue -notmatch '^[Yy]$') { + Write-Info "Setup cancelled" + exit 1 + } + + # If user chooses to continue anyway, use default URL + $BaseUrl = $DefaultBaseUrl + Write-Warning "Using default URL: $BaseUrl" + } else { + Write-Info "Selected working base URL: $BaseUrl" + } + + # Exit if test only + if ($Test) { + Write-Success "API test completed successfully" + exit 0 + } + + # Create settings directory + New-SettingsDirectory + + # Backup existing settings + Backup-Settings + + # Create new settings + if (New-Settings -BaseUrl $BaseUrl -ApiKey $ApiKey) { + Write-Host "" + + # Also set environment variables for Windows + Write-Info "Setting environment variables..." + try { + # Set user environment variables (persistent across sessions) + [Environment]::SetEnvironmentVariable("APIROUTER_API_KEY", $ApiKey, [EnvironmentVariableTarget]::User) + + # Also set for current session + $env:APIROUTER_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-Host "" + Write-Success "Codex has been configured successfully!" + 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" + + if (Test-Path $CodexConfigFile) { + Write-Host "" + Write-Info "Current settings:" + Get-Content $CodexConfigFile + } + } else { + Write-Error "Failed to create Codex settings" + exit 1 + } +} + +# Run main function +Main diff --git a/codex/setup-codex.sh b/codex/setup-codex.sh new file mode 100644 index 0000000..7f1b851 --- /dev/null +++ b/codex/setup-codex.sh @@ -0,0 +1,422 @@ +#!/bin/bash +# Codex Configuration Script for XCodeCLI +# This script configures Codex to use your XCodeCLI instance +# Automatically tests multiple API endpoints and selects the working one + +set -e + +# Color functions for output +print_info() { + echo -e "\033[34m[INFO]\033[0m $1" +} + +print_success() { + echo -e "\033[32m[SUCCESS]\033[0m $1" +} + +print_warning() { + echo -e "\033[33m[WARNING]\033[0m $1" +} + +print_error() { + echo -e "\033[31m[ERROR]\033[0m $1" +} + +# Default values +DEFAULT_BASE_URL="https://api2.xcodecli.com" +BASE_URL="" +TEST_ONLY=false +SHOW_SETTINGS=false + +# Check for environment variable API_KEY +if [ -n "$API_KEY" ]; then + API_KEY_FROM_ENV="$API_KEY" +else + API_KEY_FROM_ENV="" +fi +API_KEY="" + +# Function to show help +show_help() { + cat << EOF +Codex Configuration Script for XCodeCLI + +This script automatically tests multiple API endpoints and selects the working one: + - https://api2.xcodecli.com + - https://api.xcodecli.com + +Usage: $0 [OPTIONS] + +Options: + --key KEY Set the API key + --test Test API connections only (requires --key) + --show Show current settings and exit + --help Show this help message + +Examples: + $0 --key your-api-key-here + $0 --test --key your-api-key-here + $0 --show + +Interactive mode (no arguments): + $0 + +Environment Variables: + API_KEY API key for authentication +EOF +} + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + --key) + API_KEY="$2" + shift 2 + ;; + --test) + TEST_ONLY=true + shift + ;; + --show) + SHOW_SETTINGS=true + shift + ;; + --help) + show_help + exit 0 + ;; + *) + print_error "Unknown option: $1" + show_help + exit 1 + ;; + esac +done + +# Use environment variable if no --key provided +if [ -z "$API_KEY" ] && [ -n "$API_KEY_FROM_ENV" ]; then + API_KEY="$API_KEY_FROM_ENV" +fi + +# Function to backup existing configuration +backup_config() { + if [ -f "$HOME/.codex/config.toml" ]; then + local timestamp=$(date +%Y%m%d_%H%M%S) + local backup_file="$HOME/.codex/config.toml.backup.$timestamp" + local backup_auth_file="$HOME/.codex/auth.json.backup.$timestamp" + cp "$HOME/.codex/config.toml" "$backup_file" + if [ -f "$HOME/.codex/auth.json" ]; then + cp "$HOME/.codex/auth.json" "$backup_auth_file" + print_info "Backed up existing auth file to: $backup_auth_file" + fi + print_info "Backed up existing configuration to: $backup_file" + fi +} + +# Function to test API connection and return working base URL +test_api_connection() { + local api_key="$1" + + local test_urls=( + "https://api2.xcodecli.com" + "https://api.xcodecli.com" + ) + + print_info "Testing API connections..." >&2 + + for base_url in "${test_urls[@]}"; do + print_info "Testing $base_url..." >&2 + + local test_endpoint="$base_url/v1/models" + + # Test with Authorization Bearer header (OpenAI API style) + local response + response=$(curl -s -w "%{http_code}" -o /tmp/codex_test_response \ + -X GET "$test_endpoint" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $api_key" \ + 2>/dev/null || echo "000") + + if [ "$response" = "200" ]; then + # Check if response contains models data + if grep -qE '"data".*\[|"object"' /tmp/codex_test_response 2>/dev/null; then + local model_count + model_count=$(grep -oE '"id"[[:space:]]*:' /tmp/codex_test_response | wc -l | tr -d ' ') + print_success "API connection successful! Found $model_count models at $base_url" >&2 + rm -f /tmp/codex_test_response + echo "$base_url" + return 0 + else + print_warning "API responded but no models found at $base_url" >&2 + fi + elif [ "$response" = "401" ]; then + print_warning "API key authentication failed for $base_url" >&2 + elif [ "$response" = "000" ]; then + print_warning "Cannot connect to $base_url" >&2 + else + print_warning "API test failed for $base_url with HTTP status: $response" >&2 + fi + + rm -f /tmp/codex_test_response + done + + print_error "All API connections failed. Please check your API key and internet connection." >&2 + return 1 +} + +# Function to create Codex configuration +create_codex_config() { + local base_url="$1" + local api_key="$2" + + # Create config directory if it doesn't exist + mkdir -p "$HOME/.codex" + + # Create config.toml + cat > "$HOME/.codex/config.toml" << EOF +model_provider = "apirouter" +model = "gpt-5-codex" +model_reasoning_effort = "high" + +[model_providers.apirouter] +name = "apirouter" +base_url = "${base_url}/v1" +wire_api = "responses" +env_key = "APIROUTER_API_KEY" +EOF + + cat > "$HOME/.codex/auth.json" << EOF +{ + "OPENAI_API_KEY": "$api_key", + "APIROUTER_API_KEY": "$api_key" +} +EOF + + print_success "Codex configuration written to: $HOME/.codex/config.toml" + print_success "Codex auth file written to: $HOME/.codex/auth.json" + return 0 +} + +# Function to set environment variable +set_environment_variable() { + local api_key="$1" + + # Export for current session + export APIROUTER_API_KEY="$api_key" + + # Detect shell and add to appropriate config file + local shell_config="" + local shell_name="" + + # First check $SHELL to determine user's default shell + if [ -n "$SHELL" ]; then + shell_name=$(basename "$SHELL") + case "$shell_name" in + bash) + shell_config="$HOME/.bashrc" + [ -f "$HOME/.bash_profile" ] && shell_config="$HOME/.bash_profile" + ;; + zsh) + shell_config="$HOME/.zshrc" + ;; + fish) + shell_config="$HOME/.config/fish/config.fish" + ;; + *) + shell_config="$HOME/.profile" + ;; + esac + # Fallback to checking version variables if $SHELL is not set + elif [ -n "$BASH_VERSION" ]; then + shell_config="$HOME/.bashrc" + [ -f "$HOME/.bash_profile" ] && shell_config="$HOME/.bash_profile" + elif [ -n "$ZSH_VERSION" ]; then + shell_config="$HOME/.zshrc" + elif [ -n "$FISH_VERSION" ]; then + shell_config="$HOME/.config/fish/config.fish" + else + shell_config="$HOME/.profile" + fi + + print_info "Detected shell: ${shell_name:-$(basename $SHELL 2>/dev/null || echo 'unknown')}" + print_info "Using config file: $shell_config" + + # 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 + # Update existing + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/set -x APIROUTER_API_KEY.*/set -x APIROUTER_API_KEY \"$api_key\"/" "$shell_config" + else + sed -i "s/set -x APIROUTER_API_KEY.*/set -x APIROUTER_API_KEY \"$api_key\"/" "$shell_config" + fi + print_info "Updated APIROUTER_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" + fi + else + # Bash/Zsh/sh syntax + if [ -f "$shell_config" ] && grep -q "export APIROUTER_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" + else + # Linux + sed -i "s/export APIROUTER_API_KEY=.*/export APIROUTER_API_KEY=\"$api_key\"/" "$shell_config" + fi + print_info "Updated APIROUTER_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" + fi + fi + + return 0 +} + +# Function to show current settings +show_current_settings() { + print_info "Current Codex settings:" + echo "----------------------------------------" + + if [ -f "$HOME/.codex/config.toml" ]; then + print_info "Configuration file: $HOME/.codex/config.toml" + echo "" + cat "$HOME/.codex/config.toml" + echo "" + else + print_info "No configuration file found at $HOME/.codex/config.toml" + fi + + 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" + else + print_info "APIROUTER_API_KEY: (not set)" + fi + + echo "----------------------------------------" +} + +# Main function +main() { + print_info "Codex Configuration Script for XCodeCLI" + echo "=======================================" + echo "" + + # Show current settings and exit if requested + if [ "$SHOW_SETTINGS" = true ]; then + show_current_settings + exit 0 + fi + + # Interactive mode if no API key provided + if [ -z "$API_KEY" ]; then + print_info "Interactive setup mode" + echo "" + + # Get API key + while [ -z "$API_KEY" ]; do + read -p "Enter your API key: " API_KEY + if [ -z "$API_KEY" ]; then + print_warning "API key is required" + fi + done + fi + + # Validate inputs + if [ -z "$API_KEY" ]; then + print_error "API key is required" + print_info "Use --help for usage information" + exit 1 + fi + + # Mask API key for display + if [ ${#API_KEY} -gt 12 ]; then + masked_key="${API_KEY:0:8}...${API_KEY: -4}" + else + masked_key="${API_KEY:0:4}..." + fi + print_info "API Key: $masked_key" + echo "" + + # Test API connection and get working base URL + BASE_URL=$(test_api_connection "$API_KEY") + + if [ $? -ne 0 ] || [ -z "$BASE_URL" ]; then + if [ "$TEST_ONLY" = true ]; then + exit 1 + fi + + read -p "All API tests failed. Continue anyway? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Setup cancelled" + exit 1 + fi + + # If user chooses to continue anyway, use default URL + BASE_URL="$DEFAULT_BASE_URL" + print_warning "Using default URL: $BASE_URL" + else + print_info "Selected working base URL: $BASE_URL" + fi + + # Exit if test only + if [ "$TEST_ONLY" = true ]; then + print_success "API test completed successfully" + exit 0 + fi + + # Backup existing configuration + backup_config + + # Create Codex configuration + if ! create_codex_config "$BASE_URL" "$API_KEY"; then + print_error "Failed to create Codex configuration" + exit 1 + fi + + # 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\"" + fi + + echo "" + print_success "Codex has been configured successfully!" + print_info "You can now use Codex with your XCodeCLI API router." + print_info "" + print_info "To apply the environment variable in your current session, run:" + + # 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\"" + else + print_info " export APIROUTER_API_KEY=\"$API_KEY\"" + fi + print_info "Or restart your terminal." + print_info "" + print_info "Configuration file: $HOME/.codex/config.toml" + + # Show current settings + echo "" + show_current_settings +} + +# Run main function +main