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
demo: every surface card now shows a live progress bar - poll verb derived from the show verb's namespace, so a bridge that ships <prefix>_progress animates with no per-app code
1 file changed
+45
web-control-demo.html+45@@ -829,12 +829,57 @@ for (const w of mine) { // cfg.pickTitle: render just the one window this surface is about. // cfg.fallback {cmd,args}: retried when the primary verb is unknown (a not-yet- // shipped show verb degrades to today's open verb instead of a dead button).+ // Live progress for a surface open, using the SAME canonical renderer as the+ // demo cards. Opening a symbol / board / 3D view is a 30-60s job, so a card+ // that shows only a text log leaves the user with no sense of how far along it+ // is - the exact gap the measured-progress contract exists to close.+ //+ // The poll verb is DERIVED from the show verb's namespace+ // (kicad_show_symbol -> kicad_progress), so any bridge that ships one gets a+ // bar here with no per-app code, and one that does not (fusion today, which+ // has only fusion_demo_progress) simply keeps the text log: the poll 404s and+ // is ignored. That is the generic-renderer rule applied to the demo itself.+ //+ // It polls ALONGSIDE the slow verb rather than after it, for the usual reason:+ // the show verb's own response cannot animate anything, because it does not+ // arrive until the work is already done.+ function startSurfaceProgress(c, showCmd) {+ var prefix = String(showCmd || "").split("_")[0];+ if (!prefix) return;+ var pollCmd = prefix + "_progress";+ c._lastShotKey = null;+ (function tick() {+ // The card disables its button for the whole run and re-enables it on+ // EVERY exit path, so that flag is the one stop condition that cannot+ // leave this loop polling forever.+ if (!c.btn.disabled) return;+ postVerb(pollCmd, {}).then(function (res) {+ if (!c.btn.disabled) return;+ var block = readProgressBlock(res.j);+ if (block) {+ renderProgressBlock(c.card, block);+ var ss = readStepShot(block);+ var img = ss && (ss.image || ss.base64);+ if (img) {+ var key = (ss.step || "") + "|" + (ss.title || "") + "|" + String(img).length;+ if (key !== c._lastShotKey) {+ c._lastShotKey = key;+ addShot(c.card, img, "step: " + (ss.step || ss.title || "step"));+ }+ }+ }+ setTimeout(tick, 1000);+ }).catch(function () { setTimeout(tick, 1500); });+ })();+ }+ function showSurface(c, cfg) { c.btn.disabled = true; cardLog(c.card).textContent = ""; var sb = c.card.querySelector("div.shots"); if (sb) sb.innerHTML = ""; setRes(c.res, "pending", "asking permission (choose “Allow 1 hr”) ...", "on " + esc(selfLabel()) + " - " + (cfg.note || "opens in the background, then we screenshot it")); clog(c, "Target machine: " + selfLabel());+ startSurfaceProgress(c, cfg.showCmd); var staged = cfg.stage ? cfg.stage(c) : Promise.resolve(); staged.then(function () { var args = (typeof cfg.showArgs === "function") ? cfg.showArgs() : (cfg.showArgs || {});