From 47139e0b9c9fdc0841ce330b0d7a65870b25e599 Mon Sep 17 00:00:00 2001 From: sususu98 Date: Fri, 12 Dec 2025 13:16:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E5=86=99=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Claude Code: 写入 ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN - Codex: 写入 OPENAI_API_KEY, OPENAI_BASE_URL - Bash 脚本: 自动检测 shell 配置文件 (.bashrc/.zshrc/.profile) - PowerShell 脚本: 使用 [Environment]::SetEnvironmentVariable 设置用户环境变量 - 添加 API key 格式验证 - 修复文件末尾换行问题,使用单引号包裹值更安全 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ClaudeCode/setup-claude-code.ps1 | 24 ++++- ClaudeCode/setup-claude-code.sh | 146 ++++++++++++++++++++++--------- codex/setup-codex.ps1 | 20 +++++ codex/setup-codex.sh | 84 ++++++++++++++++++ 4 files changed, 232 insertions(+), 42 deletions(-) diff --git a/ClaudeCode/setup-claude-code.ps1 b/ClaudeCode/setup-claude-code.ps1 index 9961713..fc9ccf5 100644 --- a/ClaudeCode/setup-claude-code.ps1 +++ b/ClaudeCode/setup-claude-code.ps1 @@ -18,6 +18,19 @@ $DefaultBaseUrl = "https://api2.xcodecli.com" $ClaudeConfigDir = "$env:USERPROFILE\.claude" $ClaudeSettingsFile = "$ClaudeConfigDir\settings.json" +# Function to write environment variable (User level) +function Set-EnvVariable { + param( + [string]$Name, + [string]$Value + ) + # Set for current session + [Environment]::SetEnvironmentVariable($Name, $Value, [System.EnvironmentVariableTarget]::Process) + # Set permanently for user + [Environment]::SetEnvironmentVariable($Name, $Value, [System.EnvironmentVariableTarget]::User) + Write-Info "Environment variable set: $Name" +} + # Color functions for output function Write-Info { param([string]$Message) @@ -165,7 +178,7 @@ function New-Settings { [string]$BaseUrl, [string]$ApiKey ) - + $settings = @{ env = @{ ANTHROPIC_BASE_URL = $BaseUrl @@ -175,7 +188,7 @@ function New-Settings { CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = 1 } } - + try { $json = $settings | ConvertTo-Json -Depth 10 Set-Content -Path $ClaudeSettingsFile -Value $json -Encoding UTF8 @@ -186,6 +199,13 @@ function New-Settings { $configJson = @{ primaryApiKey = "xcodecli" } $configJson | ConvertTo-Json | Set-Content -Path $configJsonPath -Encoding UTF8 Write-Success "VSCode Claude config written to: $configJsonPath" + + # Set environment variables + Write-Info "Setting environment variables..." + Set-EnvVariable -Name "ANTHROPIC_BASE_URL" -Value $BaseUrl + Set-EnvVariable -Name "ANTHROPIC_AUTH_TOKEN" -Value $ApiKey + Write-Success "Environment variables configured" + return $true } catch { diff --git a/ClaudeCode/setup-claude-code.sh b/ClaudeCode/setup-claude-code.sh index 4b1587c..7ac23cf 100644 --- a/ClaudeCode/setup-claude-code.sh +++ b/ClaudeCode/setup-claude-code.sh @@ -18,6 +18,64 @@ DEFAULT_BASE_URL="https://api2.xcodecli.com" CLAUDE_CONFIG_DIR="$HOME/.claude" CLAUDE_SETTINGS_FILE="$CLAUDE_CONFIG_DIR/settings.json" +# ========== Shell 环境变量配置 ========== +# 检测当前 shell 配置文件 +get_shell_rc() { + if [ -n "${ZSH_VERSION:-}" ] || [ "${SHELL##*/}" = "zsh" ]; then + echo "$HOME/.zshrc" + elif [ -n "${BASH_VERSION:-}" ] || [ "${SHELL##*/}" = "bash" ]; then + if [ -f "$HOME/.bashrc" ]; then + echo "$HOME/.bashrc" + else + echo "$HOME/.bash_profile" + fi + elif [ "${SHELL##*/}" = "fish" ]; then + echo "$HOME/.config/fish/config.fish" + else + echo "$HOME/.profile" + fi +} + +# 写入环境变量到 shell 配置文件 +write_env_to_shell() { + local var_name="$1" + local var_value="$2" + local rc_file + rc_file=$(get_shell_rc) + + # 确保配置文件存在 + mkdir -p "$(dirname "$rc_file")" + touch "$rc_file" + + # 确保文件末尾有换行 + if [ -s "$rc_file" ] && [ "$(tail -c1 "$rc_file" | wc -l)" -eq 0 ]; then + echo "" >>"$rc_file" + fi + + # 转义特殊字符(使用单引号包裹更安全) + local export_line + if [ "${SHELL##*/}" = "fish" ]; then + export_line="set -Ux $var_name '$var_value'" + else + export_line="export $var_name='$var_value'" + fi + + # 删除旧的同名变量行,添加新行 + local tmp_file + tmp_file=$(mktemp) + if [ -s "$rc_file" ]; then + grep -v "^export $var_name=" "$rc_file" | grep -v "^set -Ux $var_name " >"$tmp_file" 2>/dev/null || true + fi + echo "$export_line" >>"$tmp_file" + + # 保留原文件权限 + cat "$tmp_file" >"$rc_file" + rm -f "$tmp_file" + + # 立即生效 + export "$var_name=$var_value" +} + # Function to print colored output print_info() { echo -e "${BLUE}[INFO]${NC} $1" @@ -37,7 +95,7 @@ print_error() { # Function to check if jq is installed check_jq() { - if ! command -v jq &> /dev/null; then + if ! command -v jq &>/dev/null; then print_error "jq is required but not installed." print_info "Please install jq:" print_info " macOS: brew install jq" @@ -134,7 +192,7 @@ test_api_connection() { create_settings() { local base_url="$1" local api_key="$2" - + # Create JSON using jq to ensure proper escaping local settings_json settings_json=$(jq -n \ @@ -149,25 +207,33 @@ create_settings() { "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1 } }') - + # Validate JSON - if ! echo "$settings_json" | jq . > /dev/null 2>&1; then + if ! echo "$settings_json" | jq . >/dev/null 2>&1; then print_error "Generated settings JSON is invalid" return 1 fi - + # Write settings file - echo "$settings_json" > "$CLAUDE_SETTINGS_FILE" + echo "$settings_json" >"$CLAUDE_SETTINGS_FILE" print_success "Claude Code settings written to: $CLAUDE_SETTINGS_FILE" # Write config.json for VSCode Claude extension local config_json_path="$CLAUDE_CONFIG_DIR/config.json" - cat < "$config_json_path" + cat <"$config_json_path" { "primaryApiKey": "xcodecli" } EOF print_success "VSCode Claude config written to: $config_json_path" + + # Write environment variables to shell config + local rc_file + rc_file=$(get_shell_rc) + print_info "Writing environment variables to: $rc_file" + write_env_to_shell "ANTHROPIC_BASE_URL" "$base_url" + write_env_to_shell "ANTHROPIC_AUTH_TOKEN" "$api_key" + print_success "Environment variables written to shell config" } # Function to display current settings @@ -187,10 +253,10 @@ main() { print_info "Claude Code Configuration Script for XCodeCLI" echo "=======================================================" echo - + # Check dependencies check_jq - + # Parse command line arguments local api_key="" local test_only=false @@ -203,20 +269,20 @@ main() { while [[ $# -gt 0 ]]; do case $1 in - -k|--key) - api_key="$2" - shift 2 - ;; - -t|--test) - test_only=true - shift - ;; - -s|--show) - show_settings=true - shift - ;; - -h|--help) - cat <> "$rc_file" + fi + + # 转义特殊字符(使用单引号包裹更安全) + local export_line + if [ "${SHELL##*/}" = "fish" ]; then + export_line="set -Ux $var_name '$var_value'" + else + export_line="export $var_name='$var_value'" + fi + + # 删除旧的同名变量行,添加新行 + local tmp_file + tmp_file=$(mktemp) + if [ -s "$rc_file" ]; then + grep -v "^export $var_name=" "$rc_file" | grep -v "^set -Ux $var_name " > "$tmp_file" 2>/dev/null || true + fi + echo "$export_line" >> "$tmp_file" + + # 保留原文件权限 + cat "$tmp_file" > "$rc_file" + rm -f "$tmp_file" + + # 立即生效 + export "$var_name=$var_value" +} + +# Function to validate API key format +validate_api_key() { + local api_key="$1" + if [[ ! "$api_key" =~ ^[A-Za-z0-9_-]+$ ]]; then + print_error "Invalid API key format. API key should contain only alphanumeric characters, hyphens, and underscores." + return 1 + fi + return 0 +} + # Check for environment variable API_KEY if [ -n "$API_KEY" ]; then API_KEY_FROM_ENV="$API_KEY" @@ -193,6 +261,15 @@ EOF print_success "Codex configuration written to: $HOME/.codex/config.toml" print_success "Codex auth file written to: $HOME/.codex/auth.json" + + # Write environment variables to shell config + local rc_file + rc_file=$(get_shell_rc) + print_info "Writing environment variables to: $rc_file" + write_env_to_shell "OPENAI_API_KEY" "$api_key" + write_env_to_shell "OPENAI_BASE_URL" "${base_url}/v1" + print_success "Environment variables written to shell config" + return 0 } @@ -247,6 +324,8 @@ main() { read -p "Enter your API key: " API_KEY if [ -z "$API_KEY" ]; then print_warning "API key is required" + elif ! validate_api_key "$API_KEY"; then + API_KEY="" fi done fi @@ -258,6 +337,11 @@ main() { exit 1 fi + # Validate API key format + if ! validate_api_key "$API_KEY"; then + exit 1 + fi + # Mask API key for display if [ ${#API_KEY} -gt 12 ]; then masked_key="${API_KEY:0:8}...${API_KEY: -4}"