|
#!/usr/bin/env bash |
|
# |
|
# Z.AI Claude Code Installer |
|
# |
|
# Quick install: |
|
# curl -sL https://gist.githubusercontent.com/andkirby/f7a02ed799c13091ea8eacaa82bc3a4a/raw/zai_cc_install.sh | sh |
|
# |
|
# What it does: |
|
# - Prompts for Z.AI API key location (creates file if needed) |
|
# - Installs ~/.config/zai/.env with API credentials |
|
# - Installs ~/.config/zai/toggle.sh for on/off switching |
|
# - Installs ~/bin/zcode wrapper (or your preferred bin dir) |
|
# - Updates your shell rc file (.zshrc, .bashrc, etc.) |
|
# |
|
# Value: |
|
# - Easy toggle between official Claude API and Z.AI API |
|
# - Use 'zai' command to switch, 'zcode' for direct access |
|
# - Keeps credentials secure in ~/.ssh/ with 600 permissions |
|
# |
|
|
|
set -e |
|
|
|
# Colors for output |
|
RED='\033[0;31m' |
|
GREEN='\033[0;32m' |
|
DARK_GREEN='\033[38;5;28m' |
|
YELLOW='\033[1;33m' |
|
GRAY='\033[0;90m' |
|
ORANGE='\033[38;5;208m' |
|
WHITE_BOLD='\033[1;37m' |
|
NC='\033[0m' # No Color |
|
|
|
info() { printf "${DARK_GREEN}[INFO]${NC} ${GRAY}%s${NC}\n" "$1"; } |
|
warn() { printf "${YELLOW}[WARN]${NC} %s\n" "$1"; } |
|
error() { printf "${RED}[ERROR]${NC} %s\n" "$1"; exit 1; } |
|
|
|
# Detect shell and rc file |
|
detect_shell_rc() { |
|
case "${SHELL##*/}" in |
|
zsh) |
|
RC_FILE="$HOME/.zshrc" |
|
;; |
|
bash) |
|
RC_FILE="$HOME/.bashrc" |
|
;; |
|
fish) |
|
RC_FILE="$HOME/.config/fish/config.fish" |
|
;; |
|
*) |
|
# Try to detect from common locations |
|
if [[ -f "$HOME/.zshrc" ]]; then |
|
RC_FILE="$HOME/.zshrc" |
|
elif [[ -f "$HOME/.bashrc" ]]; then |
|
RC_FILE="$HOME/.bashrc" |
|
else |
|
RC_FILE="$HOME/.profile" |
|
fi |
|
;; |
|
esac |
|
} |
|
|
|
# Expand ~ to $HOME in paths |
|
expand_path() { |
|
local path="$1" |
|
path="${path/#\~/$HOME}" |
|
echo "$path" |
|
} |
|
|
|
# Main installation |
|
main() { |
|
echo "=========================================" |
|
echo " Z.AI Claude Code Installer" |
|
echo " Original: https://docs.z.ai/devpack/tool/claude" |
|
echo "=========================================" |
|
echo |
|
|
|
# Ask for API key path |
|
read -rp "API key file path [~/.ssh/zai_claude.apikey]: " api_key_path </dev/tty |
|
api_key_path="${api_key_path:-~/.ssh/zai_claude.apikey}" |
|
api_key_path=$(expand_path "$api_key_path") |
|
|
|
# Check if API key file exists |
|
if [[ ! -f "$api_key_path" ]]; then |
|
warn "API key file not found at: $api_key_path" |
|
read -rp "Create it now and paste your API key? [y/N] " create_key </dev/tty |
|
if [[ "$create_key" =~ ^[Yy]$ ]]; then |
|
mkdir -p "$(dirname "$api_key_path")" |
|
read -rp "Paste your Z.AI API key: " api_key </dev/tty |
|
echo "$api_key" > "$api_key_path" |
|
chmod 600 "$api_key_path" |
|
info "API key saved to: $api_key_path" |
|
else |
|
error "API key file required. Please create it first." |
|
fi |
|
else |
|
info "Using existing API key file: $api_key_path" |
|
fi |
|
|
|
# Create directories |
|
ZAI_CONFIG_DIR="$HOME/.config/zai" |
|
|
|
# Find existing bin directories in ~/ |
|
bin_dirs=() |
|
for dir in "$HOME"/*/"bin"; do |
|
[[ -d "$dir" ]] && bin_dirs+=("${dir#$HOME/}") |
|
done |
|
[[ -d "$HOME/bin" ]] && bin_dirs+=("bin") |
|
|
|
# Ask which bin dir to use |
|
if [[ ${#bin_dirs[@]} -gt 0 ]]; then |
|
echo |
|
info "Found existing bin directories:" |
|
for dir in "${bin_dirs[@]}"; do |
|
echo " - ~/$dir" |
|
done |
|
echo |
|
read -rp "Use one of these? [path or Enter for ~/bin]: " bin_choice </dev/tty |
|
if [[ -n "$bin_choice" ]]; then |
|
BIN_DIR="$HOME/$bin_choice" |
|
else |
|
BIN_DIR="$HOME/bin" |
|
fi |
|
else |
|
BIN_DIR="$HOME/bin" |
|
fi |
|
|
|
info "Using bin directory: $BIN_DIR" |
|
|
|
mkdir -p "$ZAI_CONFIG_DIR" |
|
mkdir -p "$BIN_DIR" |
|
|
|
# Create .env file |
|
info "Creating $ZAI_CONFIG_DIR/.env" |
|
cat > "$ZAI_CONFIG_DIR/.env" << EOF |
|
export ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropic |
|
export ANTHROPIC_AUTH_TOKEN="\$(cat '$api_key_path')" |
|
export ANTHROPIC_DEFAULT_OPUS_MODEL=GLM-5 |
|
export ANTHROPIC_DEFAULT_SONNET_MODEL=GLM-4.7 |
|
export ANTHROPIC_DEFAULT_HAIKU_MODEL=glm-4.7-flashx |
|
EOF |
|
|
|
# Create toggle.sh |
|
info "Creating $ZAI_CONFIG_DIR/toggle.sh" |
|
cat > "$ZAI_CONFIG_DIR/toggle.sh" << 'EOF' |
|
zai() { |
|
if [[ -n "${ANTHROPIC_BASE_URL:-}" ]]; then |
|
unset ANTHROPIC_BASE_URL ANTHROPIC_AUTH_TOKEN ANTHROPIC_DEFAULT_OPUS_MODEL \ |
|
ANTHROPIC_DEFAULT_SONNET_MODEL ANTHROPIC_DEFAULT_HAIKU_MODEL |
|
echo "Z.AI env unloaded" |
|
else |
|
. ~/.config/zai/.env |
|
echo "Z.AI env loaded" |
|
fi |
|
} |
|
EOF |
|
|
|
# Create zcode wrapper |
|
info "Creating $BIN_DIR/zcode" |
|
cat > "$BIN_DIR/zcode" << 'EOF' |
|
#!/usr/bin/env bash |
|
. ~/.config/zai/.env |
|
claude --allow-dangerously-skip-permissions "${@}" |
|
EOF |
|
chmod +x "$BIN_DIR/zcode" |
|
|
|
# Detect shell rc file |
|
detect_shell_rc |
|
info "Detected shell rc file: $RC_FILE" |
|
|
|
# Check if already sourced |
|
if [[ -f "$RC_FILE" ]] && grep -q "source ~/.config/zai/toggle.sh" "$RC_FILE" 2>/dev/null; then |
|
info "Z.AI toggle already sourced in $RC_FILE" |
|
else |
|
echo |
|
warn "About to update: $RC_FILE" |
|
echo "Will add these lines:" |
|
echo |
|
echo " # >>> zai envs >>>" |
|
echo " source ~/.config/zai/toggle.sh" |
|
echo " # <<< zai envs <<<" |
|
echo |
|
read -rp "Continue? [y/n/a] (a=abort all): " confirm </dev/tty |
|
if [[ "$confirm" =~ ^[Aa]$ ]]; then |
|
error "Installation aborted by user" |
|
elif [[ "$confirm" =~ ^[Yy]$ ]]; then |
|
cat >> "$RC_FILE" << EOF |
|
|
|
# >>> zai envs >>> |
|
source ~/.config/zai/toggle.sh |
|
# <<< zai envs <<< |
|
EOF |
|
info "Updated $RC_FILE" |
|
else |
|
warn "Skipped updating $RC_FILE" |
|
warn "Add this manually:" |
|
echo " source ~/.config/zai/toggle.sh" |
|
fi |
|
fi |
|
|
|
echo |
|
echo "=========================================" |
|
printf "${GREEN}Installation complete!${NC}\n" |
|
echo "=========================================" |
|
echo |
|
printf "${ORANGE}Files created:${NC}\n" |
|
echo " - $ZAI_CONFIG_DIR/.env" |
|
echo " - $ZAI_CONFIG_DIR/toggle.sh" |
|
echo " - $BIN_DIR/zcode" |
|
echo |
|
|
|
# Check if BIN_DIR is in PATH |
|
if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then |
|
warn "Note: $BIN_DIR is not in your PATH" |
|
warn "Add it to your $RC_FILE:" |
|
printf " ${WHITE_BOLD}export PATH=\"\$PATH:$BIN_DIR\"${NC}\n" |
|
echo |
|
fi |
|
|
|
printf "${ORANGE}Usage:${NC}\n" |
|
echo |
|
echo " 1. Activate in your current shell:" |
|
printf " ${WHITE_BOLD}source $RC_FILE${NC}\n" |
|
echo |
|
echo " 2. Toggle Z.AI credentials:" |
|
printf " ${WHITE_BOLD}zai${NC} # enable/disable Z.AI env\n" |
|
printf " ${WHITE_BOLD}claude <args>${NC} # run claude with Z.AI (when enabled)\n" |
|
echo |
|
echo " 3. Or use directly:" |
|
printf " ${WHITE_BOLD}zcode <args>${NC} # auto-loads Z.AI credentials\n" |
|
echo |
|
printf "${ORANGE}Configured models ($ZAI_CONFIG_DIR/.env):${NC}\n" |
|
grep "_MODEL" "$ZAI_CONFIG_DIR/.env" |
|
} |
|
|
|
main "$@" |