app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.
← Commit history
Publish 1.0.65
4 files changed
+28−15
dashboard/kicad_dashboard.py+1−1@@ -49,7 +49,7 @@ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path from urllib.parse import unquote, urlparse -VERSION = "2.2.6"+VERSION = "2.2.7" AI_THREAD = "kicad-dashboard" DEFAULT_PORT = 8931 UI_DIR = Path(__file__).resolve().parent / "ui"
dashboard/ui/index.html+25−12@@ -17,12 +17,15 @@ @font-face{font-family:'Satoshi';src:url('https://adom.inc/fonts/Satoshi-Regular.woff2') format('woff2');font-weight:400} @font-face{font-family:'Satoshi';src:url('https://adom.inc/fonts/Satoshi-Medium.woff2') format('woff2');font-weight:500} body{background:var(--bg);color:var(--text-body);font:15px/1.5 'Satoshi',sans-serif;min-height:100vh}-/* House scrollbar everywhere (scrollbars sub-skill): thin, transparent track, translucent pill, teal on hover. */-html{scrollbar-width:thin;scrollbar-color:rgba(139,148,158,.35) transparent}-::-webkit-scrollbar{width:8px;height:8px}+/* House scrollbar everywhere (scrollbars sub-skill, applied verbatim per the+ dock thread 2026-08-23: match the wiki's slim dark pill on every surface). */+*{scrollbar-width:thin;scrollbar-color:rgba(139,148,158,.38) transparent}+::-webkit-scrollbar{width:10px;height:10px} ::-webkit-scrollbar-track{background:transparent}-::-webkit-scrollbar-thumb{background:rgba(139,148,158,.35);border-radius:999px;border:2px solid transparent;background-clip:padding-box}-::-webkit-scrollbar-thumb:hover{background:var(--accent);background-clip:padding-box}+::-webkit-scrollbar-thumb{background:rgba(139,148,158,.32);border-radius:999px;border:2px solid transparent;background-clip:padding-box}+::-webkit-scrollbar-thumb:hover{background:rgba(0,184,177,.55);background-clip:padding-box}+::-webkit-scrollbar-corner{background:transparent}+body{overflow-x:hidden} /* the page never scrolls horizontally */ header{height:44px;display:flex;align-items:center;gap:12px;padding:0 16px;background:var(--surface);border-bottom:1px solid var(--border)} .brand{display:flex;align-items:center;gap:8px;font-family:'Familjen Grotesk',sans-serif;font-weight:600;color:var(--accent);white-space:nowrap;cursor:default} .brand img{width:18px;height:18px;border-radius:4px;display:block}@@ -119,11 +122,7 @@ dialog.settings:focus{outline:none} .settings-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px 12px 18px;border-bottom:1px solid var(--border);cursor:move;user-select:none} .settings-head h2{margin:0;font:600 15px/1.3 var(--brand-heading);color:var(--text);display:flex;align-items:center;gap:10px} .settings-head .card-status{font-family:var(--brand-body)}-.settings-body{max-height:70vh;overflow:auto;padding:18px;scrollbar-width:thin;scrollbar-color:rgba(139,148,158,.35) transparent}-.settings-body::-webkit-scrollbar{width:8px}-.settings-body::-webkit-scrollbar-track{background:transparent}-.settings-body::-webkit-scrollbar-thumb{background:rgba(139,148,158,.35);border-radius:999px;border:2px solid transparent;background-clip:padding-box}-.settings-body::-webkit-scrollbar-thumb:hover{background:var(--accent);background-clip:padding-box}+.settings-body{max-height:70vh;overflow:auto;padding:18px;scrollbar-gutter:stable} .settings-card{background:var(--elevated);border:1px solid var(--border);border-left:3px solid color-mix(in srgb,var(--accent) 45%,transparent);border-radius:10px;padding:.9rem 1.1rem 1rem;margin-bottom:1rem} .card-title{font:600 13px/1.3 var(--brand-heading);color:var(--text);display:flex;align-items:center;gap:10px;margin:0 0 .45rem} .card-status{font-size:11px;color:var(--text-2);font-weight:400;font-family:var(--brand-body)}@@ -470,11 +469,25 @@ $('#btnPartTour').onclick=async()=>{ // is standing in. Copy-only until the dock thread lifts the park; the server // action and this button code stay, flip the flag to restore. const TRY_IT_PARKED=true; // still parks the SERVER staging path; the button below never calls it-async function copyText(txt){- try{await navigator.clipboard.writeText(txt);return true;}catch(e){}+function copyViaTextarea(txt){ try{const ta=document.createElement('textarea');ta.value=txt;ta.style.position='fixed';ta.style.opacity='0'; document.body.appendChild(ta);ta.select();const ok=document.execCommand('copy');ta.remove();return ok;}catch(e){return false;} }+async function copyText(txt){+ // In an UNFOCUSED window navigator.clipboard.writeText never settles+ // ("document is not focused") and would hang this click forever, so route+ // synchronously by hasFocus() and race the async API at 800ms anyway+ // (parts-search 1.1.2 finding, via the dock thread).+ if(!document.hasFocus())return copyViaTextarea(txt);+ try{+ const ok=await Promise.race([+ navigator.clipboard.writeText(txt).then(()=>true),+ new Promise(res=>setTimeout(()=>res('timeout'),800)),+ ]);+ if(ok===true)return true;+ }catch(e){}+ return copyViaTextarea(txt);+} async function buildSay(){ let phrases=[]; try{const r=await act('say');phrases=((r.data||r).phrases)||[];}catch(e){}
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "kicad-bridge",- "version": "1.0.64",+ "version": "1.0.65", "type": "app", "description": "Skills for your container so your AI knows how to drive the KiCad bridge. The bridge runtime itself is the release zip; Adom Bridge loads that.", "tags": [
page.json+1−1@@ -4,7 +4,7 @@ "slug": "kicad-bridge", "title": "KiCad - the KiCad Bridge", "brief": "Reference implementation of the KiCad bridge — multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.",- "version": "1.0.64",+ "version": "1.0.65", "tags": [ "kicad", "pcb",