Root Cause: npm install -g @z_ai/coding-helper was failing with EACCES
(permission denied) when trying to create /usr/local/lib/node_modules/@z_ai,
but the error was being suppressed by 2>/dev/null in the original version.
The script would report "Installation completed" even though it failed.
Solution: Enhanced error handling with three paths:
1. Success Path (exit code = 0):
- Verify installation with 'npm list -g'
- Show "installed and verified!" message
- Offer to launch wizard
2. Permission Error Path (EACCES detected):
- Clear error message explaining the permission issue
- Show 3 options:
a) Use sudo (with interactive retry)
b) Fix npm permissions permanently (chown command)
c) Run without installation using npx
- Interactive prompt to try sudo immediately
3. Other Error Path:
- Show full error output
- Suggest manual installation with sudo
- Remind that npx works without installation
Changes:
- install_coding_helper(): Added EACCES detection, sudo retry option,
and clear error messages for all failure scenarios
- Error output is now captured and displayed for debugging
- Added verification step after sudo installation
The script now properly handles the common case where users don't have
write permissions to /usr/local/lib/node_modules and offers multiple
solutions including an interactive sudo retry.
Co-Authored-By: Claude <noreply@anthropic.com>
1015 lines
36 KiB
Bash
Executable File
1015 lines
36 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_version=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
|
|
if [ "$node_version" -lt 18 ]; then
|
|
log_error "Node.js version $node_version is too old!"
|
|
echo "Node.js 18 or newer is required."
|
|
exit 1
|
|
fi
|
|
|
|
log_success "Node.js $(node -v) 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
|
|
}
|
|
|
|
check_coding_helper_installed() {
|
|
if command -v chelper &> /dev/null || npm list -g @z_ai/coding-helper &> /dev/null 2>&1; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Detect coding-helper components and their installation status
|
|
detect_coding_helper_components() {
|
|
local status_json="{"
|
|
|
|
# 1. Core coding-helper installation
|
|
if command -v chelper &> /dev/null || npm list -g @z_ai/coding-helper &> /dev/null 2>&1; then
|
|
status_json+='"core":true,'
|
|
else
|
|
status_json+='"core":false,'
|
|
fi
|
|
|
|
# 2. Interactive wizard (part of core, but check if wizard can run)
|
|
if command -v chelper &> /dev/null || npm list -g @z_ai/coding-helper &> /dev/null 2>&1; then
|
|
status_json+='"wizard":true,'
|
|
else
|
|
status_json+='"wizard":false,'
|
|
fi
|
|
|
|
# 3. Multi-tool management (check for chelper config)
|
|
if [ -f "$HOME/.chelper/config.json" ] || [ -d "$HOME/.chelper" ]; then
|
|
status_json+='"multi_tool":true,'
|
|
else
|
|
status_json+='"multi_tool":false,'
|
|
fi
|
|
|
|
# 4. MCP service configuration (check for MCP configs in Claude settings)
|
|
if [ -f "$CLAUDE_DIR/settings.json" ]; then
|
|
if grep -q "mcpServers" "$CLAUDE_DIR/settings.json" 2>/dev/null || \
|
|
grep -q "mcp.*servers" "$CLAUDE_DIR/settings.json" 2>/dev/null; then
|
|
status_json+='"mcp_config":true,'
|
|
else
|
|
status_json+='"mcp_config":false,'
|
|
fi
|
|
else
|
|
status_json+='"mcp_config":false,'
|
|
fi
|
|
|
|
# 5. API key management (check for Z.AI API keys in settings)
|
|
if [ -f "$CLAUDE_DIR/settings.json" ]; then
|
|
if grep -q "dashscope-intl.aliyuncs.com" "$CLAUDE_DIR/settings.json" 2>/dev/null; then
|
|
status_json+='"api_management":true,'
|
|
else
|
|
status_json+='"api_management":false,'
|
|
fi
|
|
else
|
|
status_json+='"api_management":false,'
|
|
fi
|
|
|
|
# 6. Bilingual interface (inherent to coding-helper)
|
|
if command -v chelper &> /dev/null || npm list -g @z_ai/coding-helper &> /dev/null 2>&1; then
|
|
status_json+='"bilingual":true,'
|
|
else
|
|
status_json+='"bilingual":false,'
|
|
fi
|
|
|
|
# 7. MCP servers integration (check for installed MCP servers)
|
|
local mcp_count=0
|
|
if [ -d "$CLAUDE_DIR/plugins" ]; then
|
|
mcp_count=$(find "$CLAUDE_DIR/plugins" -name "*mcp*" -o -name "*zai*" 2>/dev/null | wc -l)
|
|
fi
|
|
if [ "$mcp_count" -gt 0 ]; then
|
|
status_json+='"mcp_servers":true,'
|
|
else
|
|
status_json+='"mcp_servers":false,'
|
|
fi
|
|
|
|
# 8. Plugin marketplace (check for marketplace config)
|
|
if [ -f "$CLAUDE_DIR/config.json" ] && grep -q "marketplace" "$CLAUDE_DIR/config.json" 2>/dev/null; then
|
|
status_json+='"marketplace":true,'
|
|
else
|
|
status_json+='"marketplace":false,'
|
|
fi
|
|
|
|
# 9. Tool detection (check for tool-discovery-agent skill)
|
|
if [ -f "$CLAUDE_DIR/skills/tool-discovery-agent/SKILL.md" ]; then
|
|
status_json+='"tool_detection":true,'
|
|
else
|
|
status_json+='"tool_detection":false,'
|
|
fi
|
|
|
|
# 10. Configuration backup/sync (check for sync scripts)
|
|
if [ -f "$CLAUDE_DIR/scripts/sync-agents.sh" ] || [ -f "$CLAUDE_DIR/agents/export-claude-customizations.sh" ]; then
|
|
status_json+='"backup_sync":true'
|
|
else
|
|
status_json+='"backup_sync":false'
|
|
fi
|
|
|
|
status_json+="}"
|
|
echo "$status_json"
|
|
}
|
|
|
|
# Display component status with colored indicators
|
|
display_component_status() {
|
|
local component_name="$1"
|
|
local is_installed="$2"
|
|
local indent="${3:- }"
|
|
|
|
if [ "$is_installed" = "true" ]; then
|
|
echo -e "${indent}${GREEN}✓${NC} ${component_name} ${GREEN}[Installed]${NC}"
|
|
else
|
|
echo -e "${indent}${RED}✗${NC} ${component_name} ${YELLOW}[Not installed]${NC}"
|
|
fi
|
|
}
|
|
|
|
offer_coding_helper_addons() {
|
|
log_step "Z.AI Coding-Helper Addons"
|
|
echo ""
|
|
|
|
# Detect installed components
|
|
local status_json=$(detect_coding_helper_components)
|
|
|
|
# Parse JSON using simple string matching (bash compatible)
|
|
local core=$(echo "$status_json" | grep -o '"core":[^,}]*' | cut -d: -f2)
|
|
local wizard=$(echo "$status_json" | grep -o '"wizard":[^,}]*' | cut -d: -f2)
|
|
local multi_tool=$(echo "$status_json" | grep -o '"multi_tool":[^,}]*' | cut -d: -f2)
|
|
local mcp_config=$(echo "$status_json" | grep -o '"mcp_config":[^,}]*' | cut -d: -f2)
|
|
local api_management=$(echo "$status_json" | grep -o '"api_management":[^,}]*' | cut -d: -f2)
|
|
local bilingual=$(echo "$status_json" | grep -o '"bilingual":[^,}]*' | cut -d: -f2)
|
|
local mcp_servers=$(echo "$status_json" | grep -o '"mcp_servers":[^,}]*' | cut -d: -f2)
|
|
local marketplace=$(echo "$status_json" | grep -o '"marketplace":[^,}]*' | cut -d: -f2)
|
|
local tool_detection=$(echo "$status_json" | grep -o '"tool_detection":[^,}]*' | cut -d: -f2)
|
|
local backup_sync=$(echo "$status_json" | grep -o '"backup_sync":[^,}]*' | cut -d: -f2)
|
|
|
|
echo -e "${CYAN}Z.AI's coding-helper (chelper) provides additional features:${NC}"
|
|
echo ""
|
|
display_component_status "Interactive wizard for easy setup" "$wizard"
|
|
display_component_status "Multi-tool management (Claude Code, OpenCode, etc.)" "$multi_tool"
|
|
display_component_status "MCP service configuration" "$mcp_config"
|
|
display_component_status "API key management for both Global and China plans" "$api_management"
|
|
display_component_status "Bilingual interface (English/Chinese)" "$bilingual"
|
|
echo ""
|
|
echo -e "${YELLOW}Available addons/features:${NC}"
|
|
display_component_status "MCP servers integration (Blender, filesystem, etc.)" "$mcp_servers"
|
|
display_component_status "Plugin marketplace access" "$marketplace"
|
|
display_component_status "Automatic tool detection and installation" "$tool_detection"
|
|
display_component_status "Configuration backup and sync" "$backup_sync"
|
|
echo ""
|
|
|
|
# Calculate overall status
|
|
local total=10
|
|
local installed=0
|
|
[ "$core" = "true" ] && ((installed++))
|
|
[ "$wizard" = "true" ] && ((installed++))
|
|
[ "$multi_tool" = "true" ] && ((installed++))
|
|
[ "$mcp_config" = "true" ] && ((installed++))
|
|
[ "$api_management" = "true" ] && ((installed++))
|
|
[ "$bilingual" = "true" ] && ((installed++))
|
|
[ "$mcp_servers" = "true" ] && ((installed++))
|
|
[ "$marketplace" = "true" ] && ((installed++))
|
|
[ "$tool_detection" = "true" ] && ((installed++))
|
|
[ "$backup_sync" = "true" ] && ((installed++))
|
|
|
|
echo -e "${CYAN}Installation Status:${NC} ${GREEN}${installed}${NC}/${total} components installed"
|
|
echo ""
|
|
|
|
# If everything is installed, offer to launch wizard or skip
|
|
if [ "$installed" -eq "$total" ]; then
|
|
log_success "All coding-helper components are already installed!"
|
|
echo ""
|
|
read -p "Launch coding-helper wizard now? [y/N] " -n 1 -r launch_helper < /dev/tty
|
|
echo ""
|
|
if [[ $launch_helper =~ ^[Yy]$ ]]; then
|
|
launch_coding_helper
|
|
fi
|
|
return
|
|
fi
|
|
|
|
# If core is installed but some components missing, ask to install
|
|
if [ "$core" = "true" ]; then
|
|
log_info "coding-helper is installed, but some components may be missing"
|
|
echo ""
|
|
read -p "Launch coding-helper wizard to configure missing components? [y/N] " -n 1 -r launch_helper < /dev/tty
|
|
echo ""
|
|
if [[ $launch_helper =~ ^[Yy]$ ]]; then
|
|
launch_coding_helper
|
|
fi
|
|
return
|
|
fi
|
|
|
|
# Core not installed, offer installation
|
|
read -p "Install Z.AI coding-helper? [y/N] " -n 1 -r install_helper < /dev/tty
|
|
echo ""
|
|
|
|
if [[ ! $install_helper =~ ^[Yy]$ ]]; then
|
|
log_info "Skipping coding-helper installation"
|
|
return
|
|
fi
|
|
|
|
install_coding_helper
|
|
}
|
|
|
|
install_coding_helper() {
|
|
log_info "Installing @z_ai/coding-helper..."
|
|
echo ""
|
|
|
|
if check_coding_helper_installed; then
|
|
log_info "coding-helper already installed"
|
|
echo ""
|
|
read -p "Launch coding-helper wizard now? [y/N] " -n 1 -r launch_helper < /dev/tty
|
|
echo ""
|
|
if [[ $launch_helper =~ ^[Yy]$ ]]; then
|
|
launch_coding_helper
|
|
fi
|
|
return
|
|
fi
|
|
|
|
# Install the helper
|
|
local install_output
|
|
install_output=$(npm install -g @z_ai/coding-helper 2>&1)
|
|
local install_exit_code=$?
|
|
|
|
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 and verified!"
|
|
echo ""
|
|
echo -e "${CYAN}You can now run:${NC} ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
echo ""
|
|
read -p "Launch coding-helper wizard now? [y/N] " -n 1 -r launch_helper < /dev/tty
|
|
echo ""
|
|
if [[ $launch_helper =~ ^[Yy]$ ]]; then
|
|
launch_coding_helper
|
|
fi
|
|
else
|
|
log_warn "Installation appeared to succeed but verification failed"
|
|
echo ""
|
|
echo -e "${YELLOW}Installation output:${NC}"
|
|
echo "$install_output"
|
|
echo ""
|
|
echo -e "${CYAN}You can try running manually:${NC}"
|
|
echo -e " ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
fi
|
|
else
|
|
# Check if it's a permission error (EACCES)
|
|
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: Fix npm permissions permanently${NC}"
|
|
echo -e " Run: ${YELLOW}sudo chown -R \$(whoami) /usr/local/lib/node_modules${NC}"
|
|
echo -e " ${YELLOW}sudo chown -R \$(whoami) /usr/local/bin${NC}"
|
|
echo -e " Then: ${YELLOW}npm install -g @z_ai/coding-helper${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Option 3: Run without installation (works immediately)${NC}"
|
|
echo -e " Just use: ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Want to try with sudo now? [y/N]${NC}"
|
|
read -p " " -n 1 -r use_sudo < /dev/tty
|
|
echo ""
|
|
if [[ $use_sudo =~ ^[Yy]$ ]]; then
|
|
echo ""
|
|
log_info "Installing with sudo..."
|
|
if sudo npm install -g @z_ai/coding-helper 2>&1; then
|
|
if npm list -g @z_ai/coding-helper &> /dev/null 2>&1; then
|
|
log_success "coding-helper installed and verified with sudo!"
|
|
echo ""
|
|
read -p "Launch coding-helper wizard now? [y/N] " -n 1 -r launch_helper < /dev/tty
|
|
echo ""
|
|
if [[ $launch_helper =~ ^[Yy]$ ]]; then
|
|
launch_coding_helper
|
|
fi
|
|
fi
|
|
else
|
|
log_warn "Sudo installation also failed"
|
|
echo ""
|
|
echo -e "${CYAN}You can still run it without installation:${NC}"
|
|
echo -e " ${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
|
|
# Non-permission error
|
|
log_error "Installation failed!"
|
|
echo ""
|
|
echo -e "${YELLOW}Error output:${NC}"
|
|
echo "$install_output"
|
|
echo ""
|
|
echo -e "${CYAN}You can try installing manually:${NC}"
|
|
echo -e " ${YELLOW}npm install -g @z_ai/coding-helper${NC}"
|
|
echo -e " ${YELLOW}sudo npm install -g @z_ai/coding-helper${NC}"
|
|
echo ""
|
|
echo -e "${CYAN}Or run without installation:${NC}"
|
|
echo -e " ${YELLOW}npx @z_ai/coding-helper${NC}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
launch_coding_helper() {
|
|
log_info "Launching Z.AI coding-helper wizard..."
|
|
echo ""
|
|
echo -e "${CYAN}The wizard will guide you through:${NC}"
|
|
echo " 1. Selecting UI language"
|
|
echo " 2. Choosing coding plan (Global/China)"
|
|
echo " 3. Entering API key"
|
|
echo " 4. Selecting tools to manage"
|
|
echo " 5. Installing and configuring tools"
|
|
echo " 6. Managing MCP services"
|
|
echo ""
|
|
|
|
if command -v chelper &> /dev/null; then
|
|
chelper
|
|
else
|
|
npx @z_ai/coding-helper
|
|
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 "$@"
|