- 环境变量加载时展开 value 中的变量引用(如 $HOME) - DeepSeek ds 模型启用 1M 上下文(deepseek-v4-pro[1m]) - 新增导出 ANTHROPIC_MODEL 与 CLAUDE_CODE_SUBAGENT_MODEL
203 lines
9.0 KiB
Bash
Executable File
203 lines
9.0 KiB
Bash
Executable File
#!/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]}"
|
||
# 展开 value 中的环境变量引用(如 $HOME → /home/arno)
|
||
eval "value=\"$value\""
|
||
# 仅导出合法变量名
|
||
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=<name> → <NAME>_BASE_URL + <NAME>_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[1m]" ;;
|
||
dsf) MODEL="deepseek-v4-flash" ;;
|
||
# 其他: 直接作为模型名称
|
||
*) MODEL="$MODEL_KEY" ;;
|
||
esac
|
||
|
||
# ── 模型环境变量(三个层级统一为同一模型)────────────────
|
||
export ANTHROPIC_MODEL="$MODEL"
|
||
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$MODEL"
|
||
export ANTHROPIC_DEFAULT_SONNET_MODEL="$MODEL"
|
||
export ANTHROPIC_DEFAULT_OPUS_MODEL="$MODEL"
|
||
export CLAUDE_CODE_SUBAGENT_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"}
|