Skip to content

Instantly share code, notes, and snippets.

@irfnrdh
Created October 2, 2025 16:22
Show Gist options
  • Save irfnrdh/8428d6611464755834231fe4316d3e85 to your computer and use it in GitHub Desktop.
Save irfnrdh/8428d6611464755834231fe4316d3e85 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euo pipefail
# ========================
# 常量定义
# ========================
SCRIPT_NAME=$(basename "$0")
NODE_MIN_VERSION=18
NODE_INSTALL_VERSION=22
NVM_VERSION="v0.40.3"
CLAUDE_PACKAGE="@anthropic-ai/claude-code"
CONFIG_DIR="$HOME/.claude"
CONFIG_FILE="$CONFIG_DIR/settings.json"
API_BASE_URL="https://api.z.ai/api/anthropic"
API_KEY_URL="https://z.ai/manage-apikey/apikey-list"
API_TIMEOUT_MS=3000000
# Detect current shell
CURRENT_SHELL=$(basename "$SHELL")
# ========================
# 工具函数
# ========================
log_info() {
echo "🔹 $*"
}
log_success() {
echo "✅ $*"
}
log_error() {
echo "❌ $*" >&2
}
ensure_dir_exists() {
local dir="$1"
if [ ! -d "$dir" ]; then
mkdir -p "$dir" || {
log_error "Failed to create directory: $dir"
exit 1
}
fi
}
# ========================
# 检测包管理器
# ========================
detect_package_manager() {
if command -v pacman &>/dev/null; then
echo "pacman"
elif command -v apt-get &>/dev/null; then
echo "apt"
elif command -v dnf &>/dev/null; then
echo "dnf"
elif command -v brew &>/dev/null; then
echo "brew"
else
echo "unknown"
fi
}
# ========================
# Node.js 安装函数
# ========================
install_nodejs_via_package_manager() {
local pkg_manager=$(detect_package_manager)
log_info "Detected package manager: $pkg_manager"
case "$pkg_manager" in
pacman)
log_info "Installing Node.js via pacman..."
if ! sudo pacman -S --noconfirm nodejs npm; then
log_error "Failed to install Node.js via pacman"
return 1
fi
;;
apt)
log_info "Installing Node.js via apt..."
sudo apt-get update
sudo apt-get install -y nodejs npm || return 1
;;
dnf)
log_info "Installing Node.js via dnf..."
sudo dnf install -y nodejs npm || return 1
;;
brew)
log_info "Installing Node.js via Homebrew..."
brew install node || return 1
;;
*)
return 1
;;
esac
return 0
}
install_nodejs_via_nvm() {
log_info "Installing Node.js via nvm..."
# 安装 nvm
log_info "Installing nvm ($NVM_VERSION)..."
curl -s https://raw.githubusercontent.com/nvm-sh/nvm/"$NVM_VERSION"/install.sh | bash
# 加载 nvm - 兼容多种 shell
export NVM_DIR="$HOME/.nvm"
if [ -s "$NVM_DIR/nvm.sh" ]; then
log_info "Loading nvm for bash/zsh..."
\. "$NVM_DIR/nvm.sh"
fi
# 验证 nvm 是否加载
if ! command -v nvm &>/dev/null; then
# 尝试直接通过脚本使用 nvm
if [ -s "$NVM_DIR/nvm.sh" ]; then
source "$NVM_DIR/nvm.sh"
else
log_error "nvm installation failed"
exit 1
fi
fi
# 安装 Node.js
log_info "Installing Node.js $NODE_INSTALL_VERSION via nvm..."
nvm install "$NODE_INSTALL_VERSION"
nvm use "$NODE_INSTALL_VERSION"
nvm alias default "$NODE_INSTALL_VERSION"
}
install_nodejs() {
local platform=$(uname -s)
log_info "Installing Node.js on $platform..."
# 首先尝试通过包管理器安装(更适合 Manjaro)
if install_nodejs_via_package_manager; then
log_success "Node.js installed via package manager"
else
log_info "Package manager installation failed or not available. Trying nvm..."
install_nodejs_via_nvm
fi
# 验证安装
if ! command -v node &>/dev/null; then
log_error "Node.js installation failed"
exit 1
fi
log_success "Node.js installed: $(node -v)"
log_success "npm version: $(npm -v)"
}
# ========================
# Node.js 检查函数
# ========================
check_nodejs() {
if command -v node &>/dev/null; then
current_version=$(node -v | sed 's/v//')
major_version=$(echo "$current_version" | cut -d. -f1)
if [ "$major_version" -ge "$NODE_MIN_VERSION" ]; then
log_success "Node.js is already installed: v$current_version"
return 0
else
log_info "Node.js v$current_version is installed but version < $NODE_MIN_VERSION. Upgrading..."
install_nodejs
fi
else
log_info "Node.js not found. Installing..."
install_nodejs
fi
}
# ========================
# Claude Code 安装
# ========================
install_claude_code() {
if command -v claude &>/dev/null; then
log_success "Claude Code is already installed: $(claude --version)"
else
log_info "Installing Claude Code..."
npm install -g "$CLAUDE_PACKAGE" || {
log_error "Failed to install claude-code"
exit 1
}
log_success "Claude Code installed successfully"
fi
}
configure_claude_json() {
log_info "Configuring onboarding settings..."
node --eval '
const os = require("os");
const fs = require("fs");
const path = require("path");
const homeDir = os.homedir();
const filePath = path.join(homeDir, ".claude.json");
if (fs.existsSync(filePath)) {
const content = JSON.parse(fs.readFileSync(filePath, "utf-8"));
fs.writeFileSync(filePath, JSON.stringify({ ...content, hasCompletedOnboarding: true }, null, 2), "utf-8");
} else {
fs.writeFileSync(filePath, JSON.stringify({ hasCompletedOnboarding: true }, null, 2), "utf-8");
}
' || {
log_error "Failed to configure onboarding"
exit 1
}
}
# ========================
# API Key 配置
# ========================
configure_claude() {
log_info "Configuring Claude Code..."
echo " You can get your API key from: $API_KEY_URL"
read -s -p "🔑 Please enter your ZHIPU API key: " api_key
echo
if [ -z "$api_key" ]; then
log_error "API key cannot be empty. Please run the script again."
exit 1
fi
ensure_dir_exists "$CONFIG_DIR"
# 写入配置文件
node --eval '
const fs = require("fs");
const path = require("path");
const configDir = "'"$CONFIG_DIR"'";
const filePath = path.join(configDir, "settings.json");
const apiKey = "'"$api_key"'";
const content = fs.existsSync(filePath)
? JSON.parse(fs.readFileSync(filePath, "utf-8"))
: {};
fs.writeFileSync(filePath, JSON.stringify({
...content,
env: {
ANTHROPIC_AUTH_TOKEN: apiKey,
ANTHROPIC_BASE_URL: "'"$API_BASE_URL"'",
API_TIMEOUT_MS: '"$API_TIMEOUT_MS"'
}
}, null, 2), "utf-8");
' || {
log_error "Failed to write settings.json"
exit 1
}
log_success "Claude Code configured successfully"
}
# ========================
# Shell 配置提示
# ========================
print_shell_instructions() {
echo ""
log_info "Shell-specific instructions:"
if [ "$CURRENT_SHELL" = "fish" ]; then
echo " For Fish shell, if you used nvm, add to ~/.config/fish/config.fish:"
echo " set -gx NVM_DIR ~/.nvm"
echo " bass source ~/.nvm/nvm.sh"
echo ""
echo " Or install 'fisher' and 'nvm.fish' plugin:"
echo " fisher install jorgebucaran/fisher"
echo " fisher install jorgebucaran/nvm.fish"
elif [ "$CURRENT_SHELL" = "bash" ]; then
echo " For Bash, nvm should be automatically configured in ~/.bashrc"
elif [ "$CURRENT_SHELL" = "zsh" ]; then
echo " For Zsh, nvm should be automatically configured in ~/.zshrc"
fi
}
# ========================
# 主流程
# ========================
main() {
echo "🚀 Starting $SCRIPT_NAME"
echo " Detected shell: $CURRENT_SHELL"
echo ""
check_nodejs
install_claude_code
configure_claude_json
configure_claude
echo ""
log_success "🎉 Installation completed successfully!"
print_shell_instructions
echo ""
echo "🚀 You can now start using Claude Code with:"
echo " claude"
echo ""
echo " Note: If 'claude' command is not found, try:"
echo " - Restart your terminal"
echo " - Or run: hash -r (bash) / rehash (zsh) / hash -r (fish)"
}
main "$@"
@irfnrdh
Copy link
Author

irfnrdh commented Oct 2, 2025

  1. Deteksi Package Manager - Prioritas menggunakan pacman (native Manjaro) daripada nvm
  2. Multi-shell Support - Mendeteksi shell yang digunakan dan memberikan instruksi spesifik
  3. Fallback Mechanism - Jika instalasi via pacman gagal, akan fallback ke nvm
  4. Fish Shell Instructions - Menampilkan petunjuk untuk konfigurasi fish shell
chmod +x install-glm-claudecode-fish.sh
./install-glm-claudecode-fish.sh

alternatif

# Install fisher (package manager untuk fish)
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher

# Install nvm.fish
fisher install jorgebucaran/nvm.fish

#atau

fisher install edc/bass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment