#!/usr/bin/env bash set -euo pipefail log() { echo "[openclaw-docker-ui] $*" } fail() { echo "[openclaw-docker-ui] ERROR: $*" >&2 exit 1 } require_cmd() { local cmd="$1" command -v "$cmd" >/dev/null 2>&1 || fail "missing required command: $cmd" } require_cmd docker require_cmd git require_cmd curl require_cmd openssl require_cmd grep OPENCLAW_REPO_URL="${OPENCLAW_REPO_URL:-https://github.com/openclaw/openclaw.git}" OPENCLAW_DOCKER_DIR="${OPENCLAW_DOCKER_DIR:-/tmp/openclaw-docker}" OPENCLAW_IMAGE="${OPENCLAW_IMAGE:-openclaw:local}" OPENCLAW_CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw-paperclip-smoke}" OPENCLAW_WORKSPACE_DIR="${OPENCLAW_WORKSPACE_DIR:-$OPENCLAW_CONFIG_DIR/workspace}" OPENCLAW_GATEWAY_PORT="${OPENCLAW_GATEWAY_PORT:-18789}" OPENCLAW_BRIDGE_PORT="${OPENCLAW_BRIDGE_PORT:-18790}" OPENCLAW_GATEWAY_BIND="${OPENCLAW_GATEWAY_BIND:-lan}" OPENCLAW_GATEWAY_TOKEN="${OPENCLAW_GATEWAY_TOKEN:-$(openssl rand -hex 32)}" OPENCLAW_BUILD="${OPENCLAW_BUILD:-1}" OPENCLAW_WAIT_SECONDS="${OPENCLAW_WAIT_SECONDS:-45}" OPENCLAW_OPEN_BROWSER="${OPENCLAW_OPEN_BROWSER:-0}" OPENCLAW_SECRETS_FILE="${OPENCLAW_SECRETS_FILE:-$HOME/.secrets}" # Keep default one-command UX: local smoke run should not require manual pairing. OPENCLAW_DISABLE_DEVICE_AUTH="${OPENCLAW_DISABLE_DEVICE_AUTH:-1}" OPENCLAW_MODEL_PRIMARY="${OPENCLAW_MODEL_PRIMARY:-openai/gpt-5.2}" OPENCLAW_MODEL_FALLBACK="${OPENCLAW_MODEL_FALLBACK:-openai/gpt-5.2-chat-latest}" OPENCLAW_RESET_STATE="${OPENCLAW_RESET_STATE:-1}" PAPERCLIP_HOST_PORT="${PAPERCLIP_HOST_PORT:-3100}" PAPERCLIP_HOST_FROM_CONTAINER="${PAPERCLIP_HOST_FROM_CONTAINER:-host.docker.internal}" case "$OPENCLAW_DISABLE_DEVICE_AUTH" in 1|true|TRUE|True|yes|YES|Yes) OPENCLAW_DISABLE_DEVICE_AUTH_JSON="true" ;; 0|false|FALSE|False|no|NO|No) OPENCLAW_DISABLE_DEVICE_AUTH_JSON="false" ;; *) fail "OPENCLAW_DISABLE_DEVICE_AUTH must be one of: 1,0,true,false,yes,no" ;; esac if [[ -z "${OPENAI_API_KEY:-}" && -f "$OPENCLAW_SECRETS_FILE" ]]; then set +u # shellcheck source=/dev/null source "$OPENCLAW_SECRETS_FILE" set -u fi [[ -n "${OPENAI_API_KEY:-}" ]] || fail "OPENAI_API_KEY is required (set env var or include it in $OPENCLAW_SECRETS_FILE)" log "preparing OpenClaw repo at $OPENCLAW_DOCKER_DIR" if [[ -d "$OPENCLAW_DOCKER_DIR/.git" ]]; then git -C "$OPENCLAW_DOCKER_DIR" fetch --quiet origin || true git -C "$OPENCLAW_DOCKER_DIR" checkout --quiet main || true git -C "$OPENCLAW_DOCKER_DIR" pull --ff-only --quiet origin main || true else rm -rf "$OPENCLAW_DOCKER_DIR" git clone "$OPENCLAW_REPO_URL" "$OPENCLAW_DOCKER_DIR" fi if [[ "$OPENCLAW_BUILD" == "1" ]]; then log "building Docker image $OPENCLAW_IMAGE" docker build -t "$OPENCLAW_IMAGE" -f "$OPENCLAW_DOCKER_DIR/Dockerfile" "$OPENCLAW_DOCKER_DIR" fi log "writing OpenClaw config under $OPENCLAW_CONFIG_DIR" if [[ "$OPENCLAW_RESET_STATE" == "1" ]]; then # Ensure deterministic smoke behavior across reruns by removing stale agent/auth state. rm -rf "$OPENCLAW_CONFIG_DIR/agents" fi mkdir -p "$OPENCLAW_WORKSPACE_DIR" "$OPENCLAW_CONFIG_DIR/identity" "$OPENCLAW_CONFIG_DIR/credentials" chmod 700 "$OPENCLAW_CONFIG_DIR" "$OPENCLAW_CONFIG_DIR/credentials" cat > "$OPENCLAW_CONFIG_DIR/openclaw.json" < "$OPENCLAW_DOCKER_DIR/.env" < "$COMPOSE_OVERRIDE" <process.exit(r.ok?0:1)).catch(()=>process.exit(1))" >/dev/null 2>&1; then echo "http://${candidate}:${PAPERCLIP_HOST_PORT}" return 0 fi done return 1 } log "starting OpenClaw gateway container" compose up -d openclaw-gateway log "waiting for gateway health on http://127.0.0.1:${OPENCLAW_GATEWAY_PORT}/" READY="0" for _ in $(seq 1 "$OPENCLAW_WAIT_SECONDS"); do code="$(curl -sS -o /dev/null -w "%{http_code}" "http://127.0.0.1:${OPENCLAW_GATEWAY_PORT}/" || true)" if [[ "$code" == "200" ]]; then READY="1" break fi sleep 1 done if [[ "$READY" != "1" ]]; then compose logs --tail=100 openclaw-gateway || true fail "gateway did not become healthy in ${OPENCLAW_WAIT_SECONDS}s" fi paperclip_base_url="$(detect_paperclip_base_url || true)" dashboard_output="$(compose run --rm openclaw-cli dashboard --no-open)" dashboard_url="$(grep -Eo 'https?://[^[:space:]]+#token=[^[:space:]]+' <<<"$dashboard_output" | head -n1 || true)" if [[ -z "$dashboard_url" ]]; then dashboard_url="http://127.0.0.1:${OPENCLAW_GATEWAY_PORT}/#token=${OPENCLAW_GATEWAY_TOKEN}" fi cat </dev/null 2>&1; then log "opening dashboard in browser" open "$dashboard_url" fi