Files
tech/.claude/tools/runcc.sh
T
arno da3109a5c9 维护(ClaudeCode): 完善 runcc 脚本的模型与环境变量配置
- 环境变量加载时展开 value 中的变量引用(如 $HOME)
- DeepSeek ds 模型启用 1M 上下文(deepseek-v4-pro[1m])
- 新增导出 ANTHROPIC_MODEL 与 CLAUDE_CODE_SUBAGENT_MODEL
2026-06-25 12:47:01 +08:00

203 lines
9.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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"}