diff --git a/README.md b/README.md index 84732dff..0970f5d7 100644 --- a/README.md +++ b/README.md @@ -224,39 +224,47 @@ Each profile points to a Claude settings JSON file. Create settings files per [C ### Windows Configuration -**Important**: Windows Claude CLI uses **environment variables** instead of settings files. +**Important**: Windows Claude CLI uses **environment variables** instead of --settings flag. -Config format: +Windows uses the same file structure as Linux, but settings files contain environment variables: +**Config format** (`~/.ccs/config.json`): ```json { "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": {} + "glm": "~/.ccs/glm.settings.json", + "son": "~/.ccs/sonnet.settings.json", + "default": "~/.claude/settings.json" } } ``` -**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 +**GLM profile** (`~/.ccs/glm.settings.json`): +```json +{ + "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" +} +``` -**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 +**Claude profile** (`~/.ccs/sonnet.settings.json`): +```json +{ + "env": {} +} +``` + +**How it works**: +- CCS reads the settings file for the selected profile +- Temporarily sets environment variables from the settings file +- Executes Claude CLI with those variables +- Restores original environment variables after execution + +**Compatibility**: Settings files support both direct format (Windows) and `{"env": {...}}` wrapper (Linux compatibility). ## Usage diff --git a/README.vi.md b/README.vi.md index 12b71b2a..e8c1daab 100644 --- a/README.vi.md +++ b/README.vi.md @@ -209,33 +209,65 @@ Nếu cần tùy chỉnh: } ``` -**Lưu ý**: Config dùng Unix-style paths (`~/`) để tương thích đa nền tảng. Phiên bản Windows tự động chuyển đổi paths. +### Cấu Hình macOS / Linux -Mỗi profile trỏ đến một file settings JSON của Claude. Tạo file settings theo [tài liệu Claude CLI](https://docs.claude.com/en/docs/claude-code/installation). - -### Cấu Hình GLM Profile - -Installer tự động cấu hình GLM profiles với các biến môi trường nâng cao: +Dùng file paths trỏ đến settings files: ```json { - "env": { - "ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic", - "ANTHROPIC_AUTH_TOKEN": "GLM_API_KEY_CUA_BAN", - "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": "~/.ccs/glm.settings.json", + "sonnet": "~/.ccs/sonnet.settings.json", + "default": "~/.claude/settings.json" } } ``` -**Các biến môi trường**: -- `ANTHROPIC_DEFAULT_OPUS_MODEL`: Model mặc định cho requests Opus-class -- `ANTHROPIC_DEFAULT_SONNET_MODEL`: Model mặc định cho requests Sonnet-class -- `ANTHROPIC_DEFAULT_HAIKU_MODEL`: Model mặc định cho requests Haiku-class +Mỗi profile trỏ đến một file settings JSON của Claude. Tạo file settings theo [tài liệu Claude CLI](https://docs.claude.com/en/docs/claude-code/installation). -Các biến này đảm bảo GLM được dùng làm provider mặc định khi chuyển profiles. +### Cấu Hình Windows + +**Quan trọng**: Claude CLI trên Windows dùng **biến môi trường** thay vì --settings flag. + +Windows dùng cùng cấu trúc file như Linux, nhưng settings files chứa environment variables: + +**Config format** (`~/.ccs/config.json`): +```json +{ + "profiles": { + "glm": "~/.ccs/glm.settings.json", + "son": "~/.ccs/sonnet.settings.json", + "default": "~/.claude/settings.json" + } +} +``` + +**GLM profile** (`~/.ccs/glm.settings.json`): +```json +{ + "ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic", + "ANTHROPIC_AUTH_TOKEN": "GLM_API_KEY_CUA_BAN", + "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" +} +``` + +**Claude profile** (`~/.ccs/sonnet.settings.json`): +```json +{ + "env": {} +} +``` + +**Cách hoạt động**: +- CCS đọc settings file của profile được chọn +- Tạm thời set biến môi trường từ settings file +- Chạy Claude CLI với các biến đó +- Khôi phục biến môi trường gốc sau khi thực thi + +**Tương thích**: Settings files hỗ trợ cả format trực tiếp (Windows) và wrapper `{"env": {...}}` (tương thích Linux). ## Sử Dụng diff --git a/ccs.ps1 b/ccs.ps1 index fc3657f7..cdd5ef31 100644 --- a/ccs.ps1 +++ b/ccs.ps1 @@ -1,5 +1,5 @@ # CCS - Claude Code Switch (Windows PowerShell) -# Cross-platform Claude CLI profile switcher using environment variables +# Cross-platform Claude CLI profile switcher # https://github.com/kaitranntt/ccs param( @@ -50,10 +50,10 @@ if (-not $Config.profiles) { exit 1 } -# Get profile config -$ProfileConfig = $Config.profiles.$Profile +# Get settings path for profile +$SettingsPath = $Config.profiles.$Profile -if (-not $ProfileConfig) { +if (-not $SettingsPath) { Write-Host "Error: Profile '$Profile' not found in $ConfigFile" -ForegroundColor Red Write-Host "" Write-Host "Available profiles:" @@ -63,40 +63,59 @@ if (-not $ProfileConfig) { exit 1 } -# Profile config can be either a string (settings file path) or object (env vars) -# For backward compatibility with Unix, support both formats +# Path expansion and normalization +# 1. Handle Unix-style tilde expansion (~/path -> %USERPROFILE%\path) +if ($SettingsPath -match '^~[/\\]') { + $SettingsPath = $SettingsPath -replace '^~', $env:USERPROFILE +} -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 +# 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 Write-Host "" - 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)." + Write-Host "Create the settings file or update the path in $ConfigFile" exit 1 } -# Apply environment variables from profile -# Save original values to restore after command execution +# Read settings file (contains environment variables for Windows) +try { + $SettingsContent = Get-Content $SettingsPath -Raw -ErrorAction Stop + $Settings = $SettingsContent | ConvertFrom-Json -ErrorAction Stop +} catch { + Write-Host "Error: Invalid JSON in $SettingsPath" -ForegroundColor Red + exit 1 +} + +# Windows Claude CLI uses environment variables instead of --settings flag +# Settings file contains env vars directly or nested in "env" object (Linux compat) + +# Check if settings contain "env" wrapper (Linux format) or direct env vars (Windows format) +$EnvVars = if ($Settings.env) { + # Linux format: { "env": { "ANTHROPIC_AUTH_TOKEN": "..." } } + $Settings.env +} else { + # Windows format: { "ANTHROPIC_AUTH_TOKEN": "..." } + $Settings +} + +# Save original environment variables to restore after execution $OriginalEnvVars = @{} -if ($ProfileConfig.PSObject.Properties.Count -gt 0) { - foreach ($Property in $ProfileConfig.PSObject.Properties) { +if ($EnvVars.PSObject.Properties.Count -gt 0) { + foreach ($Property in $EnvVars.PSObject.Properties) { $VarName = $Property.Name $VarValue = $Property.Value # Save original value $OriginalEnvVars[$VarName] = [System.Environment]::GetEnvironmentVariable($VarName, 'Process') - # Set new value for this process + # Set new value for this process only [System.Environment]::SetEnvironmentVariable($VarName, $VarValue, 'Process') } } diff --git a/install.ps1 b/install.ps1 index 93e7d130..7e7b21bd 100644 --- a/install.ps1 +++ b/install.ps1 @@ -198,33 +198,38 @@ Write-Host "┌─ Configuring Profiles$ProviderLabel" $NeedsGlmKey = $false -# Create ccs config (Windows uses environment variables, not settings files) +# Create ccs config with file paths (same structure as Linux) $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 = @{ - 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 + glm = "~/.ccs/glm.settings.json" + son = "~/.ccs/sonnet.settings.json" + default = "~/.claude/settings.json" } } $ConfigContent | ConvertTo-Json -Depth 10 | Set-Content $ConfigFile Write-Host "| [OK] Config -> $env:USERPROFILE\.ccs\config.json" +} - if (-not $HasGlmKey) { +# Create profile settings files +$GlmSettings = "$CcsDir\glm.settings.json" +$SonnetSettings = "$CcsDir\sonnet.settings.json" + +if (-not (Test-Path $GlmSettings)) { + New-GlmProfile -Provider $CurrentProvider + if ($CurrentProvider -ne "glm") { $NeedsGlmKey = $true } +} else { + Write-Host "| [OK] GLM profile exists: $GlmSettings" +} + +if (-not (Test-Path $SonnetSettings)) { + New-SonnetProfile -Provider $CurrentProvider +} else { + Write-Host "| [OK] Sonnet profile exists: $SonnetSettings" } Write-Host "└─" @@ -254,8 +259,8 @@ if ($UserPath -notlike "*$CcsDir*") { if ($NeedsGlmKey) { Write-Host "[!] ACTION REQUIRED" Write-Host "" - 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 " Edit $env:USERPROFILE\.ccs\glm.settings.json and add your GLM API key" + Write-Host " Replace YOUR_GLM_API_KEY_HERE with your actual API key" Write-Host "" }