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
fuller web-control demo + fix duplicate Versioning
2 files changed
+45−41
README.md−2@@ -303,6 +303,4 @@ If you are reading this on the Adom wiki with Adom Bridge running, the **Overvie ## Versioning -## Versioning- This package version tracks the Adom Bridge release. The scaffold is small; the multi-MB binaries are fetched at install time with SHA256 verification (the manifest's `assets` map carries server-computed checksums per platform).
readme.html+45−39@@ -297,86 +297,92 @@ curl -s -X POST 127.0.0.1:24680/command \ </li> </ul> <h3>Try it live</h3>-<div id="abwc" style="font-family:system-ui,Segoe UI,sans-serif;border:1px solid #30363d;border-radius:10px;background:#0d1117;color:#e6edf3;padding:18px;max-width:820px">+<div id="abwc" style="font-family:system-ui,Segoe UI,sans-serif;border:1px solid #30363d;border-radius:10px;background:#0d1117;color:#e6edf3;padding:18px;max-width:860px"> <div style="display:flex;align-items:center;gap:10px;margin-bottom:6px"> <span id="abwc-dot" style="width:12px;height:12px;border-radius:50%;background:#484f58;display:inline-block"></span> <strong>Try Web Control (live)</strong> </div> <div style="font-size:12px;color:#8b949e;margin-bottom:12px">This runs against <code>http://127.0.0.1:24680</code> on <em>your</em> machine. If Adom Bridge is running, the buttons below reach it. Nothing changes your machine without a permission prompt you click.</div>- <div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px">- <button id="abwc-detect" style="padding:8px 14px;border-radius:6px;border:1px solid #30363d;background:#21262d;color:#e6edf3;cursor:pointer">Detect Adom Bridge</button>- <button id="abwc-status" style="padding:8px 14px;border-radius:6px;border:1px solid #30363d;background:#21262d;color:#e6edf3;cursor:pointer">Read status</button>- <button id="abwc-run" style="padding:8px 14px;border-radius:6px;border:1px solid #1f6feb;background:#1f6feb;color:#fff;cursor:pointer">Run a verb (asks your permission)</button>++ <div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px">+ <button id="abwc-detect" style="padding:8px 13px;border-radius:6px;border:1px solid #30363d;background:#21262d;color:#e6edf3;cursor:pointer">Detect Adom Bridge</button>+ <button id="abwc-status" style="padding:8px 13px;border-radius:6px;border:1px solid #30363d;background:#21262d;color:#e6edf3;cursor:pointer">Read status</button> </div>+ <div style="font-size:11px;color:#6e7681;margin-bottom:4px">Do something (each asks your permission):</div>+ <div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px">+ <button data-verb="desktop_screenshot_base64" data-args='{"maxWidth":760}' data-label="Screenshot my screen" class="abwc-do" style="padding:8px 13px;border-radius:6px;border:1px solid #1f6feb;background:#1f6feb;color:#fff;cursor:pointer">Screenshot my screen</button>+ <button data-verb="desktop_open_url" data-args='{"url":"https://wiki.adom.inc"}' data-label="Open a URL" class="abwc-do" style="padding:8px 13px;border-radius:6px;border:1px solid #30363d;background:#21262d;color:#e6edf3;cursor:pointer">Open a URL</button>+ <button data-verb="notify_user" data-args='{"title":"Hello from the web","body":"A web page asked Adom Bridge to notify you."}' data-label="Notify me" class="abwc-do" style="padding:8px 13px;border-radius:6px;border:1px solid #30363d;background:#21262d;color:#e6edf3;cursor:pointer">Notify me</button>+ <button data-verb="desktop_list_windows" data-args='{}' data-label="List open windows" class="abwc-do" style="padding:8px 13px;border-radius:6px;border:1px solid #30363d;background:#21262d;color:#e6edf3;cursor:pointer">List open windows</button>+ <button data-verb="kicad_open_symbol_editor" data-args='{}' data-label="Open KiCad" class="abwc-do" style="padding:8px 13px;border-radius:6px;border:1px solid #30363d;background:#21262d;color:#e6edf3;cursor:pointer">Open KiCad</button>+ </div>+ <div style="border:1px solid #21262d;border-radius:6px;padding:10px 12px;margin-bottom:12px;font-size:13px"> <div style="font-weight:600;margin-bottom:6px">Security mode</div> <label style="display:block;margin-bottom:4px;cursor:pointer"><input type="radio" name="abwc-mode" value="consent" checked> Consent only (the default): every request pops an Allow / Deny prompt in Adom Bridge.</label> <label style="display:block;cursor:pointer"><input type="radio" name="abwc-mode" value="handshake"> Handshake + consent: the page must also prove it is really the Adom wiki, acting as you, before the prompt appears.</label> <div id="abwc-mode-note" style="color:#8b949e;margin-top:8px;font-size:12px"></div> </div>- <pre id="abwc-log" style="background:#010409;border:1px solid #21262d;border-radius:6px;padding:12px;font-size:12px;max-height:320px;overflow:auto;white-space:pre-wrap;margin:0">Ready. Click "Detect Adom Bridge" to begin.</pre>++ <pre id="abwc-log" style="background:#010409;border:1px solid #21262d;border-radius:6px;padding:12px;font-size:12px;max-height:280px;overflow:auto;white-space:pre-wrap;margin:0">Ready. Click "Detect Adom Bridge" to begin.</pre>+ <img id="abwc-img" alt="" style="display:none;margin-top:10px;max-width:100%;border:1px solid #30363d;border-radius:6px" /> <script> (function () { var AB = "http://127.0.0.1:24680";- var log = document.getElementById("abwc-log"), dot = document.getElementById("abwc-dot"), note = document.getElementById("abwc-mode-note");+ var log = document.getElementById("abwc-log"), dot = document.getElementById("abwc-dot"),+ note = document.getElementById("abwc-mode-note"), img = document.getElementById("abwc-img"); function line(m){ log.textContent += " " + m; log.scrollTop = log.scrollHeight; }+ function reset(m){ log.textContent = m; img.style.display = "none"; } function mode(){ var r = document.querySelector('input[name="abwc-mode"]:checked'); return r ? r.value : "consent"; } function refreshNote(){ note.textContent = mode() === "handshake"- ? "In this mode a page must send a per-launch secret that Adom Bridge publishes only to YOUR Adom account key-value. Only wiki.adom.inc, signed in as you, can read it. This page (a plain frame) cannot, so if you have turned ON Settings > Web Control > \"Require wiki handshake\", the run below is refused BEFORE the prompt. That refusal is the point: a random site could not get past it either. It is off by default; turn it on for the stronger gate, and it could become the default later."- : "The default. Every request from a web page pops an Allow once / Allow 1 hr / Deny prompt in Adom Bridge. Nothing runs until you click.";+ ? "In this mode a page must send a per-launch secret that Adom Bridge publishes only to YOUR Adom account key-value. Only wiki.adom.inc, signed in as you, can read it. This page cannot, so if you turned ON Settings > Web Control > \"Require wiki handshake\", the actions below are refused BEFORE the prompt. That refusal is the point: a random site could not get past it either. It is off by default; it could become the default later."+ : "The default. Every request pops an Allow once / Allow 1 hr / Deny prompt in Adom Bridge. Nothing runs until you click."; } Array.prototype.forEach.call(document.querySelectorAll('input[name="abwc-mode"]'), function(el){ el.onchange = refreshNote; }); refreshNote(); document.getElementById("abwc-detect").onclick = function () {- log.textContent = "GET " + AB + "/health ...";+ reset("GET " + AB + "/health ..."); fetch(AB + "/health").then(function(r){return r.ok?r.json():Promise.reject("HTTP "+r.status);}) .then(function(j){ dot.style.background = j.service==="adom-bridge" ? "#00b8b0" : "#e6c86c"; line("RUNNING: " + JSON.stringify(j)); }) .catch(function(e){ dot.style.background = "#484f58"; line("Not reachable (" + e + "). Is Adom Bridge running on this machine?"); }); }; document.getElementById("abwc-status").onclick = function () {- log.textContent = "GET " + AB + "/status ...";+ reset("GET " + AB + "/status ..."); fetch(AB + "/status").then(function(r){return r.json();}).then(function(j){ var wc = (j && j.webControl) || {}; line("Web Control enabled: " + wc.enabled + " | requireHandshake: " + wc.requireHandshake + " | gate: " + wc.commandGate); }).catch(function(e){ line("failed: " + e); }); };- document.getElementById("abwc-run").onclick = function () {- var m = mode();- log.textContent = "POST " + AB + "/command {bridge_list}" + (m === "handshake" ? " (handshake mode: no secret sent)" : "") + " ...";- var headers = { "Content-Type": "application/json" };- // A real wiki backend would read bridge.webcontrol for the signed-in user and add- // X-Adom-WebControl-Secret here. This demo frame cannot, on purpose.- fetch(AB + "/command", { method:"POST", headers: headers, body: JSON.stringify({ command:"bridge_list" }) })- .then(function(r){ return r.json().then(function(j){ return { status:r.status, body:j }; }); })- .then(function(res){- if (res.status === 200) { line("APPROVED and ran: " + JSON.stringify(res.body).slice(0, 400)); return; }- if (res.body && res.body.errorCode === "handshake_required") {- line("REFUSED (handshake_required): this page has no secret, so Adom Bridge refused BEFORE the prompt. In production, wiki.adom.inc's backend supplies the secret and only then does the Allow prompt appear. evil.com is stuck exactly here.");- return;- }- if (res.body && res.body.errorCode === "web_control_disabled") { line("Web Control is turned OFF in Adom Bridge > Settings."); return; }- line("Not approved (HTTP " + res.status + "): " + JSON.stringify(res.body));- })- .catch(function(e){ line("blocked before Adom Bridge answered: " + e); });- };+ Array.prototype.forEach.call(document.querySelectorAll(".abwc-do"), function (btn) {+ btn.onclick = function () {+ var verb = btn.getAttribute("data-verb"), label = btn.getAttribute("data-label");+ var args; try { args = JSON.parse(btn.getAttribute("data-args") || "{}"); } catch (e) { args = {}; }+ reset('"' + label + '": POST ' + AB + "/command {" + verb + "}" + (mode()==="handshake" ? " (handshake mode: no secret sent)" : " - Adom Bridge will ask YOU to approve ..."));+ fetch(AB + "/command", { method:"POST", headers:{ "Content-Type":"application/json" }, body: JSON.stringify({ command: verb, args: args }) })+ .then(function(r){ return r.json().then(function(j){ return { status:r.status, body:j }; }); })+ .then(function(res){+ if (res.body && res.body.errorCode === "handshake_required") { line("REFUSED (handshake_required): this page has no secret, so Adom Bridge refused BEFORE the prompt. On the real wiki, wiki.adom.inc's backend supplies it. evil.com is stuck exactly here."); return; }+ if (res.body && res.body.errorCode === "web_control_disabled") { line("Web Control is turned OFF in Adom Bridge > Settings."); return; }+ if (res.body && res.body.errorCode === "web_denied") { line("You clicked Deny (or the prompt timed out). Nothing ran."); return; }+ if (res.status !== 200) { line("Not approved (HTTP " + res.status + "): " + JSON.stringify(res.body).slice(0,300)); return; }+ // success+ if (res.body && res.body.image) { line("APPROVED. Captured " + res.body.width + "x" + res.body.height + "."); img.src = "data:image/png;base64," + res.body.image; img.style.display = "block"; return; }+ line("APPROVED and ran: " + JSON.stringify(res.body).slice(0, 400));+ })+ .catch(function(e){ line("blocked before Adom Bridge answered: " + e); });+ };+ }); })(); </script> </div> <h2>Versioning</h2>-<h2>Versioning</h2> <p>This package version tracks the Adom Bridge release. The scaffold is small; the multi-MB binaries are fetched at install time with SHA256 verification (the manifest's <code>assets</code> map carries server-computed checksums per platform).</p> <script>- // Report our height to the wiki so the sandboxed iframe sizes to content.- function reportHeight(){- var h = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);- parent.postMessage({ type: 'readme-height', height: h }, '*');- parent.postMessage({ readmeHeight: h }, '*');- }+ function reportHeight(){ var h = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight); parent.postMessage({ type: 'readme-height', height: h }, '*'); parent.postMessage({ readmeHeight: h }, '*'); } window.addEventListener('load', reportHeight); if (window.ResizeObserver) new ResizeObserver(reportHeight).observe(document.body);- setInterval(reportHeight, 1200);- reportHeight();+ setInterval(reportHeight, 1200); reportHeight(); </script> </body></html>