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: the Library card explains its leftover window (show_library loads no part by design, so the editor keeps whatever was open - a stale ADOM_MECHANICAL_PIN read as if the card had opened it), plus anonymous-first wiki fetch with a wiki_fetch fallback for private parts
1 file changed
+39−3
web-control-demo.html+39−3@@ -1445,8 +1445,44 @@ for (const w of mine) { }; } var PART = partFrom(PARTS[3]); // IN-S42ATR: small, fast, known-good default- function fetchPartText(f) { return fetch(PART.filesBase + f).then(function (r) { if (!r.ok) throw new Error("wiki fetch " + f + ": HTTP " + r.status); return r.text(); }); }- function fetchPartBytes(f) { return fetch(PART.filesBase + f).then(function (r) { if (!r.ok) throw new Error("wiki fetch " + f + ": HTTP " + r.status); return r.arrayBuffer(); }); }+ // ANONYMOUS FIRST, then ask ab to fetch it as the signed-in user.+ //+ // The browser has no Adom session for wiki.adom.inc, so a part page that is+ // PRIVATE to the user simply 404s here - which is what made 3 of the 10 picker+ // parts fail with a mystery "blocked" until the anonymous-vs-authenticated+ // difference was spotted. ab IS signed in, so wiki_fetch (ab 2.0.74) can read+ // it on the page's behalf.+ //+ // Anonymous stays the DEFAULT deliberately: the credential is used only for the+ // reads that actually need it, and the fallback pops the normal consent prompt+ // naming the URL, so nothing reads your private wiki without you saying yes.+ function wikiFetch(f, asBytes) {+ var url = PART.filesBase + f;+ return fetch(url).then(function (r) {+ if (r.ok) return asBytes ? r.arrayBuffer() : r.text();+ if (r.status !== 404 && r.status !== 403) throw new Error("wiki fetch " + f + ": HTTP " + r.status);+ // Private to this user: ask ab, which is signed in.+ return postSelf("wiki_fetch", { url: url }).then(function (res) {+ var j = res.j || {};+ if (!(res.s === 200 && j.success && j.base64)) {+ throw new Error("wiki fetch " + f + ": HTTP " + r.status + " anonymously" ++ (j.error ? ", and signed-in fetch said: " + j.error : "") );+ }+ var bin = atob(j.base64);+ if (!asBytes) {+ // base64 -> UTF-8 text+ var bytes = new Uint8Array(bin.length);+ for (var i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);+ return new TextDecoder("utf-8").decode(bytes);+ }+ var buf = new ArrayBuffer(bin.length), view = new Uint8Array(buf);+ for (var k = 0; k < bin.length; k++) view[k] = bin.charCodeAt(k);+ return buf;+ });+ });+ }+ function fetchPartText(f) { return wikiFetch(f, false); }+ function fetchPartBytes(f) { return wikiFetch(f, true); } function b64Text(s) { return btoa(unescape(encodeURIComponent(s))); } function b64Bytes(buf) { var u8 = new Uint8Array(buf), out = "", CH = 0x8000;@@ -1589,7 +1625,7 @@ for (const w of mine) { { label: function () { return "Symbol (" + PART.name + ")"; }, cmd: "kicad_show_symbol", args: function () { return { symbolName: PART.kicadSymbolName || PART.name, libraryName: PART.kicadLib }; }, stage: stageKicadPart, pick: "symbol editor", note: "installs the part from its wiki page, then shows JUST the symbol" }, { label: function () { return "Footprint (" + PART.name + ")"; }, cmd: "kicad_show_footprint", args: function () { return { footprintName: PART.name, library: PART.kicadLib }; }, stage: stageKicadPart, pick: "footprint editor", note: "just the land pattern: pads + courtyard" }, { label: function () { return "3D chip (" + PART.name + ")"; }, cmd: "kicad_show_3d_chip", args: function () { return { footprintName: PART.name, library: PART.kicadLib }; }, stage: stageKicadPart, pick: "3d viewer", note: "the part's STEP model on its footprint" },- { label: function () { return "Library (" + PART.name + " in '" + PART.kicadLib + "')"; }, cmd: "kicad_show_library", args: function () { return { libraryName: PART.kicadLib }; }, stage: stageKicadPart, pick: "symbol editor", note: "the library holding the symbol + footprint + 3D model" },+ { label: function () { return "Library (" + PART.name + " in '" + PART.kicadLib + "')"; }, cmd: "kicad_show_library", args: function () { return { libraryName: PART.kicadLib }; }, stage: stageKicadPart, pick: "symbol editor", note: "browses the library TREE - by design this verb loads NO part (kicad_show_library: \"no part loaded\"), so the editor window keeps showing whichever symbol was already open. A leftover name in the shot below is that, not this part." }, { label: function () { return "Schematic (just the " + PART.name + ")"; }, cmd: "kicad_show_schematic", args: function () { return { filePath: (PART.kicadProject || {}).schPath }; }, stage: stageKicadProject, pick: "schematic editor", note: "the generated single-component schematic (kicad_make_part_project)" }, { label: "2D board (part placed, tight edge cuts)", cmd: "kicad_show_2d_board", args: function () { return { filePath: (PART.kicadProject || {}).pcbPath }; }, stage: stageKicadProject, pick: "pcb editor", note: "the part-dominant board" }, { label: "3D board (real 3D body on the board)", cmd: "kicad_show_3d_board", args: function () { return { filePath: (PART.kicadProject || {}).pcbPath }; }, stage: stageKicadProject, pick: "3d viewer", note: "the populated board in 3D - the whole ladder underneath it" },