#!/bin/bash # Claude Code 启动脚本 # 支持多 Provider (通过 .env 配置,自动解析 ${PROVIDER}_BASE_URL / ${PROVIDER}_AUTH_TOKEN) # # 每天首次启动时自动执行 claude upgrade # ── 路径配置 ────────────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE="${SCRIPT_DIR}/.env" # ── 加载 .env 文件 ────────────────────────────────────── if [ -f "$ENV_FILE" ]; then while IFS= read -r line || [ -n "$line" ]; do # 跳过注释和空行 [[ "$line" =~ ^[[:space:]]*# ]] && continue [[ -z "${line// /}" ]] && continue # 解析 key=value key="${line%%=*}" value="${line#*=}" # 去除引号 [[ "$value" =~ ^\"(.*)\"$ ]] && value="${BASH_REMATCH[1]}" [[ "$value" =~ ^\'(.*)\'$ ]] && value="${BASH_REMATCH[1]}" # 仅导出合法变量名 if [[ "$key" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then export "$key=$value" fi done < "$ENV_FILE" fi # ── 参数解析 ────────────────────────────────────────────── SESSION_NAME="" MODEL_KEY="" PROVIDER_OVERRIDE="" while [ $# -gt 0 ]; do case "$1" in --name|-n) [ $# -ge 2 ] || { echo "错误: --name 需要参数" >&2; exit 1; } SESSION_NAME="$2"; shift 2 ;; --provider|-p) [ $# -ge 2 ] || { echo "错误: --provider 需要参数" >&2; exit 1; } PROVIDER_OVERRIDE="$2"; shift 2 ;; -h|--help) echo "用法: runcc.sh [选项] [模型]" echo "" echo "选项:" echo " --name, -n <名称> Claude Code 会话显示名称" echo " --provider, -p <名称> API 提供商 (由 .env 配置,如 glm / deepseek)" echo "" echo "GLM 模型: 45|45a|46|47|5|5t|51|52" echo "Qwen 模型: qw37|qw36f" echo "DeepSeek 模型: ds|dsf" echo "其他: 直接传入模型名称" echo "" echo "Provider 变量规则: CC_PROVIDER=_BASE_URL + _AUTH_TOKEN" echo " 添加新 Provider 只需在 .env 中按此格式添加变量即可" echo "" echo "示例:" echo " runcc.sh # 默认 Provider + 默认模型" echo " runcc.sh 47 # 默认 Provider + glm-4.7" echo " runcc.sh --provider qwen # Qwen + 默认模型" echo " runcc.sh -p qwen qw37 # Qwen + qwen3.7-max" echo " runcc.sh --provider deepseek # DeepSeek + 默认模型" echo " runcc.sh -p deepseek dsf # DeepSeek + deepseek-v4-flash" exit 0 ;; *) MODEL_KEY="$1"; shift ;; esac done # ── Provider 动态解析 ───────────────────────────────────── # CC_PROVIDER=glm → GLM_BASE_URL, GLM_AUTH_TOKEN, GLM_DEFAULT_MODEL # CC_PROVIDER=deepseek → DEEPSEEK_BASE_URL, DEEPSEEK_AUTH_TOKEN, DEEPSEEK_DEFAULT_MODEL # CC_PROVIDER=xxx → XXX_BASE_URL, XXX_AUTH_TOKEN, XXX_DEFAULT_MODEL, XXX_CONTEXT_WINDOW CC_PROVIDER="${PROVIDER_OVERRIDE:-${CC_PROVIDER:-glm}}" upper_provider="$(echo "$CC_PROVIDER" | tr '[:lower:]' '[:upper:]')" base_url_var="${upper_provider}_BASE_URL" token_var="${upper_provider}_AUTH_TOKEN" default_model_var="${upper_provider}_DEFAULT_MODEL" context_window_var="${upper_provider}_CONTEXT_WINDOW" compact_pct_var="${upper_provider}_COMPACT_PCT" disable_compact_var="${upper_provider}_DISABLE_COMPACT" max_ctx_var="${upper_provider}_MAX_CONTEXT_TOKENS" ANTHROPIC_BASE_URL="${!base_url_var}" ANTHROPIC_AUTH_TOKEN="${!token_var}" DEFAULT_MODEL="${!default_model_var:-}" CONTEXT_WINDOW="${!context_window_var:-200000}" COMPACT_PCT="${!compact_pct_var:-75}" DISABLE_COMPACT="${!disable_compact_var:-}" MAX_CONTEXT_TOKENS="${!max_ctx_var:-}" if [ -z "$ANTHROPIC_BASE_URL" ] || [ -z "$ANTHROPIC_AUTH_TOKEN" ]; then echo "错误: Provider '$CC_PROVIDER' 未配置 BASE_URL 或 AUTH_TOKEN" >&2 echo "请在 ${ENV_FILE} 中添加: ${upper_provider}_BASE_URL, ${upper_provider}_AUTH_TOKEN" >&2 exit 1 fi export ANTHROPIC_BASE_URL ANTHROPIC_AUTH_TOKEN export CC_CONTEXT_WINDOW="$CONTEXT_WINDOW" # DISABLE_COMPACT 模式: 禁用自动压缩,覆盖上下文窗口(适用于 API 报告值 < 实际值的模型) if [ "$DISABLE_COMPACT" = "1" ]; then export DISABLE_COMPACT=1 export CLAUDE_CODE_MAX_CONTEXT_TOKENS="${MAX_CONTEXT_TOKENS:-$CONTEXT_WINDOW}" else export CLAUDE_AUTOCOMPACT_PCT_OVERRIDE="$COMPACT_PCT" fi # ── 更新 settings.json ────────────────────────────────── # 删除凭据、模型和窗口变量(由环境变量接管) # SETTINGS_FILE 路径由 .env 配置,默认 ~/.claude/settings.json SETTINGS_FILE="${SETTINGS_FILE:-$HOME/.claude/settings.json}" if command -v jq &>/dev/null && [ -f "$SETTINGS_FILE" ]; then jq 'del(.env.ANTHROPIC_BASE_URL, .env.ANTHROPIC_AUTH_TOKEN, .env.CLAUDE_CODE_AUTO_COMPACT_WINDOW, .env.CLAUDE_AUTOCOMPACT_PCT_OVERRIDE, .env.DISABLE_COMPACT, .env.CLAUDE_CODE_MAX_CONTEXT_TOKENS, .env.ANTHROPIC_DEFAULT_OPUS_MODEL, .env.ANTHROPIC_DEFAULT_HAIKU_MODEL, .env.ANTHROPIC_DEFAULT_SONNET_MODEL)' \ "$SETTINGS_FILE" > "${SETTINGS_FILE}.tmp" \ && mv "${SETTINGS_FILE}.tmp" "$SETTINGS_FILE" fi # ── 模型解析 ────────────────────────────────────────────── MODEL_KEY="${MODEL_KEY:-$DEFAULT_MODEL}" case "$MODEL_KEY" in # GLM 系列 45) MODEL="glm-4.5" ;; 45a) MODEL="glm-4.5-air" ;; 46) MODEL="glm-4.6" ;; 47) MODEL="glm-4.7" ;; 5) MODEL="glm-5" ;; 5t) MODEL="glm-5-turbo" ;; 51) MODEL="glm-5.1" ;; 52) MODEL="glm-5.2" ;; # Qwen 系列 qw37) MODEL="qwen3.7-max" ;; qw36f) MODEL="qwen3.6-flash" ;; qwim) MODEL="qwen-image-max" ;; # DeepSeek 系列 ds) MODEL="deepseek-v4-pro" ;; dsf) MODEL="deepseek-v4-flash" ;; # 其他: 直接作为模型名称 *) MODEL="$MODEL_KEY" ;; esac # ── 模型环境变量(三个层级统一为同一模型)──────────────── export ANTHROPIC_DEFAULT_HAIKU_MODEL="$MODEL" export ANTHROPIC_DEFAULT_SONNET_MODEL="$MODEL" export ANTHROPIC_DEFAULT_OPUS_MODEL="$MODEL" # ── tmux 模型传播(确保子 pane 能获取正确模型)───────── if [ -n "${TMUX:-}" ]; then SESSION_ID="$(tmux display-message -p '#{session_id}')" tmux setenv -t "$SESSION_ID" ANTHROPIC_DEFAULT_OPUS_MODEL "$MODEL" tmux setenv -t "$SESSION_ID" ANTHROPIC_DEFAULT_HAIKU_MODEL "$MODEL" tmux setenv -t "$SESSION_ID" ANTHROPIC_DEFAULT_SONNET_MODEL "$MODEL" tmux setenv -t "$SESSION_ID" CC_CONTEXT_WINDOW "$CONTEXT_WINDOW" if [ "$DISABLE_COMPACT" = "1" ]; then tmux setenv -t "$SESSION_ID" DISABLE_COMPACT 1 tmux setenv -t "$SESSION_ID" CLAUDE_CODE_MAX_CONTEXT_TOKENS "${MAX_CONTEXT_TOKENS:-$CONTEXT_WINDOW}" tmux setenv -u -t "$SESSION_ID" CLAUDE_AUTOCOMPACT_PCT_OVERRIDE 2>/dev/null || true else tmux setenv -t "$SESSION_ID" CLAUDE_AUTOCOMPACT_PCT_OVERRIDE "$COMPACT_PCT" tmux setenv -u -t "$SESSION_ID" DISABLE_COMPACT 2>/dev/null || true tmux setenv -u -t "$SESSION_ID" CLAUDE_CODE_MAX_CONTEXT_TOKENS 2>/dev/null || true fi tmux set-option -p @anthropic_model "$MODEL" fi # ── 每日自动更新 ──────────────────────────────────────── UPGRADE_MARKER="${HOME}/.claude/.last-upgrade-date" TODAY="$(date +%Y-%m-%d)" if [ ! -f "$UPGRADE_MARKER" ] || [ "$(cat "$UPGRADE_MARKER" 2>/dev/null)" != "$TODAY" ]; then echo "每日首次启动,检查 Claude Code 更新..." if claude upgrade 2>&1; then mkdir -p "$(dirname "$UPGRADE_MARKER")" echo "$TODAY" > "$UPGRADE_MARKER" else echo "警告: claude upgrade 失败,跳过更新继续启动" fi fi # ── 启动 Claude Code ──────────────────────────────────── CC_ARGS=(--ide --dangerously-skip-permissions --allow-dangerously-skip-permissions --effort max) # CC_ARGS=(--verbose) if [ -n "$SESSION_NAME" ]; then INITIAL_PROMPT="/rename $SESSION_NAME" fi echo "启动 Claude Code (provider: $CC_PROVIDER, 模型: $MODEL${SESSION_NAME:+, 会话: $SESSION_NAME})" claude "${CC_ARGS[@]}" ${INITIAL_PROMPT:+"$INITIAL_PROMPT"}