#!/bin/sh # OpenClaw on HF Spaces - 实时状态在本地磁盘, /data 仅只读导入旧配置/工作区 umask 022 ts() { date -u +"%H:%M:%S"; } log() { echo "[$(ts)] [entrypoint] $*"; } warn() { echo "[$(ts)] [entrypoint] WARN: $*"; } OPENCLAW_HOME=/home/user mkdir -p "$OPENCLAW_HOME/.openclaw" export OPENCLAW_HOME log "OPENCLAW_HOME=$OPENCLAW_HOME (live state on local disk)" # ── 从 Secrets 导出各家 Key ── for VAR in $(env | cut -d= -f1); do case "$VAR" in OPENCLAW_*|SPACE_*|SYSTEM_*|HF_*|NODE_*|npm_*) continue ;; esac case "$VAR" in *_API_KEY|*_SECRET_KEY|*_ACCESS_TOKEN|*_BOT_TOKEN|*_AUTH_TOKEN|*_APP_KEY) [ -n "$(printenv "$VAR" 2>/dev/null)" ] && { export "$VAR"; log "exported: $VAR"; } ;; esac done # ── 生成配置 + 安全检查 ── log "Running setup..." node /app/spaces/huggingface/setup-hf-config.mjs || warn "setup failed" sh /app/security-check.sh || true # ── doctor (本地新状态, 做一次迁移/校验) ── log "Running openclaw doctor --fix..." timeout 300 openclaw doctor --fix --non-interactive /tmp/doctor.out 2>&1 tail -n 30 /tmp/doctor.out chmod -R go-w "$OPENCLAW_HOME/.openclaw/npm" "$OPENCLAW_HOME/.openclaw/extensions" 2>/dev/null || true GW_URL="ws://127.0.0.1:7860" GW_TOKEN="${OPENCLAW_GATEWAY_TOKEN:-}" if [ -z "$GW_TOKEN" ]; then GW_TOKEN=$(node -e 'try{console.log(JSON.parse(require("fs").readFileSync(process.env.OPENCLAW_HOME+"/.openclaw/openclaw.json","utf8")).gateway.auth.token||"")}catch(e){}' 2>/dev/null) fi for kv in "gateway.mode local" "gateway.port 7860"; do set -- $kv openclaw config set "$1" "$2" /tmp/cfg.out 2>&1 \ && log "config set $1 = $2" || warn "config set $1 failed: $(head -c 200 /tmp/cfg.out | tr '\n' ' ')" done # ── Telegram 网络: 启动先探测一次, 之后后台持续重试 ── export TG_IP_CACHE=/tmp/tg-ips.json GW_NODE_OPTIONS="--dns-result-order=ipv4first" if [ "${TG_NET_FIX:-1}" = "1" ]; then log "Probing api.telegram.org..." timeout 30 node /app/tg-net-fix.cjs probe || true GW_NODE_OPTIONS="$GW_NODE_OPTIONS --require /app/tg-net-fix.cjs" ( while true; do sleep 45; timeout 40 node /app/tg-net-fix.cjs probe quiet; done ) & fi # ── 只靠密码登录: 通过网关认证后才会出现配对请求, 自动批准 ── UUID_RE='[0-9a-f]\{8\}-[0-9a-f]\{4\}-[0-9a-f]\{4\}-[0-9a-f]\{4\}-[0-9a-f]\{12\}' try_approve() { ID="$1" grep -qx "$ID" /tmp/approved.ids 2>/dev/null && return 0 N=$(cat "/tmp/fail.$ID" 2>/dev/null || echo 0) [ "$N" -ge 2 ] && return 0 if openclaw devices approve "$ID" --url "$GW_URL" --token "$GW_TOKEN" /tmp/approve.out 2>&1 \ || openclaw devices approve "$ID" /tmp/approve.out 2>&1; then echo "$ID" >> /tmp/approved.ids log "Approved pairing request $ID" else echo $((N+1)) > "/tmp/fail.$ID" warn "approve failed for $ID: $(head -c 300 /tmp/approve.out | tr '\n' ' ')" fi } if [ "${AUTO_APPROVE_PAIRING:-1}" = "1" ]; then ( log "Pairing auto-approver started" while true; do sleep 4 IDS="" if openclaw devices list --json --url "$GW_URL" --token "$GW_TOKEN" /tmp/devices.json 2>/dev/null \ || openclaw devices list --json /tmp/devices.json 2>/dev/null; then IDS=$(node - <<'JSEOF' const fs = require('fs'); let data; try { data = JSON.parse(fs.readFileSync('/tmp/devices.json', 'utf8')); } catch (e) { process.exit(0); } const out = []; (function walk(v, key) { if (Array.isArray(v)) { const pending = /pending/i.test(key || ''); for (const x of v) { if (pending && x && typeof x === 'object') { const id = x.requestId || x.id; if (typeof id === 'string') out.push(id); } else walk(x, key); } } else if (v && typeof v === 'object') { for (const k of Object.keys(v)) walk(v[k], k); } })(data, ''); console.log(out.join('\n')); JSEOF ) fi LOGIDS="" LATEST=$(ls -t /tmp/openclaw/openclaw-*.log 2>/dev/null | head -n 1) [ -n "$LATEST" ] && LOGIDS=$(tail -n 300 "$LATEST" 2>/dev/null \ | grep -o "requestId[^0-9a-f]\{0,4\}$UUID_RE" | grep -o "$UUID_RE" | sort -u) for ID in $IDS $LOGIDS; do try_approve "$ID"; done done ) & fi # ── 网关循环 ── for U in "${TELEGRAM_API_ROOT}/bot0:x/getMe" "https://api.telegram.org/bot0:x/getMe" "https://example.com"; do log "net-test $U -> $(curl -sS -m 10 -o /dev/null -w 'http=%{http_code} connect=%{time_connect}s tls=%{time_appconnect}s' "$U" 2>&1 | tr '\n' ' ')" done log "Starting gateway loop..." while true; do for d in "$OPENCLAW_HOME"/.openclaw/tmp/openclaw-*; do [ -d "$d" ] && rm -f "$d"/*.lock 2>/dev/null done log "Gateway starting..." NODE_OPTIONS="$GW_NODE_OPTIONS ${NODE_OPTIONS:-}" openclaw gateway --allow-unconfigured --bind lan --port 7860 CODE=$? log "Gateway exited (code $CODE)" WAITED=0 while nc -z 127.0.0.1 7860 2>/dev/null; do [ $WAITED -eq 0 ] && log "Port 7860 still held - waiting..." sleep 2; WAITED=$((WAITED + 2)) [ $WAITED -ge 90 ] && { warn "Port still in use after 90s - forcing restart"; break; } done sleep 1 done