feat(windows): add native PowerShell 5.1+ support with full cross-platform compatibility

- Add ccs.ps1: PowerShell core script with native JSON parsing
- Add install.ps1: Windows installer with provider auto-detection
- Add uninstall.ps1: Clean Windows uninstaller
- Update install.sh: Add platform detection to redirect Windows users
- Update README.md: Add comprehensive Windows installation docs
- Update README.vi.md: Add Vietnamese Windows documentation

Features:
- PowerShell 5.1+ compatible (Windows 10+ built-in)
- Cross-platform config: Unix paths work on all platforms
- Smart path expansion: ~/  → %USERPROFILE%\ on Windows
- Zero breaking changes: Linux/macOS unchanged
- No external dependencies: Uses PowerShell built-in JSON

Install directory: %USERPROFILE%\.ccs\
Usage: irm ccs.kaitran.ca/install.ps1 | iex (after Cloudflare setup)
This commit is contained in:
kaitranntt
2025-11-02 02:20:48 -05:00
parent 92903ddb68
commit a4245e9031
6 changed files with 773 additions and 46 deletions
+155 -24
View File
@@ -1,8 +1,8 @@
# CCS - Claude Code Switch
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Language: Bash](https://img.shields.io/badge/Language-Bash-blue.svg)](https://www.gnu.org/software/bash/)
[![Platform: macOS | Linux](https://img.shields.io/badge/Platform-macOS%20%7C%20Linux-lightgrey.svg)]()
[![Language: Bash | PowerShell](https://img.shields.io/badge/Language-Bash%20%7C%20PowerShell-blue.svg)]()
[![Platform: macOS | Linux | Windows](https://img.shields.io/badge/Platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey.svg)]()
**Languages**: [English](README.md) | [Tiếng Việt](README.vi.md)
@@ -26,11 +26,18 @@ One command. Zero downtime. No file editing. Right model, right task.
## Quick Start
**Install** (one-liner):
**Install**:
**macOS / Linux**:
```bash
curl -fsSL ccs.kaitran.ca/install | bash
```
**Windows PowerShell**:
```powershell
irm ccs.kaitran.ca/install.ps1 | iex
```
**Configure**:
```bash
# Edit with your profiles
@@ -103,30 +110,49 @@ If you have both Claude subscription and GLM Coding Plan, you know the pain:
### One-Liner (Recommended)
**Short URL** (via CloudFlare):
**macOS / Linux**:
```bash
# Short URL (via CloudFlare)
curl -fsSL ccs.kaitran.ca/install | bash
```
**Direct from GitHub**:
```bash
# Or direct from GitHub
curl -fsSL https://raw.githubusercontent.com/kaitranntt/ccs/main/install.sh | bash
```
**Note**: The installer supports both direct execution (`./install.sh`) and piped installation (`curl | bash`).
**Windows PowerShell**:
```powershell
# Short URL (via CloudFlare)
irm ccs.kaitran.ca/install.ps1 | iex
# Or direct from GitHub
irm https://raw.githubusercontent.com/kaitranntt/ccs/main/install.ps1 | iex
```
**Note**:
- Unix installer supports both direct execution (`./install.sh`) and piped installation (`curl | bash`)
- Windows installer requires PowerShell 5.1+ (pre-installed on Windows 10+)
### Git Clone
**macOS / Linux**:
```bash
git clone https://github.com/kaitranntt/ccs.git
cd ccs
./install.sh
```
**Windows PowerShell**:
```powershell
git clone https://github.com/kaitranntt/ccs.git
cd ccs
.\install.ps1
```
**Note**: Works with git worktrees and submodules - the installer detects both `.git` directory and `.git` file.
### Manual
**macOS / Linux**:
```bash
# Download script
curl -fsSL https://raw.githubusercontent.com/kaitranntt/ccs/main/ccs -o ~/.local/bin/ccs
@@ -136,27 +162,51 @@ chmod +x ~/.local/bin/ccs
export PATH="$HOME/.local/bin:$PATH"
```
### Upgrade
**Windows PowerShell**:
```powershell
# Create directory
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.ccs"
**From git clone**:
```bash
cd ccs && git pull && ./install.sh
# Download script
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/kaitranntt/ccs/main/ccs.ps1" -OutFile "$env:USERPROFILE\.ccs\ccs.ps1"
# Add to PATH (restart terminal after)
$Path = [Environment]::GetEnvironmentVariable("Path", "User")
[Environment]::SetEnvironmentVariable("Path", "$Path;$env:USERPROFILE\.ccs", "User")
```
**From curl install**:
```bash
# Short URL
curl -fsSL ccs.kaitran.ca/install | bash
### Upgrade
# Or direct from GitHub
curl -fsSL https://raw.githubusercontent.com/kaitranntt/ccs/main/install.sh | bash
**macOS / Linux**:
```bash
# From git clone
cd ccs && git pull && ./install.sh
# From curl install
curl -fsSL ccs.kaitran.ca/install | bash
```
**Windows PowerShell**:
```powershell
# From git clone
cd ccs
git pull
.\install.ps1
# From irm install
irm ccs.kaitran.ca/install.ps1 | iex
```
**Note**: Upgrading preserves your existing API keys and settings. The installer only adds new features without overwriting your configuration.
## Configuration
The installer auto-creates `~/.ccs/config.json` and profile templates during installation. If you need to customize:
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:
```json
{
@@ -168,6 +218,8 @@ The installer auto-creates `~/.ccs/config.json` and profile templates during ins
}
```
**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
@@ -199,11 +251,14 @@ These variables ensure GLM is used as the default provider when switching profil
### Basic
```bash
# Works on macOS, Linux, and Windows
ccs # Use default profile (no args)
ccs glm # Use GLM profile
ccs son # Use Sonnet profile
```
**Windows Note**: Commands work identically in PowerShell, CMD, and Git Bash.
### With Arguments
All args after profile name pass directly to Claude CLI:
@@ -304,11 +359,16 @@ No magic. No file modification. Pure delegation.
## Requirements
### macOS / Linux
- `bash` 3.2+
- `jq` (JSON processor)
- [Claude CLI](https://docs.claude.com/en/docs/claude-code/installation)
### Installing jq
### Windows
- PowerShell 5.1+ (pre-installed on Windows 10+)
- [Claude CLI](https://docs.claude.com/en/docs/claude-code/installation)
### Installing jq (macOS / Linux only)
```bash
# macOS
@@ -324,8 +384,46 @@ sudo dnf install jq
sudo pacman -S jq
```
**Note**: Windows version uses PowerShell's built-in JSON support - no jq required.
## Troubleshooting
### Windows-Specific Issues
#### PowerShell Execution Policy
If you see "cannot be loaded because running scripts is disabled":
```powershell
# Check current policy
Get-ExecutionPolicy
# Allow current user to run scripts (recommended)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Or run with bypass (one-time)
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.ccs\ccs.ps1" glm
```
#### PATH not updated (Windows)
If `ccs` command not found after installation:
1. Restart your terminal
2. Or manually add to PATH:
- Open "Edit environment variables for your account"
- Add `%USERPROFILE%\.ccs` to User PATH
- Restart terminal
#### Claude CLI not found (Windows)
```powershell
# Check Claude CLI
where.exe claude
# If missing, install from Claude docs
```
### Installation Issues
#### BASH_SOURCE unbound variable error
@@ -421,12 +519,14 @@ Error: Profile 'default' not found in ~/.ccs/config.json
## Uninstallation
### macOS / Linux
**Using installed command**:
```bash
ccs-uninstall
```
**One-liner** (if ccs-uninstall not available):
**One-liner**:
```bash
# Short URL
curl -fsSL ccs.kaitran.ca/uninstall | bash
@@ -442,14 +542,45 @@ rm ~/.local/bin/ccs-uninstall
rm -rf ~/.ccs # If you want to remove all CCS files
```
### Windows PowerShell
**Using installed command**:
```powershell
ccs-uninstall
```
**One-liner**:
```powershell
# Short URL
irm ccs.kaitran.ca/uninstall.ps1 | iex
# Or direct from GitHub
irm https://raw.githubusercontent.com/kaitranntt/ccs/main/uninstall.ps1 | iex
```
**Manual**:
```powershell
# Remove scripts
Remove-Item "$env:USERPROFILE\.ccs\ccs.ps1" -Force
Remove-Item "$env:USERPROFILE\.ccs\uninstall.ps1" -Force
# Remove from PATH
$Path = [Environment]::GetEnvironmentVariable("Path", "User")
$NewPath = ($Path -split ';' | Where-Object { $_ -ne "$env:USERPROFILE\.ccs" }) -join ';'
[Environment]::SetEnvironmentVariable("Path", $NewPath, "User")
# Optional: Remove all CCS files
Remove-Item "$env:USERPROFILE\.ccs" -Recurse -Force
```
## Contributing
PRs welcome! Keep it simple (KISS principle).
**Guidelines**:
- Maintain bash 3.2+ compatibility
- No dependencies beyond jq
- Test on macOS and Linux
- Maintain bash 3.2+ compatibility (Unix) and PowerShell 5.1+ (Windows)
- No dependencies beyond jq (Unix) or built-in PowerShell (Windows)
- Test on macOS, Linux, and Windows
- Follow existing code style
## Philosophy
+159 -22
View File
@@ -1,8 +1,8 @@
# CCS - Claude Code Switch
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Language: Bash](https://img.shields.io/badge/Language-Bash-blue.svg)](https://www.gnu.org/software/bash/)
[![Platform: macOS | Linux](https://img.shields.io/badge/Platform-macOS%20%7C%20Linux-lightgrey.svg)]()
[![Language: Bash | PowerShell](https://img.shields.io/badge/Language-Bash%20%7C%20PowerShell-blue.svg)]()
[![Platform: macOS | Linux | Windows](https://img.shields.io/badge/Platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey.svg)]()
**Ngôn ngữ**: [English](README.md) | [Tiếng Việt](README.vi.md)
@@ -26,11 +26,18 @@ Một lệnh. Không downtime. Không phải sửa file. Đúng model, đúng vi
## Bắt Đầu Nhanh
**Cài đặt** (một dòng lệnh):
**Cài đặt**:
**macOS / Linux**:
```bash
curl -fsSL ccs.kaitran.ca/install | bash
```
**Windows PowerShell**:
```powershell
irm ccs.kaitran.ca/install.ps1 | iex
```
**Cấu hình**:
```bash
# Sửa theo profile của bạn
@@ -94,30 +101,49 @@ Nếu bạn có cả Claude subscription và GLM Coding Plan, bạn biết cái
### Một Dòng Lệnh (Khuyến Nghị)
**URL ngắn** (qua CloudFlare):
**macOS / Linux**:
```bash
# URL ngắn (qua CloudFlare)
curl -fsSL ccs.kaitran.ca/install | bash
```
**Trực tiếp từ GitHub**:
```bash
# Hoặc trực tiếp từ GitHub
curl -fsSL https://raw.githubusercontent.com/kaitranntt/ccs/main/install.sh | bash
```
**Lưu ý**: Installer hỗ trợ cả chạy trực tiếp (`./install.sh`) và piped installation (`curl | bash`).
**Windows PowerShell**:
```powershell
# URL ngắn (qua CloudFlare)
irm ccs.kaitran.ca/install.ps1 | iex
# Hoặc trực tiếp từ GitHub
irm https://raw.githubusercontent.com/kaitranntt/ccs/main/install.ps1 | iex
```
**Lưu ý**:
- Installer Unix hỗ trợ cả chạy trực tiếp (`./install.sh`) và piped installation (`curl | bash`)
- Installer Windows yêu cầu PowerShell 5.1+ (có sẵn trên Windows 10+)
### Git Clone
**macOS / Linux**:
```bash
git clone https://github.com/kaitranntt/ccs.git
cd ccs
./install.sh
```
**Windows PowerShell**:
```powershell
git clone https://github.com/kaitranntt/ccs.git
cd ccs
.\install.ps1
```
**Lưu ý**: Hoạt động với git worktrees và submodules - installer phát hiện cả `.git` directory và `.git` file.
### Thủ Công
**macOS / Linux**:
```bash
# Tải script
curl -fsSL https://raw.githubusercontent.com/kaitranntt/ccs/main/ccs -o ~/.local/bin/ccs
@@ -127,27 +153,51 @@ chmod +x ~/.local/bin/ccs
export PATH="$HOME/.local/bin:$PATH"
```
### Nâng Cấp
**Windows PowerShell**:
```powershell
# Tạo thư mục
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.ccs"
**Từ git clone**:
```bash
cd ccs && git pull && ./install.sh
# Tải script
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/kaitranntt/ccs/main/ccs.ps1" -OutFile "$env:USERPROFILE\.ccs\ccs.ps1"
# Thêm vào PATH (khởi động lại terminal sau đó)
$Path = [Environment]::GetEnvironmentVariable("Path", "User")
[Environment]::SetEnvironmentVariable("Path", "$Path;$env:USERPROFILE\.ccs", "User")
```
**Từ curl install**:
```bash
# URL ngắn
curl -fsSL ccs.kaitran.ca/install | bash
### Nâng Cấp
# Hoặc trực tiếp từ GitHub
curl -fsSL https://raw.githubusercontent.com/kaitranntt/ccs/main/install.sh | bash
**macOS / Linux**:
```bash
# Từ git clone
cd ccs && git pull && ./install.sh
# Từ curl install
curl -fsSL ccs.kaitran.ca/install | bash
```
**Windows PowerShell**:
```powershell
# Từ git clone
cd ccs
git pull
.\install.ps1
# Từ irm install
irm ccs.kaitran.ca/install.ps1 | iex
```
**Lưu ý**: Nâng cấp giữ nguyên API keys và settings hiện tại. Installer chỉ thêm tính năng mới mà không ghi đè cấu hình của bạn.
## Cấu Hình
Installer tự động tạo `~/.ccs/config.json` và profile templates khi cài đặt. Nếu cần tùy chỉnh:
Installer tự động tạo config và profile templates khi cài đặt:
**macOS / Linux**: `~/.ccs/config.json`
**Windows**: `%USERPROFILE%\.ccs\config.json`
Nếu cần tùy chỉnh:
```json
{
@@ -159,6 +209,8 @@ Installer tự động tạo `~/.ccs/config.json` và profile templates khi cài
}
```
**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.
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
@@ -190,11 +242,14 @@ Các biến này đảm bảo GLM được dùng làm provider mặc định khi
### Cơ Bản
```bash
# Hoạt động trên macOS, Linux, và Windows
ccs # Dùng profile mặc định (không args)
ccs glm # Dùng GLM profile
ccs son # Dùng Sonnet profile
```
**Lưu ý Windows**: Lệnh hoạt động giống nhau trên PowerShell, CMD, và Git Bash.
### Với Arguments
Tất cả args sau tên profile được truyền trực tiếp cho Claude CLI:
@@ -284,11 +339,16 @@ ccs son
## Yêu Cầu
### macOS / Linux
- **Bash** 3.2+
- **jq** (để xử lý JSON)
- **Claude CLI** đã cài đặt
### Cài jq
### Windows
- **PowerShell** 5.1+ (có sẵn trên Windows 10+)
- **Claude CLI** đã cài đặt
### Cài jq (chỉ macOS / Linux)
**macOS**:
```bash
@@ -310,8 +370,46 @@ sudo dnf install jq
sudo pacman -S jq
```
**Lưu ý**: Phiên bản Windows dùng JSON support có sẵn của PowerShell - không cần jq.
## Troubleshooting
### Vấn Đề Riêng Cho Windows
#### PowerShell Execution Policy
Nếu bạn thấy lỗi "cannot be loaded because running scripts is disabled":
```powershell
# Kiểm tra policy hiện tại
Get-ExecutionPolicy
# Cho phép user hiện tại chạy scripts (khuyến nghị)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Hoặc chạy với bypass (một lần)
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.ccs\ccs.ps1" glm
```
#### PATH chưa được cập nhật (Windows)
Nếu lệnh `ccs` không tìm thấy sau khi cài đặt:
1. Khởi động lại terminal
2. Hoặc thêm thủ công vào PATH:
- Mở "Edit environment variables for your account"
- Thêm `%USERPROFILE%\.ccs` vào User PATH
- Khởi động lại terminal
#### Claude CLI không tìm thấy (Windows)
```powershell
# Kiểm tra Claude CLI
where.exe claude
# Nếu thiếu, cài đặt từ tài liệu Claude
```
### Vấn Đề Cài Đặt
#### Lỗi BASH_SOURCE unbound variable
@@ -407,12 +505,14 @@ Error: Profile 'default' not found in ~/.ccs/config.json
## Gỡ Cài Đặt
### macOS / Linux
**Dùng lệnh đã cài**:
```bash
ccs-uninstall
```
**Một dòng lệnh** (nếu ccs-uninstall không có):
**Một dòng lệnh**:
```bash
# URL ngắn
curl -fsSL ccs.kaitran.ca/uninstall | bash
@@ -428,6 +528,37 @@ rm ~/.local/bin/ccs-uninstall
rm -rf ~/.ccs # Nếu muốn xóa tất cả files của CCS
```
### Windows PowerShell
**Dùng lệnh đã cài**:
```powershell
ccs-uninstall
```
**Một dòng lệnh**:
```powershell
# URL ngắn
irm ccs.kaitran.ca/uninstall.ps1 | iex
# Hoặc trực tiếp từ GitHub
irm https://raw.githubusercontent.com/kaitranntt/ccs/main/uninstall.ps1 | iex
```
**Thủ công**:
```powershell
# Xóa scripts
Remove-Item "$env:USERPROFILE\.ccs\ccs.ps1" -Force
Remove-Item "$env:USERPROFILE\.ccs\uninstall.ps1" -Force
# Xóa khỏi PATH
$Path = [Environment]::GetEnvironmentVariable("Path", "User")
$NewPath = ($Path -split ';' | Where-Object { $_ -ne "$env:USERPROFILE\.ccs" }) -join ';'
[Environment]::SetEnvironmentVariable("Path", $NewPath, "User")
# Tùy chọn: Xóa tất cả files CCS
Remove-Item "$env:USERPROFILE\.ccs" -Recurse -Force
```
## Bảo Mật
- ✅ Zero dependencies (chỉ bash + jq)
@@ -454,7 +585,7 @@ A: Không. Profile switching hoàn toàn offline. Chỉ cần internet cho API c
A: Không. Installer tạo files mới và giữ nguyên configs hiện tại.
**Q: CCS có hoạt động trên Windows không?**
A: CCS cần bash. Dùng WSL, Git Bash, hoặc Cygwin trên Windows.
A: Có! CCS bây giờ hỗ trợ Windows PowerShell 5.1+ ngoài macOS/Linux bash.
## Đóng Góp
@@ -466,6 +597,12 @@ Contributions được chào đón! Vui lòng:
4. Push lên branch
5. Mở Pull Request
**Guidelines**:
- Duy trì tương thích bash 3.2+ (Unix) và PowerShell 5.1+ (Windows)
- Không dependencies ngoài jq (Unix) hoặc PowerShell có sẵn (Windows)
- Test trên macOS, Linux, và Windows
- Tuân theo code style hiện có
## License
MIT License - xem [LICENSE](LICENSE) để biết chi tiết.
+95
View File
@@ -0,0 +1,95 @@
# CCS - Claude Code Switch (Windows PowerShell)
# Cross-platform Claude CLI profile switcher
# https://github.com/kaitranntt/ccs
param(
[Parameter(Position=0)]
[string]$Profile = "default",
[Parameter(ValueFromRemainingArguments=$true)]
[string[]]$RemainingArgs
)
$ErrorActionPreference = "Stop"
# Config file location (supports environment variable override)
$ConfigFile = if ($env:CCS_CONFIG) {
$env:CCS_CONFIG
} else {
"$env:USERPROFILE\.ccs\config.json"
}
# Check config exists
if (-not (Test-Path $ConfigFile)) {
Write-Host "Error: Config file not found: $ConfigFile" -ForegroundColor Red
Write-Host ""
Write-Host "Create $env:USERPROFILE\.ccs\config.json with your profile mappings."
Write-Host "See .ccs.example.json for template."
exit 1
}
# Validate profile name (alphanumeric, dash, underscore only)
if ($Profile -notmatch '^[a-zA-Z0-9_-]+$') {
Write-Host "Error: Invalid profile name. Use only alphanumeric characters, dash, or underscore." -ForegroundColor Red
exit 1
}
# Read and parse JSON config
try {
$ConfigContent = Get-Content $ConfigFile -Raw -ErrorAction Stop
$Config = $ConfigContent | ConvertFrom-Json -ErrorAction Stop
} catch {
Write-Host "Error: Invalid JSON in $ConfigFile" -ForegroundColor Red
exit 1
}
# Validate config has profiles object
if (-not $Config.profiles) {
Write-Host "Error: Config must have 'profiles' object" -ForegroundColor Red
Write-Host "See .ccs.example.json for correct format"
exit 1
}
# Get settings path for profile
$SettingsPath = $Config.profiles.$Profile
if (-not $SettingsPath) {
Write-Host "Error: Profile '$Profile' not found in $ConfigFile" -ForegroundColor Red
Write-Host ""
Write-Host "Available profiles:"
$Config.profiles.PSObject.Properties.Name | ForEach-Object {
Write-Host " - $_"
}
exit 1
}
# Path expansion and normalization
# 1. Handle Unix-style tilde expansion (~/path -> %USERPROFILE%\path)
if ($SettingsPath -match '^~[/\\]') {
$SettingsPath = $SettingsPath -replace '^~', $env:USERPROFILE
}
# 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 "Create the settings file or update the path in $ConfigFile"
exit 1
}
# Execute claude with settings
# Build argument array to pass all remaining arguments to Claude CLI
$ClaudeArgs = @("--settings", $SettingsPath)
if ($RemainingArgs) {
$ClaudeArgs += $RemainingArgs
}
# Execute claude and preserve exit code
& claude $ClaudeArgs
exit $LASTEXITCODE
+277
View File
@@ -0,0 +1,277 @@
# CCS Installation Script (Windows PowerShell)
# https://github.com/kaitranntt/ccs
param(
[string]$InstallDir = "$env:USERPROFILE\.ccs"
)
$ErrorActionPreference = "Stop"
# Configuration
$CcsDir = "$env:USERPROFILE\.ccs"
$ClaudeDir = "$env:USERPROFILE\.claude"
$GlmModel = "glm-4.6"
# Detect if running from git repository or standalone
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$InstallMethod = if (Test-Path "$ScriptDir\ccs.ps1") { "git" } else { "standalone" }
# Helper Functions
function Detect-CurrentProvider {
$SettingsFile = "$ClaudeDir\settings.json"
if (-not (Test-Path $SettingsFile)) {
return "unknown"
}
try {
$Content = Get-Content $SettingsFile -Raw
if ($Content -match "api\.z\.ai|glm-4") {
return "glm"
} elseif ($Content -match "ANTHROPIC_BASE_URL" -and $Content -notmatch "api\.z\.ai") {
return "custom"
} else {
return "claude"
}
} catch {
return "unknown"
}
}
function New-GlmTemplate {
$Template = @{
env = @{
ANTHROPIC_BASE_URL = "https://api.z.ai/api/anthropic"
ANTHROPIC_AUTH_TOKEN = "YOUR_GLM_API_KEY_HERE"
ANTHROPIC_MODEL = $GlmModel
ANTHROPIC_DEFAULT_OPUS_MODEL = $GlmModel
ANTHROPIC_DEFAULT_SONNET_MODEL = $GlmModel
ANTHROPIC_DEFAULT_HAIKU_MODEL = $GlmModel
}
}
return $Template | ConvertTo-Json -Depth 10
}
function New-SonnetTemplate {
$Template = @{ env = @{} }
return $Template | ConvertTo-Json -Depth 10
}
function New-GlmProfile {
param([string]$Provider)
$CurrentSettings = "$ClaudeDir\settings.json"
$GlmSettings = "$CcsDir\glm.settings.json"
if ($Provider -eq "glm" -and (Test-Path $CurrentSettings)) {
Write-Host "✓ Copying current GLM config to profile..."
try {
$Config = Get-Content $CurrentSettings -Raw | ConvertFrom-Json
if (-not $Config.env) {
$Config | Add-Member -NotePropertyName env -NotePropertyValue @{} -Force
}
$Config.env | Add-Member -NotePropertyName ANTHROPIC_DEFAULT_OPUS_MODEL -NotePropertyValue $GlmModel -Force
$Config.env | Add-Member -NotePropertyName ANTHROPIC_DEFAULT_SONNET_MODEL -NotePropertyValue $GlmModel -Force
$Config.env | Add-Member -NotePropertyName ANTHROPIC_DEFAULT_HAIKU_MODEL -NotePropertyValue $GlmModel -Force
$Config | ConvertTo-Json -Depth 10 | Set-Content $GlmSettings
Write-Host " Created: $GlmSettings (with your existing API key + enhanced settings)"
} catch {
Write-Host " ️ Copying current settings failed, using template"
New-GlmTemplate | Set-Content $GlmSettings
}
} else {
Write-Host "Creating GLM profile template at $GlmSettings"
New-GlmTemplate | Set-Content $GlmSettings
Write-Host " Created: $GlmSettings"
Write-Host " ⚠️ Edit this file and replace YOUR_GLM_API_KEY_HERE with your actual GLM API key"
}
}
function New-SonnetProfile {
param([string]$Provider)
$CurrentSettings = "$ClaudeDir\settings.json"
$SonnetSettings = "$CcsDir\sonnet.settings.json"
if ($Provider -eq "claude" -and (Test-Path $CurrentSettings)) {
Write-Host "✓ Copying current Claude config to profile..."
Copy-Item $CurrentSettings $SonnetSettings
Write-Host " Created: $SonnetSettings"
} else {
Write-Host "Creating Claude Sonnet profile template at $SonnetSettings"
if (Test-Path $CurrentSettings) {
try {
$Config = Get-Content $CurrentSettings -Raw | ConvertFrom-Json
# Remove GLM-specific vars
if ($Config.env) {
$Config.env.PSObject.Properties.Remove('ANTHROPIC_BASE_URL')
$Config.env.PSObject.Properties.Remove('ANTHROPIC_AUTH_TOKEN')
$Config.env.PSObject.Properties.Remove('ANTHROPIC_MODEL')
}
$Config | ConvertTo-Json -Depth 10 | Set-Content $SonnetSettings
} catch {
New-SonnetTemplate | Set-Content $SonnetSettings
}
} else {
New-SonnetTemplate | Set-Content $SonnetSettings
}
Write-Host " Created: $SonnetSettings"
Write-Host " ️ This uses your Claude subscription (no API key needed)"
}
}
# Main Installation
Write-Host "┌─ Installing CCS (Windows)"
# Create directories
New-Item -ItemType Directory -Force -Path $CcsDir | Out-Null
# Install main executable
if ($InstallMethod -eq "standalone") {
# Standalone install - download from GitHub
Write-Host "│ Downloading CCS from GitHub..."
try {
$BaseUrl = "https://raw.githubusercontent.com/kaitranntt/ccs/main"
Invoke-WebRequest -Uri "$BaseUrl/ccs.ps1" -OutFile "$CcsDir\ccs.ps1" -UseBasicParsing
Write-Host "│ ✓ Downloaded ccs.ps1"
} catch {
Write-Host ""
Write-Host "✗ Error: Failed to download ccs.ps1 from GitHub" -ForegroundColor Red
Write-Host " $_"
exit 1
}
} else {
# Git install - copy local file
Copy-Item "$ScriptDir\ccs.ps1" "$CcsDir\ccs.ps1" -Force
Write-Host "│ ✓ Installed ccs.ps1"
}
# Install uninstall script
if (Test-Path "$ScriptDir\uninstall.ps1") {
# Only copy if source and destination are different
if ($ScriptDir -ne $CcsDir) {
Copy-Item "$ScriptDir\uninstall.ps1" "$CcsDir\uninstall.ps1" -Force
}
Write-Host "│ ✓ Installed uninstaller"
} elseif ($InstallMethod -eq "standalone") {
try {
$BaseUrl = "https://raw.githubusercontent.com/kaitranntt/ccs/main"
Invoke-WebRequest -Uri "$BaseUrl/uninstall.ps1" -OutFile "$CcsDir\uninstall.ps1" -UseBasicParsing
Write-Host "│ ✓ Installed uninstaller"
} catch {
Write-Host "│ ⚠️ Could not download uninstaller (optional)"
}
}
Write-Host "│ ✓ Created directories"
Write-Host "└─"
Write-Host ""
# Profile Setup
$CurrentProvider = Detect-CurrentProvider
$GlmSettings = "$CcsDir\glm.settings.json"
$SonnetSettings = "$CcsDir\sonnet.settings.json"
$ProviderLabel = switch ($CurrentProvider) {
"glm" { " (detected: GLM)" }
"claude" { " (detected: Claude)" }
"custom" { " (detected: custom)" }
default { "" }
}
Write-Host "┌─ Configuring Profiles$ProviderLabel"
$NeedsGlmKey = $false
if (-not (Test-Path $GlmSettings)) {
New-GlmProfile -Provider $CurrentProvider | Out-Null
Write-Host "│ ✓ 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 "│ ✓ Sonnet profile → $env:USERPROFILE\.ccs\sonnet.settings.json"
}
# Create ccs config (using Unix-style paths for cross-platform compatibility)
$ConfigFile = "$CcsDir\config.json"
if (-not (Test-Path $ConfigFile)) {
$ConfigContent = @{
profiles = @{
glm = "~/.ccs/glm.settings.json"
son = "~/.ccs/sonnet.settings.json"
default = "~/.claude/settings.json"
}
}
$ConfigContent | ConvertTo-Json -Depth 10 | Set-Content $ConfigFile
Write-Host "│ ✓ Config → $env:USERPROFILE\.ccs\config.json"
}
Write-Host "└─"
Write-Host ""
# Check and update PATH
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($UserPath -notlike "*$CcsDir*") {
Write-Host "⚠️ PATH Configuration Required"
Write-Host ""
Write-Host " Adding $CcsDir to your PATH..."
try {
$NewPath = if ($UserPath) { "$UserPath;$CcsDir" } else { $CcsDir }
[Environment]::SetEnvironmentVariable("Path", $NewPath, "User")
Write-Host " ✓ PATH updated. Restart your terminal for changes to take effect."
Write-Host ""
} catch {
Write-Host " ✗ Could not update PATH automatically." -ForegroundColor Yellow
Write-Host " Please add manually: $CcsDir"
Write-Host ""
}
}
# Show API key warning if needed
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 ""
}
Write-Host "✅ CCS installed successfully!"
Write-Host ""
# Build quick start based on current provider
if ($CurrentProvider -eq "claude") {
Write-Host " Quick start:"
Write-Host " ccs son # Claude Sonnet (current)"
Write-Host " ccs glm # GLM (after adding API key)"
Write-Host " ccs # Default profile"
} elseif ($CurrentProvider -eq "glm") {
Write-Host " Quick start:"
Write-Host " ccs glm # GLM (current)"
Write-Host " ccs son # Claude Sonnet"
Write-Host " ccs # Default profile"
} else {
Write-Host " Quick start:"
Write-Host " ccs # Default profile"
Write-Host " ccs son # Claude Sonnet"
Write-Host " ccs glm # GLM (after adding API key)"
}
Write-Host ""
Write-Host " Usage: ccs [profile] [claude-args]"
Write-Host " Example: ccs glm /plan 'implement feature'"
Write-Host ""
Write-Host " To uninstall: ccs-uninstall"
Write-Host ""
+31
View File
@@ -27,6 +27,37 @@ else
INSTALL_METHOD="standalone"
fi
# --- Platform Detection ---
# Detect platform and redirect to Windows installer if needed
detect_platform() {
case "$OSTYPE" in
msys*|mingw*|cygwin*|win32*)
echo "windows"
;;
*)
echo "unix"
;;
esac
}
PLATFORM=$(detect_platform)
if [[ "$PLATFORM" == "windows" ]]; then
echo "Windows detected. Using PowerShell installer..."
if [[ -f "$SCRIPT_DIR/install.ps1" ]]; then
powershell.exe -ExecutionPolicy Bypass -File "$SCRIPT_DIR/install.ps1"
exit $?
else
echo "Error: install.ps1 not found."
echo "Please download the full CCS package from:"
echo " https://github.com/kaitranntt/ccs"
exit 1
fi
fi
# Continue with Unix installation...
# --- Helper Functions ---
detect_current_provider() {
+56
View File
@@ -0,0 +1,56 @@
# CCS Uninstallation Script (Windows PowerShell)
# https://github.com/kaitranntt/ccs
$ErrorActionPreference = "Stop"
Write-Host "Uninstalling ccs..."
Write-Host ""
$CcsDir = "$env:USERPROFILE\.ccs"
# Remove ccs.ps1
if (Test-Path "$CcsDir\ccs.ps1") {
Remove-Item "$CcsDir\ccs.ps1" -Force
Write-Host "✅ Removed: $CcsDir\ccs.ps1"
} else {
Write-Host "️ No ccs.ps1 found at $CcsDir"
}
# Remove uninstall script itself (will be last)
$UninstallScript = "$CcsDir\uninstall.ps1"
# Remove from PATH
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($UserPath -like "*$CcsDir*") {
try {
$NewPath = ($UserPath -split ';' | Where-Object { $_ -ne $CcsDir }) -join ';'
[Environment]::SetEnvironmentVariable("Path", $NewPath, "User")
Write-Host "✅ Removed from PATH: $CcsDir"
Write-Host " Restart your terminal for changes to take effect."
} catch {
Write-Host "⚠️ Could not remove from PATH automatically. Please remove manually: $CcsDir" -ForegroundColor Yellow
}
}
# Ask about ~/.ccs directory
if (Test-Path $CcsDir) {
Write-Host ""
$Response = Read-Host "Remove CCS directory $CcsDir`? This includes config and profiles. (y/N)"
if ($Response -match '^[Yy]$') {
Remove-Item $CcsDir -Recurse -Force
Write-Host "✅ Removed: $CcsDir"
} else {
# If keeping directory, remove uninstall script
if (Test-Path $UninstallScript) {
Remove-Item $UninstallScript -Force
Write-Host "✅ Removed: $UninstallScript"
}
Write-Host "️ Kept: $CcsDir"
}
} else {
Write-Host "️ No CCS directory found at $CcsDir"
}
Write-Host ""
Write-Host "✅ Uninstall complete!"
Write-Host ""