File size: 5,310 Bytes
0a24085 01a571d dd094e5 01a571d dd094e5 01a571d dd094e5 01a571d dd094e5 01a571d afe3e7c dd094e5 01a571d dd094e5 7684a29 8924dbd dd094e5 8924dbd 7684a29 6af251e ad67ccc dd094e5 08da1b7 dd094e5 01a571d dd094e5 ad67ccc 8924dbd ad67ccc dd094e5 c0df9f7 8924dbd dd094e5 8924dbd c0df9f7 dd094e5 c0df9f7 dd094e5 8924dbd dd094e5 8924dbd dd094e5 01a571d c0df9f7 8924dbd c0df9f7 bdea495 dd094e5 d30ca03 dd094e5 01a571d c0df9f7 dd094e5 8924dbd dd094e5 fd83f78 dd094e5 fd83f78 dd094e5 fd83f78 dd094e5 fd83f78 dd094e5 01a571d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | #!/bin/sh
# OpenClaw HF Spaces - Production Entrypoint
# Storage: HF Storage Bucket at /data (100 GB persistent)
# ----------------------------------------------------------------
# Logging
# ----------------------------------------------------------------
ts() { date -u +"%H:%M:%S"; }
log() { echo "[$(ts)] [entrypoint] $*"; }
warn() { echo "[$(ts)] [entrypoint] WARN: $*"; }
# ----------------------------------------------------------------
# Storage: resolve OPENCLAW_HOME
# Prefer /data (HF Storage Bucket). Fall back to /home/user.
# Retry up to 5s in case the bucket mount is slightly delayed.
# ----------------------------------------------------------------
OPENCLAW_HOME=/home/user
mkdir -p /home/user/.openclaw
RETRIES=5
i=0
while [ $i -lt $RETRIES ]; do
if [ -d /data ] && touch /data/.write-test 2>/dev/null; then
rm -f /data/.write-test
OPENCLAW_HOME=/data
mkdir -p /data/.openclaw
log "Storage bucket /data is writable - using persistent storage"
break
fi
i=$((i+1))
if [ $i -lt $RETRIES ]; then
log "Waiting for /data mount... ($i/$RETRIES)"
sleep 1
fi
done
if [ "$OPENCLAW_HOME" = "/home/user" ]; then
warn "/data not writable after ${RETRIES}s - using ephemeral /home/user"
fi
export OPENCLAW_HOME
log "OPENCLAW_HOME=$OPENCLAW_HOME"
# ----------------------------------------------------------------
# Export provider API keys from Secrets
# ----------------------------------------------------------------
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)
VAL=$(printenv "$VAR" 2>/dev/null || true)
if [ -n "$VAL" ]; then
export "$VAR"
log "exported: $VAR"
fi
;;
esac
done
export HF_TOKEN="${HF_TOKEN:-}"
# ----------------------------------------------------------------
# One-time setup (config write, webhook registration, seed files)
# ----------------------------------------------------------------
log "Running setup..."
node /app/spaces/huggingface/setup-hf-config.mjs || true
log "Setup done."
# ----------------------------------------------------------------
# Security audit (non-fatal)
# ----------------------------------------------------------------
if [ -f /app/security-check.sh ]; then
sh /app/security-check.sh || true
fi
# ----------------------------------------------------------------
# Auto-approve pending device pairings (background)
# ----------------------------------------------------------------
(
DEVICES_DIR="$OPENCLAW_HOME/.openclaw/devices"
mkdir -p "$DEVICES_DIR"
log "Device auto-pairing watcher started"
while true; do
sleep 8
PENDING="$DEVICES_DIR/pending.json"
PAIRED="$DEVICES_DIR/paired.json"
if [ -f "$PENDING" ]; then
node - << 'JSEOF'
const fs = require('fs');
const dir = process.env.OPENCLAW_HOME + '/.openclaw/devices';
const pend = dir + '/pending.json';
const pair = dir + '/paired.json';
try {
const raw = fs.readFileSync(pend, 'utf-8').trim();
if (!raw || raw === '[]' || raw === '{}') process.exit(0);
let pending = JSON.parse(raw);
if (!Array.isArray(pending)) pending = Object.values(pending);
if (pending.length === 0) process.exit(0);
let paired = [];
try { paired = JSON.parse(fs.readFileSync(pair, 'utf-8')); } catch(e) {}
if (!Array.isArray(paired)) paired = [];
const ids = new Set(paired.map(function(d){ return d.id||d.deviceId||d.name; }));
const todo = pending.filter(function(d){ return !ids.has(d.id||d.deviceId||d.name); });
if (todo.length === 0) process.exit(0);
const now = new Date().toISOString();
paired = paired.concat(todo.map(function(d){
return Object.assign({}, d, { approved: true, approvedAt: now });
}));
fs.writeFileSync(pair, JSON.stringify(paired, null, 2));
fs.writeFileSync(pend, '[]');
console.log('[auto-pair] Approved ' + todo.length + ' device(s)');
} catch(e) { /* ignore */ }
JSEOF
fi
done
) &
# ----------------------------------------------------------------
# Gateway loop
#
# OpenClaw restart behaviour:
# - On config save it spawns a child process (new gateway) then
# the parent exits with code 0.
# - The child inherits the port 7860 lock.
# - We must NOT restart until the child also exits (port is free).
#
# Normal crash: port is immediately free, loop restarts quickly.
# Config-save restart: port stays held by child; we wait up to 90s.
# ----------------------------------------------------------------
log "Starting gateway loop..."
while true; do
log "Gateway starting..."
node /app/openclaw.mjs gateway \
--allow-unconfigured \
--bind lan \
--port 7860
CODE=$?
log "Gateway exited (code $CODE)"
# Wait for port 7860 to be released before starting a new instance
WAITED=0
while nc -z 127.0.0.1 7860 2>/dev/null; do
if [ $WAITED -eq 0 ]; then
log "Port 7860 still held (spawned child running) - waiting..."
fi
sleep 2
WAITED=$((WAITED + 2))
if [ $WAITED -ge 90 ]; then
warn "Port 7860 still in use after 90s - forcing restart"
break
fi
done
if [ $WAITED -gt 0 ]; then
log "Port free after ${WAITED}s"
fi
sleep 1
log "Restarting gateway..."
done |