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
2.0.79: web-control demo gains the AI-thread card (named thread + staged prompt + measured bar + evidence)
1 file changed
+78
web-control-demo.html+78@@ -181,6 +181,19 @@ <div class="grp">Fusion surfaces - the SAME selected part (.lbr + .step from its page), one first-class verb per content type (fusion_show_*, v1.9.10+). Component surfaces stage the library automatically; design surfaces additionally need the part project staged (fusion-bridge #30).</div> <div class="cards" id="grp-fusion"></div> + <div class="grp">AI threads - hand a written prompt to the AI running in Hydrogen. The wiki composes the prompt; Adom Bridge opens a NAMED thread and stages it. It is left UNSENT by default: you read it and press enter. Evidence is a screenshot of the thread itself.</div>+ <div class="bar" id="ai-bar">+ <span>Thread name:</span>+ <input id="ai-name" type="text" value="wiki thread" style="width:170px" />+ <span>Prompt:</span>+ <input id="ai-prompt" type="text" style="flex:1;min-width:260px"+ value="Open the KiCad bridge page on the wiki and tell me what it does." />+ <label style="font-size:12px;display:flex;align-items:center;gap:4px">+ <input id="ai-submit" type="checkbox" /> send it (skip the human read)+ </label>+ </div>+ <div class="cards" id="grp-ai"></div>+ <div class="grp">Multi-machine - fan a verb across every connected computer</div> <div class="cards" id="grp-multi"></div> @@ -1918,6 +1931,71 @@ for (const w of mine) { }); }; });+ // ── AI thread card ────────────────────────────────────────────────────────+ // The whole point of the demo: a wiki page composes a prompt and hands it to+ // the AI on the user's machine. Same shape as the KiCad/Fusion cards - a slow+ // verb, a bar polled ALONGSIDE it, and a screenshot as the receipt.+ var cAi = card("grp-ai", "verb", "Open a named AI thread with this prompt");+ cAi.btn.onclick = function () {+ var name = (document.getElementById("ai-name").value || "").trim();+ var prompt = (document.getElementById("ai-prompt").value || "").trim();+ var submit = !!document.getElementById("ai-submit").checked;+ if (!prompt) { cAi.res.className = "res bad"; cAi.res.textContent = "type a prompt first"; return; }++ cAi.btn.disabled = true;+ cAi.res.className = "res run";+ cAi.res.textContent = submit ? "opening a thread and SENDING..." : "opening a thread, staging the prompt...";+ cardLog(cAi.card).textContent = "";+ shotsBox(cAi.card).innerHTML = "";+ clog(cAi, "opening a thread named " + JSON.stringify(name || "Untitled"));+ if (!submit) clog(cAi, "submit is OFF - the prompt waits in the composer for you");++ // Poll the fast companion WHILE the slow verb runs. Awaiting the slow call+ // first would collapse the bar to a single 100% frame.+ startSurfaceProgress(cAi, "ai_thread");++ postVerb("ai_thread", {+ prompt: prompt,+ name: name,+ submit: submit,+ tags: ["source:web-control"],+ reason: "A wiki page asked to open an AI thread with a written prompt"+ }).then(function (res) {+ var j = res.j || {};+ finishSurfaceBar(cAi);+ cAi.btn.disabled = false;+ if (!j.ok && !j.success) {+ cAi.res.className = "res bad";+ cAi.res.textContent = (j.errorCode || "failed") + ": " + String(j.error || "").slice(0, 160);+ if (j._hint) clog(cAi, "hint: " + j._hint);+ return;+ }+ cAi.res.className = "res ok";+ cAi.res.textContent = (j.submitted ? "sent to " : "staged in ") + (j.name || "thread")+ + " (" + (j.seconds || "?") + "s)";+ clog(cAi, "thread " + (j.tid || "?") + (j.lateAttach ? " (attached late)" : ""));+ // Say which surface the evidence came from. A whole-window grab instead of+ // the panel is still evidence, but the viewer deserves to know which they+ // are looking at rather than inferring it from the pixels.+ if (j.evidenceKind) clog(cAi, "evidence: " + j.evidenceKind);+ if (j.evidenceNote) clog(cAi, "note: " + j.evidenceNote);+ // The verb returns a PATH on the user's machine; read it back as base64 so+ // the page can actually show it (screenshot_base64 re-reads a prior shot).+ if (j.evidence) {+ postVerb("screenshot_base64", { path: j.evidence, maxWidth: 900 }).then(function (r2) {+ var b64 = (r2.j && (r2.j.image || (r2.j.data && r2.j.data.image))) || null;+ if (b64) addShot(cAi.card, b64, "AI thread (" + (j.evidenceKind || "capture") + ")");+ else clog(cAi, "evidence saved on the PC: " + j.evidence);+ }).catch(function () { clog(cAi, "evidence saved on the PC: " + j.evidence); });+ }+ }).catch(function (e) {+ finishSurfaceBar(cAi);+ cAi.btn.disabled = false;+ cAi.res.className = "res bad";+ cAi.res.textContent = "failed: " + e;+ });+ };+ var cKState = card("grp-kicad", "read", "Show KiCad state (every window)"); cKState.btn.onclick = function () { showSurface(cKState, { showCmd: "kicad_state", showArgs: { maxWidth: 900 }, stateCmd: "kicad_state", note: "captures every KiCad window as a screenshot" }); };