Add a China-only Claude Code third-party API setup
This commit is contained in:
1 parent
f4bb97018e
commit
23072924c4
5 files changed
+127
-1
No files matched your search
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Point Claude Code at a third-party API key and model, or remove that setup
|
||||
# omarchy:args=[--remove]
|
||||
# omarchy:examples=omarchy setup claude-api | omarchy setup claude-api --remove
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
settings="$HOME/.claude/settings.json"
|
||||
keys=(ANTHROPIC_BASE_URL ANTHROPIC_AUTH_TOKEN ANTHROPIC_MODEL ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL ANTHROPIC_DEFAULT_HAIKU_MODEL CLAUDE_CODE_SUBAGENT_MODEL)
|
||||
|
||||
keys_json=$(printf '%s\n' "${keys[@]}" | jq -R . | jq -s .)
|
||||
|
||||
# rewrite <file> <jq filter> [jq args...] keeps the file private.
|
||||
rewrite() {
|
||||
local file=$1 filter=$2
|
||||
shift 2
|
||||
mkdir -p "${file%/*}"
|
||||
[[ -f $file ]] || echo '{}' >"$file"
|
||||
(
|
||||
umask 077
|
||||
jq --argjson keys "$keys_json" "$@" "$filter" "$file" >"$file.tmp"
|
||||
)
|
||||
mv "$file.tmp" "$file"
|
||||
}
|
||||
|
||||
if [[ ${1:-} == "--remove" ]]; then
|
||||
if [[ -f $settings ]]; then
|
||||
rewrite "$settings" 'if .env then .env |= delpaths($keys | map([.])) | if .env == {} then del(.env) end end'
|
||||
fi
|
||||
echo "Claude Code third-party API removed from $settings"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
provider=$(gum choose --header "Claude Code API provider" DeepSeek "Kimi Code" "GLM (Zhipu)" MiniMax Custom)
|
||||
case "$provider" in
|
||||
DeepSeek) base_url="https://api.deepseek.com/anthropic" model="deepseek-flash[1m]" key_url="https://platform.deepseek.com/api_keys" ;;
|
||||
"Kimi Code") base_url="https://api.kimi.com/coding/" model="kimi-for-coding" key_url="https://www.kimi.com/code" ;;
|
||||
"GLM (Zhipu)") base_url="https://open.bigmodel.cn/api/anthropic" model="glm-5.3[1m]" key_url="https://open.bigmodel.cn/usercenter/apikeys" ;;
|
||||
MiniMax) base_url="https://api.minimaxi.com/anthropic" model="MiniMax-M3[1m]" key_url="https://platform.minimaxi.com/user-center/basic-information/interface-key" ;;
|
||||
Custom)
|
||||
base_url=$(gum input --header "Anthropic-compatible base URL" --placeholder "https://example.com/anthropic")
|
||||
model=""
|
||||
key_url=""
|
||||
;;
|
||||
esac
|
||||
|
||||
key=$(gum input --password --header "$provider API key${key_url:+ ($key_url)}")
|
||||
model=$(gum input --header "Model for every Claude Code tier" --value "$model")
|
||||
|
||||
if [[ -z $base_url || -z $key || -z $model ]]; then
|
||||
echo "Base URL, API key and model are all required" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rewrite "$settings" '.env = (.env // {}) + ([$keys[] | {key: ., value: $model}] | from_entries) + {ANTHROPIC_BASE_URL: $url, ANTHROPIC_AUTH_TOKEN: $token}' \
|
||||
--arg url "$base_url" --arg token "$key" --arg model "$model"
|
||||
|
||||
# Third-party keys skip Anthropic's sign-in screen.
|
||||
rewrite "$HOME/.claude.json" '.hasCompletedOnboarding = true'
|
||||
|
||||
echo "Claude Code now uses $model at $base_url"
|
||||
@@ -135,6 +135,7 @@
|
||||
"setup.network.dns.google": {"icon":"","label":"Google","checked":"[[ \"$(omarchy-dns)\" == \"Google\" ]]","action":"omarchy-dns Google"},
|
||||
"setup.network.dns.custom": {"icon":"","label":"Custom","checked":"[[ \"$(omarchy-dns)\" == \"Custom\" ]]","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-dns Custom'"},
|
||||
"setup.network.qr": {"icon":"","label":"QR Code","aliases":["wifi-qr"],"when":"[[ $(omarchy-network-status) == wifi* ]]","action":"omarchy-shell shell summon omarchy.wifiqr"},
|
||||
"setup.claude-api": {"icon":"","label":"Claude Code API","when":"[[ \"$(omarchy-region)\" == \"China\" ]]","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-claude-api"},
|
||||
"setup.default": {"icon":"","label":"Defaults","aliases":["default","defaults"]},
|
||||
"setup.default.agent": {"icon":"","label":"Agent","title":"Default Agent"},
|
||||
"setup.default.agent.agy": {"icon":"","label":"Antigravity","checked":"[[ \"$(omarchy-default-agent)\" == \"agy\" ]]","action":"omarchy-default-agent agy"},
|
||||
|
||||
@@ -26,6 +26,8 @@ To wrap an additional CLI the same way, run `omarchy-mise-install <package> [com
|
||||
|
||||
`grok` is installed through mise's first-party `grok` package, the same way as `claude` and `codex`. Run `grok`, or pick it under _Setup > Defaults > Agent_. Skip the `curl | bash` installer on x.ai. That path puts a second copy in `~/.grok/bin`, prepends it on `PATH`, and overwrites Omarchy's wrapper.
|
||||
|
||||
On a machine set up for China, _Setup > Claude Code API_ points Claude Code at DeepSeek, Kimi Code, GLM, MiniMax or any Anthropic-compatible endpoint: pick a provider, paste its API key and confirm the model. The answers land in the `env` block of `~/.claude/settings.json`, and switching the region back to Global removes them.
|
||||
|
||||
### The default agent
|
||||
|
||||
Pick your default agent with `omarchy default agent <name>` or under _Setup > Defaults > Agent_ in the Omarchy Menu (`Super + Space`). If the agent isn't installed yet, picking it installs it first. A fresh Omarchy will invite you to make this choice with a one-time notification.
|
||||
|
||||
@@ -398,7 +398,8 @@ var GUARD_READERS = [
|
||||
"omarchy-default-browser",
|
||||
"omarchy-default-editor",
|
||||
"omarchy-default-terminal",
|
||||
"omarchy-dns"
|
||||
"omarchy-dns",
|
||||
"omarchy-region"
|
||||
]
|
||||
|
||||
// Package and command presence account for most of what the guards ask, and
|
||||
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
||||
|
||||
test_tmp=$(mktemp -d)
|
||||
trap 'rm -rf "$test_tmp"' EXIT
|
||||
|
||||
mkdir -p "$test_tmp/bin" "$test_tmp/home/.claude"
|
||||
cat >"$test_tmp/bin/gum" <<'SH'
|
||||
#!/bin/bash
|
||||
count=$(($(cat "$GUM_COUNT") + 1))
|
||||
printf '%s' "$count" >"$GUM_COUNT"
|
||||
sed -n "${count}p" "$GUM_SCRIPT"
|
||||
SH
|
||||
chmod +x "$test_tmp/bin/gum"
|
||||
export PATH="$test_tmp/bin:$PATH" HOME="$test_tmp/home" GUM_COUNT="$test_tmp/count" GUM_SCRIPT="$test_tmp/script"
|
||||
|
||||
settings="$HOME/.claude/settings.json"
|
||||
run_setup() {
|
||||
printf '%s\n' "$@" >"$GUM_SCRIPT"
|
||||
printf '0' >"$GUM_COUNT"
|
||||
"$ROOT/bin/omarchy-setup-claude-api" >/dev/null
|
||||
}
|
||||
|
||||
echo '{"theme":"dark","env":{"KEEP_ME":"1"}}' >"$settings"
|
||||
echo '{"userID":"abc"}' >"$HOME/.claude.json"
|
||||
run_setup DeepSeek sk-test "deepseek-flash[1m]"
|
||||
|
||||
expected='{"ANTHROPIC_AUTH_TOKEN":"sk-test","ANTHROPIC_BASE_URL":"https://api.deepseek.com/anthropic","ANTHROPIC_DEFAULT_HAIKU_MODEL":"deepseek-flash[1m]","ANTHROPIC_DEFAULT_OPUS_MODEL":"deepseek-flash[1m]","ANTHROPIC_DEFAULT_SONNET_MODEL":"deepseek-flash[1m]","ANTHROPIC_MODEL":"deepseek-flash[1m]","CLAUDE_CODE_SUBAGENT_MODEL":"deepseek-flash[1m]","KEEP_ME":"1"}'
|
||||
[[ $(jq -cS .env "$settings") == "$expected" ]] || fail "DeepSeek writes the base URL, key and model for every tier" "$(jq -cS .env "$settings")"
|
||||
[[ $(jq -r .theme "$settings") == "dark" ]] || fail "setup keeps unrelated Claude settings"
|
||||
[[ $(stat -c %a "$settings") == "600" ]] || fail "the settings holding the key are private"
|
||||
[[ $(jq -cS . "$HOME/.claude.json") == '{"hasCompletedOnboarding":true,"userID":"abc"}' ]] || fail "setup skips Anthropic sign-in and keeps Claude state"
|
||||
pass "a provider preset writes Claude Code's env and skips Anthropic sign-in"
|
||||
|
||||
run_setup Custom https://example.com/anthropic sk-custom my-model
|
||||
[[ $(jq -r '.env.ANTHROPIC_BASE_URL + " " + .env.ANTHROPIC_MODEL + " " + .env.ANTHROPIC_DEFAULT_HAIKU_MODEL' "$settings") == "https://example.com/anthropic my-model my-model" ]] ||
|
||||
fail "Custom uses the typed base URL and model"
|
||||
pass "Custom uses the typed base URL and model"
|
||||
|
||||
if run_setup Custom "" sk-custom my-model 2>/dev/null; then
|
||||
fail "setup refuses an empty base URL"
|
||||
fi
|
||||
[[ $(jq -r .env.ANTHROPIC_MODEL "$settings") == "my-model" ]] || fail "a refused setup leaves the previous config"
|
||||
pass "setup refuses an empty base URL and keeps the previous config"
|
||||
|
||||
"$ROOT/bin/omarchy-setup-claude-api" --remove >/dev/null
|
||||
[[ $(jq -cS . "$settings") == '{"env":{"KEEP_ME":"1"},"theme":"dark"}' ]] || fail "remove deletes only the API setup" "$(jq -cS . "$settings")"
|
||||
jq 'del(.env)' "$settings" >"$settings.tmp" && mv "$settings.tmp" "$settings"
|
||||
run_setup MiniMax sk-mm "MiniMax-M3[1m]"
|
||||
"$ROOT/bin/omarchy-setup-claude-api" --remove >/dev/null
|
||||
[[ $(jq -cS . "$settings") == '{"theme":"dark"}' ]] || fail "remove drops an env it emptied" "$(jq -cS . "$settings")"
|
||||
pass "remove deletes only the keys setup wrote"
|
||||
|
||||
grep -F '"setup.claude-api"' "$ROOT/default/omarchy/omarchy-menu.jsonc" | grep -qF '"when":"[[ \"$(omarchy-region)\" == \"China\" ]]"' ||
|
||||
fail "the Claude Code API entry shows only in China"
|
||||
pass "the Claude Code API entry shows only in China"
|
||||
Reference in new issue
Block a user