Improved Node.js version check logic to handle prefixed version strings and avoid brittle cut commands. Verified with multiple version formats including v24.11.1.
861 lines
30 KiB
Bash
Executable File
861 lines
30 KiB
Bash
Executable File
#!/bin/bash
|
|
################################################################################
|
|
# Claude Code Installation Script with Z.AI API Support
|
|
################################################################################
|
|
# This script optionally installs Claude Code and configures it with Z.AI API
|
|
# from https://docs.z.ai/devpack/tool/claude
|
|
#
|
|
# Features:
|
|
# - Automated Claude Code installation via npm
|
|
# - Z.AI API configuration (GLM models)
|
|
# - Anthropic/Z.AI provider switching
|
|
# - API key update functionality
|
|
# - Z.AI coding-helper addon installation
|
|
# - Manual configuration instructions
|
|
#
|
|
# Usage: ./install-claude-code.sh [options]
|
|
# --auto Automatic installation with API key prompt
|
|
# --manual Show manual installation steps only
|
|
# --skip-install Skip Claude Code installation, just configure API
|
|
################################################################################
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
MAGENTA='\033[0;35m'
|
|
BOLD='\033[1m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Claude config directory
|
|
CLAUDE_DIR="${HOME}/.claude"
|
|
SETTINGS_FILE="$CLAUDE_DIR/settings.json"
|
|
|
|
# Flags
|
|
AUTO_MODE=true
|
|
SKIP_INSTALL=false
|
|
|
|
################################################################################
|
|
# Helper Functions
|
|
################################################################################
|
|
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
log_step() {
|
|
echo -e "${CYAN}${BOLD}==>${NC} ${BOLD}$1${NC}"
|
|
}
|
|
|
|
print_banner() {
|
|
echo -e "${MAGENTA}${BOLD}"
|
|
cat << "EOF"
|
|
╔═══════════════════════════════════════════════════════════════╗
|
|
║ ║
|
|
║ ███████╗██╗ █████╗ ██████╗ ║
|
|
║ ██╔════╝██║ ██╔══██╗██╔════╝ ║
|
|
║ ███████╗██║ ███████║██║ ███╗ ║
|
|
║ ╚════██║██║ ██╔══██║██║ ██║ ║
|
|
║ ███████║███████╗██║ ██║╚██████╔╝ ║
|
|
║ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ║
|
|
║ ║
|
|
║ + Z.AI API Integration (GLM Models) ║
|
|
║ + Provider Switching ║
|
|
║ + Coding-Helper Addons ║
|
|
║ ║
|
|
║ Enhanced Installation Script ║
|
|
║ ║
|
|
╚═══════════════════════════════════════════════════════════════╝
|
|
EOF
|
|
echo -e "${NC}"
|
|
echo ""
|
|
echo -e "${MAGENTA}${BOLD}🎁 Grab 10% OFF Token for z.ai coding plan:${NC} ${YELLOW}https://z.ai/subscribe?ic=R0K78RJKNW${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Official Documentation:${NC} https://docs.z.ai/devpack/tool/claude"
|
|
echo ""
|
|
}
|
|
|
|
check_nodejs() {
|
|
log_step "Checking for Node.js 18+..."
|
|
|
|
if ! command -v node &> /dev/null; then
|
|
log_error "Node.js not found!"
|
|
echo ""
|
|
echo -e "${YELLOW}Node.js 18 or newer is required to install Claude Code.${NC}"
|
|
echo ""
|
|
echo "Please install Node.js first:"
|
|
echo " - Ubuntu/Debian: sudo apt install nodejs npm"
|
|
echo " - Arch: sudo pacman -S nodejs npm"
|
|
echo " - macOS: brew install node"
|
|
echo " - Or visit: https://nodejs.org/"
|
|
echo ""
|
|
exit 1
|
|
fi
|
|
|
|
local node_full_version=$(node -v 2>&1)
|
|
local node_version=$(echo "$node_full_version" | grep -oE '[0-9]+' | head -n1)
|
|
|
|
if [ -z "$node_version" ]; then
|
|
log_error "Could not parse Node.js version from: $node_full_version"
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$node_version" -lt 18 ]; then
|
|
log_error "Node.js version $node_version is too old!"
|
|
echo "Node.js 18 or newer is required. Found: $node_full_version"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "Node.js $node_full_version found"
|
|
}
|
|
|
|
check_claude_code_installed() {
|
|
if command -v claude &> /dev/null; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
install_claude_code() {
|
|
if [ "$SKIP_INSTALL" = true ]; then
|
|
log_info "Skipping Claude Code installation (--skip-install flag)"
|
|
return
|
|
fi
|
|
|
|
log_step "Installing Claude Code..."
|
|
|
|
if check_claude_code_installed; then
|
|
local current_version=$(claude --version 2>/dev/null | head -1 || echo "unknown")
|
|
log_info "Claude Code already installed: $current_version"
|
|
echo ""
|
|
read -p "Update to latest version? [y/N] " -n 1 -r < /dev/tty
|
|
echo ""
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
log_info "Updating Claude Code..."
|
|
npm update -g @anthropic-ai/claude-code
|
|
log_success "Claude Code updated"
|
|
fi
|
|
else
|
|
log_info "Installing Claude Code via npm..."
|
|
npm install -g @anthropic-ai/claude-code
|
|
log_success "Claude Code installed"
|
|
fi
|
|
|
|
echo ""
|
|
claude --version
|
|
}
|
|
|
|
detect_current_provider() {
|
|
if [ -f "$SETTINGS_FILE" ]; then
|
|
if grep -q "dashscope-intl.aliyuncs.com" "$SETTINGS_FILE" 2>/dev/null; then
|
|
echo "zai"
|
|
elif grep -q "anthropic.com" "$SETTINGS_FILE" 2>/dev/null || \
|
|
grep -q "ANTHROPIC_API_KEY" "$SETTINGS_FILE" 2>/dev/null; then
|
|
echo "anthropic"
|
|
else
|
|
echo "unknown"
|
|
fi
|
|
else
|
|
echo "none"
|
|
fi
|
|
}
|
|
|
|
get_current_api_key() {
|
|
if [ -f "$SETTINGS_FILE" ]; then
|
|
# Try to extract API key using various methods
|
|
if command -v python3 &> /dev/null; then
|
|
python3 -c "
|
|
import json
|
|
import sys
|
|
try:
|
|
with open('$SETTINGS_FILE', 'r') as f:
|
|
settings = json.load(f)
|
|
key = settings.get('env', {}).get('ANTHROPIC_API_KEY', '')
|
|
if key:
|
|
print(key)
|
|
except:
|
|
pass
|
|
" 2>/dev/null
|
|
fi
|
|
fi
|
|
}
|
|
|
|
switch_provider() {
|
|
local current_provider=$(detect_current_provider)
|
|
local current_api_key=$(get_current_api_key)
|
|
|
|
log_step "Current Configuration"
|
|
echo ""
|
|
|
|
case $current_provider in
|
|
"anthropic")
|
|
echo -e "${GREEN}Current Provider:${NC} Anthropic (Official)"
|
|
if [ -n "$current_api_key" ]; then
|
|
echo -e "${CYAN}API Key:${NC} ${current_api_key:0:10}...${current_api_key: -4}"
|
|
fi
|
|
;;
|
|
"zai")
|
|
echo -e "${GREEN}Current Provider:${NC} Z.AI (GLM Models)"
|
|
if [ -n "$current_api_key" ]; then
|
|
echo -e "${CYAN}API Key:${NC} ${current_api_key:0:10}...${current_api_key: -4}"
|
|
fi
|
|
;;
|
|
"none")
|
|
echo -e "${YELLOW}No configuration found.${NC}"
|
|
;;
|
|
*)
|
|
echo -e "${YELLOW}Unknown configuration.${NC}"
|
|
;;
|
|
esac
|
|
echo ""
|
|
|
|
echo -e "${CYAN}${BOLD}Select your preferred API provider:${NC}"
|
|
echo " 1) Z.AI (GLM Models: glm-4.5-air, glm-4.7) - 🎁 10% OFF: https://z.ai/subscribe?ic=R0K78RJKNW"
|
|
echo " 2) Anthropic (Official Claude Models)"
|
|
echo " 3) Update API key only (keep current provider)"
|
|
echo " 4) Skip configuration"
|
|
echo ""
|
|
read -p "Choose option [1-4]: " -n 1 -r provider_choice < /dev/tty
|
|
echo ""
|
|
echo ""
|
|
|
|
case $provider_choice in
|
|
1)
|
|
configure_zai_api
|
|
;;
|
|
2)
|
|
configure_anthropic_api
|
|
;;
|
|
3)
|
|
update_api_key_only
|
|
;;
|
|
4)
|
|
log_info "Skipping API configuration"
|
|
return 1
|
|
;;
|
|
*)
|
|
log_error "Invalid choice"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
return 0
|
|
}
|
|
|
|
configure_zai_api() {
|
|
log_step "Z.AI API Configuration"
|
|
echo ""
|
|
echo -e "${CYAN}To use Claude Code with Z.AI's GLM models, you need an API key.${NC}"
|
|
echo ""
|
|
echo -e "${YELLOW}Get your API key from:${NC} https://docs.z.ai/devpack/tool/claude"
|
|
echo ""
|
|
echo -e "${MAGENTA}${BOLD}🎁 Grab 10% OFF Token for z.ai coding plan:${NC} ${YELLOW}https://z.ai/subscribe?ic=R0K78RJKNW${NC}"
|
|
echo ""
|
|
echo -e "${MAGENTA}Your API key format is: ${BOLD}your-api-key-here${NC}"
|
|
echo ""
|
|
|
|
read -p "Enter your Z.AI API key (or press Enter to skip): " -r API_KEY < /dev/tty
|
|
echo ""
|
|
|
|
if [ -z "$API_KEY" ]; then
|
|
log_warn "No API key provided."
|
|
return 1
|
|
fi
|
|
|
|
apply_zai_config "$API_KEY"
|
|
log_success "Z.AI API configured"
|
|
log_info "API key set to: ${API_KEY:0:10}...${API_KEY: -4}"
|
|
}
|
|
|
|
configure_anthropic_api() {
|
|
log_step "Anthropic API Configuration"
|
|
echo ""
|
|
echo -e "${CYAN}To use Claude Code with Anthropic's official models, you need an API key.${NC}"
|
|
echo ""
|
|
echo -e "${YELLOW}Get your API key from:${NC} https://console.anthropic.com/"
|
|
echo ""
|
|
echo -e "${MAGENTA}Your API key format is: ${BOLD}sk-ant-api03-...${NC}"
|
|
echo ""
|
|
|
|
read -p "Enter your Anthropic API key (or press Enter to skip): " -r API_KEY < /dev/tty
|
|
echo ""
|
|
|
|
if [ -z "$API_KEY" ]; then
|
|
log_warn "No API key provided."
|
|
return 1
|
|
fi
|
|
|
|
apply_anthropic_config "$API_KEY"
|
|
log_success "Anthropic API configured"
|
|
log_info "API key set to: ${API_KEY:0:10}...${API_KEY: -4}"
|
|
}
|
|
|
|
update_api_key_only() {
|
|
local current_provider=$(detect_current_provider)
|
|
|
|
log_step "Update API Key"
|
|
echo ""
|
|
|
|
case $current_provider in
|
|
"anthropic")
|
|
echo -e "${CYAN}Current provider: Anthropic${NC}"
|
|
echo -e "${YELLOW}Enter new Anthropic API key:${NC}"
|
|
;;
|
|
"zai")
|
|
echo -e "${CYAN}Current provider: Z.AI${NC}"
|
|
echo -e "${YELLOW}Enter new Z.AI API key:${NC}"
|
|
;;
|
|
*)
|
|
echo -e "${YELLOW}Could not detect current provider.${NC}"
|
|
echo "Which provider's API key do you want to update?"
|
|
echo " 1) Z.AI"
|
|
echo " 2) Anthropic"
|
|
read -p "Choose [1-2]: " -n 1 -r key_choice < /dev/tty
|
|
echo ""
|
|
case $key_choice in
|
|
1) current_provider="zai" ;;
|
|
2) current_provider="anthropic" ;;
|
|
*) return 1 ;;
|
|
esac
|
|
;;
|
|
esac
|
|
|
|
read -p "Enter new API key: " -r API_KEY < /dev/tty
|
|
echo ""
|
|
|
|
if [ -z "$API_KEY" ]; then
|
|
log_warn "No API key provided."
|
|
return 1
|
|
fi
|
|
|
|
if [ "$current_provider" = "zai" ]; then
|
|
apply_zai_config "$API_KEY"
|
|
else
|
|
apply_anthropic_config "$API_KEY"
|
|
fi
|
|
|
|
log_success "API key updated"
|
|
}
|
|
|
|
apply_zai_config() {
|
|
local api_key="$1"
|
|
|
|
mkdir -p "$CLAUDE_DIR"
|
|
|
|
# Backup existing settings
|
|
if [ -f "$SETTINGS_FILE" ]; then
|
|
cp "$SETTINGS_FILE" "$SETTINGS_FILE.backup-$(date +%Y%m%d_%H%M%S)"
|
|
log_info "Backed up existing settings.json"
|
|
fi
|
|
|
|
# Create or update settings.json with Z.AI configuration
|
|
if [ -f "$SETTINGS_FILE" ]; then
|
|
# Merge with existing settings
|
|
if command -v python3 &> /dev/null; then
|
|
python3 << PYTHON_SCRIPT
|
|
import json
|
|
import sys
|
|
|
|
try:
|
|
with open('$SETTINGS_FILE', 'r') as f:
|
|
settings = json.load(f)
|
|
except:
|
|
settings = {}
|
|
|
|
# Add or update env section
|
|
if 'env' not in settings:
|
|
settings['env'] = {}
|
|
|
|
# Configure Z.AI GLM models
|
|
settings['env']['ANTHROPIC_API_KEY'] = '$api_key'
|
|
settings['env']['ANTHROPIC_DEFAULT_HAIKU_MODEL'] = 'glm-4.5-air'
|
|
settings['env']['ANTHROPIC_DEFAULT_SONNET_MODEL'] = 'glm-4.7'
|
|
settings['env']['ANTHROPIC_DEFAULT_OPUS_MODEL'] = 'glm-4.7'
|
|
settings['env']['ANTHROPIC_BASE_URL'] = 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1'
|
|
|
|
with open('$SETTINGS_FILE', 'w') as f:
|
|
json.dump(settings, f, indent=2)
|
|
PYTHON_SCRIPT
|
|
else
|
|
# Fallback if python3 not available
|
|
cat > "$SETTINGS_FILE" << EOF
|
|
{
|
|
"env": {
|
|
"ANTHROPIC_API_KEY": "$api_key",
|
|
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-4.5-air",
|
|
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-4.7",
|
|
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-4.7",
|
|
"ANTHROPIC_BASE_URL": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
|
|
}
|
|
}
|
|
EOF
|
|
fi
|
|
else
|
|
# Create new settings.json
|
|
cat > "$SETTINGS_FILE" << EOF
|
|
{
|
|
"env": {
|
|
"ANTHROPIC_API_KEY": "$api_key",
|
|
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "glm-4.5-air",
|
|
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-4.7",
|
|
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-4.7",
|
|
"ANTHROPIC_BASE_URL": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
|
|
}
|
|
}
|
|
EOF
|
|
fi
|
|
}
|
|
|
|
apply_anthropic_config() {
|
|
local api_key="$1"
|
|
|
|
mkdir -p "$CLAUDE_DIR"
|
|
|
|
# Backup existing settings
|
|
if [ -f "$SETTINGS_FILE" ]; then
|
|
cp "$SETTINGS_FILE" "$SETTINGS_FILE.backup-$(date +%Y%m%d_%H%M%S)"
|
|
log_info "Backed up existing settings.json"
|
|
fi
|
|
|
|
# Create or update settings.json with Anthropic configuration
|
|
if [ -f "$SETTINGS_FILE" ]; then
|
|
# Merge with existing settings
|
|
if command -v python3 &> /dev/null; then
|
|
python3 << PYTHON_SCRIPT
|
|
import json
|
|
import sys
|
|
|
|
try:
|
|
with open('$SETTINGS_FILE', 'r') as f:
|
|
settings = json.load(f)
|
|
except:
|
|
settings = {}
|
|
|
|
# Add or update env section
|
|
if 'env' not in settings:
|
|
settings['env'] = {}
|
|
|
|
# Configure Anthropic (remove Z.AI specific settings if present)
|
|
settings['env']['ANTHROPIC_API_KEY'] = '$api_key'
|
|
# Remove Z.AI base URL if present
|
|
settings['env'].pop('ANTHROPIC_BASE_URL', None)
|
|
# Reset to default Anthropic models if they were set to GLM
|
|
if settings['env'].get('ANTHROPIC_DEFAULT_HAIKU_MODEL', '').startswith('glm-'):
|
|
settings['env']['ANTHROPIC_DEFAULT_HAIKU_MODEL'] = 'claude-3-5-haiku'
|
|
if settings['env'].get('ANTHROPIC_DEFAULT_SONNET_MODEL', '').startswith('glm-'):
|
|
settings['env']['ANTHROPIC_DEFAULT_SONNET_MODEL'] = 'claude-3-5-sonnet'
|
|
if settings['env'].get('ANTHROPIC_DEFAULT_OPUS_MODEL', '').startswith('glm-'):
|
|
settings['env']['ANTHROPIC_DEFAULT_OPUS_MODEL'] = 'claude-3-5-sonnet'
|
|
|
|
with open('$SETTINGS_FILE', 'w') as f:
|
|
json.dump(settings, f, indent=2)
|
|
PYTHON_SCRIPT
|
|
else
|
|
# Fallback minimal config
|
|
cat > "$SETTINGS_FILE" << EOF
|
|
{
|
|
"env": {
|
|
"ANTHROPIC_API_KEY": "$api_key"
|
|
}
|
|
}
|
|
EOF
|
|
fi
|
|
else
|
|
# Create new settings.json
|
|
cat > "$SETTINGS_FILE" << EOF
|
|
{
|
|
"env": {
|
|
"ANTHROPIC_API_KEY": "$api_key"
|
|
}
|
|
}
|
|
EOF
|
|
fi
|
|
}
|
|
|
|
offer_coding_helper_addons() {
|
|
log_step "Z.AI Coding-Helper Addons"
|
|
echo ""
|
|
echo -e "${CYAN}Z.AI's coding-helper (chelper) provides additional features:${NC}"
|
|
echo ""
|
|
echo " • Interactive wizard for easy setup"
|
|
echo " • Multi-tool management (Claude Code, OpenCode, etc.)"
|
|
echo " • MCP service configuration"
|
|
echo " • API key management for both Global and China plans"
|
|
echo " • Bilingual interface (English/Chinese)"
|
|
echo ""
|
|
echo -e "${YELLOW}Available addons/features:${NC}"
|
|
echo " • MCP servers integration (Blender, filesystem, etc.)"
|
|
echo " • Plugin marketplace access"
|
|
echo " • Automatic tool detection and installation"
|
|
echo " • Configuration backup and sync"
|
|
echo ""
|
|
|
|
# Check if chelper command exists or npm package is installed
|
|
local is_installed=false
|
|
if command -v chelper &> /dev/null; then
|
|
is_installed=true
|
|
elif npm list -g @z_ai/coding-helper &> /dev/null 2>&1; then
|
|
is_installed=true
|
|
fi
|
|
|
|
if [ "$is_installed" = true ]; then
|
|
log_success "coding-helper is installed!"
|
|
echo ""
|
|
echo -e "${CYAN}You can run it anytime with:${NC} ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Launch coding-helper wizard now?${NC} ${GREEN}[Y/n]${NC}"
|
|
>&2 echo -en "\033[0;36m> \033[0m"
|
|
set +e
|
|
read -n 1 -r launch_helper < /dev/tty 2>/dev/null || launch_helper="N"
|
|
set -e
|
|
echo ""
|
|
if [[ $launch_helper =~ ^[Yy]$ ]]; then
|
|
npx @z_ai/coding-helper
|
|
fi
|
|
return
|
|
fi
|
|
|
|
# Not installed - offer installation
|
|
echo ""
|
|
echo -e "${BOLD}${MAGENTA}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${BOLD}${MAGENTA} Install Z.AI coding-helper now?${NC} ${GREEN}[Y/n]${NC}"
|
|
echo -e "${BOLD}${MAGENTA}═══════════════════════════════════════════════════════════${NC}"
|
|
set +e
|
|
read -n 1 -r install_helper < /dev/tty 2>/dev/null || install_helper="Y"
|
|
set -e
|
|
echo ""
|
|
|
|
# Default to Yes if user just presses Enter or enters Y/y
|
|
if [[ -z "$install_helper" ]] || [[ $install_helper =~ ^[Yy]$ ]]; then
|
|
install_coding_helper_simple
|
|
else
|
|
log_info "Skipping coding-helper installation"
|
|
echo ""
|
|
echo -e "${CYAN}You can install it later with:${NC}"
|
|
echo -e " ${YELLOW}npm install -g @z_ai/coding-helper${NC}"
|
|
echo " ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
fi
|
|
}
|
|
|
|
# Simplified installation function
|
|
install_coding_helper_simple() {
|
|
log_info "Installing @z_ai/coding-helper..."
|
|
echo ""
|
|
|
|
# Try regular install first
|
|
set +e
|
|
local install_output
|
|
install_output=$(npm install -g @z_ai/coding-helper 2>&1)
|
|
local install_exit_code=$?
|
|
set -e
|
|
|
|
if [ $install_exit_code -eq 0 ]; then
|
|
# Verify installation
|
|
if npm list -g @z_ai/coding-helper &> /dev/null 2>&1; then
|
|
log_success "coding-helper installed!"
|
|
echo ""
|
|
echo -e "${CYAN}You can now run:${NC} ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Launch the wizard now?${NC} ${GREEN}[Y/n]${NC}"
|
|
set +e
|
|
read -n 1 -r launch_helper < /dev/tty 2>/dev/null || launch_helper="Y"
|
|
set -e
|
|
echo ""
|
|
if [[ -z "$launch_helper" ]] || [[ $launch_helper =~ ^[Yy]$ ]]; then
|
|
npx @z_ai/coding-helper
|
|
fi
|
|
else
|
|
log_warn "Installation appeared to succeed but verification failed"
|
|
echo ""
|
|
echo -e "${CYAN}You can still run it with:${NC} ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
fi
|
|
return
|
|
fi
|
|
|
|
# Check if permission error
|
|
if echo "$install_output" | grep -q "EACCES\|permission denied"; then
|
|
log_error "Installation failed due to permissions!"
|
|
echo ""
|
|
echo -e "${YELLOW}The installation requires write permissions to:${NC}"
|
|
echo -e " ${CYAN}/usr/local/lib/node_modules/@z_ai${NC}"
|
|
echo ""
|
|
echo -e "${BOLD}You have several options:${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Option 1: Use sudo (recommended)${NC}"
|
|
echo -e " Run: ${YELLOW}sudo npm install -g @z_ai/coding-helper${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Option 2: Run without installation (works immediately)${NC}"
|
|
echo -e " Just use: ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
echo ""
|
|
echo -e "${BOLD}${YELLOW}═══════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${BOLD} Try installing with sudo now?${NC} ${GREEN}[Y/n]${NC} ${BOLD}(recommended)${NC}"
|
|
echo -e "${BOLD}${YELLOW}═══════════════════════════════════════════════════════════${NC}"
|
|
set +e
|
|
read -n 1 -r use_sudo < /dev/tty 2>/dev/null || use_sudo="Y"
|
|
set -e
|
|
echo ""
|
|
|
|
if [[ -z "$use_sudo" ]] || [[ $use_sudo =~ ^[Yy]$ ]]; then
|
|
echo ""
|
|
log_info "Installing with sudo..."
|
|
set +e
|
|
if sudo npm install -g @z_ai/coding-helper 2>&1; then
|
|
set -e
|
|
if npm list -g @z_ai/coding-helper &> /dev/null 2>&1; then
|
|
log_success "coding-helper installed!"
|
|
echo ""
|
|
echo -e "${CYAN}Launch the wizard now?${NC} ${GREEN}[Y/n]${NC}"
|
|
set +e
|
|
read -n 1 -r launch_helper < /dev/tty 2>/dev/null || launch_helper="Y"
|
|
set -e
|
|
echo ""
|
|
if [[ -z "$launch_helper" ]] || [[ $launch_helper =~ ^[Yy]$ ]]; then
|
|
npx @z_ai/coding-helper
|
|
fi
|
|
fi
|
|
else
|
|
set -e
|
|
log_warn "Sudo installation also failed"
|
|
echo ""
|
|
echo -e "${CYAN}You can still run it with:${NC} ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
fi
|
|
else
|
|
echo ""
|
|
echo -e "${CYAN}No problem! You can run it anytime with:${NC}"
|
|
echo -e " ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
fi
|
|
else
|
|
# Other error
|
|
log_error "Installation failed!"
|
|
echo ""
|
|
echo -e "${YELLOW}Error output:${NC}"
|
|
echo "$install_output"
|
|
echo ""
|
|
echo -e "${CYAN}You can still run it with:${NC} ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
fi
|
|
}
|
|
|
|
show_manual_instructions() {
|
|
echo ""
|
|
echo -e "${CYAN}${BOLD}═══════════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${CYAN}${BOLD} Manual Installation Instructions${NC}"
|
|
echo -e "${CYAN}${BOLD}═══════════════════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Step 1: Install Claude Code${NC}"
|
|
echo "─────────────────────────────────────────────────────────────────"
|
|
echo ""
|
|
echo " # Prerequisites: Node.js 18 or newer"
|
|
echo " npm install -g @anthropic-ai/claude-code"
|
|
echo ""
|
|
echo " # Verify installation"
|
|
echo " claude --version"
|
|
echo ""
|
|
echo -e "${GREEN}Step 2: Choose Your API Provider${NC}"
|
|
echo "─────────────────────────────────────────────────────────────────"
|
|
echo ""
|
|
echo -e "${CYAN}Option A: Z.AI (GLM Models)${NC}"
|
|
echo -e " ${MAGENTA}${BOLD}🎁 Grab 10% OFF Token for z.ai coding plan:${NC}"
|
|
echo -e " ${YELLOW}https://z.ai/subscribe?ic=R0K78RJKNW${NC}"
|
|
echo ""
|
|
echo " Get your API key: https://docs.z.ai/devpack/tool/claude"
|
|
echo ""
|
|
echo " Configure ~/.claude/settings.json:"
|
|
echo -e "${YELLOW} {${NC}"
|
|
echo -e "${YELLOW} \"env\": {${NC}"
|
|
echo -e "${YELLOW} \"ANTHROPIC_API_KEY\": \"your-zai-api-key\",${NC}"
|
|
echo -e "${YELLOW} \"ANTHROPIC_DEFAULT_HAIKU_MODEL\": \"glm-4.5-air\",${NC}"
|
|
echo -e "${YELLOW} \"ANTHROPIC_DEFAULT_SONNET_MODEL\": \"glm-4.7\",${NC}"
|
|
echo -e "${YELLOW} \"ANTHROPIC_DEFAULT_OPUS_MODEL\": \"glm-4.7\",${NC}"
|
|
echo -e "${YELLOW} \"ANTHROPIC_BASE_URL\": \"https://dashscope-intl.aliyuncs.com/compatible-mode/v1\"${NC}"
|
|
echo -e "${YELLOW} }${NC}"
|
|
echo -e "${YELLOW} }${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Option B: Anthropic (Official)${NC}"
|
|
echo " Get your API key: https://console.anthropic.com/"
|
|
echo ""
|
|
echo " Configure ~/.claude/settings.json:"
|
|
echo -e "${YELLOW} {${NC}"
|
|
echo -e "${YELLOW} \"env\": {${NC}"
|
|
echo -e "${YELLOW} \"ANTHROPIC_API_KEY\": \"sk-ant-api03-...\"${NC}"
|
|
echo -e "${YELLOW} }${NC}"
|
|
echo -e "${YELLOW} }${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Step 3: Start Claude Code${NC}"
|
|
echo "─────────────────────────────────────────────────────────────────"
|
|
echo ""
|
|
echo " cd your-project-directory"
|
|
echo " claude"
|
|
echo ""
|
|
echo " # Check model status with: /status"
|
|
echo ""
|
|
echo -e "${GREEN}Step 4 (Optional): Z.AI Coding-Helper${NC}"
|
|
echo "─────────────────────────────────────────────────────────────────"
|
|
echo ""
|
|
echo " # Install the helper tool"
|
|
echo " npm install -g @z_ai/coding-helper"
|
|
echo ""
|
|
echo " # Or run directly"
|
|
echo " npx @z_ai/coding-helper"
|
|
echo ""
|
|
echo -e "${GREEN}Available Models${NC}"
|
|
echo "─────────────────────────────────────────────────────────────────"
|
|
echo ""
|
|
echo -e "${CYAN}Z.AI GLM Models:${NC}"
|
|
echo " • glm-4.5-air - Fast, efficient (Haiku class)"
|
|
echo " • glm-4.7 - Powerful (Sonnet/Opus class)"
|
|
echo ""
|
|
echo -e "${CYAN}Anthropic Models (default):${NC}"
|
|
echo " • claude-3-5-haiku - Fast & efficient"
|
|
echo " • claude-3-5-sonnet - Balanced power"
|
|
echo " • claude-3-5-sonnet - Most capable"
|
|
echo ""
|
|
echo -e "${CYAN}${BOLD}═══════════════════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
}
|
|
|
|
print_success_summary() {
|
|
echo ""
|
|
echo -e "${GREEN}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${GREEN}${BOLD}║ Installation Complete! ║${NC}"
|
|
echo -e "${GREEN}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}"
|
|
echo ""
|
|
echo -e "${BOLD}Claude Code is ready with your chosen configuration!${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Quick Start:${NC}"
|
|
echo -e " 1. ${YELLOW}cd your-project-directory${NC}"
|
|
echo -e " 2. ${YELLOW}claude${NC}"
|
|
echo -e " 3. ${YELLOW}/status${NC} - Check current model status"
|
|
echo ""
|
|
echo -e "${CYAN}Configuration File:${NC}"
|
|
echo -e " ${YELLOW}~/.claude/settings.json${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Switch Providers:${NC}"
|
|
echo -e " Run this script again: ${YELLOW}./install-claude-code.sh${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Z.AI Coding-Helper:${NC}"
|
|
echo -e " ${YELLOW}npx @z_ai/coding-helper${NC} - Interactive wizard"
|
|
echo ""
|
|
echo -e "${CYAN}Documentation:${NC}"
|
|
echo -e " ${YELLOW}https://docs.z.ai/devpack/tool/claude${NC}"
|
|
echo ""
|
|
}
|
|
|
|
################################################################################
|
|
# Main Installation
|
|
################################################################################
|
|
|
|
main() {
|
|
print_banner
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--auto)
|
|
AUTO_MODE=true
|
|
shift
|
|
;;
|
|
--manual)
|
|
AUTO_MODE=false
|
|
shift
|
|
;;
|
|
--skip-install)
|
|
SKIP_INSTALL=true
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
echo "Usage: $0 [options]"
|
|
echo " --auto Automatic installation with provider selection (default)"
|
|
echo " --manual Show manual installation steps only"
|
|
echo " --skip-install Skip Claude Code installation, just configure API"
|
|
exit 0
|
|
;;
|
|
*)
|
|
log_error "Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Manual mode - just show instructions
|
|
if [ "$AUTO_MODE" = false ]; then
|
|
show_manual_instructions
|
|
exit 0
|
|
fi
|
|
|
|
# Automatic mode
|
|
check_nodejs
|
|
|
|
# Check if Claude Code is already installed
|
|
if check_claude_code_installed; then
|
|
echo ""
|
|
log_step "Claude Code Detection"
|
|
log_info "Claude Code is already installed!"
|
|
echo ""
|
|
claude --version
|
|
echo ""
|
|
|
|
# Offer to switch provider or update API key
|
|
if [ "$SKIP_INSTALL" = false ]; then
|
|
if ! switch_provider; then
|
|
log_info "No configuration changes made"
|
|
fi
|
|
fi
|
|
else
|
|
# Not installed - proceed with installation
|
|
install_claude_code
|
|
|
|
# After installation, configure API
|
|
echo ""
|
|
log_step "API Configuration"
|
|
echo ""
|
|
echo -e "${CYAN}${BOLD}Select your preferred API provider:${NC}"
|
|
echo " 1) Z.AI (GLM Models: glm-4.5-air, glm-4.7) - 🎁 10% OFF"
|
|
echo " 2) Anthropic (Official Claude Models)"
|
|
echo " 3) Skip for now"
|
|
echo ""
|
|
read -p "Choose option [1-3]: " -n 1 -r initial_choice < /dev/tty
|
|
echo ""
|
|
echo ""
|
|
|
|
case $initial_choice in
|
|
1)
|
|
configure_zai_api
|
|
;;
|
|
2)
|
|
configure_anthropic_api
|
|
;;
|
|
3)
|
|
log_info "Skipping API configuration"
|
|
;;
|
|
*)
|
|
log_error "Invalid choice"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
# Offer Z.AI coding-helper addons
|
|
offer_coding_helper_addons
|
|
|
|
print_success_summary
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|