1<!doctype html> 2<html data-openclaw-control-ui-base-path="" data-openclaw-terminal-enabled="true" data-openclaw-control-ui-build-id="2026.9.7-release-c074824a27c9-2026-09-29T23-33-45.013Z-987738c52d34b655508e269302eef45d770c63ff77a096e6ee6ee2016233811d" lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta 6 name="viewport" 7 content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content" 8 /> 9 <title>OpenClaw Control</title> 10 <meta name="color-scheme" content="dark light" /> 11 <!-- These mirror the claw theme's --bg tokens for first paint; runtime theme application keeps them synchronized. --> 12 <meta name="theme-color" media="(prefers-color-scheme: light)" content="#faf9f7" /> 13 <meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0e1015" /> 14 <link rel="icon" type="image/svg+xml" href="/favicon.svg?v=2026.9.7-release-c074824a27c9-2026-09-29T23-33-45.013Z-987738c52d34b655508e269302eef45d770c63ff77a096e6ee6ee2016233811d" /> 15 <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png?v=2026.9.7-release-c074824a27c9-2026-09-29T23-33-45.013Z-987738c52d34b655508e269302eef45d770c63ff77a096e6ee6ee2016233811d" /> 16 <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=2026.9.7-release-c074824a27c9-2026-09-29T23-33-45.013Z-987738c52d34b655508e269302eef45d770c63ff77a096e6ee6ee2016233811d" /> 17 <link rel="manifest" href="/manifest.webmanifest?v=2026.9.7-release-c074824a27c9-2026-09-29T23-33-45.013Z-987738c52d34b655508e269302eef45d770c63ff77a096e6ee6ee2016233811d" crossorigin="use-credentials" /> 18
18<script data-cfasync="false"> 19 // Configure Zod before module evaluation so its JIT probe cannot violate strict CSP. 20 globalThis.__zod_globalConfig ??= {}; 21 globalThis.__zod_globalConfig.jitless = true; 22 23 (function () { 24 var THEMES = { 25 claw: 1, 26 knot: 1, 27 dash: 1, 28 absolutely: 1, 29 tide: 1, 30 beacon: 1, 31 phosphor: 1, 32 crt: 1, 33 manuscript: 1, 34 rose: 1, 35 miami: 1, 36 }; 37 var MODES = { system: 1, light: 1, dark: 1 }; 38 var LEGACY = { 39 dark: "claw:dark", 40 light: "claw:light", 41 openknot: "knot:dark", 42 fieldmanual: "dash:dark", 43 clawdash: "dash:light", 44 system: "claw:system", 45 }; 46 try { 47 var keys = Object.keys(localStorage); 48 var raw; 49 for (var i = 0; i < keys.length; i++) { 50 if (keys[i].indexOf("openclaw.control.settings.v1") === 0) { 51 raw = localStorage.getItem(keys[i]); 52 if (raw) break; 53 } 54 } 55 var s = raw ? JSON.parse(raw) : null; 56 var t = s && s.theme; 57 var m = s && s.themeMode; 58 if (typeof t !== "string") t = ""; 59 if (typeof m !== "string") m = ""; 60 var legacy = LEGACY[t]; 61 var theme = THEMES[t] ? t : legacy ? legacy.split(":")[0] : "claw"; 62 var mode = MODES[m] ? m : legacy ? legacy.split(":")[1] : "system"; 63 if (mode === "system") { 64 mode = window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"; 65 } 66 // family -> [dark, light] resolved names. Kept in lockstep with 67 // resolveTheme() in app/theme.ts and the files in public/themes. 68 var FAMILIES = { 69 knot: ["openknot", "openknot-light"], 70 dash: ["dash", "dash-light"], 71 absolutely: ["absolutely", "absolutely-light"], 72 tide: ["tide", "tide-light"], 73 beacon: ["beacon", "beacon-light"], 74 phosphor: ["phosphor", "phosphor-light"], 75 crt: ["crt", "crt-light"], 76 manuscript: ["manuscript", "manuscript-light"], 77 rose: ["rose", "rose-light"], 78 miami: ["miami", "miami-light"], 79 }; 80 var pair = FAMILIES[theme]; 81 var resolved = pair 82 ? pair[mode === "light" ? 1 : 0] 83 : mode === "light" 84 ? "light" 85 : "dark"; 86 if (pair) { 87 // Script-created links need explicit render blocking before first paint. 88 // The gateway stamps the mount prefix and asset version before this runs. 89 var base = 90 document.documentElement.getAttribute("data-openclaw-control-ui-base-path") || ""; 91 var buildId = document.documentElement.getAttribute( 92 "data-openclaw-control-ui-build-id", 93 ); 94 var version = buildId ? "?v=" + encodeURIComponent(buildId) : ""; 95 var palette = document.createElement("link"); 96 palette.rel = "stylesheet"; 97 palette.setAttribute("blocking", "render"); 98 palette.id = "openclaw-theme-palette-" + theme; 99 palette.onerror = function () { 100 palette.remove(); 101 }; 102 palette.href = base + "/themes/" + theme + ".css" + version; 103 document.head.appendChild(palette); 104 } 105 document.documentElement.setAttribute("data-theme", resolved); 106 var resolvedMode = resolved.includes("light") ? "light" : "dark"; 107 document.documentElement.setAttribute("data-theme-mode", resolvedMode); 108 // Plugin semantic styles select on [data-theme-resolved]; keep in lockstep. 109 document.documentElement.setAttribute("data-theme-resolved", resolvedMode); 110 } catch (e) {} 111 })(); 112 </script>
112 113 <style>html,body{min-height:100%}html{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;background:#0e1015}html[data-theme-mode=light]{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;background:#faf9f7}html[data-theme=openknot]{background:#080808}html[data-theme=openknot-light]{background:#f9f9fb}html[data-theme=dash]{background:#1a1210}html[data-theme=dash-light]{background:#f7f2ec}html[data-theme=absolutely]{background:#1c1c1a}html[data-theme=absolutely-light]{background:#faf9f5}html[data-theme=tide]{background:#10151b}html[data-theme=tide-light]{background:#f7f9fb}html[data-theme=beacon]{background:#000}html[data-theme=beacon-light]{background:#fff}html[data-theme=phosphor]{background:#0a0f0a}html[data-theme=phosphor-light]{background:#f4f7f4}html[data-theme=crt]{background:#090a09}html[data-theme=crt-light]{background:#f5f5f4}html[data-theme=manuscript]{background:#211e18}html[data-theme=manuscript-light]{background:#f6f1e4}html[data-theme=rose]{background:#191724}html[data-theme=rose-light]{background:#faf4ed}html[data-theme=miami]{background:#140f1e}html[data-theme=miami-light]{background:#f7f3f6}body{background:inherit;min-height:100%;color-scheme:inherit;margin:0}body.openclaw-mount-fallback-active{--mount-fallback-bg:var(--bg,#0e1015);--mount-fallback-card:var(--card,#161920);--mount-fallback-text:var(--text-strong,#f4f4f5);--mount-fallback-muted:var(--muted,#8b8b94);--mount-fallback-link:var(--link,#ff7070);--mount-fallback-ring:var(--ring,#ff5c5c);color:var(--mount-fallback-text);background:var(--mount-fallback-bg);font-family:var(--font-body,ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);-webkit-font-smoothing:antialiased;margin:0}body.openclaw-mount-fallback-active openclaw-app{display:none}.mount-fallback{box-sizing:border-box;height:100dvh;padding:max(24px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left));place-items:safe center;overflow-y:auto}.mount-fallback:not([hidden]){display:grid}.mount-fallback__panel{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--mount-fallback-text) 7%, transparent);background:var(--mount-fallback-card);width:min(100%,560px);box-shadow:var(--shadow-lg,0 12px 32px #0003);border-radius:20px;padding:32px}.mount-fallback__panel .mount-fallback__eyebrow{color:var(--mount-fallback-muted);letter-spacing:.08em;text-transform:uppercase;margin:0 0 16px;font-size:.78rem;font-weight:700}.mount-fallback__panel h1{color:inherit;letter-spacing:-.02em;margin:0;font-size:clamp(1.375rem,3vw,1.625rem);font-weight:650;line-height:1.25}.mount-fallback__panel p{color:var(--mount-fallback-muted);margin:12px 0 0;font-size:.9375rem;line-height:1.55}.mount-fallback__panel ul{color:var(--mount-fallback-muted);margin:18px 0 0;padding-left:1.2rem;font-size:.875rem;line-height:1.55}.mount-fallback__panel li+li{margin-top:8px}.mount-fallback__panel a{color:var(--mount-fallback-link);text-underline-offset:.18em;text-decoration-thickness:.08em}.mount-fallback__actions{flex-wrap:wrap;gap:10px;margin-top:24px;display:flex}.mount-fallback__button{appearance:none;min-height:44px;color:inherit;background:color-mix(in srgb, var(--mount-fallback-text) 8%, var(--mount-fallback-card));font:inherit;cursor:default;border:0;border-radius:10px;padding:10px 16px;font-size:.875rem;font-weight:600;line-height:1.4;transition:background .12s}@media (hover:hover){.mount-fallback__button:hover{background:color-mix(in srgb, var(--mount-fallback-text) 12%, var(--mount-fallback-card))}}.mount-fallback__button:active{background:color-mix(in srgb, var(--mount-fallback-text) 16%, var(--mount-fallback-card))}.mount-fallback__button--primary{color:var(--primary-foreground,#fff);background:var(--primary,#d13c3c)}.mount-fallback__button--primary:active{background:var(--primary-hover,#c22e2e)}@media (hover:hover){.mount-fallback__button--primary:hover{background:var(--primary-hover,#c22e2e)}}.mount-fallback__panel:focus{outline:none}.mount-fallback__button:focus-visible,.mount-fallback__panel a:focus-visible{outline:2px solid var(--mount-fallback-ring);outline-offset:3px}html[data-theme-mode=light] body.openclaw-mount-fallback-active{--mount-fallback-bg:var(--bg,#faf9f7);--mount-fallback-card:var(--card,#fff);--mount-fallback-text:var(--text-strong,#18181b);--mount-fallback-muted:var(--muted,#64646e);--mount-fallback-link:var(--link,#b91c1c);--mount-fallback-ring:var(--ring,#dc2626)}html[data-theme-mode=light] .mount-fallback__panel{box-shadow:var(--shadow-lg,0 12px 32px #0f172a14)}@media (width<=560px){.mount-fallback__panel{padding:24px}}@media (prefers-reduced-motion:reduce){.mount-fallback__button{transition:none}}</style> 114
114<script data-cfasync="false" type="module" crossorigin src="/assets/index-BLeYLjXu.js"></script>
114 115 <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-8BhlS34s.js"> 116 <link rel="modulepreload" crossorigin href="/assets/lit-runtime-DtunxUr3.js"> 117 <link rel="modulepreload" crossorigin href="/assets/gateway-runtime-DNbpoLUI.js"> 118 <link rel="modulepreload" crossorigin href="/assets/control-ui-core-DYDz4MXJ.js"> 119 <link rel="modulepreload" crossorigin href="/assets/control-ui-core-DP2O3q2k.js"> 120 <link rel="modulepreload" crossorigin href="/assets/control-ui-foundation-owRvZUKw.js"> 121 <link rel="stylesheet" crossorigin href="/assets/control-ui-core-D-VUH4Gq.css"> 122 </head> 123 <body> 124 <openclaw-app></openclaw-app> 125 <section 126 id="openclaw-mount-fallback" 127 class="mount-fallback" 128 data-openclaw-mount-timeout-ms="12000" 129 role="alert" 130 aria-labelledby="openclaw-mount-fallback-title" 131 hidden 132 > 133 <div class="mount-fallback__panel" tabindex="-1"> 134 <p class="mount-fallback__eyebrow">OpenClaw Control UI</p> 135 <h1 id="openclaw-mount-fallback-title">Control UI did not start</h1> 136 <p id="openclaw-mount-fallback-summary"> 137 The browser loaded the static page, but the app bundle did not start. The gateway may be 138 restarting, or this page may reference assets from a different OpenClaw version. 139 </p> 140 <ul> 141 <li>If startup fails, OpenClaw will retry the current app bundle automatically.</li> 142 <li>If this persists, reload or try a clean browser profile.</li> 143 <li> 144 See 145 <a 146 href="https://docs.openclaw.ai/web/control-ui#blank-control-ui-page" 147 target="_blank" 148 rel="noopener noreferrer" 149 >Control UI troubleshooting</a 150 >. 151 </li> 152 </ul> 153 <div class="mount-fallback__actions"> 154 <button 155 type="button" 156 id="openclaw-mount-retry" 157 class="mount-fallback__button mount-fallback__button--primary" 158 > 159 Try again 160 </button> 161 <button type="button" id="openclaw-mount-wait" class="mount-fallback__button"> 162 Keep waiting 163 </button> 164 </div> 165 </div> 166 </section> 167
167<script data-cfasync="false"> 168 (function () { 169 var app = document.querySelector("openclaw-app"); 170 var fallback = document.getElementById("openclaw-mount-fallback"); 171 if (!app || !fallback) return; 172 173 var panel = fallback.querySelector(".mount-fallback__panel"); 174 var title = document.getElementById("openclaw-mount-fallback-title"); 175 var summary = document.getElementById("openclaw-mount-fallback-summary"); 176 var failureSummary = summary.textContent; 177 var retry = document.getElementById("openclaw-mount-retry"); 178 var wait = document.getElementById("openclaw-mount-wait"); 179 var rawDelay = Number(fallback.getAttribute("data-openclaw-mount-timeout-ms")); 180 var delay = Number.isFinite(rawDelay) && rawDelay > 0 ? rawDelay : 12000; 181 var maxRecoveryAttempts = 6; 182 var timer; 183 var recoveryTimer; 184 var recoveryAttempt = 0; 185 var recoveryNavigation = false; 186 var appStarted = false; 187 var documentLoaded = document.readyState === "complete"; 188 var recoveryController; 189 190 // The recovery page cannot import the app's drag helper when its bundle failed. 191 fallback.addEventListener("mousedown", function (event) { 192 if (event.button !== 0 || event.defaultPrevented || event.target !== fallback) return; 193 var drag = window.webkit?.messageHandlers?.openclawWindowDrag; 194 if (!drag) return; 195 try { 196 drag.postMessage({ type: "window-drag" }); 197 event.preventDefault(); 198 } catch (e) {} 199 }); 200 201 try { 202 var initialUrl = new URL(window.location.href); 203 recoveryNavigation = initialUrl.searchParams.has("openclaw_mount_recovery"); 204 if (recoveryNavigation) { 205 initialUrl.searchParams.delete("openclaw_mount_recovery"); 206 window.history.replaceState(null, "", initialUrl.href); 207 } 208 } catch (e) {} 209 210 function hideFallback() { 211 fallback.hidden = true; 212 document.body.classList.remove("openclaw-mount-fallback-active"); 213 } 214 215 function setSummary(text) { 216 if (summary) summary.textContent = text; 217 } 218 219 function cancelRecovery() { 220 window.clearTimeout(recoveryTimer); 221 if (recoveryController) recoveryController.abort(); 222 recoveryController = undefined; 223 } 224 225 function scheduleRecovery() { 226 window.clearTimeout(recoveryTimer); 227 if (appStarted || recoveryAttempt >= maxRecoveryAttempts) return; 228 var retryDelay = Math.min(delay, 1000 * Math.pow(2, recoveryAttempt)); 229 recoveryTimer = window.setTimeout(retryCurrentDocument, retryDelay); 230 } 231 232 function finishRecoveryAttempt() { 233 recoveryController = undefined; 234 if (appStarted) return; 235 if (recoveryAttempt >= maxRecoveryAttempts) { 236 setSummary( 237 "The gateway is still unavailable. Try again, then check the troubleshooting guide if the problem persists.", 238 ); 239 return; 240 } 241 setSummary( 242 "The gateway is not reachable yet. OpenClaw will keep retrying while it restarts.", 243 ); 244 scheduleRecovery(); 245 } 246 247 function unregisterServiceWorkers() { 248 if (!navigator.serviceWorker?.getRegistrations) return; 249 // Recovery must not depend on a possibly broken worker. Navigations bypass it, 250 // so a reload can self-heal after the registrations are removed. 251 void navigator.serviceWorker 252 .getRegistrations() 253 .then(function (registrations) { 254 return Promise.all( 255 registrations.map(function (registration) { 256 return registration.unregister(); 257 }), 258 ); 259 }) 260 .catch(function () {}); 261 } 262 263 function retryCurrentDocument() { 264 if ( 265 appStarted || 266 recoveryController || 267 recoveryAttempt >= maxRecoveryAttempts || 268 typeof window.fetch !== "function" 269 ) 270 return; 271 var documentUrl = new URL(window.location.href); 272 if (recoveryNavigation) { 273 setSummary( 274 "A fresh page still could not start the Control UI. Try again, then check the troubleshooting guide if the problem persists.", 275 ); 276 return; 277 } 278 recoveryAttempt += 1; 279 documentUrl.searchParams.set("openclaw_mount_recovery", String(Date.now())); 280 var controller = new AbortController(); 281 recoveryController = controller; 282 var requestTimer = window.setTimeout(function () { 283 controller.abort(); 284 }, delay); 285 window 286 .fetch(documentUrl.href, { 287 cache: "no-store", 288 credentials: "same-origin", 289 signal: controller.signal, 290 }) 291 .then(function (response) { 292 if (!response.ok) throw new Error("gateway unavailable"); 293 if (!appStarted && recoveryController === controller) 294 window.location.replace(documentUrl.href); 295 }) 296 .catch(function () { 297 if (recoveryController !== controller) return; 298 unregisterServiceWorkers(); 299 finishRecoveryAttempt(); 300 }) 301 .finally(function () { 302 window.clearTimeout(requestTimer); 303 }); 304 } 305 306 function showFallback() { 307 if (appStarted) return; 308 title.textContent = documentLoaded 309 ? "Control UI did not start" 310 : "Control UI is still loading"; 311 fallback.setAttribute("role", documentLoaded ? "alert" : "status"); 312 setSummary( 313 documentLoaded 314 ? failureSummary 315 : "The browser is still loading the app. OpenClaw will keep waiting without interrupting the download.", 316 ); 317 if (documentLoaded) retryCurrentDocument(); 318 fallback.hidden = false;
319 document.body.classList.add("openclaw-mount-fallback-active"); 320 if (documentLoaded && panel && typeof panel.focus === "function") { 321 try { 322 panel.focus({ preventScroll: true }); 323 } catch (e) { 324 panel.focus(); 325 } 326 } 327 } 328 329 function armFallbackTimer() { 330 window.clearTimeout(timer); 331 timer = window.setTimeout(showFallback, delay); 332 } 333 334 armFallbackTimer(); 335 336 // Deferred module graphs settle before DOMContentLoaded. A slow download 337 // is not a failed bootstrap: replacing the document would cancel it. 338 document.addEventListener( 339 "DOMContentLoaded", 340 function () { 341 documentLoaded = true; 342 if (!fallback.hidden) showFallback(); 343 }, 344 { once: true }, 345 ); 346 347 window.addEventListener( 348 "openclaw-control-ui-rendered", 349 function () { 350 appStarted = true; 351 window.clearTimeout(timer); 352 cancelRecovery(); 353 hideFallback(); 354 }, 355 { once: true }, 356 ); 357 358 if (retry) { 359 retry.addEventListener("click", function () { 360 cancelRecovery(); 361 unregisterServiceWorkers(); 362 window.location.reload(); 363 }); 364 } 365 if (wait) { 366 wait.addEventListener("click", function () { 367 hideFallback(); 368 cancelRecovery(); 369 recoveryAttempt = 0; 370 armFallbackTimer(); 371 }); 372 } 373 })(); 374 </script>
374 375 </body> 376</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.