Anurag commited on
Commit
ec5616f
Β·
1 Parent(s): 1d367af

Align terminal enablement messaging with runtime behavior

Browse files
Files changed (3) hide show
  1. README.md +8 -6
  2. health-server.js +5 -2
  3. start.sh +25 -5
README.md CHANGED
@@ -20,7 +20,7 @@ secrets:
20
  - name: GATEWAY_TOKEN
21
  description: "Strong token to secure your OpenClaw Control UI (generate: openssl rand -hex 32)."
22
  - name: JUPYTER_TOKEN
23
- description: "Optional strong token for the JupyterLab terminal at /terminal/ (defaults to huggingface)."
24
  - name: CLOUDFLARE_WORKERS_TOKEN
25
  description: "Cloudflare API token β€” auto-creates a Worker proxy and KeepAlive monitor."
26
  - name: TELEGRAM_ALLOWED_USERS
@@ -78,7 +78,7 @@ secrets:
78
  - πŸ“Š **Visual Dashboard:** Beautiful Web UI to monitor uptime, sync status, and active models.
79
  - πŸ”” **Webhooks:** Get notified on restarts or backup failures via standard webhooks.
80
  - πŸ” **Flexible Auth:** Secure the Control UI with either a gateway token or password.
81
- - πŸ’» **Optional Dev Terminal:** JupyterLab is available at `/terminal/` only when `DEV_MODE=true` (disabled by default).
82
  - 🏠 **100% HF-Native:** Runs entirely on HuggingFace’s free infrastructure (2 vCPU, 16GB RAM).
83
 
84
  ## πŸŽ₯ Video Tutorial
@@ -104,7 +104,9 @@ Navigate to your new Space's **Settings**, scroll down to the **Variables and se
104
  > [!TIP]
105
  > HuggingClaw is completely flexible! You only need these three secrets to get started. You can set other secrets later.
106
 
107
- Optional: set `DEV_MODE=true` (Variable) to enable JupyterLab support and install Jupyter dependencies at build time. You can also set `JUPYTER_TOKEN` as a Secret to set a strong terminal token (must not be `huggingface`). If you want to pin a specific OpenClaw release instead of `latest`, add `OPENCLAW_VERSION` under **Variables** in your Space settings. For Docker Spaces, HF passes Variables as build args during image build, so these should be Variables, not Secrets (except tokens).
 
 
108
 
109
  ### Step 3: Deploy & Run
110
 
@@ -366,12 +368,12 @@ The merged Space includes the Hugging Face JupyterLab template behavior inside t
366
  | :--- | :--- | :--- | :--- |
367
  | `/` | HuggingClaw dashboard | `7861` | Public HF Spaces entrypoint |
368
  | `/app/` | OpenClaw Control UI | `7860` | Mounted behind the local reverse proxy |
369
- | `/terminal/` | JupyterLab terminal (DEV_MODE only) | `8888` | Available only when `DEV_MODE=true`; token login uses `JUPYTER_TOKEN` (set a strong value) |
370
 
371
  When enabled, the terminal notebook root is `/home/node`, so you can inspect HuggingClaw files, logs, workspace state, and runtime scripts from the browser.
372
 
373
  > [!IMPORTANT]
374
- > For real deployments, set a strong `JUPYTER_TOKEN` secret. Do not use `huggingface`; generate a strong token with `openssl rand -hex 32`.
375
 
376
  ## πŸ” Merge Comparison
377
 
@@ -402,7 +404,7 @@ HuggingClaw uses a multi-layered approach to ensure stability and persistence on
402
  2. Resolve backup namespace and restore workspace from HF Dataset.
403
  3. Generate `openclaw.json` configuration.
404
  4. Launch background tasks (auto-sync, channel helpers).
405
- 5. Start the local dashboard/reverse proxy and OpenClaw gateway (JupyterLab starts only when `DEV_MODE=true`).
406
 
407
  </details>
408
 
 
20
  - name: GATEWAY_TOKEN
21
  description: "Strong token to secure your OpenClaw Control UI (generate: openssl rand -hex 32)."
22
  - name: JUPYTER_TOKEN
23
+ description: "Optional token for the JupyterLab terminal at /terminal/. Defaults to GATEWAY_TOKEN when set β€” no extra secret needed."
24
  - name: CLOUDFLARE_WORKERS_TOKEN
25
  description: "Cloudflare API token β€” auto-creates a Worker proxy and KeepAlive monitor."
26
  - name: TELEGRAM_ALLOWED_USERS
 
78
  - πŸ“Š **Visual Dashboard:** Beautiful Web UI to monitor uptime, sync status, and active models.
79
  - πŸ”” **Webhooks:** Get notified on restarts or backup failures via standard webhooks.
80
  - πŸ” **Flexible Auth:** Secure the Control UI with either a gateway token or password.
81
+ - πŸ’» **Terminal Out of the Box:** JupyterLab is available at `/terminal/` automatically when `GATEWAY_TOKEN` is set β€” no extra config needed. `GATEWAY_TOKEN` is reused as the terminal auth token. Set `DEV_MODE=false` explicitly to opt out.
82
  - 🏠 **100% HF-Native:** Runs entirely on HuggingFace’s free infrastructure (2 vCPU, 16GB RAM).
83
 
84
  ## πŸŽ₯ Video Tutorial
 
104
  > [!TIP]
105
  > HuggingClaw is completely flexible! You only need these three secrets to get started. You can set other secrets later.
106
 
107
+ **Terminal auto-enables when `GATEWAY_TOKEN` is set** β€” no extra secrets needed. `GATEWAY_TOKEN` is reused as `JUPYTER_TOKEN`, so the terminal is protected by the same credential as the Control UI. To set a different token, add `JUPYTER_TOKEN` as a Secret. To disable the terminal entirely, set `DEV_MODE=false` as a Variable.
108
+
109
+ If you want to pin a specific OpenClaw release instead of `latest`, add `OPENCLAW_VERSION` under **Variables** in your Space settings. For Docker Spaces, HF passes Variables as build args during image build, so these should be Variables, not Secrets (except tokens).
110
 
111
  ### Step 3: Deploy & Run
112
 
 
368
  | :--- | :--- | :--- | :--- |
369
  | `/` | HuggingClaw dashboard | `7861` | Public HF Spaces entrypoint |
370
  | `/app/` | OpenClaw Control UI | `7860` | Mounted behind the local reverse proxy |
371
+ | `/terminal/` | JupyterLab terminal | `8888` | Auto-enabled when `GATEWAY_TOKEN` is set; uses `GATEWAY_TOKEN` as auth token unless `JUPYTER_TOKEN` is set separately. Set `DEV_MODE=false` to disable. |
372
 
373
  When enabled, the terminal notebook root is `/home/node`, so you can inspect HuggingClaw files, logs, workspace state, and runtime scripts from the browser.
374
 
375
  > [!IMPORTANT]
376
+ > No extra secret needed β€” `GATEWAY_TOKEN` is automatically reused as `JUPYTER_TOKEN`. Set a separate `JUPYTER_TOKEN` secret only if you want a different terminal credential.
377
 
378
  ## πŸ” Merge Comparison
379
 
 
404
  2. Resolve backup namespace and restore workspace from HF Dataset.
405
  3. Generate `openclaw.json` configuration.
406
  4. Launch background tasks (auto-sync, channel helpers).
407
+ 5. Start the local dashboard/reverse proxy and OpenClaw gateway (JupyterLab starts when `GATEWAY_TOKEN` is set, `DEV_MODE=true`, or `HUGGINGCLAW_JUPYTER_ENABLED=true`).
408
 
409
  </details>
410
 
health-server.js CHANGED
@@ -20,9 +20,12 @@ const GATEWAY_HOST = "127.0.0.1";
20
  const JUPYTER_PORT = Number.parseInt(process.env.JUPYTER_PORT || "8888", 10);
21
  const JUPYTER_HOST = "127.0.0.1";
22
  const JUPYTER_BASE = normalizeBase(process.env.JUPYTER_BASE, "/terminal");
 
23
  const DEV_MODE_ENABLED = isTrue(process.env.DEV_MODE);
 
 
24
  const JUPYTER_ENABLED = /^(true|1|yes|on)$/i.test(
25
- process.env.HUGGINGCLAW_JUPYTER_ENABLED || (DEV_MODE_ENABLED ? "true" : "false")
26
  );
27
  const startTime = Date.now();
28
  const LLM_MODEL = process.env.LLM_MODEL || "Not Set";
@@ -634,7 +637,7 @@ const server = http.createServer(async (req, res) => {
634
  if (pathname === JUPYTER_BASE || pathname.startsWith(JUPYTER_BASE + "/")) {
635
  if (!JUPYTER_ENABLED) {
636
  res.writeHead(404, { "Content-Type": "application/json" });
637
- return res.end(JSON.stringify({ status: "disabled", message: "JupyterLab terminal is disabled. Set DEV_MODE=true to enable /terminal/." }));
638
  }
639
  if (isDirectHfSpaceRequest) {
640
  res.writeHead(200, { "Content-Type": "text/html" });
 
20
  const JUPYTER_PORT = Number.parseInt(process.env.JUPYTER_PORT || "8888", 10);
21
  const JUPYTER_HOST = "127.0.0.1";
22
  const JUPYTER_BASE = normalizeBase(process.env.JUPYTER_BASE, "/terminal");
23
+ const GATEWAY_TOKEN = (process.env.GATEWAY_TOKEN || "").trim();
24
  const DEV_MODE_ENABLED = isTrue(process.env.DEV_MODE);
25
+ // Auto-enable Jupyter when DEV_MODE=true, HUGGINGCLAW_JUPYTER_ENABLED=true, or GATEWAY_TOKEN is set.
26
+ // GATEWAY_TOKEN doubles as JUPYTER_TOKEN in start.sh β€” no extra secret needed.
27
  const JUPYTER_ENABLED = /^(true|1|yes|on)$/i.test(
28
+ process.env.HUGGINGCLAW_JUPYTER_ENABLED || (DEV_MODE_ENABLED ? "true" : GATEWAY_TOKEN ? "true" : "false")
29
  );
30
  const startTime = Date.now();
31
  const LLM_MODEL = process.env.LLM_MODEL || "Not Set";
 
637
  if (pathname === JUPYTER_BASE || pathname.startsWith(JUPYTER_BASE + "/")) {
638
  if (!JUPYTER_ENABLED) {
639
  res.writeHead(404, { "Content-Type": "application/json" });
640
+ return res.end(JSON.stringify({ status: "disabled", message: "JupyterLab terminal is disabled. Set GATEWAY_TOKEN or DEV_MODE=true to enable /terminal/ (or set HUGGINGCLAW_JUPYTER_ENABLED=true)." }));
641
  }
642
  if (isDirectHfSpaceRequest) {
643
  res.writeHead(200, { "Content-Type": "text/html" });
start.sh CHANGED
@@ -93,6 +93,12 @@ DEV_MODE_ENABLED=false
93
  if hc_is_true "$DEV_MODE_NORMALIZED"; then
94
  DEV_MODE_ENABLED=true
95
  fi
 
 
 
 
 
 
96
  SYNC_INTERVAL="$(trim_var "${SYNC_INTERVAL:-180}")"
97
  DEVDATA_DATASET_NAME="$(trim_var "${DEVDATA_DATASET_NAME:-huggingclaw-devdata}")"
98
  DEVDATA_SYNC_INTERVAL="$(trim_var "${DEVDATA_SYNC_INTERVAL:-180}")"
@@ -514,10 +520,10 @@ inject_provider_models_from_env "github-copilot" "GITHUB_COPILOT_MODELS" "COPILO
514
 
515
  # Browser configuration (managed local Chromium in HF/Docker)
516
  BROWSER_EXECUTABLE_PATH=""
517
- # On Debian/Ubuntu, /usr/bin/chromium is a shell wrapper; the real ELF binary
518
- # lives at /usr/lib/chromium/chromium. Check the real binary first, then fall
519
- # back to wrapper scripts (which are also valid executablePath values for
520
- # Playwright/OpenClaw β€” they re-exec the real binary internally).
521
  for candidate in \
522
  /usr/lib/chromium/chromium \
523
  /usr/lib/chromium-browser/chromium-browser \
@@ -529,10 +535,17 @@ for candidate in \
529
  BROWSER_EXECUTABLE_PATH="$candidate"
530
  break
531
  fi
 
 
 
532
  fi
533
  done
 
 
 
 
534
  if [ -z "$BROWSER_EXECUTABLE_PATH" ]; then
535
- echo "Warning: No real Chromium binary found. Browser plugin will be disabled."
536
  fi
537
 
538
  BROWSER_SHOULD_ENABLE=false
@@ -925,6 +938,13 @@ start_jupyter_once() {
925
  return 0
926
  fi
927
 
 
 
 
 
 
 
 
928
  # Security guard: refuse to start JupyterLab with the insecure default token.
929
  # JupyterLab exposes a full shell β€” a weak token is equivalent to no auth.
930
  if [ -z "${JUPYTER_TOKEN:-}" ] || [ "${JUPYTER_TOKEN}" = "huggingface" ]; then
 
93
  if hc_is_true "$DEV_MODE_NORMALIZED"; then
94
  DEV_MODE_ENABLED=true
95
  fi
96
+ # Auto-enable DEV_MODE when GATEWAY_TOKEN is set and DEV_MODE was not explicitly configured.
97
+ # GATEWAY_TOKEN doubles as JUPYTER_TOKEN (see start_jupyter_once) β€” no extra secret required.
98
+ if [ "$DEV_MODE_ENABLED" != "true" ] && [ -z "${DEV_MODE:-}" ] && [ -n "${GATEWAY_TOKEN:-}" ]; then
99
+ DEV_MODE_ENABLED=true
100
+ echo "GATEWAY_TOKEN set and DEV_MODE not explicitly configured β€” auto-enabling terminal (set DEV_MODE=false to opt out)"
101
+ fi
102
  SYNC_INTERVAL="$(trim_var "${SYNC_INTERVAL:-180}")"
103
  DEVDATA_DATASET_NAME="$(trim_var "${DEVDATA_DATASET_NAME:-huggingclaw-devdata}")"
104
  DEVDATA_SYNC_INTERVAL="$(trim_var "${DEVDATA_SYNC_INTERVAL:-180}")"
 
520
 
521
  # Browser configuration (managed local Chromium in HF/Docker)
522
  BROWSER_EXECUTABLE_PATH=""
523
+ BROWSER_WRAPPER_PATH=""
524
+ # On Debian/Ubuntu, /usr/bin/chromium is often a shell wrapper while the real
525
+ # ELF binary lives under /usr/lib/chromium/*. Prefer a real ELF binary, then
526
+ # fall back to wrapper launchers (Playwright/OpenClaw can execute those too).
527
  for candidate in \
528
  /usr/lib/chromium/chromium \
529
  /usr/lib/chromium-browser/chromium-browser \
 
535
  BROWSER_EXECUTABLE_PATH="$candidate"
536
  break
537
  fi
538
+ if [ -z "$BROWSER_WRAPPER_PATH" ]; then
539
+ BROWSER_WRAPPER_PATH="$candidate"
540
+ fi
541
  fi
542
  done
543
+ if [ -z "$BROWSER_EXECUTABLE_PATH" ] && [ -n "$BROWSER_WRAPPER_PATH" ]; then
544
+ BROWSER_EXECUTABLE_PATH="$BROWSER_WRAPPER_PATH"
545
+ echo "No ELF Chromium binary found; using launcher wrapper at $BROWSER_EXECUTABLE_PATH"
546
+ fi
547
  if [ -z "$BROWSER_EXECUTABLE_PATH" ]; then
548
+ echo "Warning: Chromium executable not found. Browser plugin will be disabled."
549
  fi
550
 
551
  BROWSER_SHOULD_ENABLE=false
 
938
  return 0
939
  fi
940
 
941
+ # GATEWAY_TOKEN fallback: if JUPYTER_TOKEN is unset or still the insecure default,
942
+ # reuse GATEWAY_TOKEN. Both protect the same Space, so the credential is equivalent.
943
+ if { [ -z "${JUPYTER_TOKEN:-}" ] || [ "${JUPYTER_TOKEN}" = "huggingface" ]; } && [ -n "${GATEWAY_TOKEN:-}" ]; then
944
+ JUPYTER_TOKEN="$GATEWAY_TOKEN"
945
+ echo "JUPYTER_TOKEN not set β€” using GATEWAY_TOKEN as terminal auth token"
946
+ fi
947
+
948
  # Security guard: refuse to start JupyterLab with the insecure default token.
949
  # JupyterLab exposes a full shell β€” a weak token is equivalent to no auth.
950
  if [ -z "${JUPYTER_TOKEN:-}" ] || [ "${JUPYTER_TOKEN}" = "huggingface" ]; then