#!/usr/bin/env bash set -euo pipefail OPENCLAW_ENTRYPOINT_TAG="upgrade-openclaw" timestamp_utc() { date -u +"%Y-%m-%dT%H:%M:%SZ" } log_info() { printf '[%s] [INFO] [%s] %s\n' "$(timestamp_utc)" "$OPENCLAW_ENTRYPOINT_TAG" "$*" } log_warn() { printf '[%s] [WARN] [%s] %s\n' "$(timestamp_utc)" "$OPENCLAW_ENTRYPOINT_TAG" "$*" >&2 } log_error() { printf '[%s] [ERROR] [%s] %s\n' "$(timestamp_utc)" "$OPENCLAW_ENTRYPOINT_TAG" "$*" >&2 } is_true() { local value value="$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" [[ "$value" == "1" || "$value" == "true" || "$value" == "yes" || "$value" == "on" ]] } get_current_version() { local version if command -v openclaw >/dev/null 2>&1; then version="$(openclaw --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" || version="" if [[ -z "$version" ]]; then version="$(openclaw --version 2>/dev/null | head -1 | awk '{print $NF}')" || version="unknown" fi else version="not-installed" fi printf '%s' "$version" } resolve_latest_version() { local version version="$(curl -fsSL https://registry.npmjs.org/openclaw/latest 2>/dev/null | python3 -c " import json, sys try: data = json.load(sys.stdin) print(data.get('version', 'latest')) except: print('latest') " 2>/dev/null)" || version="latest" printf '%s' "$version" } backup_openclaw_state() { local backup_dir="/root/.openclaw.backup.$(date +%Y%m%d%H%M%S)" if [[ -d "/root/.openclaw" ]]; then log_info "Backing up OpenClaw state to $backup_dir..." cp -r /root/.openclaw "$backup_dir" log_info "Backup completed: $backup_dir" else log_warn "No existing OpenClaw state found, skipping backup" fi } upgrade_openclaw() { local target_version="$1" local skip_backup="$2" if ! is_true "$skip_backup"; then backup_openclaw_state fi log_info "Upgrading OpenClaw to version: $target_version..." local install_start install_start=$(date +%s) HOME=/root curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard --version "$target_version" local install_end install_end=$(date +%s) local install_duration=$((install_end - install_start)) log_info "Installation completed in ${install_duration}s" local new_version new_version="$(get_current_version)" log_info "OpenClaw upgraded to: $new_version" if [[ "$new_version" == "unknown" || "$new_version" == "not-installed" ]]; then log_error "Upgrade verification failed: openclaw command not found" return 1 fi if [[ "$target_version" != "latest" && "$new_version" != *"$target_version"* ]]; then log_warn "Version mismatch: expected $target_version, got $new_version" fi return 0 } restart_gateway() { log_info "Restarting OpenClaw gateway..." if command -v openclaw-gateway-ctl >/dev/null 2>&1; then if openclaw-gateway-ctl status >/dev/null 2>&1; then openclaw-gateway-ctl restart || log_warn "Gateway restart failed, manual restart may be needed" else log_warn "Gateway is not running, skipping restart" fi else log_warn "openclaw-gateway-ctl not found, skipping gateway restart" fi } show_usage() { cat <<'EOF' Usage: upgrade-openclaw.sh [OPTIONS] [VERSION] Upgrade OpenClaw to a specific version or the latest version. Arguments: VERSION Target version (default: from OPENCLAW_VERSION env var, or "latest") Options: -l, --latest Upgrade to the latest version -v, --version VER Specify version to upgrade to -s, --skip-backup Skip backup of current state -n, --dry-run Show what would be done without making changes -h, --help Show this help message Environment Variables: OPENCLAW_VERSION Target version (overridden by command line arguments) Examples: upgrade-openclaw.sh # Use OPENCLAW_VERSION or "latest" upgrade-openclaw.sh 2026.5.1 # Upgrade to specific version upgrade-openclaw.sh --latest # Upgrade to latest version upgrade-openclaw.sh -v 2026.4.15 -s # Upgrade to version, skip backup upgrade-openclaw.sh --dry-run # Preview upgrade without executing EOF } main() { local target_version="" local skip_backup="false" local dry_run="false" local use_latest="false" while [[ $# -gt 0 ]]; do case "$1" in -l|--latest) use_latest="true" shift ;; -v|--version) target_version="$2" shift 2 ;; -s|--skip-backup) skip_backup="true" shift ;; -n|--dry-run) dry_run="true" shift ;; -h|--help) show_usage exit 0 ;; -*) log_error "Unknown option: $1" show_usage exit 1 ;; *) target_version="$1" shift ;; esac done if [[ -z "$target_version" ]]; then if is_true "$use_latest"; then target_version="latest" elif [[ -n "${OPENCLAW_VERSION:-}" ]]; then target_version="$OPENCLAW_VERSION" else target_version="latest" fi fi local current_version current_version="$(get_current_version)" log_info "==========================================" log_info "OpenClaw Upgrade Tool" log_info "==========================================" log_info "Current version: $current_version" log_info "Target version: $target_version" log_info "Skip backup: $skip_backup" log_info "Dry run: $dry_run" log_info "==========================================" if [[ "$current_version" == "$target_version" ]] || [[ "$current_version" == *"$target_version"* && "$target_version" != "latest" ]]; then log_info "Already at target version, no upgrade needed" exit 0 fi if is_true "$dry_run"; then log_info "[DRY RUN] Would upgrade OpenClaw from $current_version to $target_version" if ! is_true "$skip_backup"; then log_info "[DRY RUN] Would backup current state to /root/.openclaw.backup." fi log_info "[DRY RUN] Would restart gateway after upgrade" exit 0 fi if [[ "$target_version" == "latest" ]]; then local resolved_version resolved_version="$(resolve_latest_version)" log_info "Resolved 'latest' to: $resolved_version" if [[ "$current_version" == "$resolved_version" ]] || [[ "$current_version" == *"$resolved_version"* ]]; then log_info "Already at latest version ($resolved_version), no upgrade needed" exit 0 fi target_version="$resolved_version" fi upgrade_openclaw "$target_version" "$skip_backup" log_info "Upgrade completed successfully" log_info "New version: $(get_current_version)" restart_gateway log_info "==========================================" log_info "Upgrade finished!" log_info "==========================================" } main "$@"