mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-05 18:16:28 +00:00
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:
@@ -1,8 +1,8 @@
|
||||
# CCS - Claude Code Switch
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://www.gnu.org/software/bash/)
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
|
||||
**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
@@ -1,8 +1,8 @@
|
||||
# CCS - Claude Code Switch
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://www.gnu.org/software/bash/)
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
|
||||
**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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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 ""
|
||||
Reference in New Issue
Block a user