app
Adom Bridge
Public Made by Adomby adom
Adom Bridge unleashes your AI onto your full PC: full power, full safety. The AI breaks out of the container it runs in and onto your real machine, managing and running your entire laptop as you: launch apps, move files, drive any window, control KiCad, Fusion 360 or your real signed-in browser. Works with any AI, cloud or local (Claude Desktop, Claude Code, Codex), no Hydrogen required. Bridge and its bridges are an operating system for AI, with managed Node and Python runtimes, and a human-onl
← Commit history
web-control-demo.html+23−8@@ -177,10 +177,25 @@ for (const w of mine) { var SANDBOXED = !location.origin || location.origin === "null"; function sandboxWarn() { document.getElementById("sandbox-warn").style.display = "block"; } if (SANDBOXED) sandboxWarn(); - // Any fetch that dies with the browser's opaque TypeError (CSP block, no - // listener, mixed-content) escalates the banner too - the single most - // common cause is the sandboxed-embed case above. - function fetchDied(e) { if (/failed to fetch|networkerror/i.test(String(e))) sandboxWarn(); } + // A dead fetch means the SANDBOX banner ONLY when we actually are sandboxed. + // In a real tab the same TypeError is a network transient (ab restarting, a + // stale keep-alive socket after a reboot) - showing the null-origin banner + // there was a lie John caught on 2026-08-17. Real-tab failures are handled + // by the one-shot POST retry in postRaw below. + function fetchDied(e) { if (SANDBOXED && /failed to fetch|networkerror/i.test(String(e))) sandboxWarn(); } + // Chrome auto-retries a GET on a stale reused connection but NEVER a POST - + // so one dead keep-alive socket makes exactly one button fail instantly. + // Retry a network-failed POST once after 600ms; a repeat failure is real. + function postRaw(body) { + var doFetch = function () { + return fetch(AB + "/command", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); + }; + return doFetch().catch(function (e) { + if (SANDBOXED || !/failed to fetch|networkerror/i.test(String(e))) throw e; + logLine(" (network drop - retrying the POST once)"); + return new Promise(function (r) { setTimeout(r, 600); }).then(doFetch); + }); + } function logLine(m) { log.textContent += "\n" + m; log.scrollTop = log.scrollHeight; } function chosenTarget() { return sel.value || null; } // WHO is "this machine": ab 2.0.53+ reports its relay client name at @@ -253,9 +268,9 @@ for (const w of mine) { if (target === undefined) target = chosenTarget(); if (target) body.target = target; if (target) { body.args = body.args || {}; if (!body.args.caller) body.args.caller = { aiThread: "web-control demo page", containerName: selfLabel() }; } var who = machineLabel(target || null); - setRes(el, "pending", "asking permission...", "on " + esc(who) + " - approve the Adom Bridge toast"); + setRes(el, "pending", "asking permission...", "on " + esc(who) + " - approve the Adom Bridge toast (no banner? Windows may have tucked it in the notification center - press Win+N)"); logLine("POST /command " + JSON.stringify(body) + " [on " + who + "]"); - fetch(AB + "/command", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }) + postRaw(body) .then(function (r) { return r.json().then(function (j) { return { s: r.status, j: j }; }); }) .then(function (res) { logLine(" <- HTTP " + res.s + " " + JSON.stringify(res.j).slice(0, 300)); @@ -263,7 +278,7 @@ for (const w of mine) { else if (res.j && res.j.errorCode === "web_control_disabled") setRes(el, "err", "Refused: web control OFF", "re-enable in Settings → Web Control"); else setRes(el, "err", "Not approved", ((res.j && (res.j.error || res.j.errorCode)) || ("HTTP " + res.s)) + " - missed the prompt? The toast waits in your notification center for 1 hour; Allow 1 hr there, then click again"); }) - .catch(function (e) { fetchDied(e); setRes(el, "err", "blocked", SANDBOXED ? "sandboxed embed blocks loopback - open http://127.0.0.1:24681 directly (see banner)" : String(e)); }); + .catch(function (e) { fetchDied(e); setRes(el, "err", "blocked", SANDBOXED ? "sandboxed embed blocks loopback - open http://127.0.0.1:24681 directly (see banner)" : "network drop to ab (stale connection or ab restarting) - retried once; click again in a moment. " + String(e)); }); } // POST that returns the flattened JSON. Optional target. function postVerb(command, args, target) { @@ -272,7 +287,7 @@ for (const w of mine) { // caller identity - name this page as the thread so the run is attributed. if (target) { body.args = body.args || {}; if (!body.args.caller) body.args.caller = { aiThread: "web-control demo page", containerName: selfLabel() }; } logLine("POST /command " + JSON.stringify(body)); - return fetch(AB + "/command", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }) + return postRaw(body) .then(function (r) { return r.json().then(function (j) { return { s: r.status, j: flat(j) }; }); }); } // Loopback self POST (the window array + per-window screenshots run on THIS machine).