← Commit history

Publish 1.0.81

John Lauer ·11a493e6fc ·1mo ago ·parent d6b1407
4 files changed +32−5
dashboard/kicad_dashboard.py+13−1
@@ -49,7 +49,7 @@ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path from urllib.parse import unquote, urlparse -VERSION = "3.3.1"+VERSION = "3.4.0" AI_THREAD = "kicad-dashboard" DEFAULT_PORT = 8931 UI_DIR = Path(__file__).resolve().parent / "ui"@@ -111,6 +111,7 @@ def _hydrogen_control_url():         return None  +LAST_VIEWPORT = {} MIN_SHELL_VERSION = (1, 0, 142)   # the build that fixed the run-prompt kill  @@ -1158,6 +1159,8 @@ class Handler(BaseHTTPRequestHandler):                                                "application/octet-stream")             return self._send(200, mime, f.read_bytes(),                               {"Cache-Control": "no-cache"})+        if path.endswith("/api/viewport"):+            return self._json(LAST_VIEWPORT or {"note": "no page has reported a viewport yet"})         if path == "/console":             with _console_lock:                 return self._json({"lines": list(CONSOLE)})@@ -1213,6 +1216,15 @@ class Handler(BaseHTTPRequestHandler):             return self._json({"ok": True, "delivered": HUB.count(),                                "_hint": "delivered = live SSE viewers that showed it. "                                         "0 means nobody has the page open - open it first."})+        if path.endswith("/api/viewport"):+            # The page reports the width of the surface it actually rendered in.+            # Assumption is how the 760px breakpoint bug survived: John's dock+            # pane is 744px and nobody's test matrix included it.+            global LAST_VIEWPORT+            LAST_VIEWPORT = dict(body or {})+            LAST_VIEWPORT["at"] = time.strftime("%H:%M:%S")+            log(f"viewport {LAST_VIEWPORT.get('innerWidth')}px cols={LAST_VIEWPORT.get('panelCols')}")+            return self._json({"ok": True})         if path.endswith("/api/say-send"):             phrase = str((body or {}).get("phrase") or "").strip()             if not phrase:
dashboard/ui/index.html+17−2
@@ -86,9 +86,14 @@ main{margin:0;padding:20px 16px 84px}   color:var(--muted);font-size:18px;line-height:1;cursor:pointer} .panel-x:hover{color:var(--teal);border-color:var(--line);background:rgba(0,184,177,.08)} .panel-x:focus-visible{outline:2px solid var(--teal);outline-offset:2px}-.panel-cols{display:grid;grid-template-columns:220px 1fr;gap:24px;align-items:start;margin-top:14px}+.panel-cols{display:grid;grid-template-columns:minmax(180px,220px) 1fr;gap:24px;align-items:start;margin-top:14px} .panel-right{border-left:1px solid var(--line);padding-left:24px;min-width:0}-@media (max-width:760px){+/* 620px, NOT 760 (adom-ui-design 1.25.0). John's dock pane measures 744px,+   which sits BELOW 760, so the two-column panel never rendered in the pane it+   was designed for: the app looked compliant and every screenshot he saw was+   the collapsed fallback. A breakpoint bug is invisible to anyone whose test+   widths straddle it, so 744 is now in my matrix. */+@media (max-width:620px){   .panel-cols{grid-template-columns:1fr}   .panel-right{border-left:none;border-top:1px solid var(--line);padding-left:0;padding-top:16px} }@@ -1018,6 +1023,16 @@ $('#dtNext').onclick=()=>demoCtl('next'); $('#dtExit').onclick=()=>demoCtl('exit'); setMuteUI(); +// Measure, never assume: report the real viewport of whatever surface we are+// rendered in (ah webview pane, browser, iframe) back to our own server, so+// `GET /api/viewport` can prove which side of the breakpoint we landed on.+(function reportViewport(){+  const send=()=>{try{fetch('api/viewport',{method:'POST',headers:{'Content-Type':'application/json'},+    body:JSON.stringify({innerWidth:window.innerWidth,innerHeight:window.innerHeight,+      dpr:window.devicePixelRatio,twoCol:window.innerWidth>620,+      panelCols:getComputedStyle(document.querySelector('.panel-cols')||document.body).gridTemplateColumns})}).catch(()=>{});}catch(e){}};+  send();window.addEventListener('resize',()=>{clearTimeout(window.__vpT);window.__vpT=setTimeout(send,400);});+})(); renderSkeleton(); buildSay(); applyGraduation();
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "kicad-bridge",-  "version": "1.0.80",+  "version": "1.0.81",   "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.80",+  "version": "1.0.81",   "tags": [     "kicad",     "pcb",