diff --git a/README.md b/README.md index 424972be..84732dff 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,9 @@ The installer auto-creates config and profile templates during installation: **macOS / Linux**: `~/.ccs/config.json` **Windows**: `%USERPROFILE%\.ccs\config.json` -If you need to customize: +### macOS / Linux Configuration + +Uses settings file paths: ```json { @@ -218,33 +220,43 @@ If you need to customize: } ``` -**Note**: Config uses Unix-style paths (`~/`) for cross-platform compatibility. Windows version automatically converts paths. - Each profile points to a Claude settings JSON file. Create settings files per [Claude CLI docs](https://docs.claude.com/en/docs/claude-code/installation). -### GLM Profile Configuration +### Windows Configuration -The installer automatically configures GLM profiles with enhanced environment variables: +**Important**: Windows Claude CLI uses **environment variables** instead of settings files. + +Config format: ```json { - "env": { - "ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic", - "ANTHROPIC_AUTH_TOKEN": "YOUR_GLM_API_KEY_HERE", - "ANTHROPIC_MODEL": "glm-4.6", - "ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-4.6", - "ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-4.6", - "ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-4.6" + "profiles": { + "glm": { + "ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic", + "ANTHROPIC_AUTH_TOKEN": "your_glm_api_key", + "ANTHROPIC_MODEL": "glm-4.6", + "ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-4.6", + "ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-4.6", + "ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-4.6" + }, + "son": {}, + "default": {} } } ``` -**Environment Variables**: -- `ANTHROPIC_DEFAULT_OPUS_MODEL`: Default model for Opus-class requests -- `ANTHROPIC_DEFAULT_SONNET_MODEL`: Default model for Sonnet-class requests -- `ANTHROPIC_DEFAULT_HAIKU_MODEL`: Default model for Haiku-class requests +**Profile types**: +- **With env vars** (GLM): Sets environment variables for API providers +- **Empty object** `{}` (Claude): Uses Claude subscription (no API key needed) +- **Empty object** `{}` (default): Uses current environment variables -These variables ensure GLM is used as the default provider when switching profiles. +**Environment Variables**: +- `ANTHROPIC_BASE_URL`: API endpoint URL +- `ANTHROPIC_AUTH_TOKEN`: Your API key +- `ANTHROPIC_MODEL`: Default model +- `ANTHROPIC_DEFAULT_OPUS_MODEL`: Model for Opus-class requests +- `ANTHROPIC_DEFAULT_SONNET_MODEL`: Model for Sonnet-class requests +- `ANTHROPIC_DEFAULT_HAIKU_MODEL`: Model for Haiku-class requests ## Usage diff --git a/ccs.ps1 b/ccs.ps1 index 246ea2bf..fc3657f7 100644 --- a/ccs.ps1 +++ b/ccs.ps1 @@ -1,5 +1,5 @@ # CCS - Claude Code Switch (Windows PowerShell) -# Cross-platform Claude CLI profile switcher +# Cross-platform Claude CLI profile switcher using environment variables # https://github.com/kaitranntt/ccs param( @@ -50,10 +50,10 @@ if (-not $Config.profiles) { exit 1 } -# Get settings path for profile -$SettingsPath = $Config.profiles.$Profile +# Get profile config +$ProfileConfig = $Config.profiles.$Profile -if (-not $SettingsPath) { +if (-not $ProfileConfig) { Write-Host "Error: Profile '$Profile' not found in $ConfigFile" -ForegroundColor Red Write-Host "" Write-Host "Available profiles:" @@ -63,31 +63,64 @@ if (-not $SettingsPath) { exit 1 } -# Path expansion and normalization -# 1. Handle Unix-style tilde expansion (~/path -> %USERPROFILE%\path) -if ($SettingsPath -match '^~[/\\]') { - $SettingsPath = $SettingsPath -replace '^~', $env:USERPROFILE -} +# Profile config can be either a string (settings file path) or object (env vars) +# For backward compatibility with Unix, support both formats -# 2. Expand Windows environment variables (%USERPROFILE%, etc.) -$SettingsPath = [System.Environment]::ExpandEnvironmentVariables($SettingsPath) - -# 3. Convert forward slashes to backslashes (Unix path compatibility) -$SettingsPath = $SettingsPath -replace '/', '\' - -# Validate settings file exists -if (-not (Test-Path $SettingsPath)) { - Write-Host "Error: Settings file not found: $SettingsPath" -ForegroundColor Red +if ($ProfileConfig -is [string]) { + # Legacy format: path to settings file (for cross-platform configs) + # This won't work on Windows Claude CLI, show helpful error + Write-Host "Error: Windows Claude CLI doesn't support settings files." -ForegroundColor Red Write-Host "" - Write-Host "Create the settings file or update the path in $ConfigFile" + Write-Host "Windows uses environment variables instead." + Write-Host "Update your profile in $ConfigFile to use this format:" + Write-Host "" + Write-Host ' "' + $Profile + '": {' + Write-Host ' "ANTHROPIC_AUTH_TOKEN": "your_api_key",' + Write-Host ' "ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",' + Write-Host ' "ANTHROPIC_MODEL": "glm-4.6"' + Write-Host ' }' + Write-Host "" + Write-Host "Or leave empty {} for Claude subscription (no API key needed)." exit 1 } -# Execute claude with settings -# Pass arguments directly to Claude CLI with proper splatting -if ($RemainingArgs) { - & claude --settings $SettingsPath @RemainingArgs -} else { - & claude --settings $SettingsPath +# Apply environment variables from profile +# Save original values to restore after command execution +$OriginalEnvVars = @{} + +if ($ProfileConfig.PSObject.Properties.Count -gt 0) { + foreach ($Property in $ProfileConfig.PSObject.Properties) { + $VarName = $Property.Name + $VarValue = $Property.Value + + # Save original value + $OriginalEnvVars[$VarName] = [System.Environment]::GetEnvironmentVariable($VarName, 'Process') + + # Set new value for this process + [System.Environment]::SetEnvironmentVariable($VarName, $VarValue, 'Process') + } } -exit $LASTEXITCODE + +# Execute claude with environment variables set +try { + if ($RemainingArgs) { + & claude @RemainingArgs + } else { + & claude + } + $ExitCode = $LASTEXITCODE +} finally { + # Restore original environment variables + foreach ($VarName in $OriginalEnvVars.Keys) { + $OriginalValue = $OriginalEnvVars[$VarName] + if ($null -eq $OriginalValue) { + # Variable didn't exist before, remove it + [System.Environment]::SetEnvironmentVariable($VarName, $null, 'Process') + } else { + # Restore original value + [System.Environment]::SetEnvironmentVariable($VarName, $OriginalValue, 'Process') + } + } +} + +exit $ExitCode diff --git a/install.ps1 b/install.ps1 index a4b9f45f..93e7d130 100644 --- a/install.ps1 +++ b/install.ps1 @@ -186,8 +186,6 @@ Write-Host "" # Profile Setup $CurrentProvider = Detect-CurrentProvider -$GlmSettings = "$CcsDir\glm.settings.json" -$SonnetSettings = "$CcsDir\sonnet.settings.json" $ProviderLabel = switch ($CurrentProvider) { "glm" { " (detected: GLM)" } @@ -200,30 +198,33 @@ Write-Host "┌─ Configuring Profiles$ProviderLabel" $NeedsGlmKey = $false -if (-not (Test-Path $GlmSettings)) { - New-GlmProfile -Provider $CurrentProvider | Out-Null - Write-Host "| [OK] GLM profile -> $env:USERPROFILE\.ccs\glm.settings.json" - if ($CurrentProvider -ne "glm") { $NeedsGlmKey = $true } -} - -if (-not (Test-Path $SonnetSettings)) { - New-SonnetProfile -Provider $CurrentProvider | Out-Null - Write-Host "| [OK] Sonnet profile -> $env:USERPROFILE\.ccs\sonnet.settings.json" -} - -# Create ccs config (using Unix-style paths for cross-platform compatibility) +# Create ccs config (Windows uses environment variables, not settings files) $ConfigFile = "$CcsDir\config.json" if (-not (Test-Path $ConfigFile)) { + # Detect if user has GLM API key set in environment + $HasGlmKey = $env:ANTHROPIC_AUTH_TOKEN -and $env:ANTHROPIC_BASE_URL -match "z\.ai" + $ConfigContent = @{ profiles = @{ - glm = "~/.ccs/glm.settings.json" - son = "~/.ccs/sonnet.settings.json" - default = "~/.claude/settings.json" + glm = @{ + ANTHROPIC_BASE_URL = "https://api.z.ai/api/anthropic" + ANTHROPIC_AUTH_TOKEN = if ($HasGlmKey) { $env:ANTHROPIC_AUTH_TOKEN } else { "YOUR_GLM_API_KEY_HERE" } + ANTHROPIC_MODEL = $GlmModel + ANTHROPIC_DEFAULT_OPUS_MODEL = $GlmModel + ANTHROPIC_DEFAULT_SONNET_MODEL = $GlmModel + ANTHROPIC_DEFAULT_HAIKU_MODEL = $GlmModel + } + son = @{} # Empty = use Claude subscription (no env vars needed) + default = @{} # Empty = use current environment settings } } $ConfigContent | ConvertTo-Json -Depth 10 | Set-Content $ConfigFile Write-Host "| [OK] Config -> $env:USERPROFILE\.ccs\config.json" + + if (-not $HasGlmKey) { + $NeedsGlmKey = $true + } } Write-Host "└─" @@ -253,8 +254,8 @@ if ($UserPath -notlike "*$CcsDir*") { if ($NeedsGlmKey) { Write-Host "[!] ACTION REQUIRED" Write-Host "" - Write-Host " Edit $env:USERPROFILE\.ccs\glm.settings.json and add your GLM API key" - Write-Host " Replace: YOUR_GLM_API_KEY_HERE" + Write-Host " Edit $env:USERPROFILE\.ccs\config.json and add your GLM API key" + Write-Host " Replace YOUR_GLM_API_KEY_HERE in the 'glm' profile with your actual API key" Write-Host "" }