#!/usr/bin/env bash
set -euo pipefail

SYSTEM_PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
if [[ -n "${PATH:-}" ]]; then
  PATH="$PATH:$SYSTEM_PATH"
else
  PATH="$SYSTEM_PATH"
fi
export PATH

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
ENV_FILE="$ROOT/.env"
RUN_DIR="$ROOT/run"
PID_FILE="$RUN_DIR/codex-app-server.pid"
LOG_FILE="$RUN_DIR/codex-app-server.log"
STDIN_FIFO="$RUN_DIR/codex-app-server.stdin"
UPGRADE_LOG_FILE="$RUN_DIR/codex-app-server-upgrade.log"
CODEX_RELEASE_REPO="${CODEX_RELEASE_REPO:-openai/codex}"
INSTALL_PREFIX=()

read_env_value() {
  local key="$1"
  if [[ -f "$ENV_FILE" ]]; then
    awk -F= -v key="$key" '$1 == key { sub(/^[^=]*=/, ""); print; exit }' "$ENV_FILE"
  fi
}

HOST_CODEX_SOCKET="${HOST_CODEX_SOCKET:-$(read_env_value HOST_CODEX_SOCKET)}"
HOST_CODEX_SOCKET="${HOST_CODEX_SOCKET:-$RUN_DIR/codex.sock}"

mkdir -p "$RUN_DIR"
chmod 700 "$RUN_DIR"

usage() {
  cat <<USAGE
Usage: $0 <start|stop|status|check-updates|check-upgrade> [options]

Commands:
  start                Start codex app-server if it is not already running.
  stop                 Stop codex app-server and remove stale runtime files.
  status               Print whether codex app-server is running.
  check-updates [-y]   Check GitHub releases and optionally install the latest Codex binary.
  check-upgrade [-y]   Alias for check-updates.

Environment:
  CODEX_BIN            Codex executable to replace. Defaults to the codex found on PATH.
  CODEX_RELEASE_REPO   GitHub repo for releases. Defaults to openai/codex.
USAGE
}

pid_from_file() {
  if [[ -f "$PID_FILE" ]]; then
    tr -cd '0-9' < "$PID_FILE" 2>/dev/null || true
  fi
}

server_pid() {
  local pid
  pid="$(pid_from_file)"
  if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
    printf '%s\n' "$pid"
  fi
}

process_group_id() {
  ps -o pgid= -p "$1" 2>/dev/null | tr -d '[:space:]' || true
}

process_state() {
  ps -o stat= -p "$1" 2>/dev/null | tr -d '[:space:]' || true
}

process_group_members() {
  local pgid="$1"
  if command -v pgrep >/dev/null 2>&1; then
    pgrep -g "$pgid" 2>/dev/null || true
    return 0
  fi
  ps -eo pid=,pgid= | awk -v pgid="$pgid" '$2 == pgid { print $1 }'
}

process_group_alive() {
  local pgid="$1" members
  members="$(process_group_members "$pgid")"
  [[ -n "$members" ]]
}

is_running() {
  [[ -n "$(server_pid)" ]]
}

remove_socket_if_safe() {
  if [[ -e "$HOST_CODEX_SOCKET" ]]; then
    if [[ -S "$HOST_CODEX_SOCKET" ]]; then
      rm -f "$HOST_CODEX_SOCKET"
    else
      echo "socket path exists and is not a Unix socket: $HOST_CODEX_SOCKET" >&2
      return 1
    fi
  fi
}

show_log_excerpt() {
  sed -n '1,120p' "$LOG_FILE" >&2 || true
}

codex_bin() {
  if [[ -n "${CODEX_BIN:-}" ]]; then
    printf '%s\n' "$CODEX_BIN"
    return 0
  fi
  command -v codex
}

start_server() {
  local old_pid pid start_codex_bin
  old_pid="$(pid_from_file)"
  if [[ -n "$old_pid" ]] && kill -0 "$old_pid" 2>/dev/null; then
    if [[ -S "$HOST_CODEX_SOCKET" ]]; then
      echo "codex app-server already running: pid=$old_pid socket=$HOST_CODEX_SOCKET"
      return 0
    fi
    echo "pid $old_pid is running but socket is missing; refusing to start a second app-server" >&2
    return 1
  fi
  rm -f "$PID_FILE"
  remove_socket_if_safe

  start_codex_bin="$(codex_bin)"
  if [[ -z "$start_codex_bin" ]]; then
    echo "codex executable not found; set CODEX_BIN" >&2
    return 1
  fi

  rm -f "$STDIN_FIFO"
  mkfifo "$STDIN_FIFO"
  chmod 600 "$STDIN_FIFO"

  : > "$LOG_FILE"
  # Codex app-server currently exits if detached with stdin closed. A detached
  # wrapper keeps a private FIFO writer open and then runs Codex on the host.
  setsid -f bash -c '
    echo "$$" > "$3"
    tail -f /dev/null > "$1" &
    writer=$!
    trap "kill $writer 2>/dev/null || true" EXIT
    "$4" app-server --listen "$2" < "$1"
  ' codex-app-server "$STDIN_FIFO" "unix://$HOST_CODEX_SOCKET" "$PID_FILE" "$start_codex_bin" >> "$LOG_FILE" 2>&1

  for _ in $(seq 1 50); do
    [[ -f "$PID_FILE" ]] && break
    sleep 0.1
  done

  pid="$(pid_from_file)"
  if [[ -z "$pid" ]]; then
    echo "codex app-server did not write a pid file; log follows:" >&2
    show_log_excerpt
    return 1
  fi

  for _ in $(seq 1 100); do
    if [[ -S "$HOST_CODEX_SOCKET" ]]; then
      sleep 0.5
      if kill -0 "$pid" 2>/dev/null; then
        echo "codex app-server started: pid=$pid socket=$HOST_CODEX_SOCKET log=$LOG_FILE"
        return 0
      fi
    fi
    if ! kill -0 "$pid" 2>/dev/null; then
      echo "codex app-server exited before staying ready; log follows:" >&2
      show_log_excerpt
      rm -f "$PID_FILE"
      return 1
    fi
    sleep 0.1
  done

  echo "codex app-server did not create socket within 10 seconds; log follows:" >&2
  show_log_excerpt
  return 1
}

finish_stopped() {
  rm -f "$PID_FILE" "$STDIN_FIFO"
  remove_socket_if_safe
  echo "codex app-server stopped"
}

stop_server() {
  local pid pgid self_pgid signal_target state
  pid="$(server_pid)"
  if [[ -z "$pid" ]]; then
    rm -f "$PID_FILE" "$STDIN_FIFO"
    remove_socket_if_safe
    echo "codex app-server is not running"
    return 0
  fi

  pgid="$(process_group_id "$pid")"
  self_pgid="$(process_group_id "$$")"
  if [[ -n "$pgid" && "$pgid" != "$self_pgid" ]]; then
    signal_target="-$pgid"
    echo "stopping codex app-server process group: pgid=$pgid pid=$pid"
  else
    signal_target="$pid"
    echo "stopping codex app-server: pid=$pid"
    if [[ -n "$pgid" && "$pgid" == "$self_pgid" ]]; then
      echo "server shares this script process group; using pid-only stop" >&2
    fi
  fi

  kill -TERM -- "$signal_target" 2>/dev/null || true
  for _ in $(seq 1 50); do
    state="$(process_state "$pid")"
    if [[ -n "$pgid" && "$signal_target" == "-$pgid" ]]; then
      if ! process_group_alive "$pgid"; then
        finish_stopped
        return 0
      fi
    elif [[ -z "$state" || "$state" == Z* ]]; then
      finish_stopped
      return 0
    fi
    sleep 0.1
  done

  echo "codex app-server did not stop after 5 seconds; killing $signal_target" >&2
  kill -KILL -- "$signal_target" 2>/dev/null || true
  for _ in $(seq 1 20); do
    state="$(process_state "$pid")"
    if [[ -n "$pgid" && "$signal_target" == "-$pgid" ]]; then
      if ! process_group_alive "$pgid"; then
        finish_stopped
        return 0
      fi
    elif [[ -z "$state" || "$state" == Z* ]]; then
      finish_stopped
      return 0
    fi
    sleep 0.1
  done
  echo "failed to stop codex app-server pid=$pid" >&2
  return 1
}

status_server() {
  local pid pgid
  pid="$(server_pid)"
  if [[ -n "$pid" ]]; then
    pgid="$(process_group_id "$pid")"
    if [[ -S "$HOST_CODEX_SOCKET" ]]; then
      echo "codex app-server running: pid=$pid pgid=$pgid socket=$HOST_CODEX_SOCKET log=$LOG_FILE"
      return 0
    fi
    echo "codex app-server pid=$pid is running but socket is missing: $HOST_CODEX_SOCKET" >&2
    return 2
  fi
  if [[ -f "$PID_FILE" ]]; then
    echo "codex app-server not running; stale pid file: $PID_FILE" >&2
    return 1
  fi
  echo "codex app-server not running"
  return 1
}

require_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "missing required command: $1" >&2
    return 1
  fi
}

codex_version_from() {
  local bin="$1" line
  line="$($bin --version 2>/dev/null || true)"
  printf '%s\n' "$line" | sed -n 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/p' | head -n 1
}

release_target() {
  local os arch
  os="$(uname -s)"
  arch="$(uname -m)"
  case "$os:$arch" in
    Linux:x86_64|Linux:amd64) echo "x86_64-unknown-linux-musl" ;;
    Linux:aarch64|Linux:arm64) echo "aarch64-unknown-linux-musl" ;;
    Darwin:x86_64|Darwin:amd64) echo "x86_64-apple-darwin" ;;
    Darwin:aarch64|Darwin:arm64) echo "aarch64-apple-darwin" ;;
    *) echo "unsupported platform for Codex binary release: $os $arch" >&2; return 1 ;;
  esac
}

version_gt() {
  python3 - "$1" "$2" <<'PY'
import sys

def parse(v):
    return tuple(int(p) for p in v.split('.')[:3])

sys.exit(0 if parse(sys.argv[1]) > parse(sys.argv[2]) else 1)
PY
}

latest_release_info() {
  local target="$1" json_file="$2"
  python3 - "$target" "$json_file" <<'PY'
import json
import sys

target, path = sys.argv[1], sys.argv[2]
needs_bwrap = "linux" in target
codex_asset_name = f"codex-{target}.tar.gz"
bwrap_asset_name = f"bwrap-{target}.tar.gz" if needs_bwrap else None
with open(path, "r", encoding="utf-8") as f:
    release = json.load(f)
tag = release.get("tag_name", "")
version = tag
if version.startswith("rust-v"):
    version = version[6:]
elif version.startswith("v"):
    version = version[1:]
assets = {asset.get("name"): asset for asset in release.get("assets", [])}
codex_asset = assets.get(codex_asset_name)
bwrap_asset = assets.get(bwrap_asset_name) if needs_bwrap else None
required_assets = [(codex_asset_name, codex_asset)]
if needs_bwrap:
    required_assets.append((bwrap_asset_name, bwrap_asset))
missing = [name for name, asset in required_assets if asset is None]
if missing:
    print(f"release {tag or '<unknown>'} has no asset named {', '.join(missing)}", file=sys.stderr)
    raise SystemExit(1)
print(codex_asset.get("browser_download_url", ""))
print(codex_asset.get("digest", ""))
if bwrap_asset is not None:
    print(bwrap_asset.get("browser_download_url", ""))
    print(bwrap_asset.get("digest", ""))
else:
    print("")
    print("")
print(version)
print(tag)
PY
}

verify_digest() {
  local file="$1" digest="$2" expected
  if [[ -z "$digest" ]]; then
    echo "release asset has no digest; skipping checksum verification" >&2
    return 0
  fi
  if [[ "$digest" != sha256:* ]]; then
    echo "unsupported release digest format: $digest" >&2
    return 1
  fi
  expected="${digest#sha256:}"
  if command -v sha256sum >/dev/null 2>&1; then
    printf '%s  %s\n' "$expected" "$file" | sha256sum -c - >/dev/null
  elif command -v shasum >/dev/null 2>&1; then
    local actual
    actual="$(shasum -a 256 "$file" | awk '{print $1}')"
    [[ "$actual" == "$expected" ]]
  else
    echo "missing sha256sum or shasum for checksum verification" >&2
    return 1
  fi
}

extract_codex_binary() {
  local archive="$1" dest="$2" found
  mkdir -p "$dest/extract"
  tar -xzf "$archive" -C "$dest/extract"
  found="$(find "$dest/extract" -type f -name codex -print | head -n 1)"
  if [[ -z "$found" ]]; then
    found="$(find "$dest/extract" -type f -name 'codex-*' -perm -u+x -print | head -n 1)"
  fi
  if [[ -z "$found" ]]; then
    echo "downloaded archive does not contain a Codex executable" >&2
    return 1
  fi
  chmod +x "$found"
  printf '%s\n' "$found"
}


extract_bwrap_binary() {
  local archive="$1" dest="$2" found
  mkdir -p "$dest/bwrap-extract"
  tar -xzf "$archive" -C "$dest/bwrap-extract"
  found="$(find "$dest/bwrap-extract" -type f -name bwrap -print | head -n 1)"
  if [[ -z "$found" ]]; then
    found="$(find "$dest/bwrap-extract" -type f -name 'bwrap-*' -perm -u+x -print | head -n 1)"
  fi
  if [[ -z "$found" ]]; then
    echo "downloaded archive does not contain a bwrap executable" >&2
    return 1
  fi
  chmod +x "$found"
  printf '%s\n' "$found"
}

bundled_bwrap_path() {
  local bin="$1"
  printf '%s/codex-resources/bwrap\n' "$(dirname "$bin")"
}

bundled_bwrap_installed() {
  local bin="$1" bundled
  bundled="$(bundled_bwrap_path "$bin")"
  [[ -x "$bundled" && ! -L "$bundled" ]]
}

bwrap_required_for_target() {
  [[ "$1" == *linux* ]]
}

run_install() {
  if [[ "${#INSTALL_PREFIX[@]}" -gt 0 ]]; then
    "${INSTALL_PREFIX[@]}" "$@"
  else
    "$@"
  fi
}

choose_install_prefix() {
  local bin="$1" dir
  dir="$(dirname "$bin")"
  INSTALL_PREFIX=()
  if [[ -w "$dir" && ( ! -e "$bin" || -w "$bin" ) ]]; then
    return 0
  fi
  if command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
    INSTALL_PREFIX=(sudo)
    return 0
  fi
  echo "cannot replace $bin without write permission" >&2
  echo "Run with suitable privileges or set CODEX_BIN to a user-writable Codex binary path." >&2
  return 1
}

install_bundled_bwrap() {
  local candidate="$1" bin="$2" backup="$3" bundled resources_dir tmp_new bwrap_backup bwrap_missing
  bundled="$(bundled_bwrap_path "$bin")"
  resources_dir="$(dirname "$bundled")"
  tmp_new="$bundled.new.$$"
  bwrap_backup="$backup.bwrap"
  bwrap_missing="$backup.bwrap.missing"

  run_install mkdir -p "$resources_dir"
  if [[ -e "$bundled" ]]; then
    run_install cp -p "$bundled" "$bwrap_backup"
  else
    run_install touch "$bwrap_missing"
  fi
  run_install install -m 0755 "$candidate" "$tmp_new"
  run_install mv -f "$tmp_new" "$bundled"
}

install_candidate() {
  local candidate="$1" bwrap_candidate="$2" bin="$3" backup="$4" tmp_new="$bin.new.$$"
  choose_install_prefix "$bin"
  run_install cp -p "$bin" "$backup"
  run_install install -m 0755 "$candidate" "$tmp_new"
  run_install mv -f "$tmp_new" "$bin"
  if [[ -n "$bwrap_candidate" ]]; then
    install_bundled_bwrap "$bwrap_candidate" "$bin" "$backup"
  fi
}

restore_backup() {
  local bin="$1" backup="$2" tmp_failed="$bin.failed.$$" bundled bwrap_backup bwrap_missing
  if [[ ! -e "$backup" ]]; then
    echo "backup missing; cannot restore $bin" >&2
    return 1
  fi
  choose_install_prefix "$bin"
  if [[ -e "$bin" ]]; then
    run_install mv -f "$bin" "$tmp_failed" || true
  fi
  run_install mv -f "$backup" "$bin"

  bundled="$(bundled_bwrap_path "$bin")"
  bwrap_backup="$backup.bwrap"
  bwrap_missing="$backup.bwrap.missing"
  if [[ -e "$bwrap_backup" ]]; then
    run_install mkdir -p "$(dirname "$bundled")"
    run_install mv -f "$bwrap_backup" "$bundled"
  elif [[ -e "$bwrap_missing" ]]; then
    run_install rm -f "$bundled"
    run_install rm -f "$bwrap_missing"
  fi
}

confirm_upgrade() {
  local local_version="$1" latest_version="$2" bin="$3"
  if [[ "${ASSUME_YES:-0}" == "1" ]]; then
    return 0
  fi
  if [[ ! -t 0 ]]; then
    echo "Codex $latest_version is available for $bin; rerun with check-updates -y to upgrade." >&2
    return 2
  fi
  local reply
  read -r -p "Upgrade Codex $local_version -> $latest_version at $bin? [y/N] " reply
  [[ "$reply" == "y" || "$reply" == "Y" || "$reply" == "yes" || "$reply" == "YES" ]]
}

apply_upgrade() {
  local candidate="$1" bwrap_candidate="$2" bin="$3" backup="$4" local_version="$5" latest_version="$6" was_running=0
  if is_running; then
    was_running=1
    stop_server
  fi

  if ! install_candidate "$candidate" "$bwrap_candidate" "$bin" "$backup"; then
    echo "failed to install Codex update" >&2
    if [[ "$was_running" == "1" ]]; then
      start_server || true
    fi
    return 1
  fi

  if [[ "$was_running" == "1" ]]; then
    if ! start_server; then
      echo "new Codex failed to start; restoring previous binary" >&2
      restore_backup "$bin" "$backup" || true
      start_server || true
      return 1
    fi
  fi

  echo "Codex upgraded: $local_version -> $latest_version"
  echo "backup: $backup"
}

handoff_upgrade() {
  local candidate="$1" bwrap_candidate="$2" bin="$3" backup="$4" update_dir="$5" local_version="$6" latest_version="$7"
  : > "$UPGRADE_LOG_FILE"
  setsid -f bash -c '
    sleep 1
    "$0" __apply-upgrade "$1" "$2" "$3" "$4" "$5" "$6" "$7"
  ' "$0" "$candidate" "$bwrap_candidate" "$bin" "$backup" "$update_dir" "$local_version" "$latest_version" >> "$UPGRADE_LOG_FILE" 2>&1
  echo "Codex upgrade handoff started; app-server will restart if replacement succeeds. log=$UPGRADE_LOG_FILE"
}

check_updates() {
  ASSUME_YES=0
  while [[ $# -gt 0 ]]; do
    case "$1" in
      -y|--yes) ASSUME_YES=1 ;;
      -h|--help) usage; return 0 ;;
      *) echo "unknown check-updates option: $1" >&2; usage; return 2 ;;
    esac
    shift
  done

  require_cmd curl
  require_cmd tar
  require_cmd python3
  require_cmd ps

  local bin local_version target json latest_version latest_tag codex_download_url codex_digest bwrap_download_url bwrap_digest
  local codex_archive bwrap_archive tmp candidate bwrap_candidate candidate_version backup
  bin="$(codex_bin)"
  if [[ -z "$bin" ]]; then
    echo "codex executable not found; set CODEX_BIN" >&2
    return 1
  fi
  if [[ "$bin" != /* ]]; then
    echo "CODEX_BIN must be an absolute path: $bin" >&2
    return 1
  fi
  local_version="$(codex_version_from "$bin")"
  if [[ -z "$local_version" ]]; then
    echo "could not determine local Codex version from $bin" >&2
    return 1
  fi

  target="$(release_target)"
  tmp="$(mktemp -d "$RUN_DIR/codex-update.XXXXXX")"
  json="$tmp/latest.json"
  curl -fsSL "https://api.github.com/repos/$CODEX_RELEASE_REPO/releases/latest" -o "$json"
  mapfile -t release_info < <(latest_release_info "$target" "$json")
  codex_download_url="${release_info[0]:-}"
  codex_digest="${release_info[1]:-}"
  bwrap_download_url="${release_info[2]:-}"
  bwrap_digest="${release_info[3]:-}"
  latest_version="${release_info[4]:-}"
  latest_tag="${release_info[5]:-}"
  if [[ -z "$latest_version" || -z "$codex_download_url" ]]; then
    rm -rf "$tmp"
    echo "could not determine latest Codex release for $target" >&2
    return 1
  fi
  if bwrap_required_for_target "$target" && [[ -z "$bwrap_download_url" ]]; then
    rm -rf "$tmp"
    echo "could not determine latest bundled bwrap release for $target" >&2
    return 1
  fi

  if ! version_gt "$latest_version" "$local_version"; then
    if ! bwrap_required_for_target "$target" || bundled_bwrap_installed "$bin"; then
      rm -rf "$tmp"
      echo "Codex is already current: $local_version (latest $latest_version)"
      return 0
    fi
    echo "Codex is already current: $local_version (latest $latest_version); installing missing bundled bwrap"
    bwrap_archive="$tmp/bwrap-$target.tar.gz"
    curl -fL "$bwrap_download_url" -o "$bwrap_archive"
    verify_digest "$bwrap_archive" "$bwrap_digest"
    bwrap_candidate="$(extract_bwrap_binary "$bwrap_archive" "$tmp")"
    backup="$bin.bak.$(date -u +%Y%m%d%H%M%S)"
    choose_install_prefix "$bin"
    if install_bundled_bwrap "$bwrap_candidate" "$bin" "$backup"; then
      run_install rm -f "$backup.bwrap.missing"
      rm -rf "$tmp"
      echo "Bundled bwrap installed: $(bundled_bwrap_path "$bin")"
      return 0
    fi
    rm -rf "$tmp"
    return 1
  fi
  echo "Codex update available: $local_version -> $latest_version ($latest_tag)"
  confirm_upgrade "$local_version" "$latest_version" "$bin"

  codex_archive="$tmp/codex-$target.tar.gz"
  curl -fL "$codex_download_url" -o "$codex_archive"
  verify_digest "$codex_archive" "$codex_digest"
  candidate="$(extract_codex_binary "$codex_archive" "$tmp")"
  if bwrap_required_for_target "$target"; then
    bwrap_archive="$tmp/bwrap-$target.tar.gz"
    curl -fL "$bwrap_download_url" -o "$bwrap_archive"
    verify_digest "$bwrap_archive" "$bwrap_digest"
    bwrap_candidate="$(extract_bwrap_binary "$bwrap_archive" "$tmp")"
  else
    bwrap_candidate=""
  fi
  candidate_version="$(codex_version_from "$candidate")"
  if [[ "$candidate_version" != "$latest_version" ]]; then
    rm -rf "$tmp"
    echo "downloaded Codex version $candidate_version does not match release $latest_version" >&2
    return 1
  fi

  backup="$bin.bak.$(date -u +%Y%m%d%H%M%S)"
  choose_install_prefix "$bin"

  if is_running; then
    handoff_upgrade "$candidate" "$bwrap_candidate" "$bin" "$backup" "$tmp" "$local_version" "$latest_version"
    return 0
  fi

  if apply_upgrade "$candidate" "$bwrap_candidate" "$bin" "$backup" "$local_version" "$latest_version"; then
    rm -rf "$tmp"
    return 0
  fi
  rm -rf "$tmp"
  return 1
}

apply_upgrade_worker() {
  local candidate="$1" bwrap_candidate="$2" bin="$3" backup="$4" update_dir="$5" local_version="$6" latest_version="$7" rc=0
  if [[ ! -x "$candidate" ]]; then
    echo "upgrade candidate is missing or not executable: $candidate" >&2
    rm -rf "$update_dir"
    return 1
  fi
  if [[ -n "$bwrap_candidate" && ! -x "$bwrap_candidate" ]]; then
    echo "bundled bwrap candidate is missing or not executable: $bwrap_candidate" >&2
    rm -rf "$update_dir"
    return 1
  fi
  if ! apply_upgrade "$candidate" "$bwrap_candidate" "$bin" "$backup" "$local_version" "$latest_version"; then
    rc=1
  fi
  rm -rf "$update_dir"
  return "$rc"
}

cmd="${1:-help}"
case "$cmd" in
  start)
    shift || true
    if [[ $# -ne 0 ]]; then usage; exit 2; fi
    start_server
    ;;
  stop)
    shift || true
    if [[ $# -ne 0 ]]; then usage; exit 2; fi
    stop_server
    ;;
  status)
    shift || true
    if [[ $# -ne 0 ]]; then usage; exit 2; fi
    status_server
    ;;
  check-updates|check-upgrade)
    shift || true
    check_updates "$@"
    ;;
  __apply-upgrade)
    shift || true
    if [[ $# -ne 7 ]]; then echo "invalid upgrade worker arguments" >&2; exit 2; fi
    apply_upgrade_worker "$@"
    ;;
  -h|--help|help)
    usage
    ;;
  *)
    echo "unknown command: $cmd" >&2
    usage >&2
    exit 2
    ;;
esac
