diff --git a/.github/required-checks.txt b/.github/required-checks.txt index c9cbf6eab7..17aa1b589b 100644 --- a/.github/required-checks.txt +++ b/.github/required-checks.txt @@ -1,16 +1,3 @@ # workflow_file|job_name -pr-test-build.yml|go-ci -pr-test-build.yml|quality-ci -pr-test-build.yml|quality-staged-check -pr-test-build.yml|fmt-check -pr-test-build.yml|golangci-lint -pr-test-build.yml|route-lifecycle -pr-test-build.yml|provider-smoke-matrix -pr-test-build.yml|provider-smoke-matrix-cheapest -pr-test-build.yml|test-smoke -pr-test-build.yml|pre-release-config-compat-smoke -pr-test-build.yml|distributed-critical-paths -pr-test-build.yml|changelog-scope-classifier -pr-test-build.yml|docs-build -pr-test-build.yml|ci-summary +pr-test-build.yml|build pr-path-guard.yml|ensure-no-translator-changes diff --git a/.gitignore b/.gitignore index feda9dbf43..c18443cf39 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ cli-proxy-api cliproxy *.exe +cli-proxy-api-plus +server # Configuration @@ -53,3 +55,4 @@ _bmad-output/* .DS_Store ._* *.bak +PROJECT-wtrees/ diff --git a/docs/install.md b/docs/install.md index c8062542d3..91c3330d8f 100644 --- a/docs/install.md +++ b/docs/install.md @@ -152,6 +152,19 @@ sudo systemctl restart cliproxyapi-plusplus sudo systemctl stop cliproxyapi-plusplus ``` +Cross-platform helper (optional): + +```bash +./scripts/service install +./scripts/service start +./scripts/service status +./scripts/service restart +./scripts/service stop +./scripts/service remove +``` + +On Linux the script writes the systemd unit to `/etc/systemd/system` and requires root privileges. + ### macOS (Homebrew + launchd) Homebrew installs typically place artifacts under `/opt/homebrew`. If installed elsewhere, keep the same launchd flow and swap the binary/config paths. @@ -163,9 +176,10 @@ launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.router-for-me.clipro launchctl kickstart -k gui/$(id -u)/com.router-for-me.cliproxyapi-plusplus ``` -If your Homebrew formula supports service hooks: +You can also use a local Homebrew formula with service hooks: ```bash +brew install --HEAD --formula examples/homebrew/cliproxyapi-plusplus.rb brew services start cliproxyapi-plusplus brew services restart cliproxyapi-plusplus ``` diff --git a/examples/homebrew/cliproxyapi-plusplus.rb b/examples/homebrew/cliproxyapi-plusplus.rb new file mode 100644 index 0000000000..61d090c00a --- /dev/null +++ b/examples/homebrew/cliproxyapi-plusplus.rb @@ -0,0 +1,27 @@ +class CliproxyapiPlusplus < Formula + desc "LLM proxy CLI for OpenAI-compatible and provider-specific APIs" + homepage "https://github.com/router-for-me/CLIProxyAPI" + head "https://github.com/router-for-me/CLIProxyAPI.git", branch: "main" + + depends_on "go" => :build + + def install + system "go", "build", "-o", bin/"cliproxyapi++", "./cmd/server" + end + + service do + run [opt_bin/"cliproxyapi++", "--config", etc/"cliproxyapi/config.yaml"] + working_dir var/"log/cliproxyapi" + keep_alive true + log_path var/"log/cliproxyapi-plusplus.log" + error_log_path var/"log/cliproxyapi-plusplus.err" + end + + def post_install + (etc/"cliproxyapi").mkpath + end + + test do + assert_predicate bin/"cliproxyapi++", :exist? + end +end diff --git a/scripts/service b/scripts/service new file mode 100755 index 0000000000..400efdfcb7 --- /dev/null +++ b/scripts/service @@ -0,0 +1,232 @@ +#!/usr/bin/env bash +set -euo pipefail + +IFS=$'\n\t' + +SERVICE_NAME="cliproxyapi-plusplus" +SERVICE_LABEL="com.router-for-me.cliproxyapi-plusplus" +SYSTEMD_UNIT="$SERVICE_NAME.service" +SYSTEMD_DEST="/etc/systemd/system" +SYSTEMD_ENV="/etc/default/cliproxyapi" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +LAUNCHD_SOURCE="$REPO_ROOT/examples/launchd/$SERVICE_LABEL.plist" +SYSTEMD_SOURCE="$REPO_ROOT/examples/systemd/$SYSTEMD_UNIT" +SYSTEMD_ENV_SOURCE="$REPO_ROOT/examples/systemd/cliproxyapi-plusplus.env" + +usage() { + cat <<'USAGE' +Usage: + ./scripts/service [--config PATH] + +Actions: + install register service files and enable on boot + remove disable and remove service files + start start service now + stop stop service now + restart stop then start + status show service status + +Options: + --config PATH only used for macOS launchd fallback +USAGE +} + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +ensure_root() { + if [ "$(id -u)" -ne 0 ]; then + echo "This action requires root on Linux. Re-run with sudo." + exit 1 + fi +} + +has_brew_formula() { + command_exists brew && brew list --formula | grep -qx "cliproxyapi-plusplus" +} + +install_macos() { + local cfg="${1:-/opt/homebrew/etc/cliproxyapi/config.yaml}" + + if has_brew_formula; then + brew services start cliproxyapi-plusplus + return 0 + fi + + if ! command_exists launchctl || ! command_exists sed; then + echo "launchctl and sed are required for fallback launchd setup" + exit 1 + fi + + local prefix + local plist_dest="$HOME/Library/LaunchAgents/$SERVICE_LABEL.plist" + prefix="$(command_exists brew && brew --prefix || echo /opt/homebrew)" + mkdir -p "$HOME/Library/LaunchAgents" + sed -e "s#/opt/homebrew#$prefix#g" \ + -e "s#/opt/homebrew/etc/cliproxyapi/config.yaml#$cfg#g" \ + "$LAUNCHD_SOURCE" > "$plist_dest" + launchctl bootstrap "gui/$(id -u)" "$plist_dest" +} + +remove_macos() { + if has_brew_formula; then + brew services stop cliproxyapi-plusplus + brew services uninstall cliproxyapi-plusplus || true + return 0 + fi + + if command_exists launchctl; then + launchctl bootout "gui/$(id -u)" "$SERVICE_LABEL" || true + fi + rm -f "$HOME/Library/LaunchAgents/$SERVICE_LABEL.plist" +} + +start_macos() { + if has_brew_formula; then + brew services start cliproxyapi-plusplus + return 0 + fi + + if command_exists launchctl; then + launchctl kickstart -k "gui/$(id -u)/$SERVICE_LABEL" + fi +} + +stop_macos() { + if has_brew_formula; then + brew services stop cliproxyapi-plusplus + return 0 + fi + + if command_exists launchctl; then + launchctl stop "$SERVICE_LABEL" + fi +} + +status_macos() { + if has_brew_formula; then + brew services list | grep "cliproxyapi-plusplus" + return 0 + fi + + if command_exists launchctl; then + launchctl print "gui/$(id -u)/$SERVICE_LABEL" || true + fi +} + +install_linux() { + ensure_root + + if ! command_exists systemctl; then + echo "systemctl not available" + exit 1 + fi + if [ ! -f "$SYSTEMD_SOURCE" ]; then + echo "systemd unit template missing: $SYSTEMD_SOURCE" + exit 1 + fi + + mkdir -p "$SYSTEMD_DEST" + cp "$SYSTEMD_SOURCE" "$SYSTEMD_DEST/$SYSTEMD_UNIT" + if [ -f "$SYSTEMD_ENV_SOURCE" ]; then + mkdir -p /etc/default + cp "$SYSTEMD_ENV_SOURCE" "$SYSTEMD_ENV" + fi + systemctl daemon-reload + systemctl enable "$SYSTEMD_UNIT" +} + +remove_linux() { + ensure_root + + if ! command_exists systemctl; then + echo "systemctl not available" + exit 1 + fi + + systemctl disable "$SYSTEMD_UNIT" || true + systemctl stop "$SYSTEMD_UNIT" || true + rm -f "$SYSTEMD_DEST/$SYSTEMD_UNIT" "$SYSTEMD_ENV" + systemctl daemon-reload +} + +start_linux() { + ensure_root + systemctl start "$SYSTEMD_UNIT" +} + +stop_linux() { + ensure_root + systemctl stop "$SYSTEMD_UNIT" +} + +status_linux() { + if ! command_exists systemctl; then + echo "systemctl not available" + exit 1 + fi + systemctl status "$SYSTEMD_UNIT" --no-pager +} + +main() { + local action="${1:-}" + local config_path="/opt/homebrew/etc/cliproxyapi/config.yaml" + shift || true + + while [ "$#" -gt 0 ]; do + case "$1" in + --config) + config_path="${2:-}" + shift 2 + ;; + -h|--help) + usage + return 0 + ;; + *) + echo "Unknown option: $1" + usage + return 1 + ;; + esac + done + + if [ -z "$action" ] || [ "$action" = "--help" ] || [ "$action" = "-h" ]; then + usage + return 0 + fi + + case "$(uname -s)" in + Darwin) + case "$action" in + install) install_macos "$config_path" ;; + remove|uninstall) remove_macos ;; + start) start_macos ;; + stop) stop_macos ;; + restart) stop_macos; start_macos ;; + status) status_macos ;; + *) usage; exit 1 ;; + esac + ;; + Linux) + case "$action" in + install) install_linux ;; + remove|uninstall) remove_linux ;; + start) start_linux ;; + stop) stop_linux ;; + restart) stop_linux; start_linux ;; + status) status_linux ;; + *) usage; exit 1 ;; + esac + ;; + *) + echo "Unsupported OS: $(uname -s)" + exit 1 + ;; + esac +} + +main "$@" diff --git a/sdk/auth/codex.go b/sdk/auth/codex.go index 83bb49667e..c95a40cf23 100644 --- a/sdk/auth/codex.go +++ b/sdk/auth/codex.go @@ -7,12 +7,12 @@ import ( "strings" "time" - "github.com/router-for-me/CLIProxyAPI/v6/pkg/llmproxy/auth/codex" "github.com/router-for-me/CLIProxyAPI/v6/pkg/llmproxy/browser" + "github.com/router-for-me/CLIProxyAPI/v6/pkg/llmproxy/auth/codex" // legacy client removed "github.com/router-for-me/CLIProxyAPI/v6/internal/config" - "github.com/router-for-me/CLIProxyAPI/v6/pkg/llmproxy/misc" - "github.com/router-for-me/CLIProxyAPI/v6/pkg/llmproxy/util" + "github.com/router-for-me/CLIProxyAPI/v6/internal/misc" + "github.com/router-for-me/CLIProxyAPI/v6/internal/util" coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth" log "github.com/sirupsen/logrus" ) diff --git a/sdk/auth/codex_device.go b/sdk/auth/codex_device.go index 78a95af801..1944d27adc 100644 --- a/sdk/auth/codex_device.go +++ b/sdk/auth/codex_device.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/router-for-me/CLIProxyAPI/v6/internal/auth/codex" + "github.com/router-for-me/CLIProxyAPI/v6/pkg/llmproxy/auth/codex" "github.com/router-for-me/CLIProxyAPI/v6/internal/browser" "github.com/router-for-me/CLIProxyAPI/v6/internal/config" "github.com/router-for-me/CLIProxyAPI/v6/internal/util"