Skip to content
Closed
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
191 changes: 139 additions & 52 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -euo pipefail

# OpenClaw Installer for macOS and Linux
# Usage: curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
# Usage: curl -fsSL --proto '=https' --tlsv1.2 https://aimlapi.com/openclaw/install.sh | bash

BOLD='\033[1m'
ACCENT='\033[38;2;255;77;77m' # coral-bright #ff4d4d
Expand All @@ -16,6 +16,9 @@ MUTED='\033[38;2;90;100;128m' # text-muted #5a6480
NC='\033[0m' # No Color

DEFAULT_TAGLINE="All your chats, one OpenClaw."
DEFAULT_NPM_PACKAGE="openclaw-aimlapi"
DEFAULT_GIT_REPO_URL="https://github.com/aimlapi/openclaw-aimlapi.git"
DEFAULT_GIT_REPO_BRANCH="feature/add-aimlapi-models-provider"

ORIGINAL_PATH="${PATH:-}"

Expand Down Expand Up @@ -258,7 +261,7 @@ detect_os_or_die() {
if [[ "$OS" == "unknown" ]]; then
ui_error "Unsupported operating system"
echo "This installer supports macOS and Linux (including WSL)."
echo "For Windows, use: iwr -useb https://openclaw.ai/install.ps1 | iex"
echo "For Windows, use: iwr -useb https://aimlapi.com/openclaw/install.ps1 | iex"
exit 1
fi

Expand Down Expand Up @@ -477,7 +480,8 @@ cleanup_npm_openclaw_paths() {
if [[ -z "$npm_root" || "$npm_root" != *node_modules* ]]; then
return 1
fi
rm -rf "$npm_root"/.openclaw-* "$npm_root"/openclaw 2>/dev/null || true
local npm_package="${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}"
rm -rf "$npm_root"/.openclaw-* "$npm_root"/openclaw "$npm_root"/"$npm_package" 2>/dev/null || true
}

extract_openclaw_conflict_path() {
Expand Down Expand Up @@ -951,7 +955,10 @@ DRY_RUN=${OPENCLAW_DRY_RUN:-0}
INSTALL_METHOD=${OPENCLAW_INSTALL_METHOD:-}
OPENCLAW_VERSION=${OPENCLAW_VERSION:-latest}
USE_BETA=${OPENCLAW_BETA:-0}
GIT_DIR_DEFAULT="${HOME}/openclaw"
OPENCLAW_NPM_PACKAGE=${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}
OPENCLAW_GIT_REPO_URL=${OPENCLAW_GIT_REPO_URL:-$DEFAULT_GIT_REPO_URL}
OPENCLAW_GIT_REPO_BRANCH=${OPENCLAW_GIT_REPO_BRANCH:-$DEFAULT_GIT_REPO_BRANCH}
GIT_DIR_DEFAULT="${HOME}/openclaw-aimlapi"
GIT_DIR=${OPENCLAW_GIT_DIR:-$GIT_DIR_DEFAULT}
GIT_UPDATE=${OPENCLAW_GIT_UPDATE:-1}
SHARP_IGNORE_GLOBAL_LIBVIPS="${SHARP_IGNORE_GLOBAL_LIBVIPS:-1}"
Expand All @@ -967,7 +974,7 @@ print_usage() {
OpenClaw installer (macOS + Linux)

Usage:
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- [options]
curl -fsSL --proto '=https' --tlsv1.2 https://aimlapi.com/openclaw/install.sh | bash -s -- [options]

Options:
--install-method, --method npm|git Install via npm (default) or from a git checkout
Expand All @@ -987,6 +994,9 @@ Environment variables:
OPENCLAW_INSTALL_METHOD=git|npm
OPENCLAW_VERSION=latest|next|<semver>
OPENCLAW_BETA=0|1
OPENCLAW_NPM_PACKAGE=openclaw-aimlapi
OPENCLAW_GIT_REPO_URL=https://github.com/aimlapi/openclaw-aimlapi.git
OPENCLAW_GIT_REPO_BRANCH=feature/add-aimlapi-models-provider
OPENCLAW_GIT_DIR=...
OPENCLAW_GIT_UPDATE=0|1
OPENCLAW_NO_PROMPT=1
Expand All @@ -997,9 +1007,9 @@ Environment variables:
SHARP_IGNORE_GLOBAL_LIBVIPS=0|1 Default: 1 (avoid sharp building against global libvips)

Examples:
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --no-onboard
curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method git --no-onboard
curl -fsSL --proto '=https' --tlsv1.2 https://aimlapi.com/openclaw/install.sh | bash
curl -fsSL --proto '=https' --tlsv1.2 https://aimlapi.com/openclaw/install.sh | bash -s -- --no-onboard
curl -fsSL --proto '=https' --tlsv1.2 https://aimlapi.com/openclaw/install.sh | bash -s -- --install-method git --no-onboard
EOF
}

Expand Down Expand Up @@ -1159,7 +1169,7 @@ detect_openclaw_checkout() {
if [[ ! -f "$dir/pnpm-workspace.yaml" ]]; then
return 1
fi
if ! grep -q '"name"[[:space:]]*:[[:space:]]*"openclaw"' "$dir/package.json" 2>/dev/null; then
if ! grep -Eq '"name"[[:space:]]*:[[:space:]]*"(openclaw|openclaw-aimlapi)"' "$dir/package.json" 2>/dev/null; then
return 1
fi
echo "$dir"
Expand Down Expand Up @@ -1187,7 +1197,7 @@ print_homebrew_admin_fix() {
echo " 2) Ask an Administrator to grant admin rights, then sign out/in:"
echo " sudo dseditgroup -o edit -a ${current_user} -t user admin"
echo "Then retry:"
echo " curl -fsSL https://openclaw.ai/install.sh | bash"
echo " curl -fsSL https://aimlapi.com/openclaw/install.sh | bash"
}

install_homebrew() {
Expand Down Expand Up @@ -1520,31 +1530,61 @@ fix_npm_permissions() {
ui_success "npm configured for user installs"
}

openclaw_candidate_bins() {
# CLI command must remain `openclaw` regardless of npm package name.
echo "openclaw"
}

ensure_openclaw_bin_link() {
local npm_root=""
npm_root="$(npm root -g 2>/dev/null || true)"
if [[ -z "$npm_root" || ! -d "$npm_root/openclaw" ]]; then
local npm_package="${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}"
if [[ -z "$npm_root" || ! -d "$npm_root/$npm_package" ]]; then
return 1
fi

local npm_bin=""
npm_bin="$(npm_global_bin_dir || true)"
if [[ -z "$npm_bin" ]]; then
return 1
fi

mkdir -p "$npm_bin"
if [[ ! -x "${npm_bin}/openclaw" ]]; then
ln -sf "$npm_root/openclaw/dist/entry.js" "${npm_bin}/openclaw"
if [[ -x "${npm_bin}/openclaw" ]]; then
return 0
fi

if [[ -f "$npm_root/$npm_package/openclaw.mjs" ]]; then
ln -sf "$npm_root/$npm_package/openclaw.mjs" "${npm_bin}/openclaw"
chmod +x "$npm_root/$npm_package/openclaw.mjs" >/dev/null 2>&1 || true
ui_info "Created openclaw bin link at ${npm_bin}/openclaw"
return 0
fi
return 0

if [[ -f "$npm_root/$npm_package/dist/entry.js" ]]; then
local wrapper="${npm_bin}/openclaw"
cat > "$wrapper" <<EOF
#!/usr/bin/env bash
set -euo pipefail
exec node "$npm_root/$npm_package/dist/entry.js" "\$@"
EOF
chmod +x "$wrapper"
ui_info "Created openclaw wrapper at ${npm_bin}/openclaw"
return 0
fi

return 1
}

# Check for existing OpenClaw installation
check_existing_openclaw() {
if [[ -n "$(type -P openclaw 2>/dev/null || true)" ]]; then
ui_info "Existing OpenClaw installation detected, upgrading"
return 0
fi
local cmd=""
while IFS= read -r cmd; do
if [[ -n "$(type -P "$cmd" 2>/dev/null || true)" ]]; then
ui_info "Existing OpenClaw installation detected, upgrading"
return 0
fi
done < <(openclaw_candidate_bins)
return 1
}

Expand Down Expand Up @@ -1774,38 +1814,53 @@ warn_openclaw_not_found() {
resolve_openclaw_bin() {
refresh_shell_command_cache
local resolved=""
resolved="$(type -P openclaw 2>/dev/null || true)"
if [[ -n "$resolved" && -x "$resolved" ]]; then
echo "$resolved"
return 0
fi
local cmd=""
while IFS= read -r cmd; do
resolved="$(type -P "$cmd" 2>/dev/null || true)"
if [[ -n "$resolved" && -x "$resolved" ]]; then
echo "$resolved"
return 0
fi
done < <(openclaw_candidate_bins)

ensure_npm_global_bin_on_path
refresh_shell_command_cache
resolved="$(type -P openclaw 2>/dev/null || true)"
if [[ -n "$resolved" && -x "$resolved" ]]; then
echo "$resolved"
return 0
fi
while IFS= read -r cmd; do
resolved="$(type -P "$cmd" 2>/dev/null || true)"
if [[ -n "$resolved" && -x "$resolved" ]]; then
echo "$resolved"
return 0
fi
done < <(openclaw_candidate_bins)

local npm_bin=""
npm_bin="$(npm_global_bin_dir || true)"
if [[ -n "$npm_bin" && -x "${npm_bin}/openclaw" ]]; then
echo "${npm_bin}/openclaw"
return 0
if [[ -n "$npm_bin" ]]; then
while IFS= read -r cmd; do
if [[ -x "${npm_bin}/${cmd}" ]]; then
echo "${npm_bin}/${cmd}"
return 0
fi
done < <(openclaw_candidate_bins)
fi

maybe_nodenv_rehash
refresh_shell_command_cache
resolved="$(type -P openclaw 2>/dev/null || true)"
if [[ -n "$resolved" && -x "$resolved" ]]; then
echo "$resolved"
return 0
fi
while IFS= read -r cmd; do
resolved="$(type -P "$cmd" 2>/dev/null || true)"
if [[ -n "$resolved" && -x "$resolved" ]]; then
echo "$resolved"
return 0
fi
done < <(openclaw_candidate_bins)

if [[ -n "$npm_bin" && -x "${npm_bin}/openclaw" ]]; then
echo "${npm_bin}/openclaw"
return 0
if [[ -n "$npm_bin" ]]; then
while IFS= read -r cmd; do
if [[ -x "${npm_bin}/${cmd}" ]]; then
echo "${npm_bin}/${cmd}"
return 0
fi
done < <(openclaw_candidate_bins)
fi

echo ""
Expand All @@ -1814,7 +1869,7 @@ resolve_openclaw_bin() {

install_openclaw_from_git() {
local repo_dir="$1"
local repo_url="https://github.com/openclaw/openclaw.git"
local repo_url="${OPENCLAW_GIT_REPO_URL:-$DEFAULT_GIT_REPO_URL}"

if [[ -d "$repo_dir/.git" ]]; then
ui_info "Installing OpenClaw from git checkout: ${repo_dir}"
Expand All @@ -1833,6 +1888,18 @@ install_openclaw_from_git() {
run_quiet_step "Cloning OpenClaw" git clone "$repo_url" "$repo_dir"
fi

local repo_branch="${OPENCLAW_GIT_REPO_BRANCH:-$DEFAULT_GIT_REPO_BRANCH}"
if [[ -n "$repo_branch" ]] && [[ -z "$(git -C "$repo_dir" status --porcelain 2>/dev/null || true)" ]]; then
run_quiet_step "Fetching repository" git -C "$repo_dir" fetch --all --prune || true
if git -C "$repo_dir" show-ref --verify --quiet "refs/heads/$repo_branch"; then
run_quiet_step "Checking out branch" git -C "$repo_dir" checkout "$repo_branch" || true
elif git -C "$repo_dir" show-ref --verify --quiet "refs/remotes/origin/$repo_branch"; then
run_quiet_step "Checking out branch" git -C "$repo_dir" checkout -b "$repo_branch" "origin/$repo_branch" || true
else
ui_warn "Branch not found on origin: $repo_branch; continuing on current branch"
fi
fi

if [[ "$GIT_UPDATE" == "1" ]]; then
if [[ -z "$(git -C "$repo_dir" status --porcelain 2>/dev/null || true)" ]]; then
run_quiet_step "Updating repository" git -C "$repo_dir" pull --rebase || true
Expand Down Expand Up @@ -1865,22 +1932,32 @@ EOF
# Install OpenClaw
resolve_beta_version() {
local beta=""
beta="$(npm view openclaw dist-tags.beta 2>/dev/null || true)"
beta="$(npm view "${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}" dist-tags.beta 2>/dev/null || true)"
if [[ -z "$beta" || "$beta" == "undefined" || "$beta" == "null" ]]; then
return 1
fi
echo "$beta"
}

resolve_next_version() {
local package_name="$1"
local next=""
next="$(npm view "$package_name" dist-tags.next 2>/dev/null || true)"
if [[ -z "$next" || "$next" == "undefined" || "$next" == "null" ]]; then
return 1
fi
echo "$next"
}

install_openclaw() {
local package_name="openclaw"
local package_name="${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}"
if [[ "$USE_BETA" == "1" ]]; then
local beta_version=""
beta_version="$(resolve_beta_version || true)"
if [[ -n "$beta_version" ]]; then
OPENCLAW_VERSION="$beta_version"
ui_info "Beta tag detected (${beta_version})"
package_name="openclaw"
package_name="${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}"
else
OPENCLAW_VERSION="latest"
ui_info "No beta tag found; using latest"
Expand Down Expand Up @@ -1911,11 +1988,20 @@ install_openclaw() {
install_openclaw_npm "${install_spec}"
fi

if [[ "${OPENCLAW_VERSION}" == "latest" && "${package_name}" == "openclaw" ]]; then
if [[ "${OPENCLAW_VERSION}" == "latest" ]]; then
if ! resolve_openclaw_bin &> /dev/null; then
ui_warn "npm install openclaw@latest failed; retrying openclaw@next"
cleanup_npm_openclaw_paths
install_openclaw_npm "openclaw@next"
# npm install succeeded but CLI isn't discoverable yet; attempt explicit link before tag fallback.
ensure_openclaw_bin_link || true
fi
if ! resolve_openclaw_bin &> /dev/null; then
local next_version=""
next_version="$(resolve_next_version "$package_name" || true)"
if [[ -n "$next_version" ]]; then
ui_warn "Installed ${package_name}@latest but openclaw is not yet discoverable; retrying ${package_name}@next"
cleanup_npm_openclaw_paths
install_openclaw_npm "${package_name}@next"
ensure_openclaw_bin_link || true
fi
fi
fi

Expand Down Expand Up @@ -2015,8 +2101,9 @@ resolve_openclaw_version() {
if [[ -z "$version" ]]; then
local npm_root=""
npm_root=$(npm root -g 2>/dev/null || true)
if [[ -n "$npm_root" && -f "$npm_root/openclaw/package.json" ]]; then
version=$(node -e "console.log(require('${npm_root}/openclaw/package.json').version)" 2>/dev/null || true)
local npm_package="${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}"
if [[ -n "$npm_root" && -f "$npm_root/${npm_package}/package.json" ]]; then
version=$(node -e "console.log(require('${npm_root}/${npm_package}/package.json').version)" 2>/dev/null || true)
fi
fi
echo "$version"
Expand Down Expand Up @@ -2153,9 +2240,9 @@ main() {
local final_git_dir=""
if [[ "$INSTALL_METHOD" == "git" ]]; then
# Clean up npm global install if switching to git
if npm list -g openclaw &>/dev/null; then
if npm list -g "${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}" &>/dev/null; then
ui_info "Removing npm global install (switching to git)"
npm uninstall -g openclaw 2>/dev/null || true
npm uninstall -g "${OPENCLAW_NPM_PACKAGE:-$DEFAULT_NPM_PACKAGE}" 2>/dev/null || true
ui_success "npm global install removed"
fi

Expand Down Expand Up @@ -2275,7 +2362,7 @@ main() {
ui_kv "Checkout" "$final_git_dir"
ui_kv "Wrapper" "$HOME/.local/bin/openclaw"
ui_kv "Update command" "openclaw update --restart"
ui_kv "Switch to npm" "curl -fsSL --proto '=https' --tlsv1.2 https://openclaw.ai/install.sh | bash -s -- --install-method npm"
ui_kv "Switch to npm" "curl -fsSL --proto '=https' --tlsv1.2 https://aimlapi.com/openclaw/install.sh | bash -s -- --install-method npm"
elif [[ "$is_upgrade" == "true" ]]; then
ui_info "Upgrade complete"
if [[ -r /dev/tty && -w /dev/tty ]]; then
Expand Down
Loading