Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Multi-provider launcher for Claude Code. Switch between Anthropic subscription,

- **Single file, zero dependencies** - one bash script, download and run
- **Multiple providers** - Anthropic, DeepSeek, Zhipu, Moonshot, MiniMax, and more
- **Local server support** - Ollama, LM Studio, LlamaBarn, llama.cpp
- **Local server support** - Ollama, LM Studio, Llama (llama.cpp)
- **Custom endpoints** - any Anthropic-compatible URL
- **Model tier mapping** - configure opus/sonnet/haiku models per provider
- **Fully transparent** - readable bash, see exactly what happens before `exec claude`
Expand Down Expand Up @@ -82,8 +82,9 @@ cc-launcher ollama "qwen3:32b" # Local Ollama with model
|----------|-------------|
| `ollama` | localhost:11434 |
| `lmstudio` | localhost:1234 |
| `llama-server` | localhost:8080 |
| `llamabarn` | localhost:2276 |
| `llama` | localhost:8080 |

`llama` is the [Llama macOS app](https://github.com/ggml-org/Llama-macOS) (formerly LlamaBarn), the unified [`llama serve`](https://llama.app) CLI, or plain llama.cpp `llama-server` — all serve on port 8080. `llamabarn` and `llama-barn` still work as aliases (now pointing at 8080; pre-0.32 LlamaBarn on 2276 needs a custom URL).

```bash
cc-launcher ollama "gpt-oss" # Single model for all tiers
Expand Down
2 changes: 1 addition & 1 deletion cc-headless/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Configuration for running Claude Code with API keys instead of the default subsc

- **Custom statusline** showing context usage, model, session count, directory, git info, and line changes
- **Model preset** set to Opus
- **No Claude attribution** in commits, PRs, or session links (`attribution` set to empty; replaces the deprecated `includeCoAuthoredBy`)
- **No Claude attribution** in commits, PRs, or session links (`attribution.commit`/`pr` empty strings, `sessionUrl: false`; replaces the deprecated `includeCoAuthoredBy`)
- **Telemetry disabled** via granular `DISABLE_*` flags — deliberately not the `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` umbrella, which would also disable the auto-updater
- **Onboarding bypassed** so Claude Code starts immediately

Expand Down
94 changes: 55 additions & 39 deletions cc-launcher
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,18 @@ PROVIDERS_ANTHROPIC="https://api.anthropic.com"
PROVIDERS_DEEPSEEK="https://api.deepseek.com/anthropic"
PROVIDERS_ZHIPU="https://api.z.ai/api/anthropic"
PROVIDERS_MINIMAX="https://api.minimax.io/anthropic"
PROVIDERS_LLAMA_SERVER="http://localhost:8080"
PROVIDERS_OLLAMA="http://localhost:11434"
PROVIDERS_LMSTUDIO="http://localhost:1234"
PROVIDERS_LLAMABARN="http://localhost:2276"

MODELS_MOONSHOT_OPUS="kimi-k2.5"
MODELS_MOONSHOT="kimi-k2-turbo-preview"
MODELS_ANTHROPIC="claude-sonnet-4-5"
MODELS_DEEPSEEK="deepseek-chat"
MODELS_DEEPSEEK_FAST="deepseek-chat"
MODELS_ZHIPU="glm-5"
MODELS_ZHIPU_FAST="GLM-4.7-Flash"
MODELS_MINIMAX="MiniMax-M2.5"
MODELS_MINIMAX_FAST="MiniMax-M2.5-highspeed"
PROVIDERS_LLAMA="http://localhost:8080" # Llama app (formerly LlamaBarn), port matches llama.cpp since 0.32.0

MODELS_MOONSHOT="kimi-k2.7-code"
MODELS_ANTHROPIC="claude-sonnet-5"
# Match DeepSeek's official Claude Code guide (pro[1m] for opus/sonnet, flash for haiku/subagent)
MODELS_DEEPSEEK="deepseek-v4-pro[1m]"
MODELS_DEEPSEEK_FAST="deepseek-v4-flash"
MODELS_ZHIPU="glm-5.2"
MODELS_ZHIPU_FAST="glm-4.7"
MODELS_MINIMAX="MiniMax-M3[1m]"

# Get provider URL
get_provider_url() {
Expand All @@ -35,10 +33,9 @@ get_provider_url() {
"deepseek") echo "$PROVIDERS_DEEPSEEK" ;;
"zhipu") echo "$PROVIDERS_ZHIPU" ;;
"minimax") echo "$PROVIDERS_MINIMAX" ;;
"llama-server") echo "$PROVIDERS_LLAMA_SERVER" ;;
"ollama") echo "$PROVIDERS_OLLAMA" ;;
"lmstudio") echo "$PROVIDERS_LMSTUDIO" ;;
"llamabarn") echo "$PROVIDERS_LLAMABARN" ;;
"llama") echo "$PROVIDERS_LLAMA" ;;
esac
}

Expand All @@ -50,15 +47,14 @@ get_provider_model() {
"deepseek") echo "$MODELS_DEEPSEEK" ;;
"zhipu") echo "$MODELS_ZHIPU" ;;
"minimax") echo "$MODELS_MINIMAX" ;;
"llama-server"|"ollama"|"lmstudio"|"llamabarn") echo "" ;;
"ollama"|"lmstudio"|"llama") echo "" ;;
esac
}

get_provider_fast_model() {
case $1 in
"zhipu") echo "$MODELS_ZHIPU_FAST" ;;
"deepseek") echo "$MODELS_DEEPSEEK_FAST" ;;
"minimax") echo "$MODELS_MINIMAX_FAST" ;;
*) get_provider_model "$1" ;;
esac
}
Expand Down Expand Up @@ -145,7 +141,7 @@ get_api_key_with_fallback() {
return
fi
;;
"llama-server"|"ollama"|"lmstudio"|"llamabarn")
"ollama"|"lmstudio"|"llama")
echo "none"
return
;;
Expand All @@ -155,8 +151,8 @@ get_api_key_with_fallback() {
esac

# If we get here and it's not a local server, prompt for key
if [[ "$provider" != "llama-server" ]] && [[ "$provider" != "ollama" ]] && \
[[ "$provider" != "lmstudio" ]] && [[ "$provider" != "llamabarn" ]]; then
if [[ "$provider" != "ollama" ]] && [[ "$provider" != "lmstudio" ]] && \
[[ "$provider" != "llama" ]]; then
prompt_for_api_key "$provider_name"
fi
}
Expand Down Expand Up @@ -338,21 +334,21 @@ show_providers() {

# Third-party providers
printf " ${C_CYAN}${C_BOLD}%-12s${C_RESET} ${C_DIM}%-${col2}s${C_RESET} %b\n" "deepseek" "api.deepseek.com/anthropic" "$(get_key_status deepseek)"
echo -e " $(fmt_model "$MODELS_DEEPSEEK")"
echo -e " $(fmt_model "$MODELS_DEEPSEEK"), $(fmt_model "$MODELS_DEEPSEEK_FAST")"

printf " ${C_CYAN}${C_BOLD}%-12s${C_RESET} ${C_DIM}%-${col2}s${C_RESET} %b\n" "zhipu" "api.z.ai/api/anthropic" "$(get_key_status zhipu)"
echo -e " ${C_DIM}(zai)${C_RESET} $(fmt_model "$MODELS_ZHIPU"), $(fmt_model "$MODELS_ZHIPU_FAST")"

printf " ${C_CYAN}${C_BOLD}%-12s${C_RESET} ${C_DIM}%-${col2}s${C_RESET} %b\n" "moonshot" "api.moonshot.ai/anthropic" "$(get_key_status moonshot)"
echo -e " ${C_DIM}(kimi)${C_RESET} $(fmt_model "$MODELS_MOONSHOT_OPUS"), $(fmt_model "$MODELS_MOONSHOT")"
echo -e " ${C_DIM}(kimi)${C_RESET} $(fmt_model "$MODELS_MOONSHOT")"

printf " ${C_CYAN}${C_BOLD}%-12s${C_RESET} ${C_DIM}%-${col2}s${C_RESET} %b\n" "minimax" "api.minimax.io/anthropic" "$(get_key_status minimax)"
echo -e " $(fmt_model "$MODELS_MINIMAX"), $(fmt_model "$MODELS_MINIMAX_FAST")"
echo -e " $(fmt_model "$MODELS_MINIMAX")"

# Local servers
echo -e " ${C_DIM}── local servers [model] ──${C_RESET}"
echo -e " ${C_CYAN}${C_BOLD}ollama${C_RESET} ${C_DIM}localhost:11434${C_RESET} ${C_CYAN}${C_BOLD}lmstudio${C_RESET} ${C_DIM}localhost:1234${C_RESET}"
echo -e " ${C_CYAN}${C_BOLD}llama-server${C_RESET} ${C_DIM}localhost:8080${C_RESET} ${C_CYAN}${C_BOLD}llamabarn${C_RESET} ${C_DIM}localhost:2276${C_RESET}"
echo -e " ${C_CYAN}${C_BOLD}llama${C_RESET} ${C_DIM}localhost:8080${C_RESET} ${C_DIM}(Llama app / llama.cpp)${C_RESET}"

# Custom URL
echo -e " ${C_DIM}── custom url ──${C_RESET}"
Expand Down Expand Up @@ -454,10 +450,9 @@ main() {
# Check if it's a local server provider (handle separately for key/model args)
local local_server_url=""
case "$first_arg" in
"llama-server") local_server_url="$PROVIDERS_LLAMA_SERVER" ;;
"ollama") local_server_url="$PROVIDERS_OLLAMA" ;;
"lmstudio"|"lm-studio") local_server_url="$PROVIDERS_LMSTUDIO" ;;
"llamabarn"|"llama-barn") local_server_url="$PROVIDERS_LLAMABARN" ;;
"llama"|"llamabarn"|"llama-barn") local_server_url="$PROVIDERS_LLAMA" ;; # llamabarn kept as legacy alias
esac

if [[ -n "$local_server_url" ]]; then
Expand Down Expand Up @@ -543,7 +538,7 @@ main() {
;;
*)
echo "Error: Unknown provider '$provider'" >&2
echo "Available: subscription (sub) api moonshot (kimi) deepseek zhipu (zai glm) minimax llama-server ollama lmstudio llamabarn" >&2
echo "Available: subscription (sub) api moonshot (kimi) deepseek zhipu (zai glm) minimax ollama lmstudio llama" >&2
echo "You can also use a custom URL directly as the first argument" >&2
exit 1
;;
Expand Down Expand Up @@ -606,30 +601,51 @@ main() {
local base_url
base_url="$(get_provider_url "$provider_base")"
export ANTHROPIC_BASE_URL="$base_url"
# Claude Code third-party path uses Bearer (ANTHROPIC_AUTH_TOKEN), including DeepSeek's Claude Code guide
export ANTHROPIC_AUTH_TOKEN="$api_key"
# Avoid Claude Code's interactive API-key approval path when a parent shell has ANTHROPIC_API_KEY set
if [[ "$provider_base" != "anthropic" ]]; then
unset ANTHROPIC_API_KEY
fi

# Map Claude model aliases to provider's models
# Map Claude model aliases to provider's models (via get_provider_model / get_provider_fast_model)
# For alternative providers without true tiers, map all aliases to their best model
local model fast_model
case "$provider_base" in
"moonshot")
export ANTHROPIC_DEFAULT_OPUS_MODEL="$MODELS_MOONSHOT_OPUS"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$MODELS_MOONSHOT"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$MODELS_MOONSHOT"
model="$(get_provider_model moonshot)"
export ANTHROPIC_DEFAULT_OPUS_MODEL="$model"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$model"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$model"
export CLAUDE_CODE_SUBAGENT_MODEL="$model"
export ENABLE_TOOL_SEARCH="false"
export CLAUDE_CODE_AUTO_COMPACT_WINDOW="262144"
;;
"deepseek")
export ANTHROPIC_DEFAULT_OPUS_MODEL="$MODELS_DEEPSEEK"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$MODELS_DEEPSEEK"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$MODELS_DEEPSEEK"
# DeepSeek Claude Code guide: pro[1m] for opus/sonnet/primary, flash for haiku/subagent
model="$(get_provider_model deepseek)"
fast_model="$(get_provider_fast_model deepseek)"
export ANTHROPIC_MODEL="$model"
export ANTHROPIC_DEFAULT_OPUS_MODEL="$model"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$model"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$fast_model"
export CLAUDE_CODE_SUBAGENT_MODEL="$fast_model"
export CLAUDE_CODE_EFFORT_LEVEL="max"
;;
"minimax")
export ANTHROPIC_DEFAULT_OPUS_MODEL="$MODELS_MINIMAX"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$MODELS_MINIMAX"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$MODELS_MINIMAX_FAST"
model="$(get_provider_model minimax)"
export ANTHROPIC_DEFAULT_OPUS_MODEL="$model"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$model"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$model"
export CLAUDE_CODE_AUTO_COMPACT_WINDOW="1000000"
;;
"zhipu")
export ANTHROPIC_DEFAULT_OPUS_MODEL="$MODELS_ZHIPU"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$MODELS_ZHIPU"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$MODELS_ZHIPU_FAST"
model="$(get_provider_model zhipu)"
fast_model="$(get_provider_fast_model zhipu)"
export ANTHROPIC_DEFAULT_OPUS_MODEL="$model"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$model"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$fast_model"
export API_TIMEOUT_MS="3000000"
;;
"anthropic")
# For official Anthropic, let Claude Code use defaults
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/mock_claude
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# Capture relevant environment variables
env \
| grep -E '^(ANTHROPIC_|CLAUDE_CODE_|MOONSHOT_|DEEPSEEK_|ZAI_|ZHIPUAI_|MINIMAX_)' \
| grep -E '^(ANTHROPIC_|CLAUDE_CODE_|MOONSHOT_|DEEPSEEK_|ZAI_|ZHIPUAI_|MINIMAX_|API_TIMEOUT_MS=|ENABLE_TOOL_SEARCH=)' \
| sort > "$CC_TEST_CAPTURE_DIR/env" || true

# Capture argument count
Expand Down
4 changes: 3 additions & 1 deletion tests/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,11 @@ setup() {
export PATH="$MOCK_BIN_DIR:$ORIG_PATH"

# Unset all env vars that cc-launcher reads or sets
unset ANTHROPIC_BASE_URL ANTHROPIC_AUTH_TOKEN ANTHROPIC_API_KEY
unset ANTHROPIC_BASE_URL ANTHROPIC_AUTH_TOKEN ANTHROPIC_API_KEY ANTHROPIC_MODEL
unset ANTHROPIC_DEFAULT_OPUS_MODEL ANTHROPIC_DEFAULT_SONNET_MODEL ANTHROPIC_DEFAULT_HAIKU_MODEL
unset CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC CLAUDE_CODE_OAUTH_TOKEN
unset CLAUDE_CODE_SUBAGENT_MODEL CLAUDE_CODE_AUTO_COMPACT_WINDOW CLAUDE_CODE_ATTRIBUTION_HEADER
unset CLAUDE_CODE_EFFORT_LEVEL ENABLE_TOOL_SEARCH API_TIMEOUT_MS
unset MOONSHOT_API_KEY DEEPSEEK_API_KEY ZAI_API_KEY ZHIPUAI_API_KEY MINIMAX_API_KEY
}

Expand Down
55 changes: 33 additions & 22 deletions tests/test_cc_launcher.sh
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,6 @@ test_local_ollama() {
assert_eq "1" "$(captured_env CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC)" || return 1
}

test_local_llama_server() {
run_launcher llama-server || return 1
assert_eq "http://localhost:8080" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
assert_eq "local" "$(captured_env ANTHROPIC_AUTH_TOKEN)" || return 1
}

test_local_lmstudio() {
run_launcher lmstudio || return 1
assert_eq "http://localhost:1234" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
Expand All @@ -132,14 +126,20 @@ test_local_lm_studio_alias() {
assert_eq "http://localhost:1234" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
}

test_local_llamabarn() {
test_local_llama() {
run_launcher llama || return 1
assert_eq "http://localhost:8080" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
assert_eq "local" "$(captured_env ANTHROPIC_AUTH_TOKEN)" || return 1
}

test_local_llamabarn_alias() {
run_launcher llamabarn || return 1
assert_eq "http://localhost:2276" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
assert_eq "http://localhost:8080" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
}

test_local_llama_barn_alias() {
run_launcher llama-barn || return 1
assert_eq "http://localhost:2276" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
assert_eq "http://localhost:8080" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
}

test_local_with_model() {
Expand Down Expand Up @@ -205,30 +205,39 @@ test_provider_kimi_alias() {

test_provider_moonshot_model_tiers() {
run_launcher moonshot "key" || return 1
assert_eq "kimi-k2.5" "$(captured_env ANTHROPIC_DEFAULT_OPUS_MODEL)" || return 1
assert_eq "kimi-k2-turbo-preview" "$(captured_env ANTHROPIC_DEFAULT_SONNET_MODEL)" || return 1
assert_eq "kimi-k2-turbo-preview" "$(captured_env ANTHROPIC_DEFAULT_HAIKU_MODEL)" || return 1
assert_eq "kimi-k2.7-code" "$(captured_env ANTHROPIC_DEFAULT_OPUS_MODEL)" || return 1
assert_eq "kimi-k2.7-code" "$(captured_env ANTHROPIC_DEFAULT_SONNET_MODEL)" || return 1
assert_eq "kimi-k2.7-code" "$(captured_env ANTHROPIC_DEFAULT_HAIKU_MODEL)" || return 1
assert_eq "kimi-k2.7-code" "$(captured_env CLAUDE_CODE_SUBAGENT_MODEL)" || return 1
assert_eq "false" "$(captured_env ENABLE_TOOL_SEARCH)" || return 1
assert_eq "262144" "$(captured_env CLAUDE_CODE_AUTO_COMPACT_WINDOW)" || return 1
}

# --- Deepseek ---

test_provider_deepseek_inline_key() {
run_launcher deepseek "sk-deep-123" || return 1
assert_eq "https://api.deepseek.com/anthropic" "$(captured_env ANTHROPIC_BASE_URL)" || return 1
assert_eq "sk-deep-123" "$(captured_env ANTHROPIC_AUTH_TOKEN)" || return 1
assert_eq "sk-deep-123" "$(captured_env ANTHROPIC_AUTH_TOKEN)" "deepseek uses Bearer auth like other third-party providers" || return 1
assert_not_set ANTHROPIC_API_KEY "no x-api-key for deepseek" || return 1
}

test_provider_deepseek_env_key() {
export DEEPSEEK_API_KEY="env-deep-key"
run_launcher deepseek || return 1
assert_eq "env-deep-key" "$(captured_env ANTHROPIC_AUTH_TOKEN)" || return 1
assert_not_set ANTHROPIC_API_KEY "parent API key cleared for deepseek" || return 1
}

test_provider_deepseek_model_tiers() {
# Match DeepSeek's official Claude Code guide pins
run_launcher deepseek "key" || return 1
assert_eq "deepseek-chat" "$(captured_env ANTHROPIC_DEFAULT_OPUS_MODEL)" || return 1
assert_eq "deepseek-chat" "$(captured_env ANTHROPIC_DEFAULT_SONNET_MODEL)" || return 1
assert_eq "deepseek-chat" "$(captured_env ANTHROPIC_DEFAULT_HAIKU_MODEL)" || return 1
assert_eq "deepseek-v4-pro[1m]" "$(captured_env ANTHROPIC_MODEL)" || return 1
assert_eq "deepseek-v4-pro[1m]" "$(captured_env ANTHROPIC_DEFAULT_OPUS_MODEL)" || return 1
assert_eq "deepseek-v4-pro[1m]" "$(captured_env ANTHROPIC_DEFAULT_SONNET_MODEL)" || return 1
assert_eq "deepseek-v4-flash" "$(captured_env ANTHROPIC_DEFAULT_HAIKU_MODEL)" || return 1
assert_eq "deepseek-v4-flash" "$(captured_env CLAUDE_CODE_SUBAGENT_MODEL)" || return 1
assert_eq "max" "$(captured_env CLAUDE_CODE_EFFORT_LEVEL)" || return 1
}

# --- Zhipu ---
Expand Down Expand Up @@ -265,9 +274,10 @@ test_provider_zhipu_env_zhipuai() {

test_provider_zhipu_model_tiers() {
run_launcher zhipu "key" || return 1
assert_eq "glm-5" "$(captured_env ANTHROPIC_DEFAULT_OPUS_MODEL)" || return 1
assert_eq "glm-5" "$(captured_env ANTHROPIC_DEFAULT_SONNET_MODEL)" || return 1
assert_eq "GLM-4.7-Flash" "$(captured_env ANTHROPIC_DEFAULT_HAIKU_MODEL)" || return 1
assert_eq "glm-5.2" "$(captured_env ANTHROPIC_DEFAULT_OPUS_MODEL)" || return 1
assert_eq "glm-5.2" "$(captured_env ANTHROPIC_DEFAULT_SONNET_MODEL)" || return 1
assert_eq "glm-4.7" "$(captured_env ANTHROPIC_DEFAULT_HAIKU_MODEL)" || return 1
assert_eq "3000000" "$(captured_env API_TIMEOUT_MS)" || return 1
}

# --- Minimax ---
Expand All @@ -286,9 +296,10 @@ test_provider_minimax_env_key() {

test_provider_minimax_model_tiers() {
run_launcher minimax "key" || return 1
assert_eq "MiniMax-M2.5" "$(captured_env ANTHROPIC_DEFAULT_OPUS_MODEL)" || return 1
assert_eq "MiniMax-M2.5" "$(captured_env ANTHROPIC_DEFAULT_SONNET_MODEL)" || return 1
assert_eq "MiniMax-M2.5-highspeed" "$(captured_env ANTHROPIC_DEFAULT_HAIKU_MODEL)" || return 1
assert_eq "MiniMax-M3[1m]" "$(captured_env ANTHROPIC_DEFAULT_OPUS_MODEL)" || return 1
assert_eq "MiniMax-M3[1m]" "$(captured_env ANTHROPIC_DEFAULT_SONNET_MODEL)" || return 1
assert_eq "MiniMax-M3[1m]" "$(captured_env ANTHROPIC_DEFAULT_HAIKU_MODEL)" || return 1
assert_eq "1000000" "$(captured_env CLAUDE_CODE_AUTO_COMPACT_WINDOW)" || return 1
}

# --- Anthropic (API mode) ---
Expand Down
Loading