fix(windows): use environment variables instead of settings files

Windows Claude CLI doesn't support --settings flag or settings.json files.
It uses environment variables instead (ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL, etc.)

Changes:
- ccs.ps1: Completely rewritten to set environment variables per profile
  - Supports both env var objects (Windows) and file paths (Unix cross-compat)
  - Sets env vars before executing claude, restores after
  - Shows helpful error if user tries to use file paths on Windows

- install.ps1: Updated to create env var-based config
  - config.json now contains env var objects, not file paths
  - GLM profile: Full env var config with API key placeholder
  - Sonnet/default profiles: Empty {} = use Claude subscription

- README.md: Updated Windows configuration section
  - Documents env var approach clearly
  - Shows correct Windows config format
  - Explains difference from Unix approach

Example Windows config:
{
  "profiles": {
    "glm": {
      "ANTHROPIC_AUTH_TOKEN": "your_key",
      "ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic"
    },
    "son": {}
  }
}

Fixes: Windows users can now switch profiles with env vars instead of files
This commit is contained in:
kaitranntt committed 2025-11-02 02:47:40 -05:00
1 parent 2b03406f00
commit 999f598735
3 files changed
+108 -62

No files matched your search

+29 -17
View File
@@ -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
+59 -26
View File
@@ -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
+20 -19
View File
@@ -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 ""
}