#!/usr/bin/env bash set -euo pipefail # Optional overrides: # OPENCLAW_DATA_TARGET=/Volumes/Data/openclaw-copilot bash ./setup/setup_openclaw_copilot.sh # NPM_GLOBAL_PREFIX="$HOME/.npm-global" bash ./setup/setup_openclaw_copilot.sh # OPENCLAW_DATA_TARGET=/Volumes/Data/openclaw-copilot NPM_GLOBAL_PREFIX="$HOME/.npm-global" bash ./setup/setup_openclaw_copilot.sh OPENCLAW_DATA_TARGET="${OPENCLAW_DATA_TARGET:-}" NPM_GLOBAL_PREFIX="${NPM_GLOBAL_PREFIX:-}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' log_info() { echo -e "${GREEN}$*${NC}"; } log_warn() { echo -e "${YELLOW}$*${NC}"; } log_err() { echo -e "${RED}$*${NC}"; } require_cmd() { local cmd="$1" if ! command -v "$cmd" >/dev/null 2>&1; then log_err "ERROR: Missing required command: $cmd" exit 1 fi } node_major_version() { node -v 2>/dev/null | sed 's/^v//' | cut -d. -f1 } expand_tilde() { local p="$1" if [[ "$p" == "~" ]]; then echo "$HOME" elif [[ "$p" == "~/"* ]]; then echo "$HOME/${p#~/}" else echo "$p" fi } link_data_dir() { local source="$1" local target="$2" local label="$3" mkdir -p "$target" if [ -L "$source" ]; then local current_link current_link="$(readlink "$source")" if [ "$current_link" != "$target" ]; then rm "$source" ln -s "$target" "$source" log_info "${label}: updated symlink ${source} -> ${target}" else log_info "${label}: symlink already correct (${source} -> ${target})" fi return 0 fi if [ -d "$source" ]; then log_warn "${label}: migrating existing ${source} data to ${target}..." if command -v rsync >/dev/null 2>&1; then rsync -a "$source"/ "$target"/ else cp -a "$source"/. "$target"/ fi rm -rf "$source" elif [ -e "$source" ]; then log_err "ERROR: ${source} exists but is not a directory/symlink. Resolve manually." exit 1 fi ln -s "$target" "$source" log_info "${label}: symlink created ${source} -> ${target}" } install_npm_global() { local pkg="$1" require_cmd npm if [[ -n "$NPM_GLOBAL_PREFIX" ]]; then mkdir -p "$NPM_GLOBAL_PREFIX" npm install -g --prefix "$NPM_GLOBAL_PREFIX" "$pkg" else npm install -g "$pkg" fi } if [[ -n "$OPENCLAW_DATA_TARGET" ]]; then OPENCLAW_DATA_TARGET="$(expand_tilde "$OPENCLAW_DATA_TARGET")" fi if [[ -n "$NPM_GLOBAL_PREFIX" ]]; then NPM_GLOBAL_PREFIX="$(expand_tilde "$NPM_GLOBAL_PREFIX")" fi if [[ -n "$NPM_GLOBAL_PREFIX" ]]; then export PATH="$NPM_GLOBAL_PREFIX/bin:$PATH" fi echo -e "${GREEN}=== OpenClaw + GitHub Copilot CLI Setup ===${NC}" echo "Current time: $(date)" if [[ -n "$OPENCLAW_DATA_TARGET" ]]; then echo "OpenClaw data target: $OPENCLAW_DATA_TARGET" fi if [[ -n "$NPM_GLOBAL_PREFIX" ]]; then echo "npm global prefix: $NPM_GLOBAL_PREFIX" fi echo "" require_cmd curl # Step 1: Install / verify Node.js >= 22 need_node_install=false if ! command -v node >/dev/null 2>&1; then need_node_install=true else node_major="$(node_major_version || true)" if ! echo "$node_major" | grep -Eq '^[0-9]+$' || [ "$node_major" -lt 22 ]; then need_node_install=true fi fi if [ "$need_node_install" = true ]; then log_warn "Node.js >= 22 not found. Installing via Homebrew..." if ! command -v brew >/dev/null 2>&1; then log_err "Homebrew not found. Install it first:" echo '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' exit 1 fi brew install node fi log_info "Node.js ready ($(node -v))." # Step 2: Install / verify OpenClaw if ! command -v openclaw >/dev/null 2>&1; then log_warn "OpenClaw not found. Installing via npm..." require_cmd npm install_npm_global openclaw else log_info "OpenClaw already installed ($(openclaw --version))." fi # Step 3: Install / verify GitHub Copilot CLI if ! command -v copilot >/dev/null 2>&1; then if command -v brew >/dev/null 2>&1; then log_warn "Copilot CLI not found. Installing prerelease via Homebrew..." brew install copilot-cli@prerelease || { log_warn "Homebrew install failed, falling back to npm package..." install_npm_global @github/copilot-cli } else log_warn "Homebrew not found. Installing Copilot CLI via npm..." install_npm_global @github/copilot-cli fi else log_info "Copilot CLI already installed ($(copilot --version 2>/dev/null || echo present))." fi if [[ -n "$OPENCLAW_DATA_TARGET" ]]; then link_data_dir "$HOME/.openclaw" "$OPENCLAW_DATA_TARGET" "OpenClaw" else log_info "OpenClaw data location unchanged (~/.openclaw). Set OPENCLAW_DATA_TARGET to move it." fi FINALIZE_SCRIPT="$SCRIPT_DIR/../scripts/finalize_copilot_setup.sh" if [[ -x "$FINALIZE_SCRIPT" ]]; then if copilot auth status >/dev/null 2>&1; then log_info "Copilot auth already active. Running finalize flow now..." if ! bash "$FINALIZE_SCRIPT"; then log_warn "Finalize flow failed. Re-run manually after checking auth/models:" echo " bash ./scripts/finalize_copilot_setup.sh" fi else log_warn "Final setup step still needed after login:" echo " bash ./scripts/finalize_copilot_setup.sh" fi fi echo "" log_info "Setup complete (Copilot-first)." echo "" echo "Next steps (target machine):" echo "1. Run one-command finalize (recommended):" echo " bash ./scripts/finalize_copilot_setup.sh" echo "2. If finalize cannot open browser login, authenticate first:" echo " copilot auth login" echo " copilot auth status" echo " bash ./scripts/finalize_copilot_setup.sh" echo "3. Verify:" echo " openclaw status --deep" echo " openclaw models status" if [[ -n "$NPM_GLOBAL_PREFIX" ]]; then echo "" echo "If this is a new shell, ensure PATH includes your npm prefix bin:" echo " export PATH=\"$NPM_GLOBAL_PREFIX/bin:\$PATH\"" fi