tao-shen commited on
Commit
0d9d280
ยท
1 Parent(s): b19d31a

feat: add timing to all stages, fix OPENROUTER_API_KEY crash, async DNS

Browse files
Files changed (4) hide show
  1. Dockerfile +56 -44
  2. openclaw.json +1 -1
  3. scripts/entrypoint.sh +23 -10
  4. scripts/sync_hf.py +17 -0
Dockerfile CHANGED
@@ -1,70 +1,82 @@
1
- # OpenClaw on Hugging Face Spaces โ€” ไปŽๆบ็ ๆž„ๅปบ
2
  # ๆ–‡ๆกฃ: https://huggingface.co/docs/hub/spaces-sdks-docker
3
 
4
  FROM node:22-bookworm
 
5
 
6
- # Force rebuild - upload_folder persistence v9
7
- RUN echo "clean-build-v9-upload-folder-$(date +%s)"
 
 
 
8
 
9
- # ๆž„ๅปบไพ่ต–๏ผˆๅŒ…ๅซ Python3 ไปฅไพฟไฝฟ็”จ huggingface_hub ๅš Dataset ๆŒไน…ๅŒ–๏ผ‰
10
- RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates curl python3 python3-pip \
11
- && rm -rf /var/lib/apt/lists/*
12
- RUN pip3 install --no-cache-dir --break-system-packages huggingface_hub
13
 
14
- RUN corepack enable
15
- RUN curl -fsSL https://bun.sh/install | bash
 
 
 
16
  ENV PATH="/root/.bun/bin:${PATH}"
17
 
 
18
  WORKDIR /app
19
- RUN git clone --depth 1 https://github.com/openclaw/openclaw.git openclaw
 
 
20
  WORKDIR /app/openclaw
21
 
22
- # ่กฅไธ๏ผšไป…ๅœจๅฎž้™…ๆˆๅŠŸ่งฃๆžๆถˆๆฏ body ๅนถๅณๅฐ†ๆŠ•้€’ๅ›žๅคๆ—ถ่ฎฐๅฝ• inbound๏ผŒ
23
- # ้ฟๅ…่งฃๅฏ†ๅคฑ่ดฅ๏ผˆBad MAC๏ผ‰็š„ๆถˆๆฏ่ขซ่ฏฏ่ฎกไธบๅทฒๆŽฅๆ”ถๅฏผ่‡ด lastInboundAt ๆœ‰ๅ€ผไฝ†ๆ— ๆณ•ๅ›žๅค
24
  COPY patches /app/patches
25
- RUN if [ -f /app/patches/web-inbound-record-activity-after-body.patch ]; then patch -p1 < /app/patches/web-inbound-record-activity-after-body.patch; fi
 
 
 
 
26
 
27
- RUN pnpm install --frozen-lockfile
28
- RUN pnpm build
 
 
 
 
 
 
 
 
 
29
  ENV OPENCLAW_PREFER_PNPM=1
30
- RUN pnpm ui:build
31
-
32
- # ้ชŒ่ฏๆž„ๅปบไบง็‰ฉๅฎŒๆ•ด๏ผˆๅŒ…ๅซ Telegram ๅ’Œ WhatsApp ๆ‰ฉๅฑ•๏ผ‰
33
- RUN test -f dist/entry.js && echo "[build-check] dist/entry.js OK" \
34
- && test -f dist/plugin-sdk/index.js && echo "[build-check] dist/plugin-sdk/index.js OK" \
35
- && test -d extensions/telegram && echo "[build-check] extensions/telegram OK" \
36
- && test -d extensions/whatsapp && echo "[build-check] extensions/whatsapp OK" \
37
- && test -d dist/control-ui && echo "[build-check] dist/control-ui OK"
38
-
39
- # ๅ‘ Control UI ๆณจๅ…ฅ่‡ชๅŠจ token ้…็ฝฎ๏ผˆ่ฎฉๆต่งˆๅ™จ่‡ชๅŠจ่ฟžๆŽฅ๏ผŒๆ— ้œ€ๆ‰‹ๅŠจ่พ“ๅ…ฅ token๏ผ‰
40
- RUN python3 << 'PYEOF'
41
- import pathlib
42
- p = pathlib.Path('dist/control-ui/index.html')
43
- script = '<script>!function(){var K="openclaw.control.settings.v1";try{var s=JSON.parse(localStorage.getItem(K)||"{}")||{};if(!s.token){s.token="openclaw-space-default";localStorage.setItem(K,JSON.stringify(s))}}catch(e){}}()</script>'
44
- h = p.read_text()
45
- p.write_text(h.replace('</head>', script + '</head>'))
46
- print('[build-check] Token auto-config injected into Control UI')
47
- PYEOF
48
-
49
- # ไธไฟฎๆ”นๅ†…้ƒจไปฃ็ ๏ผŒๆ”น็”จๅค–้ƒจ WebSocket ็›‘ๆŠค่„šๆœฌๅค„็† 515 ้‡่ฟž
50
 
 
 
 
 
 
51
  ENV NODE_ENV=production
52
- # ็ฆ็”จ bundled ๆ’ไปถๅ‘็Žฐ๏ผˆๆ”น็”ฑ global symlink ๆไพ›๏ผ‰๏ผ›็”จ็ฉบ็›ฎๅฝ•ๆ›ฟไปฃ /dev/null ้ฟๅ… ENOTDIR ่ญฆๅ‘Š
53
  RUN mkdir -p /app/openclaw/empty-bundled-plugins
54
  ENV OPENCLAW_BUNDLED_PLUGINS_DIR=/app/openclaw/empty-bundled-plugins
55
  RUN chown -R node:node /app
56
 
57
- # ๅˆ›ๅปบ ~/.openclaw ็›ฎๅฝ•็ป“ๆž„
58
  RUN mkdir -p /home/node/.openclaw/workspace /home/node/.openclaw/credentials
59
- # Note: openclaw.json is NOT copied here - it will be restored from Dataset by openclaw_sync.py
60
- # The new persistence system backs up and restores the entire ~/.openclaw directory
61
 
62
- # ๆŒไน…ๅŒ–่„šๆœฌ๏ผˆๅฎŒๆ•ด็›ฎๅฝ•ๅค‡ไปฝ๏ผ‰ & DNS ไฟฎๅค
63
- COPY --chown=node:node scripts /home/node/scripts
64
  COPY --chown=node:node openclaw.json /home/node/scripts/openclaw.json.default
65
- RUN chmod +x /home/node/scripts/entrypoint.sh
66
- RUN chmod +x /home/node/scripts/sync_hf.py
67
- RUN chown -R node:node /home/node
68
 
69
  USER node
70
  ENV HOME=/home/node
 
1
+ # OpenClaw on Hugging Face Spaces โ€” ไปŽๆบ็ ๆž„ๅปบ๏ผˆๅธฆ่ฎกๆ—ถ๏ผ‰
2
  # ๆ–‡ๆกฃ: https://huggingface.co/docs/hub/spaces-sdks-docker
3
 
4
  FROM node:22-bookworm
5
+ SHELL ["/bin/bash", "-c"]
6
 
7
+ # โ”€โ”€ Step 1: System dependencies โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
8
+ RUN echo "[build][step1] Installing system deps..." && START=$(date +%s) \
9
+ && apt-get update && apt-get install -y --no-install-recommends git ca-certificates curl python3 python3-pip \
10
+ && rm -rf /var/lib/apt/lists/* \
11
+ && echo "[build][step1] System deps: $(($(date +%s) - START))s"
12
 
13
+ # โ”€โ”€ Step 2: Python dependencies โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
14
+ RUN echo "[build][step2] Installing huggingface_hub..." && START=$(date +%s) \
15
+ && pip3 install --no-cache-dir --break-system-packages huggingface_hub \
16
+ && echo "[build][step2] huggingface_hub: $(($(date +%s) - START))s"
17
 
18
+ # โ”€โ”€ Step 3: Node tooling โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
19
+ RUN echo "[build][step3] Enabling corepack + bun..." && START=$(date +%s) \
20
+ && corepack enable \
21
+ && curl -fsSL https://bun.sh/install | bash \
22
+ && echo "[build][step3] Corepack + Bun: $(($(date +%s) - START))s"
23
  ENV PATH="/root/.bun/bin:${PATH}"
24
 
25
+ # โ”€โ”€ Step 4: Clone OpenClaw โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
26
  WORKDIR /app
27
+ RUN echo "[build][step4] Cloning OpenClaw..." && START=$(date +%s) \
28
+ && git clone --depth 1 https://github.com/openclaw/openclaw.git openclaw \
29
+ && echo "[build][step4] Git clone: $(($(date +%s) - START))s"
30
  WORKDIR /app/openclaw
31
 
32
+ # โ”€โ”€ Step 5: Apply patches โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
 
33
  COPY patches /app/patches
34
+ RUN echo "[build][step5] Applying patches..." && START=$(date +%s) \
35
+ && if [ -f /app/patches/web-inbound-record-activity-after-body.patch ]; then \
36
+ patch -p1 < /app/patches/web-inbound-record-activity-after-body.patch; \
37
+ fi \
38
+ && echo "[build][step5] Patches: $(($(date +%s) - START))s"
39
 
40
+ # โ”€โ”€ Step 6: pnpm install โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
41
+ RUN echo "[build][step6] pnpm install..." && START=$(date +%s) \
42
+ && pnpm install --frozen-lockfile \
43
+ && echo "[build][step6] pnpm install: $(($(date +%s) - START))s"
44
+
45
+ # โ”€โ”€ Step 7: pnpm build โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
46
+ RUN echo "[build][step7] pnpm build..." && START=$(date +%s) \
47
+ && pnpm build \
48
+ && echo "[build][step7] pnpm build: $(($(date +%s) - START))s"
49
+
50
+ # โ”€โ”€ Step 8: pnpm ui:build โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
51
  ENV OPENCLAW_PREFER_PNPM=1
52
+ RUN echo "[build][step8] pnpm ui:build..." && START=$(date +%s) \
53
+ && pnpm ui:build \
54
+ && echo "[build][step8] pnpm ui:build: $(($(date +%s) - START))s"
55
+
56
+ # โ”€โ”€ Step 9: Verify build artifacts โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
57
+ RUN echo "[build][step9] Verifying build artifacts..." \
58
+ && test -f dist/entry.js && echo " OK dist/entry.js" \
59
+ && test -f dist/plugin-sdk/index.js && echo " OK dist/plugin-sdk/index.js" \
60
+ && test -d extensions/telegram && echo " OK extensions/telegram" \
61
+ && test -d extensions/whatsapp && echo " OK extensions/whatsapp" \
62
+ && test -d dist/control-ui && echo " OK dist/control-ui"
 
 
 
 
 
 
 
 
 
63
 
64
+ # โ”€โ”€ Step 10: Inject auto-token into Control UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
65
+ COPY --chown=node:node scripts /home/node/scripts
66
+ RUN chmod +x /home/node/scripts/inject-token.sh && bash /home/node/scripts/inject-token.sh
67
+
68
+ # โ”€โ”€ Step 11: Final setup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
69
  ENV NODE_ENV=production
 
70
  RUN mkdir -p /app/openclaw/empty-bundled-plugins
71
  ENV OPENCLAW_BUNDLED_PLUGINS_DIR=/app/openclaw/empty-bundled-plugins
72
  RUN chown -R node:node /app
73
 
 
74
  RUN mkdir -p /home/node/.openclaw/workspace /home/node/.openclaw/credentials
 
 
75
 
 
 
76
  COPY --chown=node:node openclaw.json /home/node/scripts/openclaw.json.default
77
+ RUN chmod +x /home/node/scripts/entrypoint.sh \
78
+ && chmod +x /home/node/scripts/sync_hf.py \
79
+ && chown -R node:node /home/node
80
 
81
  USER node
82
  ENV HOME=/home/node
openclaw.json CHANGED
@@ -22,7 +22,7 @@
22
  "providers": {
23
  "openrouter": {
24
  "baseUrl": "https://openrouter.ai/api/v1",
25
- "apiKey": "${OPENROUTER_API_KEY}",
26
  "api": "openai-completions",
27
  "models": [
28
  {
 
22
  "providers": {
23
  "openrouter": {
24
  "baseUrl": "https://openrouter.ai/api/v1",
25
+ "apiKey": "__OPENROUTER_API_KEY__",
26
  "api": "openai-completions",
27
  "models": [
28
  {
scripts/entrypoint.sh CHANGED
@@ -1,41 +1,54 @@
1
  #!/bin/sh
2
  set -e
3
 
 
 
4
  echo "[entrypoint] OpenClaw HuggingFace Spaces Entrypoint"
5
  echo "[entrypoint] ======================================="
6
 
7
- # DNS pre-resolution for WhatsApp
8
- echo "[entrypoint] Resolving WhatsApp domains via DNS-over-HTTPS..."
9
- python3 /home/node/scripts/dns-resolve.py /tmp/dns-resolved.json || echo "[entrypoint] DNS pre-resolve had issues (non-fatal)"
10
-
11
- # Enable Node.js DNS fix
 
 
 
 
 
 
12
  export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--require /home/node/scripts/dns-fix.cjs"
13
 
14
- # Ensure extensions symlink exists
 
15
  if [ ! -L /home/node/.openclaw/extensions ]; then
16
  rm -rf /home/node/.openclaw/extensions 2>/dev/null || true
17
  ln -s /app/openclaw/extensions /home/node/.openclaw/extensions
18
  echo "[entrypoint] Created extensions symlink -> /app/openclaw/extensions"
19
  fi
 
20
 
21
- # Check for WhatsApp credentials
22
  if [ -d /home/node/.openclaw/credentials/whatsapp ]; then
23
  echo "[entrypoint] Found existing WhatsApp credentials - will use for auto-connect"
24
  fi
25
 
26
- # Build artifacts check
27
  cd /app/openclaw
28
  echo "[entrypoint] Build artifacts check:"
29
  test -f dist/entry.js && echo " OK dist/entry.js" || echo " WARNING: dist/entry.js missing!"
30
  test -f dist/plugin-sdk/index.js && echo " OK dist/plugin-sdk/index.js" || echo " WARNING: dist/plugin-sdk/index.js missing!"
31
  echo " Extensions: $(ls extensions/ 2>/dev/null | wc -l | tr -d ' ') found"
32
  echo " Global extensions link: $(readlink /home/node/.openclaw/extensions 2>/dev/null || echo 'NOT SET')"
33
- echo " DNS resolved: $(cat /tmp/dns-resolved.json 2>/dev/null || echo 'file missing')"
34
 
35
  # Create logs directory
36
  mkdir -p /home/node/logs
37
  touch /home/node/logs/app.log
38
 
39
- # Start OpenClaw via sync_hf.py
 
 
 
40
  echo "[entrypoint] Starting OpenClaw via sync_hf.py..."
 
41
  exec python3 -u /home/node/scripts/sync_hf.py
 
1
  #!/bin/sh
2
  set -e
3
 
4
+ BOOT_START=$(date +%s)
5
+
6
  echo "[entrypoint] OpenClaw HuggingFace Spaces Entrypoint"
7
  echo "[entrypoint] ======================================="
8
 
9
+ # โ”€โ”€ DNS pre-resolution (run in BACKGROUND โ€” was 121s blocking) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
10
+ echo "[entrypoint] Resolving WhatsApp domains via DNS-over-HTTPS (background)..."
11
+ DNS_START=$(date +%s)
12
+ (
13
+ python3 /home/node/scripts/dns-resolve.py /tmp/dns-resolved.json 2>&1
14
+ DNS_END=$(date +%s)
15
+ echo "[TIMER] DNS pre-resolve (background): $((DNS_END - DNS_START))s"
16
+ ) &
17
+ DNS_PID=$!
18
+
19
+ # Enable Node.js DNS fix (will use resolved file when ready)
20
  export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--require /home/node/scripts/dns-fix.cjs"
21
 
22
+ # โ”€โ”€ Extensions symlink โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
23
+ SYMLINK_START=$(date +%s)
24
  if [ ! -L /home/node/.openclaw/extensions ]; then
25
  rm -rf /home/node/.openclaw/extensions 2>/dev/null || true
26
  ln -s /app/openclaw/extensions /home/node/.openclaw/extensions
27
  echo "[entrypoint] Created extensions symlink -> /app/openclaw/extensions"
28
  fi
29
+ echo "[TIMER] Extensions symlink: $(($(date +%s) - SYMLINK_START))s"
30
 
31
+ # โ”€โ”€ WhatsApp credentials check โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
32
  if [ -d /home/node/.openclaw/credentials/whatsapp ]; then
33
  echo "[entrypoint] Found existing WhatsApp credentials - will use for auto-connect"
34
  fi
35
 
36
+ # โ”€โ”€ Build artifacts check โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
37
  cd /app/openclaw
38
  echo "[entrypoint] Build artifacts check:"
39
  test -f dist/entry.js && echo " OK dist/entry.js" || echo " WARNING: dist/entry.js missing!"
40
  test -f dist/plugin-sdk/index.js && echo " OK dist/plugin-sdk/index.js" || echo " WARNING: dist/plugin-sdk/index.js missing!"
41
  echo " Extensions: $(ls extensions/ 2>/dev/null | wc -l | tr -d ' ') found"
42
  echo " Global extensions link: $(readlink /home/node/.openclaw/extensions 2>/dev/null || echo 'NOT SET')"
 
43
 
44
  # Create logs directory
45
  mkdir -p /home/node/logs
46
  touch /home/node/logs/app.log
47
 
48
+ ENTRYPOINT_END=$(date +%s)
49
+ echo "[TIMER] Entrypoint (before sync_hf.py): $((ENTRYPOINT_END - BOOT_START))s"
50
+
51
+ # โ”€โ”€ Start OpenClaw via sync_hf.py (don't wait for DNS โ€” it runs in bg) โ”€โ”€โ”€โ”€โ”€
52
  echo "[entrypoint] Starting OpenClaw via sync_hf.py..."
53
+ echo "[entrypoint] DNS resolution running in background (PID $DNS_PID), app will use it when ready"
54
  exec python3 -u /home/node/scripts/sync_hf.py
scripts/sync_hf.py CHANGED
@@ -252,6 +252,14 @@ class OpenClawFullSync:
252
  default_src = Path(__file__).parent / "openclaw.json.default"
253
  if default_src.exists():
254
  shutil.copy2(str(default_src), str(config_path))
 
 
 
 
 
 
 
 
255
  print("[SYNC] Created openclaw.json from default template")
256
  else:
257
  with open(config_path, "w") as f:
@@ -499,10 +507,16 @@ class OpenClawFullSync:
499
 
500
  def main():
501
  try:
 
 
 
502
  sync = OpenClawFullSync()
 
503
 
504
  # 1. Restore
 
505
  sync.load_from_repo()
 
506
 
507
  # 2. Background sync
508
  stop_event = threading.Event()
@@ -510,7 +524,10 @@ def main():
510
  t.start()
511
 
512
  # 3. Start application
 
513
  process = sync.run_openclaw()
 
 
514
 
515
  # Signal handler
516
  def handle_signal(sig, frame):
 
252
  default_src = Path(__file__).parent / "openclaw.json.default"
253
  if default_src.exists():
254
  shutil.copy2(str(default_src), str(config_path))
255
+ # Replace placeholder with actual env var value
256
+ text = config_path.read_text()
257
+ if "__OPENROUTER_API_KEY__" in text:
258
+ if OPENROUTER_API_KEY:
259
+ text = text.replace("__OPENROUTER_API_KEY__", OPENROUTER_API_KEY)
260
+ else:
261
+ text = text.replace("__OPENROUTER_API_KEY__", "")
262
+ config_path.write_text(text)
263
  print("[SYNC] Created openclaw.json from default template")
264
  else:
265
  with open(config_path, "w") as f:
 
507
 
508
  def main():
509
  try:
510
+ t_main_start = time.time()
511
+
512
+ t0 = time.time()
513
  sync = OpenClawFullSync()
514
+ print(f"[TIMER] sync_hf init: {time.time() - t0:.1f}s")
515
 
516
  # 1. Restore
517
+ t0 = time.time()
518
  sync.load_from_repo()
519
+ print(f"[TIMER] load_from_repo (restore): {time.time() - t0:.1f}s")
520
 
521
  # 2. Background sync
522
  stop_event = threading.Event()
 
524
  t.start()
525
 
526
  # 3. Start application
527
+ t0 = time.time()
528
  process = sync.run_openclaw()
529
+ print(f"[TIMER] run_openclaw launch: {time.time() - t0:.1f}s")
530
+ print(f"[TIMER] Total startup (init โ†’ app launched): {time.time() - t_main_start:.1f}s")
531
 
532
  # Signal handler
533
  def handle_signal(sig, frame):