Skip to content

Commit be8aa83

Browse files
authored
feat: shell completion support & merge install into init (#22)
* feat: add shell completion and merge install into init (#12) - Add `codes completion [bash|zsh|fish|powershell]` command using Cobra's built-in completion generators - Add dynamic completion for config names, project names, and static values on relevant subcommands - Merge `install` command into `init`: now `codes init` handles binary self-install, shell completion setup, and environment health checks - Add install.sh for quick curl-pipe installation - Update README and Makefile to reflect the changes * fix: update CI to test completion instead of removed install command * fix: address review feedback and add PowerShell install script - Check os.UserHomeDir() errors in installBinary/installShellCompletion - Use io.Copy for streaming binary copy instead of ReadFile - Reflect install failures in RunInit allGood flag - Fix ProjectRemoveCmd to use NoFileComp directive - Add install.ps1 for Windows one-liner install - Add PowerShell quick install to README
1 parent 90f8afa commit be8aa83

File tree

8 files changed

+486
-137
lines changed

8 files changed

+486
-137
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ jobs:
3535
run: |
3636
./codes add --help
3737
./codes select --help
38-
./codes install --help
38+
./codes completion --help

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ help:
99
@echo " clean - Clean build artifacts"
1010
@echo " test - Test the build"
1111
@echo " version - Show version"
12-
@echo " install - Install codes to system"
12+
@echo " install - Build and run init (install + setup)"
1313
@echo ""
1414
@echo "Usage: make [target]"
1515

@@ -28,15 +28,15 @@ test:
2828
@if [ -f "$(BINARY)" ]; then \
2929
./$(BINARY) --help > /dev/null 2>&1 && echo "✓ Help works"; \
3030
./$(BINARY) version && echo "✓ Version works"; \
31-
./$(BINARY) install --help 2>/dev/null && echo "Install command exists"; \
31+
./$(BINARY) completion bash > /dev/null 2>&1 && echo "Completion works"; \
3232
else \
3333
echo "✗ Not built"; \
3434
fi
3535

3636
version:
3737
@./$(BINARY) version 2>/dev/null || echo "Not built"
3838

39-
install:
39+
install: build
4040
@echo "Installing codes..."
41-
@./$(BINARY) install
41+
@./$(BINARY) init
4242
@echo "Install completed"

README.md

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ A powerful CLI tool for managing multiple Claude Code configurations with ease.
1616
- **Permission Control**: Manage --dangerously-skip-permissions flag for Claude CLI
1717
- **Flexible Startup Behavior**: Control where Claude starts when no arguments provided
1818

19+
## Quick Install
20+
21+
**Linux / macOS:**
22+
23+
```bash
24+
curl -fsSL https://raw.githubusercontent.com/ourines/codes/main/install.sh | sh
25+
```
26+
27+
**Windows (PowerShell):**
28+
29+
```powershell
30+
irm https://raw.githubusercontent.com/ourines/codes/main/install.ps1 | iex
31+
```
32+
1933
## Installation
2034

2135
### Pre-built Binaries
@@ -29,16 +43,16 @@ Download the latest release for your platform from the [releases page](https://g
2943
curl -L https://github.com/ourines/codes/releases/latest/download/codes-linux-amd64 -o codes
3044
chmod +x codes
3145

32-
# Install to system path
33-
./codes install
46+
# Install to system path and set up shell completion
47+
./codes init
3448
```
3549

3650
#### Windows
3751

3852
```powershell
3953
# Download the binary for your architecture
40-
# Then run the install command
41-
.\codes.exe install
54+
# Then run the init command
55+
.\codes.exe init
4256
```
4357

4458
### Build from Source
@@ -55,19 +69,19 @@ cd codes
5569
# Build the binary
5670
make build
5771

58-
# Install to system PATH
59-
./codes install
72+
# Install to system PATH and set up shell completion
73+
./codes init
6074
```
6175

6276
## Quick Start
6377

64-
### 1. Check Your Environment (Optional but Recommended)
78+
### 1. Initialize Your Environment
6579

6680
```bash
6781
codes init
6882
```
6983

70-
This will verify that everything is set up correctly and guide you if something is missing.
84+
This installs the binary to your system PATH, sets up shell completion, and verifies that everything is configured correctly.
7185

7286
### 2. Add Your First Configuration
7387

@@ -102,30 +116,32 @@ An interactive menu will appear showing all your configurations. Select one to s
102116

103117
### `codes init`
104118

105-
Check your environment and validate your configuration. This command performs comprehensive checks including:
119+
Initialize and configure the codes CLI. This command performs three main tasks:
106120

107-
- Verifies Claude CLI installation
108-
- Detects existing Claude configuration in environment variables
109-
- Offers to import existing configuration if found
110-
- Checks configuration file existence and validity
111-
- Tests API connectivity for the default configuration
112-
- Displays detailed status of all configurations
121+
1. **Installs the binary** to your system PATH (`/usr/local/bin` on Linux/macOS, `~/go/bin` on Windows)
122+
2. **Sets up shell completion** automatically for your current shell
123+
3. **Runs environment health checks**, including:
124+
- Verifies Claude CLI installation
125+
- Detects existing Claude configuration in environment variables
126+
- Offers to import existing configuration if found
127+
- Checks configuration file existence and validity
128+
- Tests API connectivity for the default configuration
113129

114130
```bash
115131
codes init
116132
```
117133

118134
**Example output:**
119-
```
135+
```text
136+
✓ Binary installed to /usr/local/bin/codes
137+
✓ Shell completion configured for zsh
120138
✓ Claude CLI is installed
121139
✓ Found existing configuration in environment variables
122140
✓ Configuration file exists
123141
✓ Found 3 configuration(s)
124142
✓ Default configuration is working
125143
```
126144

127-
This is a great command to run after installation or when troubleshooting issues.
128-
129145
### `codes` (no arguments)
130146

131147
Runs Claude CLI with the currently selected configuration in the last used directory. If Claude CLI is not installed, it will be automatically installed. The tool remembers your last working directory for convenience.
@@ -141,6 +157,30 @@ codes /path/to/project
141157
codes my-project # if you've added a project alias
142158
```
143159

160+
### `codes completion [shell]`
161+
162+
Generate shell completion scripts. While `codes init` automatically sets up completion, you can also generate scripts manually.
163+
164+
```bash
165+
codes completion [bash|zsh|fish|powershell]
166+
```
167+
168+
**Manual setup (for reference):**
169+
170+
```bash
171+
# Zsh (add to ~/.zshrc)
172+
source <(codes completion zsh)
173+
174+
# Bash (add to ~/.bashrc)
175+
source <(codes completion bash)
176+
177+
# Fish
178+
codes completion fish | source
179+
180+
# PowerShell
181+
codes completion powershell | Out-String | Invoke-Expression
182+
```
183+
144184
### `codes add`
145185

146186
Interactively add a new Claude API configuration.
@@ -269,17 +309,6 @@ codes skippermissions reset
269309
- Individual configurations can have their own `skipPermissions` setting that takes precedence
270310
- This controls whether Claude bypasses certain security checks for file system access
271311

272-
### `codes install`
273-
274-
Install the codes binary to your system PATH.
275-
276-
```bash
277-
codes install
278-
```
279-
280-
- **Linux/macOS**: Installs to `/usr/local/bin` or `~/bin`
281-
- **Windows**: Installs to `~/go/bin`
282-
283312
### `codes start [path-or-project]`
284313

285314
Start Claude Code in a specific directory or using a project alias. Without arguments, it uses the last working directory.
@@ -480,7 +509,7 @@ If you get permission errors during installation:
480509

481510
```bash
482511
# Use sudo for system-wide installation
483-
sudo ./codes install
512+
sudo ./codes init
484513

485514
# Or install to user directory
486515
mkdir -p ~/bin

cmd/codes/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ var rootCmd = &cobra.Command{
1717

1818
func init() {
1919
rootCmd.AddCommand(commands.InitCmd)
20-
rootCmd.AddCommand(commands.InstallCmd)
2120
rootCmd.AddCommand(commands.AddCmd)
2221
rootCmd.AddCommand(commands.SelectCmd)
2322
rootCmd.AddCommand(commands.TestCmd)
@@ -28,6 +27,7 @@ func init() {
2827
rootCmd.AddCommand(commands.ConfigCmd)
2928
rootCmd.AddCommand(commands.DefaultBehaviorCmd)
3029
rootCmd.AddCommand(commands.SkipPermissionsCmd)
30+
rootCmd.AddCommand(commands.CompletionCmd)
3131

3232
// 设置默认运行时行为 - 现在使用智能启动
3333
rootCmd.Run = func(cmd *cobra.Command, args []string) {

install.ps1

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Install script for codes - https://github.com/ourines/codes
2+
# Usage: irm https://raw.githubusercontent.com/ourines/codes/main/install.ps1 | iex
3+
$ErrorActionPreference = "Stop"
4+
5+
$Repo = "ourines/codes"
6+
$Binary = "codes.exe"
7+
8+
# Detect architecture
9+
$Arch = if ([Environment]::Is64BitOperatingSystem) {
10+
if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { "arm64" } else { "amd64" }
11+
} else {
12+
Write-Error "32-bit systems are not supported."
13+
return
14+
}
15+
16+
Write-Host " > Detected platform: windows/$Arch" -ForegroundColor Cyan
17+
18+
$Url = "https://github.com/$Repo/releases/latest/download/codes-windows-$Arch.exe"
19+
$TempFile = Join-Path $env:TEMP "codes-install.exe"
20+
21+
Write-Host " > Downloading codes from $Url..." -ForegroundColor Cyan
22+
try {
23+
Invoke-WebRequest -Uri $Url -OutFile $TempFile -UseBasicParsing
24+
} catch {
25+
Write-Error "Download failed. Check that a release exists for windows/$Arch."
26+
return
27+
}
28+
Write-Host " ✓ Downloaded successfully" -ForegroundColor Green
29+
30+
# Install to user's local bin directory
31+
$InstallDir = Join-Path $env:LOCALAPPDATA "codes"
32+
if (-not (Test-Path $InstallDir)) {
33+
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
34+
}
35+
36+
$InstallPath = Join-Path $InstallDir $Binary
37+
Move-Item -Path $TempFile -Destination $InstallPath -Force
38+
Write-Host " ✓ Installed to $InstallPath" -ForegroundColor Green
39+
40+
# Add to PATH if not already there
41+
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
42+
if ($UserPath -notlike "*$InstallDir*") {
43+
[Environment]::SetEnvironmentVariable("Path", "$UserPath;$InstallDir", "User")
44+
$env:Path = "$env:Path;$InstallDir"
45+
Write-Host " ✓ Added $InstallDir to PATH" -ForegroundColor Green
46+
}
47+
48+
# Run init
49+
Write-Host " > Running codes init..." -ForegroundColor Cyan
50+
& $InstallPath init
51+
52+
Write-Host ""
53+
Write-Host " ✓ Installation complete! Run 'codes --help' to get started." -ForegroundColor Green

install.sh

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/bin/sh
2+
# Install script for codes - https://github.com/ourines/codes
3+
# Usage: curl -fsSL https://raw.githubusercontent.com/ourines/codes/main/install.sh | sh
4+
set -e
5+
6+
REPO="ourines/codes"
7+
BINARY="codes"
8+
INSTALL_DIR="/usr/local/bin"
9+
10+
# --- Helpers ---
11+
12+
info() {
13+
printf ' \033[34m>\033[0m %s\n' "$1"
14+
}
15+
16+
ok() {
17+
printf ' \033[32m✓\033[0m %s\n' "$1"
18+
}
19+
20+
err() {
21+
printf ' \033[31m✗\033[0m %s\n' "$1" >&2
22+
}
23+
24+
die() {
25+
err "$1"
26+
exit 1
27+
}
28+
29+
need() {
30+
command -v "$1" >/dev/null 2>&1 || die "'$1' is required but not found"
31+
}
32+
33+
# --- Detect platform ---
34+
35+
detect_os() {
36+
case "$(uname -s)" in
37+
Linux*) echo "linux" ;;
38+
Darwin*) echo "darwin" ;;
39+
*) die "Unsupported OS: $(uname -s)" ;;
40+
esac
41+
}
42+
43+
detect_arch() {
44+
case "$(uname -m)" in
45+
x86_64|amd64) echo "amd64" ;;
46+
aarch64|arm64) echo "arm64" ;;
47+
*) die "Unsupported architecture: $(uname -m)" ;;
48+
esac
49+
}
50+
51+
# --- Main ---
52+
53+
main() {
54+
need curl
55+
56+
OS="$(detect_os)"
57+
ARCH="$(detect_arch)"
58+
59+
info "Detected platform: ${OS}/${ARCH}"
60+
61+
URL="https://github.com/${REPO}/releases/latest/download/${BINARY}-${OS}-${ARCH}"
62+
TMPFILE="$(mktemp)"
63+
trap 'rm -f "$TMPFILE"' EXIT
64+
65+
info "Downloading ${BINARY} from ${URL}..."
66+
if ! curl -fSL --progress-bar -o "$TMPFILE" "$URL"; then
67+
die "Download failed. Check that a release exists for ${OS}/${ARCH}."
68+
fi
69+
70+
chmod +x "$TMPFILE"
71+
ok "Downloaded successfully"
72+
73+
# Try /usr/local/bin first, fall back to ~/bin
74+
if [ -w "$INSTALL_DIR" ]; then
75+
mv "$TMPFILE" "${INSTALL_DIR}/${BINARY}"
76+
ok "Installed to ${INSTALL_DIR}/${BINARY}"
77+
elif command -v sudo >/dev/null 2>&1; then
78+
info "Installing to ${INSTALL_DIR} (requires sudo)..."
79+
sudo mv "$TMPFILE" "${INSTALL_DIR}/${BINARY}"
80+
ok "Installed to ${INSTALL_DIR}/${BINARY}"
81+
else
82+
INSTALL_DIR="${HOME}/bin"
83+
mkdir -p "$INSTALL_DIR"
84+
mv "$TMPFILE" "${INSTALL_DIR}/${BINARY}"
85+
ok "Installed to ${INSTALL_DIR}/${BINARY}"
86+
case ":$PATH:" in
87+
*":${INSTALL_DIR}:"*) ;;
88+
*) printf '\n %s\n\n' "Add ${INSTALL_DIR} to your PATH: export PATH=\"\$HOME/bin:\$PATH\"" ;;
89+
esac
90+
fi
91+
92+
# Run init for shell completion and environment check
93+
info "Running ${BINARY} init..."
94+
"${INSTALL_DIR}/${BINARY}" init
95+
96+
printf '\n'
97+
ok "Installation complete! Run 'codes --help' to get started."
98+
}
99+
100+
main

0 commit comments

Comments
 (0)