1guow commited on
Commit
819ac2c
·
verified ·
1 Parent(s): 96401d1

Create setup-hf-config.mjs

Browse files
Files changed (1) hide show
  1. setup-hf-config.mjs +121 -0
setup-hf-config.mjs ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ /**
3
+ * One-time setup for OpenClaw on Hugging Face Spaces.
4
+ * Runs at container startup; writes or merges openclaw.json from env (Secrets/Variables):
5
+ * - agents.defaults.model.primary from OPENCLAW_HF_DEFAULT_MODEL (default: DeepSeek-R1).
6
+ * - gateway.auth: OPENCLAW_GATEWAY_TOKEN (token) or OPENCLAW_GATEWAY_PASSWORD (password); token wins if both set.
7
+ * - gateway.controlUi.dangerouslyDisableDeviceAuth when auth is set (no device pairing in Spaces).
8
+ * - gateway.trustedProxies from OPENCLAW_GATEWAY_TRUSTED_PROXIES, or default HF proxy IPs so the UI works without extra config.
9
+ * - gateway.controlUi.allowedOrigins from OPENCLAW_CONTROL_UI_ALLOWED_ORIGINS (comma-separated origins).
10
+ * HF_TOKEN is read by the gateway at runtime; this script only writes the above into config.
11
+ */
12
+ import fs from "node:fs";
13
+ import path from "node:path";
14
+
15
+ const home = process.env.OPENCLAW_HOME || process.env.HOME || "/home/user";
16
+ const stateDir = path.join(home, ".openclaw");
17
+ const configPath = path.join(stateDir, "openclaw.json");
18
+
19
+ // Token: env var, or read from file if OPENCLAW_GATEWAY_TOKEN_FILE is set (for platforms that mount secrets as files)
20
+ function readGatewayToken() {
21
+ const fromEnv = process.env.OPENCLAW_GATEWAY_TOKEN?.trim();
22
+ if (fromEnv) return fromEnv;
23
+ const filePath = process.env.OPENCLAW_GATEWAY_TOKEN_FILE?.trim();
24
+ if (filePath && fs.existsSync(filePath)) {
25
+ try {
26
+ return fs.readFileSync(filePath, "utf-8").trim();
27
+ } catch {
28
+ return "";
29
+ }
30
+ }
31
+ return "";
32
+ }
33
+
34
+ const defaultModel =
35
+ process.env.OPENCLAW_HF_DEFAULT_MODEL?.trim() || "huggingface/deepseek-ai/DeepSeek-R1";
36
+ const gatewayToken = readGatewayToken();
37
+ const gatewayPassword = process.env.OPENCLAW_GATEWAY_PASSWORD?.trim();
38
+
39
+ // Trusted proxies: from env, or default HF Space proxy IPs so the Control UI works without setting OPENCLAW_GATEWAY_TRUSTED_PROXIES
40
+ const DEFAULT_HF_TRUSTED_PROXY_IPS = [
41
+ "10.16.4.123",
42
+ "10.16.34.155",
43
+ "10.20.1.9",
44
+ "10.20.1.222",
45
+ "10.20.26.157",
46
+ "10.20.31.87",
47
+ ];
48
+ const trustedProxiesRaw = process.env.OPENCLAW_GATEWAY_TRUSTED_PROXIES?.trim();
49
+ const trustedProxies =
50
+ trustedProxiesRaw && trustedProxiesRaw.length > 0
51
+ ? trustedProxiesRaw.split(",").map((s) => s.trim()).filter(Boolean)
52
+ : DEFAULT_HF_TRUSTED_PROXY_IPS;
53
+ // Comma-separated origins allowed for Control UI/WebSocket (e.g. https://your-space.hf.space)
54
+ const allowedOriginsRaw = process.env.OPENCLAW_CONTROL_UI_ALLOWED_ORIGINS?.trim();
55
+ const allowedOrigins = allowedOriginsRaw
56
+ ? allowedOriginsRaw.split(",").map((s) => s.trim()).filter(Boolean)
57
+ : [];
58
+
59
+ let config = {};
60
+ if (fs.existsSync(configPath)) {
61
+ try {
62
+ config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
63
+ } catch {
64
+ // keep config empty
65
+ }
66
+ }
67
+
68
+ if (!config.agents) config.agents = {};
69
+ if (!config.agents.defaults) config.agents.defaults = {};
70
+ if (!config.agents.defaults.model) config.agents.defaults.model = {};
71
+ config.agents.defaults.model.primary = defaultModel;
72
+
73
+ // Auth: token wins if both set; otherwise password
74
+ const useTokenAuth = Boolean(gatewayToken);
75
+ const usePasswordAuth = Boolean(gatewayPassword) && !useTokenAuth;
76
+ if (useTokenAuth || usePasswordAuth) {
77
+ if (!config.gateway) config.gateway = {};
78
+ if (!config.gateway.auth) config.gateway.auth = {};
79
+ if (useTokenAuth) {
80
+ config.gateway.auth.mode = "token";
81
+ config.gateway.auth.token = gatewayToken;
82
+ } else {
83
+ config.gateway.auth.mode = "password";
84
+ config.gateway.auth.password = gatewayPassword;
85
+ }
86
+ }
87
+ // So Control UI can connect with token/password only (no device pairing); Spaces have no CLI for approve.
88
+ if (useTokenAuth || usePasswordAuth) {
89
+ if (!config.gateway) config.gateway = {};
90
+ if (!config.gateway.controlUi) config.gateway.controlUi = {};
91
+ config.gateway.controlUi.dangerouslyDisableDeviceAuth = true;
92
+ }
93
+
94
+ // Always set trustedProxies (we have a default for HF so the Control UI works behind the HF proxy)
95
+ if (!config.gateway) config.gateway = {};
96
+ config.gateway.trustedProxies = trustedProxies;
97
+
98
+ if (allowedOrigins.length > 0) {
99
+ if (!config.gateway) config.gateway = {};
100
+ if (!config.gateway.controlUi) config.gateway.controlUi = {};
101
+ config.gateway.controlUi.allowedOrigins = allowedOrigins;
102
+ }
103
+
104
+ fs.mkdirSync(stateDir, { recursive: true });
105
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
106
+
107
+ // Startup log: confirm env was applied (check token_present=1 and auth=token so the UI can connect)
108
+ const authKind = useTokenAuth ? "token" : usePasswordAuth ? "password" : "none";
109
+ const parts = [
110
+ `token_present=${useTokenAuth ? "1" : "0"}`,
111
+ `password_present=${usePasswordAuth ? "1" : "0"}`,
112
+ `auth=${authKind}`,
113
+ `trustedProxies=${trustedProxies.length}`,
114
+ `allowedOrigins=${allowedOrigins.length}`,
115
+ ];
116
+ console.log(`[openclaw-hf-setup] ${parts.join(" ")} -> ${configPath}`);
117
+ if (authKind === "none") {
118
+ console.warn(
119
+ "[openclaw-hf-setup] No auth set. Add OPENCLAW_GATEWAY_TOKEN or OPENCLAW_GATEWAY_PASSWORD in Space Secrets, then restart.",
120
+ );
121
+ }