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: evidence is the FINAL frame only (in-progress shots showed the previous part and read as a wrong-part failure), and retry once when the bridge restarts KiCad to rebuild its cache
1 file changed
+45−4
web-control-demo.html+45−4@@ -828,8 +828,14 @@ for (const w of mine) { var ss = d.stepShot || (d.result && d.result.stepShot); if (ss && (ss.image || ss.base64)) { c._bridgeShots = true;- addShot(c.card, ss.image || ss.base64, "step: " + (ss.step || ss.title || d.stepLabel || "step"));- clog(c, " [proof] bridge evidence for \"" + (ss.step || ss.title || d.stepLabel) + "\"");+ // ⛔ Do NOT render an in-progress screenshot as evidence.+ // A step shot is the app MID-OPERATION, so it usually still shows the+ // PREVIOUS part - which reads as "you opened the wrong thing" even+ // when the final result is correct. John, 2026-08-20: "i keep+ // thinking you had it wrong, when possibly you didn't."+ // The step TEXT is kept because it is useful; only the misleading+ // picture is dropped. Evidence = the FINAL frame, nothing else.+ clog(c, " step: " + (ss.step || ss.title || d.stepLabel || "step")); } // Log + snap only on CHANGE - a 2.5s poll of a 30s step used to spam // the same line eight times.@@ -1009,7 +1015,8 @@ for (const w of mine) { 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"));+ // in-progress frame: log it, never render it (see note above)+ clog(c, " step: " + (ss.step || ss.title || "step")); } } }@@ -1258,7 +1265,8 @@ for (const w of mine) { 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 || label || "step"));+ // in-progress frame: log it, never render it (see note above)+ clog(c, " step: " + (ss.step || ss.title || label || "step")); } } }@@ -1606,6 +1614,39 @@ for (const w of mine) { var jj = r.j || {}; var ok = r.s === 200 && jj.success !== false && !jj.errorCode && !(typeof jj.error === "string" && jj.error.trim() !== "");+ // A KiCad restart is a SUCCESSFUL remedy that reports itself as a+ // failure. The bridge notices its footprint cache predates the part,+ // restarts KiCad, rebuilds the cache - and then runs out of time+ // waiting for the instance it just started, so the caller is told+ // "failed" about work that has already been done. Measured: the same+ // part that failed this way passed on a later call with no+ // intervention.+ //+ // So retry ONCE. "This will never work" and "this works in ten+ // seconds" need opposite responses, and only one of them should be+ // reported to a human as a broken library.+ // Asked kicad-bridge#44 for a retryable errorCode + retryAfterMs so+ // this can key on a field instead of on prose.+ var msg = ((jj.error || "") + " " + (jj._hint || "")).toLowerCase();+ var restarted = !ok && /cache predated|restarted kicad|ran out of time waiting/.test(msg);+ if (restarted && !st._retried) {+ st._retried = true;+ clog(c, " " + st.label + ": the bridge restarted KiCad to rebuild its cache and timed out waiting for it. That work is DONE, so retrying once ...");+ return new Promise(function (res2) { setTimeout(res2, 6000); }).then(function () {+ return postVerb(st.cmd, st.args()).then(function (r2) {+ var j2 = r2.j || {};+ var ok2 = r2.s === 200 && j2.success !== false && !j2.errorCode &&+ !(typeof j2.error === "string" && j2.error.trim() !== "");+ results.push({ label: st.label, ok: ok2, retried: true });+ if (!ok2) { clog(c, " " + st.label + " FAILED after the retry: " + (j2.error || j2.errorCode || ("HTTP " + r2.s))); return; }+ clog(c, " " + st.label + " opened on the retry (the restart had already fixed it)");+ return settleThenCapture(c, "kicad_state").then(function (sr) {+ if (!(sr.s === 200 && sr.j && appendPicked(c, sr.j, st.pick, st.label)))+ clog(c, " (" + st.label + " opened but no capture came back)");+ });+ });+ });+ } results.push({ label: st.label, ok: ok }); if (!ok) { clog(c, " " + st.label + " FAILED: " + (jj.error || jj.errorCode || ("HTTP " + r.s)));