#!/bin/bash # 磐石 API · Claude Code 一键配置(macOS / Linux) # 只在本地写配置文件,不上传任何数据。源码公开可审。 set -u BASE_URL="https://api.panshiapi.com" # Claude Code 要求不带 /v1 CFG="$HOME/.claude/settings.json" RED=$'\033[31m'; GRN=$'\033[32m'; YEL=$'\033[33m'; DIM=$'\033[2m'; RST=$'\033[0m' say(){ printf '%s\n' "$*"; } die(){ printf '%s%s%s\n' "$RED" "$*" "$RST" >&2; exit 1; } say "" say " 磐石 API · Claude Code 配置工具" say " ${DIM}只修改本机配置文件,不会上传任何信息${RST}" say "" # ---------- 1. 取 Key ---------- KEY="${1:-}" if [ -z "$KEY" ]; then printf ' 请粘贴你的 API Key(sk- 开头): ' read -r KEY fi KEY="$(printf '%s' "$KEY" | tr -d '[:space:]')" # 去掉粘贴时常见的空格换行 [ -z "$KEY" ] && die " 没有输入 Key,已退出" case "$KEY" in sk-*) ;; *) say " ${YEL}提示:Key 通常以 sk- 开头,请确认没复制错${RST}";; esac # ---------- 2. 选一个 JSON 处理器 ---------- # Claude Code 依赖 Node,所以 node 基本一定在;没有就退回 python3 if command -v node >/dev/null 2>&1; then JSONER=node elif command -v python3 >/dev/null 2>&1; then JSONER=python3 else die " 需要 node 或 python3 来安全地修改配置文件,请先安装其中之一" fi # ---------- 3. 备份 ---------- mkdir -p "$HOME/.claude" if [ -f "$CFG" ]; then BAK="$CFG.bak.$(date +%Y%m%d-%H%M%S)" cp "$CFG" "$BAK" say " 已备份原配置 → ${DIM}$BAK${RST}" else printf '{}' > "$CFG" BAK="" say " 未发现已有配置,将新建" fi # ---------- 4. 合并写入(只动 env 里这两项,其余原样保留)---------- if [ "$JSONER" = node ]; then BASE_URL="$BASE_URL" KEY="$KEY" CFG="$CFG" node -e ' const fs=require("fs"), p=process.env.CFG; let d={}; try{ d=JSON.parse(fs.readFileSync(p,"utf8")||"{}"); }catch(e){ console.error(" 原配置不是合法 JSON,已停止,未做修改"); process.exit(2); } d.env=d.env||{}; d.env.ANTHROPIC_BASE_URL=process.env.BASE_URL; d.env.ANTHROPIC_AUTH_TOKEN=process.env.KEY; fs.writeFileSync(p, JSON.stringify(d,null,2)+"\n"); ' || die " 写入失败,原配置未改动" else BASE_URL="$BASE_URL" KEY="$KEY" CFG="$CFG" python3 -c ' import json,os,sys p=os.environ["CFG"] try: d=json.load(open(p)) if os.path.getsize(p) else {} except Exception: print(" 原配置不是合法 JSON,已停止,未做修改"); sys.exit(2) d.setdefault("env",{}) d["env"]["ANTHROPIC_BASE_URL"]=os.environ["BASE_URL"] d["env"]["ANTHROPIC_AUTH_TOKEN"]=os.environ["KEY"] json.dump(d,open(p,"w"),ensure_ascii=False,indent=2); open(p,"a").write("\n") ' || die " 写入失败,原配置未改动" fi say " ${GRN}配置已写入${RST} ${DIM}$CFG${RST}" # ---------- 5. 真实请求验证 ---------- say "" say " 正在验证连接…" RESP=$(curl -sS -o /tmp/panshi_check.$$ -w '%{http_code}' "$BASE_URL/v1/messages" \ -H "x-api-key: $KEY" -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" -H "user-agent: claude-cli/2.1.0 (external, cli)" \ -d '{"model":"claude-sonnet-5","max_tokens":8,"messages":[{"role":"user","content":"hi"}]}' \ --max-time 60 2>/dev/null) BODY=$(cat /tmp/panshi_check.$$ 2>/dev/null); rm -f /tmp/panshi_check.$$ say "" case "$RESP" in 200) say " ${GRN}✓ 配置成功,现在可以直接使用 claude 命令了${RST}" ;; 401) say " ${RED}✗ Key 无效${RST}" say " 检查有没有复制漏字符,或去后台重新生成一个 Key" ;; 403) if printf '%s' "$BODY" | grep -qi 'balance'; then say " ${RED}✗ 账户余额不足${RST}"; say " 请先到 https://panshiapi.com 充值" else say " ${RED}✗ 访问被拒绝${RST}"; say " $(printf '%s' "$BODY" | head -c 160)" fi ;; 404) say " ${YEL}! 默认模型不可用${RST}" say " 配置已写好,但你的 Key 所在分组没有 claude-sonnet-5" say " 登录 https://panshiapi.com 查看可用模型,用 /model 切换" ;; 429) say " ${YEL}! 上游限流,稍后重试${RST}(配置本身没问题)" ;; 000|"") say " ${RED}✗ 连不上服务器${RST}"; say " 检查网络,或确认能否打开 https://panshiapi.com" ;; *) say " ${YEL}! 返回 HTTP $RESP${RST}"; say " $(printf '%s' "$BODY" | head -c 160)" ;; esac say "" say " ${DIM}接入地址 : $BASE_URL${RST}" [ -n "$BAK" ] && say " ${DIM}如需还原 : cp \"$BAK\" \"$CFG\"${RST}" say ""