Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions scripts/linux/cliproxyapi-oauth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/bin/bash
#
# CLIProxyAPI-Plus OAuth Login Helper for Linux
# Usage:
# ./cliproxyapi-oauth.sh # Interactive menu
# ./cliproxyapi-oauth.sh --all # Login to all
# ./cliproxyapi-oauth.sh --gemini # Gemini only
# ./cliproxyapi-oauth.sh --copilot # GitHub Copilot
#

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; NC='\033[0m'

CONFIG="$HOME/.cli-proxy-api/config.yaml"
BINARY="$HOME/bin/cliproxyapi-plus"

[ ! -f "$BINARY" ] && echo -e "${RED}[-] Binary not found. Run install-cliproxyapi.sh${NC}" && exit 1

declare -A FLAGS=(
["gemini"]="--login"
["antigravity"]="--antigravity-login"
["copilot"]="--github-copilot-login"
["codex"]="--codex-login"
["claude"]="--claude-login"
["qwen"]="--qwen-login"
["iflow"]="--iflow-login"
["kiro"]="--kiro-aws-login"
)

declare -A NAMES=(
["gemini"]="Gemini CLI"
["antigravity"]="Antigravity"
["copilot"]="GitHub Copilot"
["codex"]="Codex"
["claude"]="Claude"
["qwen"]="Qwen"
["iflow"]="iFlow"
["kiro"]="Kiro (AWS)"
)

ORDER=("gemini" "antigravity" "copilot" "codex" "claude" "qwen" "iflow" "kiro")

run_login() {
local key="$1"
echo -e "\n${CYAN}[*] Logging in to ${NAMES[$key]}...${NC}"
"$BINARY" --config "$CONFIG" "${FLAGS[$key]}"
[ $? -eq 0 ] && echo -e "${GREEN}[+] ${NAMES[$key]} login completed!${NC}" || echo -e "${YELLOW}[!] ${NAMES[$key]} may have issues${NC}"
}

LOGIN_ALL=false
SELECTED=()

while [[ $# -gt 0 ]]; do
case $1 in
--all|-a) LOGIN_ALL=true; shift ;;
--gemini) SELECTED+=("gemini"); shift ;;
--antigravity) SELECTED+=("antigravity"); shift ;;
--copilot) SELECTED+=("copilot"); shift ;;
--codex) SELECTED+=("codex"); shift ;;
--claude) SELECTED+=("claude"); shift ;;
--qwen) SELECTED+=("qwen"); shift ;;
--iflow) SELECTED+=("iflow"); shift ;;
--kiro) SELECTED+=("kiro"); shift ;;
*) shift ;;
esac
done

if [ "$LOGIN_ALL" = true ] || [ ${#SELECTED[@]} -gt 0 ]; then
echo -e "${MAGENTA}=== CLIProxyAPI-Plus OAuth Login ===${NC}"
if [ "$LOGIN_ALL" = true ]; then
for key in "${ORDER[@]}"; do run_login "$key"; done
else
for key in "${SELECTED[@]}"; do run_login "$key"; done
fi
else
echo -e "${MAGENTA}
==========================================
CLIProxyAPI-Plus OAuth Login Menu
==========================================
${NC}"
echo -e "${YELLOW}Available providers:${NC}"
for i in "${!ORDER[@]}"; do echo " $((i+1)). ${NAMES[${ORDER[$i]}]}"; done
echo " A. Login to ALL"
echo " Q. Quit"

while true; do
read -p "Select [1-8, A, Q]: " choice
[[ "$choice" =~ ^[Qq]$ ]] && echo "Bye!" && break
[[ "$choice" =~ ^[Aa]$ ]] && { for k in "${ORDER[@]}"; do run_login "$k"; done; break; }
[[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le 8 ] && run_login "${ORDER[$((choice-1))]}"
done
fi

echo -e "${GREEN}
==========================================
Auth files saved in: $HOME/.cli-proxy-api
==========================================
${NC}"
187 changes: 187 additions & 0 deletions scripts/linux/install-cliproxyapi.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#!/bin/bash
#
# CLIProxyAPI-Plus Installation Script for Linux
# Usage:
# ./install-cliproxyapi.sh # Auto install
# ./install-cliproxyapi.sh --prebuilt # Force prebuilt binary
# ./install-cliproxyapi.sh --source # Force build from source
# ./install-cliproxyapi.sh --skip-oauth # Skip OAuth info
# ./install-cliproxyapi.sh --force # Overwrite existing config
#

set -e

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; NC='\033[0m'

REPO_URL="https://github.com/router-for-me/CLIProxyAPIPlus.git"
RELEASE_API="https://api.github.com/repos/router-for-me/CLIProxyAPIPlus/releases/latest"
CLONE_DIR="$HOME/CLIProxyAPIPlus"
BIN_DIR="$HOME/bin"
CONFIG_DIR="$HOME/.cli-proxy-api"
FACTORY_DIR="$HOME/.factory"
BINARY_NAME="cliproxyapi-plus"

USE_PREBUILT=false; FORCE_SOURCE=false; SKIP_OAUTH=false; FORCE=false

while [[ $# -gt 0 ]]; do
case $1 in
--prebuilt) USE_PREBUILT=true; shift ;;
--source) FORCE_SOURCE=true; shift ;;
--skip-oauth) SKIP_OAUTH=true; shift ;;
--force) FORCE=true; shift ;;
*) shift ;;
esac
done

write_step() { echo -e "\n${CYAN}[*] $1${NC}"; }
write_success() { echo -e "${GREEN}[+] $1${NC}"; }
write_warning() { echo -e "${YELLOW}[!] $1${NC}"; }
write_error() { echo -e "${RED}[-] $1${NC}"; }

echo -e "${MAGENTA}
==============================================
CLIProxyAPI-Plus Installer for Linux
==============================================
${NC}"

write_step "Checking prerequisites..."

if [ "$USE_PREBUILT" = false ] && [ "$FORCE_SOURCE" = false ]; then
if command -v go &> /dev/null; then
write_success "Go found: $(go version)"
else
write_warning "Go not installed. Using prebuilt binary."
USE_PREBUILT=true
fi
fi

command -v git &> /dev/null || { write_error "Git not installed"; exit 1; }
write_success "Git found"

command -v curl &> /dev/null && DOWNLOAD_CMD="curl" || DOWNLOAD_CMD="wget"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove unused DOWNLOAD_CMD variable.

The DOWNLOAD_CMD variable is set on line 62 but never used. The script hardcodes curl -s directly throughout. Remove the dead code.

-command -v curl &> /dev/null && DOWNLOAD_CMD="curl" || DOWNLOAD_CMD="wget"
 command -v jq &> /dev/null && HAS_JQ=true || HAS_JQ=false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
command -v curl &> /dev/null && DOWNLOAD_CMD="curl" || DOWNLOAD_CMD="wget"
command -v jq &> /dev/null && HAS_JQ=true || HAS_JQ=false
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 62-62: DOWNLOAD_CMD appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In scripts/linux/install-cliproxyapi.sh around line 62, the DOWNLOAD_CMD
variable is assigned but never used; remove the dead assignment line (command -v
curl &> /dev/null && DOWNLOAD_CMD="curl" || DOWNLOAD_CMD="wget") so the script
no longer defines an unused variable, and verify there are no other references
to DOWNLOAD_CMD elsewhere in the file before committing.

command -v jq &> /dev/null && HAS_JQ=true || HAS_JQ=false

write_step "Creating directories..."
mkdir -p "$BIN_DIR" "$CONFIG_DIR" "$FACTORY_DIR"
write_success "Directories ready"

ARCH=$(uname -m)
case $ARCH in
x86_64) ARCH_SUFFIX="linux_amd64" ;;
aarch64|arm64) ARCH_SUFFIX="linux_arm64" ;;
*) ARCH_SUFFIX="linux_amd64" ;;
esac

if [ "$USE_PREBUILT" = true ]; then
write_step "Downloading pre-built binary..."
TEMP_DIR=$(mktemp -d)

if [ "$HAS_JQ" = true ]; then
RELEASE_INFO=$(curl -s -H "User-Agent: Bash" "$RELEASE_API")
DOWNLOAD_URL=$(echo "$RELEASE_INFO" | jq -r ".assets[] | select(.name | contains(\"$ARCH_SUFFIX\")) | .browser_download_url" | head -n1)
else
RELEASE_INFO=$(curl -s -H "User-Agent: Bash" "$RELEASE_API")
DOWNLOAD_URL=$(echo "$RELEASE_INFO" | grep -o "https://[^\"]*${ARCH_SUFFIX}[^\"]*" | head -n1)
fi

if [ -z "$DOWNLOAD_URL" ] || [ "$DOWNLOAD_URL" = "null" ]; then
write_warning "No prebuilt found, building from source..."
FORCE_SOURCE=true
else
echo " Downloading..."
curl -sL -o "$TEMP_DIR/archive.tar.gz" "$DOWNLOAD_URL"
cd "$TEMP_DIR"
tar -xzf archive.tar.gz 2>/dev/null || unzip -q archive.tar.gz 2>/dev/null || true
BINARY_FILE=$(find . -type f -name "cliproxyapi*" ! -name "*.gz" ! -name "*.zip" | head -n1)
if [ -n "$BINARY_FILE" ]; then
chmod +x "$BINARY_FILE"
mv "$BINARY_FILE" "$BIN_DIR/$BINARY_NAME"
write_success "Binary installed: $BIN_DIR/$BINARY_NAME"
fi
rm -rf "$TEMP_DIR"
fi
fi

if [ "$FORCE_SOURCE" = true ] || [ ! -f "$BIN_DIR/$BINARY_NAME" ]; then
write_step "Building from source..."
[ -d "$CLONE_DIR" ] && [ "$FORCE" = true ] && rm -rf "$CLONE_DIR"
[ ! -d "$CLONE_DIR" ] && git clone --depth 1 "$REPO_URL" "$CLONE_DIR"
cd "$CLONE_DIR"
go build -o "$BIN_DIR/$BINARY_NAME" ./cmd/server
write_success "Binary built: $BIN_DIR/$BINARY_NAME"
fi

write_step "Creating config.yaml..."
CONFIG_PATH="$CONFIG_DIR/config.yaml"
if [ -f "$CONFIG_PATH" ] && [ "$FORCE" = false ]; then
write_warning "config.yaml exists, skipping"
else
cat > "$CONFIG_PATH" << EOF
port: 8317
auth-dir: "$CONFIG_DIR"
api-keys:
- "sk-dummy"
quota-exceeded:
switch-project: true
switch-preview-model: true
incognito-browser: true
request-retry: 3
remote-management:
allow-remote: false
secret-key: ""
disable-control-panel: false
EOF
write_success "config.yaml created"
fi

write_step "Creating .factory/config.json..."
cat > "$FACTORY_DIR/config.json" << 'EOF'
{
"custom_models": [
{ "model_display_name": "Claude Opus 4.5 Thinking [Antigravity]", "model": "gemini-claude-opus-4-5-thinking", "base_url": "http://localhost:8317/v1", "api_key": "sk-dummy", "provider": "openai" },
{ "model_display_name": "Claude Sonnet 4.5 [Antigravity]", "model": "gemini-claude-sonnet-4-5", "base_url": "http://localhost:8317/v1", "api_key": "sk-dummy", "provider": "openai" },
{ "model_display_name": "Gemini 2.5 Pro [Gemini]", "model": "gemini-2.5-pro", "base_url": "http://localhost:8317/v1", "api_key": "sk-dummy", "provider": "openai" },
{ "model_display_name": "Claude Opus 4.5 [Copilot]", "model": "claude-opus-4.5", "base_url": "http://localhost:8317/v1", "api_key": "sk-dummy", "provider": "openai" },
{ "model_display_name": "GPT-5.1 Codex Max [Codex]", "model": "gpt-5.1-codex-max", "base_url": "http://localhost:8317/v1", "api_key": "sk-dummy", "provider": "openai" },
{ "model_display_name": "Qwen3 Coder Plus [Qwen]", "model": "qwen3-coder-plus", "base_url": "http://localhost:8317/v1", "api_key": "sk-dummy", "provider": "openai" },
{ "model_display_name": "Claude Opus 4.5 [Kiro]", "model": "kiro-claude-opus-4.5", "base_url": "http://localhost:8317/v1", "api_key": "sk-dummy", "provider": "openai" }
]
}
EOF
write_success "config.json created with custom models"

write_step "Verifying installation..."
[ -f "$BIN_DIR/$BINARY_NAME" ] && write_success "Binary verified" || { write_error "Binary not found"; exit 1; }

write_step "Configuring PATH..."
SHELL_RC="$HOME/.bashrc"; [ -f "$HOME/.zshrc" ] && SHELL_RC="$HOME/.zshrc"
if ! grep -q "$BIN_DIR" "$SHELL_RC" 2>/dev/null; then
echo -e "\n# CLIProxyAPI-Plus\nexport PATH=\"\$PATH:$BIN_DIR\"" >> "$SHELL_RC"
write_success "Added to PATH in $SHELL_RC"
fi

[ "$SKIP_OAUTH" = false ] && echo -e "${YELLOW}
OAuth Login Commands:
$BINARY_NAME --config $CONFIG_DIR/config.yaml --login # Gemini
$BINARY_NAME --config $CONFIG_DIR/config.yaml --antigravity-login # Antigravity
$BINARY_NAME --config $CONFIG_DIR/config.yaml --github-copilot-login
$BINARY_NAME --config $CONFIG_DIR/config.yaml --codex-login
$BINARY_NAME --config $CONFIG_DIR/config.yaml --claude-login
$BINARY_NAME --config $CONFIG_DIR/config.yaml --qwen-login
$BINARY_NAME --config $CONFIG_DIR/config.yaml --kiro-aws-login
${NC}"

echo -e "${GREEN}
==============================================
Installation Complete!
==============================================
Binary: $BIN_DIR/$BINARY_NAME
Config: $CONFIG_DIR/config.yaml
Droid: $FACTORY_DIR/config.json

Quick Start:
source $SHELL_RC
start-cliproxyapi.sh --background
==============================================
${NC}"
100 changes: 100 additions & 0 deletions scripts/linux/start-cliproxyapi.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/bin/bash
#
# CLIProxyAPI-Plus Server Manager for Linux
# Usage:
# ./start-cliproxyapi.sh # Start foreground
# ./start-cliproxyapi.sh --background # Start background
# ./start-cliproxyapi.sh --status # Check status
# ./start-cliproxyapi.sh --stop # Stop server
# ./start-cliproxyapi.sh --restart # Restart
# ./start-cliproxyapi.sh --logs # View logs
#

set -e

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; NC='\033[0m'

BINARY="$HOME/bin/cliproxyapi-plus"
CONFIG="$HOME/.cli-proxy-api/config.yaml"
LOG_DIR="$HOME/.cli-proxy-api/logs"
PID_FILE="$HOME/.cli-proxy-api/server.pid"
PORT=8317

BACKGROUND=false; STATUS=false; STOP=false; LOGS=false; RESTART=false

while [[ $# -gt 0 ]]; do
case $1 in
--background|-b) BACKGROUND=true; shift ;;
--status|-s) STATUS=true; shift ;;
--stop) STOP=true; shift ;;
--restart|-r) RESTART=true; shift ;;
--logs|-l) LOGS=true; shift ;;
*) shift ;;
esac
done

get_server_pid() {
[ -f "$PID_FILE" ] && PID=$(cat "$PID_FILE") && ps -p "$PID" &>/dev/null && echo "$PID" && return
pgrep -f "cliproxyapi-plus" 2>/dev/null | head -n1
}

show_status() {
echo -e "\n${MAGENTA}=== CLIProxyAPI-Plus Status ===${NC}"
PID=$(get_server_pid)
if [ -n "$PID" ]; then
echo -e "${GREEN}[+] Server RUNNING (PID: $PID)${NC}"
[ -f "/proc/$PID/status" ] && MEM=$(grep VmRSS /proc/$PID/status | awk '{print $2}') && echo " Memory: $((MEM/1024)) MB"
else
echo -e "${YELLOW}[!] Server NOT running${NC}"
fi
ss -tuln 2>/dev/null | grep -q ":$PORT " && echo -e "${GREEN}Port $PORT in use${NC}" || echo -e "${YELLOW}Port $PORT free${NC}"
curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 "http://localhost:$PORT/v1/models" | grep -q "200\|401" && echo -e "${GREEN}[+] API responding${NC}"
echo ""
}

stop_server() {
PID=$(get_server_pid)
if [ -n "$PID" ]; then
echo -e "${CYAN}[*] Stopping server (PID: $PID)...${NC}"
kill "$PID" 2>/dev/null; sleep 0.5
ps -p "$PID" &>/dev/null && kill -9 "$PID" 2>/dev/null
rm -f "$PID_FILE"
echo -e "${GREEN}[+] Server stopped${NC}"
else
echo -e "${YELLOW}[!] Server not running${NC}"
fi
}

show_logs() {
mkdir -p "$LOG_DIR"
LATEST=$(ls -t "$LOG_DIR"/*.log 2>/dev/null | head -n1)
[ -n "$LATEST" ] && tail -f "$LATEST" || echo -e "${YELLOW}[!] No logs found${NC}"
}

start_server() {
PID=$(get_server_pid)
[ -n "$PID" ] && echo -e "${YELLOW}[!] Already running (PID: $PID)${NC}" && show_status && return
[ ! -f "$BINARY" ] && echo -e "${RED}[-] Binary not found. Run install-cliproxyapi.sh${NC}" && exit 1
[ ! -f "$CONFIG" ] && echo -e "${RED}[-] Config not found. Run install-cliproxyapi.sh${NC}" && exit 1

mkdir -p "$LOG_DIR"

if [ "$BACKGROUND" = true ]; then
echo -e "${CYAN}[*] Starting in background...${NC}"
LOG_FILE="$LOG_DIR/server-$(date +%Y%m%d).log"
nohup "$BINARY" --config "$CONFIG" >> "$LOG_FILE" 2>&1 &
echo $! > "$PID_FILE"
sleep 2
ps -p $(cat "$PID_FILE") &>/dev/null && echo -e "${GREEN}[+] Started (PID: $(cat $PID_FILE))${NC}\nEndpoint: http://localhost:$PORT/v1" || echo -e "${RED}[-] Failed to start${NC}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Quote $PID_FILE to prevent word splitting in command substitution.

Line 89 uses $(cat $PID_FILE) without quotes. If the PID file path contains spaces (unlikely but possible), this breaks. Quote the variable: $(cat "$PID_FILE").

-        ps -p $(cat "$PID_FILE") &>/dev/null && echo -e "${GREEN}[+] Started (PID: $(cat $PID_FILE))${NC}\nEndpoint: http://localhost:$PORT/v1" || echo -e "${RED}[-] Failed to start${NC}"
+        ps -p $(cat "$PID_FILE") &>/dev/null && echo -e "${GREEN}[+] Started (PID: $(cat "$PID_FILE"))${NC}\nEndpoint: http://localhost:$PORT/v1" || echo -e "${RED}[-] Failed to start${NC}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ps -p $(cat "$PID_FILE") &>/dev/null && echo -e "${GREEN}[+] Started (PID: $(cat $PID_FILE))${NC}\nEndpoint: http://localhost:$PORT/v1" || echo -e "${RED}[-] Failed to start${NC}"
ps -p $(cat "$PID_FILE") &>/dev/null && echo -e "${GREEN}[+] Started (PID: $(cat "$PID_FILE"))${NC}\nEndpoint: http://localhost:$PORT/v1" || echo -e "${RED}[-] Failed to start${NC}"
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 89-89: Quote this to prevent word splitting.

(SC2046)

🤖 Prompt for AI Agents
In scripts/linux/start-cliproxyapi.sh around line 89, the command substitution
uses $(cat $PID_FILE) unquoted which can cause word-splitting if the PID file
path contains spaces; update the line to quote the variable everywhere it’s used
(use $(cat "$PID_FILE") and "$PID_FILE" in ps -p if applicable) so the PID file
path is treated as a single token and command substitutions are safe.

else
echo -e "${MAGENTA}=== CLIProxyAPI-Plus ===${NC}\nConfig: $CONFIG\nEndpoint: http://localhost:$PORT/v1\n${YELLOW}Ctrl+C to stop${NC}\n"
exec "$BINARY" --config "$CONFIG"
fi
}

[ "$STATUS" = true ] && show_status && exit 0
[ "$STOP" = true ] && stop_server && exit 0
[ "$LOGS" = true ] && show_logs && exit 0
[ "$RESTART" = true ] && stop_server && sleep 1
start_server
Loading