Skip to content

Instantly share code, notes, and snippets.

@KNN-07
Last active January 21, 2026 14:20
Show Gist options
  • Select an option

  • Save KNN-07/79e3ae566ebc8e3df20686ea20628e1c to your computer and use it in GitHub Desktop.

Select an option

Save KNN-07/79e3ae566ebc8e3df20686ea20628e1c to your computer and use it in GitHub Desktop.
Migration
#!/usr/bin/env python3
"""
Antigravity Manager for CLIProxyAPI
A comprehensive tool to:
1. Convert OpenCode Antigravity accounts to CLIProxyAPI format
2. Refresh access tokens using Google OAuth2
Usage:
python antigravity-manager.py convert # Convert antigravity accounts
python antigravity-manager.py refresh # Refresh access tokens
python antigravity-manager.py all # Convert then refresh (default)
"""
import json
import sys
import requests
from pathlib import Path
from datetime import datetime, timedelta
# ============================================================================
# Configuration
# ============================================================================
# OAuth2 credentials for Antigravity
ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com"
ANTIGRAVITY_CLIENT_SECRET = "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"
TOKEN_URL = "https://oauth2.googleapis.com/token"
# Paths
ANTIGRAVITY_FILE = Path.home() / ".config/opencode/antigravity-accounts.json"
CLIPROXYAPI_AUTH_DIR = Path.home() / ".cli-proxy-api"
CLIPROXYAPI_DIR = Path.home() / "cliproxyapi"
# ============================================================================
# Colored Output
# ============================================================================
class Colors:
GREEN = '\033[0;32m'
BLUE = '\033[0;34m'
YELLOW = '\033[1;33m'
RED = '\033[0;31m'
CYAN = '\033[0;36m'
MAGENTA = '\033[0;35m'
BOLD = '\033[1m'
NC = '\033[0m' # No Color
def log_info(msg):
print(f"{Colors.BLUE}[INFO]{Colors.NC} {msg}")
def log_success(msg):
print(f"{Colors.GREEN}[SUCCESS]{Colors.NC} {msg}")
def log_warning(msg):
print(f"{Colors.YELLOW}[WARNING]{Colors.NC} {msg}")
def log_error(msg):
print(f"{Colors.RED}[ERROR]{Colors.NC} {msg}")
def print_header(title):
width = 61
print(f"\n{Colors.CYAN}{'=' * width}{Colors.NC}")
print(f"{Colors.CYAN}{Colors.BOLD} {title}{Colors.NC}")
print(f"{Colors.CYAN}{'=' * width}{Colors.NC}\n")
def print_section(title):
print(f"\n{Colors.MAGENTA}── {title} ──{Colors.NC}\n")
# ============================================================================
# Token Refresh Functions
# ============================================================================
def refresh_token(refresh_token_value):
"""Refresh an access token using the refresh token via Google OAuth2"""
form_data = {
"client_id": ANTIGRAVITY_CLIENT_ID,
"client_secret": ANTIGRAVITY_CLIENT_SECRET,
"grant_type": "refresh_token",
"refresh_token": refresh_token_value
}
headers = {
"Host": "oauth2.googleapis.com",
"User-Agent": "Mozilla/5.0",
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(TOKEN_URL, data=form_data, headers=headers)
if response.status_code != 200:
raise Exception(f"Token refresh failed: {response.status_code} - {response.text}")
return response.json()
def update_credential_file(file_path, token_response):
"""Update credential file with new tokens"""
with open(file_path, 'r') as f:
cred = json.load(f)
now = datetime.now()
expires_in = token_response.get('expires_in', 3600)
cred['access_token'] = token_response['access_token']
if token_response.get('refresh_token'):
cred['refresh_token'] = token_response['refresh_token']
cred['expires_in'] = expires_in
cred['timestamp'] = int(now.timestamp() * 1000)
cred['expired'] = (now + timedelta(seconds=expires_in)).isoformat() + 'Z'
with open(file_path, 'w') as f:
json.dump(cred, f, indent=2)
return cred
# ============================================================================
# Convert Command
# ============================================================================
def cmd_convert():
"""Convert OpenCode Antigravity accounts to CLIProxyAPI format"""
print_header("Antigravity -> CLIProxyAPI Converter")
# Check antigravity file
if not ANTIGRAVITY_FILE.exists():
log_error(f"Antigravity accounts file not found: {ANTIGRAVITY_FILE}")
return 1, []
log_success(f"Found antigravity accounts: {ANTIGRAVITY_FILE}")
# Read antigravity accounts
with open(ANTIGRAVITY_FILE, 'r') as f:
data = json.load(f)
accounts = data.get('accounts', [])
log_info(f"Found {len(accounts)} account(s)")
if not accounts:
log_warning("No accounts found in antigravity file")
return 0, []
# Create auth directory
CLIPROXYAPI_AUTH_DIR.mkdir(parents=True, exist_ok=True)
log_success(f"Auth directory ready: {CLIPROXYAPI_AUTH_DIR}")
print_section("Processing Accounts")
# Process each account
created_files = []
for i, account in enumerate(accounts, 1):
email = account.get('email', f'unknown_{i}')
refresh_token_val = account.get('refreshToken')
project_id = account.get('projectId') or account.get('managedProjectId')
if not refresh_token_val:
log_warning(f"Account {i} ({email}): No refresh token, skipping")
continue
print(f"{Colors.YELLOW}Account {i}: {email}{Colors.NC}")
now = datetime.now()
expires_in = 3600
timestamp = int(now.timestamp() * 1000)
expired = (now + timedelta(seconds=expires_in)).isoformat() + 'Z'
credential = {
"type": "antigravity",
"email": email,
"refresh_token": refresh_token_val,
"access_token": "",
"expires_in": expires_in,
"timestamp": timestamp,
"expired": expired
}
if project_id:
credential["project_id"] = project_id
print(f" Project: {project_id}")
# Save credential file with antigravity naming convention
# CLIProxyAPI expects: antigravity-<email_sanitized>.json
safe_email = email.replace('@', '_').replace('.', '_')
cred_file = CLIPROXYAPI_AUTH_DIR / f"antigravity-{safe_email}.json"
with open(cred_file, 'w') as f:
json.dump(credential, f, indent=2)
created_files.append(cred_file)
log_success(f"Created: {cred_file.name}")
print()
# Summary
print(f"{Colors.CYAN}{'=' * 61}{Colors.NC}")
print(f"{Colors.GREEN}{Colors.BOLD} Conversion Complete!{Colors.NC}")
print(f"{Colors.CYAN}{'=' * 61}{Colors.NC}\n")
print(f"{Colors.BLUE}Created {len(created_files)} credential file(s):{Colors.NC}")
for cf in created_files:
print(f" * {cf}")
return 0, created_files
# ============================================================================
# Refresh Command
# ============================================================================
def cmd_refresh():
"""Refresh access tokens for all antigravity credential files"""
print_header("Antigravity Token Refresher")
auth_files = list(CLIPROXYAPI_AUTH_DIR.glob("antigravity-*.json"))
if not auth_files:
log_error(f"No antigravity credential files found in {CLIPROXYAPI_AUTH_DIR}")
log_info("Run 'convert' first to create credential files")
return 1
log_info(f"Found {len(auth_files)} credential file(s)")
print_section("Refreshing Tokens")
success_count = 0
fail_count = 0
for file_path in auth_files:
try:
with open(file_path, 'r') as f:
cred = json.load(f)
email = cred.get('email', 'unknown')
refresh_token_value = cred.get('refresh_token')
if not refresh_token_value:
log_warning(f"{email}: No refresh token, skipping")
fail_count += 1
continue
print(f"{Colors.YELLOW}{email}{Colors.NC}...", end=" ", flush=True)
token_response = refresh_token(refresh_token_value)
updated_cred = update_credential_file(file_path, token_response)
print(f"{Colors.GREEN}OK{Colors.NC}")
print(f" Access token: {updated_cred['access_token'][:30]}...")
print(f" Expires: {updated_cred['expired']}")
print()
success_count += 1
except Exception as e:
print(f"{Colors.RED}FAILED{Colors.NC}")
log_error(f" {str(e)}")
print()
fail_count += 1
# Summary
print(f"{Colors.CYAN}{'=' * 61}{Colors.NC}")
print(f"{Colors.GREEN} Success: {success_count}{Colors.NC}")
if fail_count > 0:
print(f"{Colors.RED} Failed: {fail_count}{Colors.NC}")
print(f"{Colors.CYAN}{'=' * 61}{Colors.NC}\n")
return 0 if fail_count == 0 else 1
# ============================================================================
# Help & Next Steps
# ============================================================================
def print_next_steps():
"""Print next steps for CLIProxyAPI setup"""
print_section("Next Steps")
step = 1
# Check if CLIProxyAPI is installed
if not CLIPROXYAPI_DIR.exists():
print(f"{Colors.YELLOW}{step}. Install CLIProxyAPI:{Colors.NC}")
print(f" ./cliproxyapi-installer install")
print()
step += 1
print(f"{Colors.YELLOW}{step}. Ensure your config.yaml has the correct auth-dir:{Colors.NC}")
print(f" {Colors.CYAN}auth-dir: \"~/.cli-proxy-api\"{Colors.NC}")
print()
step += 1
print(f"{Colors.YELLOW}{step}. Start CLIProxyAPI:{Colors.NC}")
print(f" {Colors.CYAN}cd ~/cliproxyapi && ./cli-proxy-api{Colors.NC}")
print()
step += 1
print(f"{Colors.YELLOW}{step}. Test Gemini access:{Colors.NC}")
print(f" {Colors.CYAN}curl -X POST http://localhost:8317/v1/chat/completions \\{Colors.NC}")
print(f" {Colors.CYAN} -H 'Authorization: Bearer YOUR-API-KEY' \\{Colors.NC}")
print(f" {Colors.CYAN} -H 'Content-Type: application/json' \\{Colors.NC}")
print(f" {Colors.CYAN} -d '{{\"model\": \"gemini-2.0-flash-exp\", \"messages\": [{{\"role\": \"user\", \"content\": \"Hello\"}}]}}'{Colors.NC}")
print()
print(f"{Colors.BLUE}Tip:{Colors.NC} Get your API key from ~/cliproxyapi/config.yaml (api-keys section)")
print()
def print_usage():
"""Print usage information"""
print(f"""
{Colors.CYAN}{Colors.BOLD}Antigravity Manager for CLIProxyAPI{Colors.NC}
{Colors.YELLOW}Usage:{Colors.NC}
python {sys.argv[0]} <command>
{Colors.YELLOW}Commands:{Colors.NC}
{Colors.GREEN}convert{Colors.NC} Convert antigravity accounts to CLIProxyAPI format
{Colors.GREEN}refresh{Colors.NC} Refresh access tokens for existing credentials
{Colors.GREEN}all{Colors.NC} Convert accounts then refresh tokens (default)
{Colors.GREEN}help{Colors.NC} Show this help message
{Colors.YELLOW}Examples:{Colors.NC}
python {sys.argv[0]} # Run convert + refresh
python {sys.argv[0]} convert # Only convert accounts
python {sys.argv[0]} refresh # Only refresh tokens
{Colors.YELLOW}File Locations:{Colors.NC}
Source: {ANTIGRAVITY_FILE}
Output: {CLIPROXYAPI_AUTH_DIR}/antigravity-*.json
""")
# ============================================================================
# Main
# ============================================================================
def main():
command = sys.argv[1] if len(sys.argv) > 1 else "all"
command = command.lower()
if command in ("help", "-h", "--help"):
print_usage()
return 0
if command == "convert":
result, _ = cmd_convert()
print_next_steps()
return result
elif command == "refresh":
return cmd_refresh()
elif command == "all":
# Convert first, then refresh
convert_result, created_files = cmd_convert()
if convert_result != 0:
return convert_result
if created_files:
print()
refresh_result = cmd_refresh()
print_next_steps()
return refresh_result
else:
log_warning("No files were created, skipping refresh")
print_next_steps()
return 0
else:
log_error(f"Unknown command: {command}")
print_usage()
return 1
if __name__ == '__main__':
sys.exit(main())
#!/bin/bash
# CLIProxyAPI Linux Installer
# Linux-specific script that installs, upgrades, and manages CLIProxyAPI
# Downloads, installs, and upgrades CLIProxyAPI while preserving configuration
set -euo pipefail
# Configuration
REPO_OWNER="router-for-me"
REPO_NAME="CLIProxyAPI"
REPO_NAME_PLUS="CLIProxyAPIPlus"
INSTALL_DIR="$HOME/cliproxyapi"
API_URL="https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases/latest"
API_URL_PLUS="https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME_PLUS}/releases/latest"
API_URL_ALL="https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases"
API_URL_ALL_PLUS="https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME_PLUS}/releases"
SCRIPT_NAME="cliproxyapi-installer"
VERSION_TYPE="standard" # can be "standard" or "plus"
SPECIFIC_VERSION="" # specific version to install
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${CYAN}[STEP]${NC} $1"
}
# Display authentication information for first-time setup
show_authentication_info() {
echo
echo -e "${YELLOW}🔐 IMPORTANT: Authentication Setup Required${NC}"
echo
echo -e "${BLUE}CLIProxyAPI supports authentication for multiple providers:${NC}"
echo
echo -e "${GREEN}📚 Full Documentation:${NC} https://github.com/router-for-me/CLIProxyAPI"
echo
echo -e "${YELLOW}Authentication Commands:${NC}"
echo
echo -e "${GREEN}Gemini (Google):${NC}"
echo " ./cli-proxy-api --login"
echo " ./cli-proxy-api --login --project_id <your_project_id>"
echo " (OAuth callback on port 8085)"
echo
echo -e "${GREEN}OpenAI (Codex/GPT):${NC}"
echo " ./cli-proxy-api --codex-login"
echo " (OAuth callback on port 1455)"
echo
echo -e "${GREEN}Claude (Anthropic):${NC}"
echo " ./cli-proxy-api --claude-login"
echo " (OAuth callback on port 54545)"
echo
echo -e "${GREEN}Qwen (Qwen Chat):${NC}"
echo " ./cli-proxy-api --qwen-login"
echo " (Uses OAuth device flow)"
echo
echo -e "${GREEN}iFlow:${NC}"
echo " ./cli-proxy-api --iflow-login"
echo " (OAuth callback on port 11451)"
echo
echo -e "${YELLOW}💡 Tip: Add --no-browser to any login command to print URL instead"
echo " of automatically opening a browser."
echo
}
# Generate OpenAI-format API key
generate_api_key() {
# OpenAI API keys follow the format: sk-... (48 characters total)
# Generate 48-character random string starting with "sk-"
local prefix="sk-"
local chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
local key=""
# Generate 45 random characters (48 - 3 for "sk-")
for i in {1..45}; do
key="${key}${chars:$((RANDOM % ${#chars})):1}"
done
echo "${prefix}${key}"
}
# Manage documentation intelligently
manage_documentation() {
echo "Documentation Management"
echo "========================"
if ! is_installed; then
log_error "CLIProxyAPI is not installed. Install it first to manage documentation."
exit 1
fi
local version_dir
version_dir=$(get_current_version_dir)
local readme_file="${version_dir}/README.md"
local install_readme="${INSTALL_DIR}/README.md"
echo "📚 Documentation Status:"
echo
# Check for README files
if [[ -f "$readme_file" ]]; then
echo "✅ Project README: Found ($readme_file)"
else
echo "❌ Project README: Missing"
fi
if [[ -f "$install_readme" ]]; then
echo "✅ Installer README: Found ($install_readme)"
else
echo "❌ Installer README: Missing"
fi
# Check version consistency
local current_version
current_version=$(get_current_version)
echo
echo "🔄 Version Consistency Check:"
if [[ -f "$readme_file" ]] && grep -q "$current_version" "$readme_file"; then
echo "✅ Project README: Version $current_version referenced"
else
echo "⚠️ Project README: Version $current_version not found or outdated"
fi
if [[ -f "$install_readme" ]] && grep -q "$current_version" "$install_readme"; then
echo "✅ Installer README: Version $current_version referenced"
else
echo "⚠️ Installer README: Version $current_version not found or outdated"
fi
# Check for common documentation issues
echo
echo "🔍 Documentation Quality Check:"
local issues_found=0
# Check for broken links (basic check)
if [[ -f "$install_readme" ]]; then
if grep -q "https://" "$install_readme"; then
echo "✅ External links: Present"
else
echo "ℹ️ External links: None found"
fi
fi
# Check for TODO items or placeholders
if [[ -f "$install_readme" ]] && grep -q -i "todo\|placeholder\|your-repo" "$install_readme"; then
echo "⚠️ Placeholders found: Update repository URLs and TODO items"
((issues_found++))
fi
# Check for consistent formatting
if [[ -f "$install_readme" ]]; then
local header_count=$(grep -c "^#" "$install_readme")
echo "📊 Headers found: $header_count"
if [[ $header_count -lt 5 ]]; then
echo "⚠️ Documentation structure: May need more sections"
((issues_found++))
fi
fi
# Provide recommendations
echo
echo "💡 Recommendations:"
if [[ ! -f "$install_readme" ]]; then
echo "• Create installer README.md with usage instructions"
fi
if [[ $issues_found -gt 0 ]]; then
echo "• Review and update $issues_found documentation issues"
fi
echo "• Ensure version numbers are current ($current_version)"
echo "• Update repository URLs if changed"
echo "• Add cross-references between documents"
echo
echo "📖 Quick Documentation Tasks:"
echo "• View project docs: cat $readme_file"
echo "• View installer docs: cat $install_readme"
echo "• Edit installer docs: nano $install_readme"
}
# Check if API keys are configured
check_api_keys() {
local config_file="${INSTALL_DIR}/config.yaml"
if [[ ! -f "$config_file" ]]; then
return 1
fi
# Check for default/placeholder API keys
if grep -q '"your-api-key-1"' "$config_file" || grep -q '"your-api-key-2"' "$config_file"; then
return 1
fi
# Check if api-keys section exists and has non-empty values that look like real API keys
if grep -A 10 "^api-keys:" "$config_file" | grep -v "^#" | grep -v "^api-keys:" | grep -q '"sk-[^"]*"'; then
return 0
fi
return 1
}
# Show API key setup guidance
show_api_key_setup() {
echo
echo -e "${YELLOW}🔑 IMPORTANT: API Keys Required Before First Run${NC}"
echo
echo -e "${BLUE}Before starting CLIProxyAPI, you need to configure API keys in config.yaml:${NC}"
echo
echo -e "${GREEN}1. Edit the configuration file:${NC}"
echo -e " ${CYAN}nano ${INSTALL_DIR}/config.yaml${NC}"
echo
echo -e "${GREEN}2. Find the 'api-keys' section and replace placeholder keys:${NC}"
echo
echo -e " ${YELLOW}# Replace this:${NC}"
echo -e " ${YELLOW}api-keys:${NC}"
echo -e " ${YELLOW} - \"your-api-key-1\"${NC}"
echo -e " ${YELLOW} - \"your-api-key-2\"${NC}"
echo
echo -e " ${GREEN}# With your actual API keys:${NC}"
echo -e " ${GREEN}api-keys:${NC}"
echo -e " ${GREEN} - \"sk-your-real-openai-key-here\"${NC}"
echo -e " ${GREEN} - \"your-custom-secure-key-12345\"${NC}"
echo
echo -e "${GREEN}3. Save the file (Ctrl+X, then Y, then Enter in nano)${NC}"
echo
echo -e "${BLUE}💡 Tips:${NC}"
echo -e " • Use strong, unique keys for security"
echo -e " • You can add multiple keys for different users/services"
echo -e " • Keys are used for authenticating requests to your proxy"
echo -e " • These are NOT your provider API keys (those are set via login commands)"
echo
}
# Show quick start guide
show_quick_start() {
local install_dir="$1"
echo
echo -e "${GREEN}🚀 Quick Start Guide:${NC}"
echo -e "${BLUE}1. Navigate to CLIProxyAPI:${NC}"
echo -e " ${CYAN}cd $install_dir${NC}"
echo
# Check if API keys are configured
if ! check_api_keys; then
show_api_key_setup
echo -e "${BLUE}2. Set up authentication (choose one or more):${NC}"
else
echo -e "${BLUE}2. Set up authentication (choose one or more):${NC}"
fi
echo -e " ${CYAN}./cli-proxy-api --login${NC} # For Gemini"
echo -e " ${CYAN}./cli-proxy-api --codex-login${NC} # For OpenAI"
echo -e " ${CYAN}./cli-proxy-api --claude-login${NC} # For Claude"
echo -e " ${CYAN}./cli-proxy-api --qwen-login${NC} # For Qwen"
echo -e " ${CYAN}./cli-proxy-api --iflow-login${NC} # For iFlow"
echo
if check_api_keys; then
echo -e "${BLUE}Your API keys:${NC}"
grep -A 10 "^api-keys:" "${install_dir}/config.yaml" | grep -v "^#" | head -10
echo
fi
if ! check_api_keys; then
echo -e "${BLUE}3. Configure API keys (REQUIRED):${NC}"
echo -e " ${CYAN}nano config.yaml${NC} # Edit API keys"
echo
echo -e "${BLUE}4. Start the service:${NC}"
echo -e " ${CYAN}./cli-proxy-api${NC}"
echo
echo -e "${BLUE}5. Or run as a systemd service:${NC}"
echo -e " ${CYAN}systemctl --user enable cliproxyapi.service${NC}"
echo -e " ${CYAN}systemctl --user start cliproxyapi.service${NC}"
echo -e " ${CYAN}systemctl --user status cliproxyapi.service${NC}"
echo
echo -e "${BLUE}6. Read the full documentation:${NC}"
echo -e " ${CYAN}https://github.com/router-for-me/CLIProxyAPI${NC}"
else
echo -e "${BLUE}3. Start the service:${NC}"
echo -e " ${CYAN}./cli-proxy-api${NC}"
echo
echo -e "${BLUE}4. Or run as a systemd service:${NC}"
echo -e " ${CYAN}systemctl --user enable cliproxyapi.service${NC}"
echo -e " ${CYAN}systemctl --user start cliproxyapi.service${NC}"
echo -e " ${CYAN}systemctl --user status cliproxyapi.service${NC}"
echo
echo -e "${BLUE}5. Read the full documentation:${NC}"
echo -e " ${CYAN}https://github.com/router-for-me/CLIProxyAPI${NC}"
fi
echo
}
# Detect Linux architecture
detect_linux_arch() {
# Detect architecture
case "$(uname -m)" in
x86_64|amd64)
echo "linux_amd64"
;;
arm64|aarch64)
echo "linux_arm64"
;;
*)
log_error "Unsupported architecture: $(uname -m). Only x86_64 and arm64 are supported on Linux."
exit 1
;;
esac
}
# Check if required tools are available
check_dependencies() {
local missing_tools=()
if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
missing_tools+=("curl or wget")
fi
if ! command -v tar >/dev/null 2>&1; then
missing_tools+=("tar")
fi
if [[ ${#missing_tools[@]} -gt 0 ]]; then
log_error "Missing required tools: ${missing_tools[*]}"
log_info "Please install the missing tools and try again"
log_info "On Ubuntu/Debian: sudo apt-get install curl wget tar"
log_info "On CentOS/RHEL: sudo yum install curl wget tar"
exit 1
fi
}
# Fetch all releases from GitHub API
fetch_all_releases() {
local version_type="${1:-standard}"
local api_url="$API_URL_ALL"
if [[ "$version_type" == "plus" ]]; then
api_url="$API_URL_ALL_PLUS"
fi
local releases_info
if command -v curl >/dev/null 2>&1; then
releases_info=$(curl -s "$api_url")
else
releases_info=$(wget -qO- "$api_url")
fi
if [[ -z "$releases_info" ]]; then
log_error "Failed to fetch releases information from GitHub API"
exit 1
fi
echo "$releases_info"
}
# Fetch latest release info from GitHub API
fetch_release_info() {
local version_type="${1:-standard}"
local api_url="$API_URL"
if [[ "$version_type" == "plus" ]]; then
api_url="$API_URL_PLUS"
log_info "Fetching latest CLIProxyAPI Plus release information..."
else
log_info "Fetching latest CLIProxyAPI release information..."
fi
local release_info
if command -v curl >/dev/null 2>&1; then
release_info=$(curl -s "$api_url")
else
release_info=$(wget -qO- "$api_url")
fi
if [[ -z "$release_info" ]]; then
log_error "Failed to fetch release information from GitHub API"
exit 1
fi
echo "$release_info"
}
# Fetch specific version release info from GitHub API
fetch_specific_version_info() {
local version="$1"
local version_type="${2:-standard}"
local repo_name="$REPO_NAME"
if [[ "$version_type" == "plus" ]]; then
repo_name="$REPO_NAME_PLUS"
fi
local api_url="https://api.github.com/repos/${REPO_OWNER}/${repo_name}/releases/tags/v${version}"
log_info "Fetching release information for version $version..."
local release_info
if command -v curl >/dev/null 2>&1; then
release_info=$(curl -s "$api_url")
else
release_info=$(wget -qO- "$api_url")
fi
if [[ -z "$release_info" ]] || echo "$release_info" | grep -q '"message": "Not Found"'; then
log_error "Version $version not found in GitHub releases"
log_info "Use 'list-versions' command to see available versions"
exit 1
fi
echo "$release_info"
}
# List all available versions
list_available_versions() {
local version_type="${1:-standard}"
check_dependencies
log_info "Fetching available versions..."
local releases_info
releases_info=$(fetch_all_releases "$version_type")
local versions
versions=$(echo "$releases_info" | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4 | sed 's/^v//')
if [[ -z "$versions" ]]; then
log_error "No versions found"
exit 1
fi
local current_version
current_version=$(get_current_version)
echo
echo "Available CLIProxyAPI Versions ($version_type):"
echo "============================================="
echo
local count=0
while IFS= read -r version; do
count=$((count + 1))
if [[ "$version" == "$current_version" ]]; then
echo -e "${GREEN} $version ${CYAN}(installed)${NC}"
else
echo " $version"
fi
done <<< "$versions"
echo
echo "Total: $count versions available"
echo
echo "To install a specific version:"
echo " $SCRIPT_NAME --version <version> install"
echo
echo "Example:"
echo " $SCRIPT_NAME --version 1.0.0 install"
echo
}
# Extract version and download URL from release info
extract_release_info() {
local release_info="$1"
local os_arch="$2"
local version_type="${3:-standard}"
local version
version=$(echo "$release_info" | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4 | sed 's/^v//')
if [[ -z "$version" ]]; then
log_error "Failed to extract version from release info"
exit 1
fi
local expected_filename
local download_url=""
# Handle different naming conventions for standard vs plus versions
if [[ "$version_type" == "plus" ]]; then
expected_filename="CLIProxyAPIPlus_${version}_${os_arch}"
else
expected_filename="CLIProxyAPI_${version}_${os_arch}"
fi
# Handle different file extensions
if [[ "$os_arch" == windows_* ]]; then
expected_filename="${expected_filename}.zip"
else
expected_filename="${expected_filename}.tar.gz"
fi
download_url=$(echo "$release_info" | grep -o "\"browser_download_url\": *\"[^\"]*${expected_filename}[^\"]*\"" | cut -d'"' -f4)
if [[ -z "$download_url" ]]; then
log_error "Failed to find download URL for ${expected_filename}"
exit 1
fi
echo "${version}|${download_url}"
}
# Check if CLIProxyAPI is already installed
is_installed() {
[[ -f "${INSTALL_DIR}/version.txt" ]]
}
# Get installed version type (standard or plus)
get_version_type() {
if is_installed && [[ -f "${INSTALL_DIR}/version_type.txt" ]]; then
cat "${INSTALL_DIR}/version_type.txt" 2>/dev/null || echo "standard"
else
echo "standard"
fi
}
# Get currently installed version
get_current_version() {
if is_installed; then
cat "${INSTALL_DIR}/version.txt" 2>/dev/null || echo "unknown"
else
echo "none"
fi
}
# Get current version directory
get_current_version_dir() {
local current_version
current_version=$(get_current_version)
if [[ "$current_version" != "none" ]]; then
echo "${INSTALL_DIR}/${current_version}"
else
echo ""
fi
}
# Backup existing configuration
backup_config() {
local config="${INSTALL_DIR}/config.yaml"
if [[ -f "$config" ]]; then
local backup_dir="${INSTALL_DIR}/config_backup"
mkdir -p "$backup_dir"
local timestamp
timestamp=$(date +"%Y%m%d_%H%M%S")
local backup_file="${backup_dir}/config_${timestamp}.yaml"
cp "$config" "$backup_file"
log_info "Configuration backed up to: $backup_file"
echo "$backup_file"
else
echo ""
fi
}
# Restore configuration to new version
restore_config() {
local new_version_dir="$1"
local backup_file="$2"
if [[ -n "$backup_file" && -f "$backup_file" ]]; then
cp "$backup_file" "${new_version_dir}/config.yaml"
log_success "Configuration restored from backup"
fi
}
# Check if systemd service is running
is_service_running() {
systemctl --user is-active --quiet cliproxyapi.service 2>/dev/null
}
# Check if any CLIProxyAPI processes are running
is_cliproxyapi_running() {
pgrep -f "cli-proxy-api" >/dev/null 2>&1
}
# Stop any running CLIProxyAPI processes
stop_cliproxyapi_processes() {
local pids
pids=$(pgrep -f "cli-proxy-api" 2>/dev/null || true)
if [[ -n "$pids" ]]; then
log_info "Stopping running CLIProxyAPI processes..."
echo "$pids" | while read -r pid; do
if [[ -n "$pid" ]]; then
kill "$pid" 2>/dev/null || true
log_info "Sent TERM signal to process $pid"
fi
done
# Wait a moment for graceful shutdown
sleep 2
# Check if any processes are still running and force kill if needed
local remaining_pids
remaining_pids=$(pgrep -f "cli-proxy-api" 2>/dev/null || true)
if [[ -n "$remaining_pids" ]]; then
log_warning "Some processes didn't stop gracefully, force killing..."
echo "$remaining_pids" | while read -r pid; do
if [[ -n "$pid" ]]; then
kill -9 "$pid" 2>/dev/null || true
log_info "Force killed process $pid"
fi
done
sleep 1
fi
log_success "All CLIProxyAPI processes stopped"
else
log_info "No CLIProxyAPI processes are running"
fi
}
# Stop systemd service if running
stop_service() {
if is_service_running; then
log_info "Stopping CLIProxyAPI service..."
systemctl --user stop cliproxyapi.service
log_success "Service stopped"
else
log_info "Service is not running"
fi
}
# Start systemd service
start_service() {
log_info "Starting CLIProxyAPI service..."
systemctl --user start cliproxyapi.service
# Wait a moment and check if it started successfully
sleep 2
if is_service_running; then
log_success "Service started successfully"
else
log_warning "Service may not have started properly. Check with: systemctl --user status cliproxyapi.service"
fi
}
# Restart systemd service
restart_service() {
log_info "Restarting CLIProxyAPI service..."
systemctl --user restart cliproxyapi.service
# Wait a moment and check if it started successfully
sleep 2
if is_service_running; then
log_success "Service restarted successfully"
else
log_warning "Service may not have started properly. Check with: systemctl --user status cliproxyapi.service"
fi
}
# Create systemd service file
create_systemd_service() {
local install_dir="$1"
local service_file="${install_dir}/cliproxyapi.service"
local systemd_dir="$HOME/.config/systemd/user"
local systemd_service_file="${systemd_dir}/cliproxyapi.service"
log_info "Creating systemd service file..."
# Create systemd user directory
mkdir -p "$systemd_dir"
# Create service file content with basic working configuration
cat > "$service_file" << EOF
[Unit]
Description=CLIProxyAPI Service
After=network.target
[Service]
Type=simple
WorkingDirectory=$install_dir
ExecStart=$install_dir/cli-proxy-api
Restart=always
RestartSec=10
Environment=HOME=$HOME
[Install]
WantedBy=default.target
EOF
# Copy to systemd user directory
cp "$service_file" "$systemd_service_file"
# Reload systemd daemon
systemctl --user daemon-reload || log_warning "Could not reload systemd daemon (this is normal on first run)"
log_success "Systemd service file created: $service_file"
log_success "Systemd service installed: $systemd_service_file"
log_info "To enable and start the service:"
log_info " systemctl --user enable cliproxyapi.service"
log_info " systemctl --user start cliproxyapi.service"
log_info " systemctl --user status cliproxyapi.service"
}
# Copy example config if no existing config and setup main directory structure
setup_config() {
local version_dir="$1"
local backup_file="$2"
local version_type="${3:-standard}"
log_info "Setting up configuration..."
local config="${INSTALL_DIR}/config.yaml"
local example_config="${version_dir}/config.example.yaml"
local executable
# Determine executable name based on version type
if [[ "$version_type" == "plus" ]]; then
executable="${version_dir}/cli-proxy-api-plus"
else
executable="${version_dir}/cli-proxy-api"
fi
# Copy executable to main directory with standard name for compatibility
if [[ -f "$executable" ]]; then
cp "$executable" "${INSTALL_DIR}/cli-proxy-api"
log_success "Copied executable to ${INSTALL_DIR}/cli-proxy-api"
fi
# PRIORITY 1: If we have a backup from this upgrade, restore it
if [[ -n "$backup_file" && -f "$backup_file" ]]; then
cp "$backup_file" "$config"
log_success "Restored configuration from backup"
return
fi
# PRIORITY 2: Check for existing config in main directory (NEVER overwrite)
if [[ -f "$config" ]]; then
log_success "Preserved existing user configuration (config.yaml)"
log_info "User modifications are protected during upgrades"
return
fi
# PRIORITY 3: Check for existing config in previous version directory
local current_version_dir
current_version_dir=$(get_current_version_dir)
if [[ -n "$current_version_dir" && -f "${current_version_dir}/config.yaml" ]]; then
cp "${current_version_dir}/config.yaml" "$config"
log_success "Preserved existing configuration from previous version"
return
fi
# PRIORITY 4: Only create from example if NO existing config found
if [[ -f "$example_config" ]]; then
cp "$example_config" "$config"
# Generate and replace API key
local generated_key1
local generated_key2
generated_key1=$(generate_api_key)
generated_key2=$(generate_api_key)
# Replace placeholder API keys with generated keys
sed -i "s/\"your-api-key-1\"/\"$generated_key1\"/g" "$config"
sed -i "s/\"your-api-key-2\"/\"$generated_key2\"/g" "$config"
log_success "Created config.yaml from example with generated API keys"
log_info "Generated API keys: $generated_key1, $generated_key2"
log_info "You can find your API keys in: $config"
else
log_warning "config.example.yaml not found, you may need to create config.yaml manually"
fi
}
# Download file
download_file() {
local url="$1"
local output="$2"
log_info "Downloading $(basename "$url")..."
if command -v curl >/dev/null 2>&1; then
curl -L -o "$output" "$url"
else
wget -O "$output" "$url"
fi
if [[ ! -f "$output" ]]; then
log_error "Failed to download file"
exit 1
fi
log_success "Download completed"
}
# Extract tar.gz archive
extract_archive() {
local archive="$1"
local dest_dir="$2"
log_info "Extracting archive to $dest_dir..."
mkdir -p "$dest_dir"
tar -xzf "$archive" -C "$dest_dir"
log_success "Extraction completed"
}
# Write version file
write_version_file() {
local install_dir="$1"
local version="$2"
local version_type="${3:-standard}"
echo "$version" > "${install_dir}/version.txt"
echo "$version_type" > "${install_dir}/version_type.txt"
log_success "Version $version ($version_type) written to version.txt"
}
# Clean up old versions (keep last 2 versions)
cleanup_old_versions() {
local current_version="$1"
if [[ ! -d "$INSTALL_DIR" ]]; then
return
fi
log_info "Cleaning up old versions..."
# Get all version directories, sort them, and remove all but the latest 2
local old_versions
old_versions=$(find "$INSTALL_DIR" -maxdepth 1 -type d -name "*.*.*" -printf "%f\n" | sort -V | head -n -2)
if [[ -n "$old_versions" ]]; then
echo "$old_versions" | while read -r version; do
if [[ "$version" != "$current_version" && -n "$version" ]]; then
rm -rf "${INSTALL_DIR}/${version}"
log_info "Removed old version: $version"
fi
done
fi
}
# Make binary executable
make_executable() {
local version_dir="$1"
local version_type="${2:-standard}"
local binary
if [[ "$version_type" == "plus" ]]; then
binary=$(find "$version_dir" -name "CLIProxyAPIPlus" -o -name "cli-proxy-api-plus" -type f | head -1)
else
binary=$(find "$version_dir" -name "CLIProxyAPI" -o -name "cli-proxy-api" -type f | head -1)
fi
if [[ -n "$binary" ]]; then
chmod +x "$binary"
log_success "Made CLIProxyAPI binary executable"
fi
}
# Main installation function
install_cliproxyapi() {
local version_type="${VERSION_TYPE:-standard}"
local specific_version="${SPECIFIC_VERSION}"
local current_version
current_version=$(get_current_version)
local current_version_type
current_version_type=$(get_version_type)
local is_upgrade=false
local service_was_running=false
if [[ "$current_version" != "none" ]]; then
log_info "Current CLIProxyAPI version: $current_version ($current_version_type)"
is_upgrade=true
if is_service_running; then
service_was_running=true
log_info "Service is currently running and will be restarted after upgrade"
fi
else
log_info "CLIProxyAPI not installed, performing fresh installation"
fi
check_dependencies
local os_arch
os_arch=$(detect_linux_arch)
log_step "Detected platform: $os_arch"
local release_info
if [[ -n "$specific_version" ]]; then
release_info=$(fetch_specific_version_info "$specific_version" "$version_type")
else
release_info=$(fetch_release_info "$version_type")
fi
local release_data
release_data=$(extract_release_info "$release_info" "$os_arch" "$version_type")
local version=$(echo "$release_data" | cut -d'|' -f1)
local download_url=$(echo "$release_data" | cut -d'|' -f2)
log_step "Target version: $version ($version_type)"
if [[ "$is_upgrade" == true && "$current_version" == "$version" && "$current_version_type" == "$version_type" ]]; then
log_success "CLIProxyAPI is already at version $version ($version_type)"
return
fi
if [[ "$is_upgrade" == true ]]; then
if is_service_running; then
stop_service
fi
if is_cliproxyapi_running; then
stop_cliproxyapi_processes
fi
fi
local backup_file=""
if [[ "$is_upgrade" == true ]]; then
backup_file=$(backup_config)
fi
local version_dir="${INSTALL_DIR}/${version}"
mkdir -p "$INSTALL_DIR"
local temp_file
temp_file=$(mktemp)
download_file "$download_url" "$temp_file"
extract_archive "$temp_file" "$version_dir"
rm -f "$temp_file"
make_executable "$version_dir" "$version_type"
setup_config "$version_dir" "$backup_file" "$version_type"
chmod +x "${INSTALL_DIR}/cli-proxy-api"
create_systemd_service "$INSTALL_DIR"
write_version_file "$INSTALL_DIR" "$version" "$version_type"
cleanup_old_versions "$version"
if [[ "$is_upgrade" == true && "$service_was_running" == true ]]; then
restart_service
fi
if [[ "$is_upgrade" == true ]]; then
log_success "CLIProxyAPI upgraded from $current_version to $version!"
log_info "Installation directory: $INSTALL_DIR"
if [[ "$service_was_running" == true ]]; then
log_info "Service has been restarted automatically"
elif is_service_running; then
log_info "Service is running"
else
log_info "To start the service: systemctl --user start cliproxyapi.service"
fi
if [[ ! -f "${INSTALL_DIR}/config.yaml" ]]; then
show_authentication_info
show_quick_start "$INSTALL_DIR"
else
log_info "Your existing configuration has been preserved"
log_info "To use CLIProxyAPI: cd $INSTALL_DIR && ./cli-proxy-api --help"
fi
else
log_success "CLIProxyAPI $version installed successfully!"
log_info "Installation directory: $INSTALL_DIR"
show_authentication_info
show_quick_start "$INSTALL_DIR"
fi
}
# Show current installation status
show_status() {
local current_version
current_version=$(get_current_version)
local current_version_type
current_version_type=$(get_version_type)
echo "CLIProxyAPI Installation Status"
echo "=============================="
echo "Install Directory: $INSTALL_DIR"
echo "Current Version: $current_version ($current_version_type)"
if [[ "$current_version" != "none" ]]; then
local current_version_dir
current_version_dir=$(get_current_version_dir)
echo "Version Directory: $current_version_dir"
if [[ -f "${INSTALL_DIR}/config.yaml" ]]; then
echo "Configuration: Present (at ${INSTALL_DIR}/config.yaml)"
else
echo "Configuration: Missing"
fi
if [[ -f "${INSTALL_DIR}/cli-proxy-api" ]]; then
echo "Executable: Present (at ${INSTALL_DIR}/cli-proxy-api)"
else
echo "Executable: Missing"
fi
if [[ -f "${INSTALL_DIR}/cliproxyapi.service" ]]; then
echo "Systemd Service: Available"
echo " To enable: systemctl --user enable cliproxyapi.service"
echo " To start: systemctl --user start cliproxyapi.service"
else
echo "Systemd Service: Missing"
fi
# Check API keys status
if check_api_keys; then
echo "API Keys: Configured"
else
echo -e "API Keys: ${YELLOW}NOT CONFIGURED${NC} - Edit config.yaml to add API keys"
fi
# Show available versions
if [[ -d "$INSTALL_DIR" ]]; then
echo "Installed Versions:"
find "$INSTALL_DIR" -maxdepth 1 -type d -name "*.*.*" -printf " %f\n" | sort -V
fi
else
echo "Status: Not installed"
fi
}
# Uninstall function
uninstall_cliproxyapi() {
if [[ ! -d "$INSTALL_DIR" ]]; then
log_warning "CLIProxyAPI installation directory not found: $INSTALL_DIR"
exit 0
fi
log_info "CLIProxyAPI installation found at: $INSTALL_DIR"
# Show what will be removed
echo
log_info "The following will be removed:"
find "$INSTALL_DIR" -type f -exec echo " {}" \;
echo
# Ask for confirmation
read -p "Are you sure you want to remove CLIProxyAPI? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Uninstallation cancelled"
exit 0
fi
# Remove installation directory
log_info "Removing CLIProxyAPI installation..."
rm -rf "$INSTALL_DIR"
log_success "CLIProxyAPI has been uninstalled successfully"
}
# Cleanup function on exit
cleanup() {
local temp_files
temp_files=$(find /tmp -name "tmp.*" -user "$(whoami)" 2>/dev/null || true)
if [[ -n "$temp_files" ]]; then
echo "$temp_files" | xargs rm -f 2>/dev/null || true
fi
}
# Set up cleanup trap
trap cleanup EXIT
# Main script logic
main() {
while [[ $# -gt 0 ]]; do
case "$1" in
--plus)
VERSION_TYPE="plus"
shift
;;
--standard)
VERSION_TYPE="standard"
shift
;;
--version)
if [[ -z "$2" || "$2" == -* ]]; then
log_error "Option --version requires a version number"
echo "Example: $SCRIPT_NAME --version 1.0.0 install"
exit 1
fi
SPECIFIC_VERSION="$2"
shift 2
;;
*)
break
;;
esac
done
case "${1:-install}" in
"install"|"upgrade")
install_cliproxyapi
;;
"list-versions"|"versions")
list_available_versions "$VERSION_TYPE"
;;
"status")
show_status
;;
"auth")
show_authentication_info
if is_installed; then
local current_version_dir
current_version_dir=$(get_current_version_dir)
if [[ -n "$current_version_dir" ]]; then
show_quick_start "$current_version_dir"
fi
fi
;;
"check-config")
if is_installed; then
echo "Configuration Check"
echo "=================="
echo "Config file: ${INSTALL_DIR}/config.yaml"
if check_api_keys; then
echo -e "✅ API Keys: ${GREEN}Configured${NC}"
echo -e "✅ Status: ${GREEN}Ready to run${NC}"
echo
echo -e "${BLUE}Current API keys in config.yaml:${NC}"
grep -A 10 "^api-keys:" "${INSTALL_DIR}/config.yaml" | grep -v "^#" | head -10
echo
echo -e "${BLUE}You can now start CLIProxyAPI:${NC}"
echo -e " ${CYAN}cd ${INSTALL_DIR}${NC}"
echo -e " ${CYAN}./cli-proxy-api${NC}"
echo
echo -e "${BLUE}Or run as a service:${NC}"
echo -e " ${CYAN}systemctl --user start cliproxyapi.service${NC}"
else
echo -e "❌ API Keys: ${RED}NOT CONFIGURED${NC}"
echo -e "❌ Status: ${RED}Not ready to run${NC}"
echo
show_api_key_setup
fi
else
log_error "CLIProxyAPI is not installed"
echo "Install it first with: $SCRIPT_NAME install"
fi
;;
"generate-key")
local new_key
new_key=$(generate_api_key)
echo "Generated OpenAI-format API Key:"
echo "================================"
echo -e "${GREEN}$new_key${NC}"
echo
echo -e "${BLUE}To use this key, add it to your config.yaml:${NC}"
echo -e "${CYAN}api-keys:${NC}"
echo -e "${CYAN} - \"$new_key\"${NC}"
echo
echo -e "${YELLOW}Note: This generates a new key but doesn't modify your config file.${NC}"
echo -e "${YELLOW}Edit ${INSTALL_DIR}/config.yaml manually to add this key.${NC}"
;;
"manage-docs")
manage_documentation
;;
"uninstall")
uninstall_cliproxyapi
;;
"-h"|"--help")
cat <<EOF
CLIProxyAPI Linux Installer
Usage: $SCRIPT_NAME [OPTIONS] [COMMAND]
Options:
--standard Install standard version (default)
--plus Install Plus version from CLIProxyAPIPlus repository
--version VERSION Install specific version number (e.g., --version 1.0.0)
Commands:
install, upgrade Install or upgrade CLIProxyAPI (default)
list-versions List all available versions from GitHub
versions Alias for list-versions
status Show current installation status
auth Show authentication setup information
check-config Check configuration and API keys
generate-key Generate new API key and show it
manage-docs Manage documentation (update, organize, check consistency)
uninstall Remove CLIProxyAPI completely
-h, --help Show this help message
Description:
This Linux-specific script installs, upgrades, or removes CLIProxyAPI.
It can be run from anywhere and automatically detects your Linux architecture.
During upgrades, your config.yaml file is preserved automatically.
Features:
- Automatic Linux architecture detection (amd64/arm64)
- Downloads latest or specific version from GitHub releases
- Install any older version available
- Preserves configuration during upgrades
- Automatic API key generation
- Systemd service file creation
- Cleans up old versions (keeps latest 2)
- Support for both standard and Plus versions
Installation Directory: ~/cliproxyapi/
Supported Platforms:
- Linux: amd64, arm64
Repositories:
- Standard: https://github.com/router-for-me/CLIProxyAPI
- Plus: https://github.com/router-for-me/CLIProxyAPIPlus
Examples:
$SCRIPT_NAME # Install or upgrade (standard, latest)
$SCRIPT_NAME --plus install # Install Plus version (latest)
$SCRIPT_NAME --version 1.0.0 install # Install specific version 1.0.0
$SCRIPT_NAME --plus --version 2.3.1 # Install Plus version 2.3.1
$SCRIPT_NAME list-versions # Show all available versions
$SCRIPT_NAME --plus versions # Show Plus versions
$SCRIPT_NAME status # Show current status
$SCRIPT_NAME auth # Show authentication info
$SCRIPT_NAME check-config # Check configuration
$SCRIPT_NAME generate-key # Generate new API key
$SCRIPT_NAME --plus upgrade # Upgrade to latest Plus version
$SCRIPT_NAME uninstall # Remove completely
EOF
;;
*)
log_error "Unknown command: $1"
echo "Use '$SCRIPT_NAME --help' for usage information"
exit 1
;;
esac
}
# Run main function with all arguments
main "$@"
{
"model": "cliproxy/claude-sonnet-4-5-thinking",
"permission": {
"question": "allow"
},
"plugin": [
"oh-my-opencode@3.0.0-beta.11"
],
"provider": {
"cliproxy": {
"name": "Proxy API",
"npm": "@ai-sdk/anthropic",
"options": {
"apiKey": "its_norman_here",
"baseURL": "http://localhost:8317/v1",
"timeout": 600000
},
"models": {
"claude-opus-4-5-thinking": {
"name": "Claude Opus 4.5 Thinking",
"limit": {
"context": 200000,
"output": 64000
},
"reasoning": true,
"options": {
"thinking": {
"type": "enabled",
"budgetTokens": 32000
}
}
},
"claude-sonnet-4-5": {
"name": "Claude Sonnet 4.5",
"limit": {
"context": 200000,
"output": 64000
}
},
"claude-sonnet-4-5-thinking": {
"name": "Claude Sonnet 4.5 Thinking",
"limit": {
"context": 200000,
"output": 64000
},
"reasoning": true,
"options": {
"thinking": {
"type": "enabled",
"budgetTokens": 32000
}
}
}
}
},
"cliproxygoogle": {
"name": "Proxy API (Google)",
"npm": "@ai-sdk/google",
"options": {
"apiKey": "its_norman_here",
"baseURL": "http://localhost:8317/v1beta",
"timeout": 600000
},
"models": {
"gemini-3-pro-preview": {
"name": "Gemini 3 Pro Preview",
"reasoning": true,
"limit": {
"context": 1048576,
"output": 65536
}
},
"gemini-3-pro-image-preview": {
"name": "Gemini 3 Pro Image Preview",
"limit": {
"context": 1048576,
"output": 65536
}
},
"gemini-3-flash-preview": {
"name": "Gemini 3 Flash Preview",
"limit": {
"context": 1048576,
"output": 65536
}
},
"gemini-2.5-flash": {
"name": "Gemini 2.5 Flash",
"limit": {
"context": 1048576,
"output": 65536
}
},
"gemini-2.5-flash-lite": {
"name": "Gemini 2.5 Flash Lite",
"limit": {
"context": 1048576,
"output": 65536
}
},
"gemini-2.5-computer-use-preview-10-2025": {
"name": "Gemini 2.5 Computer Use Preview",
"limit": {
"context": 1048576,
"output": 65536
}
}
}
}
},
"$schema": "https://opencode.ai/config.json"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment