-
Notifications
You must be signed in to change notification settings - Fork 8
feat: Add Linux bash scripts for installation and management #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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}" |
| 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" | ||
| 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}" | ||
| 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}" | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Quote Line 89 uses - 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
Suggested change
🧰 Tools🪛 Shellcheck (0.11.0)[warning] 89-89: Quote this to prevent word splitting. (SC2046) 🤖 Prompt for AI Agents |
||||||
| 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 | ||||||
There was a problem hiding this comment.
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_CMDvariable.The
DOWNLOAD_CMDvariable is set on line 62 but never used. The script hardcodescurl -sdirectly 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
🧰 Tools
🪛 Shellcheck (0.11.0)
[warning] 62-62: DOWNLOAD_CMD appears unused. Verify use (or export if used externally).
(SC2034)
🤖 Prompt for AI Agents