← Commit history

Update 6 file(s)

John Lauer ·ac5bde17b5 ·1mo ago ·parent 5bcdf40
4 files changed +84−12
dashboard/kicad_dashboard.py+32−2
@@ -916,10 +916,40 @@ def main():         globals()["DEV_MODE"] = True      if cmd == "serve":-        if "--print-url" in argv:-            print(proxy_url(port), flush=True)+        # BIND FIRST. The old order printed the URL and only then tried to bind,+        # so a port clash advertised a URL nothing was listening on (wiki #43).         srv = ThreadingHTTPServer(("0.0.0.0", port), Handler)         srv.daemon_threads = True++        if "--print-url" in argv:+            # The Hydrogen dock contract (adom/hydrogen-dock-sdk): print the URL+            # and SELF-BACKGROUND, so the workspace exec returns promptly.+            # Hydrogen deliberately does not detach for us - it runs this step+            # synchronously, and a serve that stays in the foreground holds the+            # exec for its whole timeout, after which the process tree is KILLED+            # and the readiness probe finds nothing listening. That is the+            # "Waiting to answer" hang John measured on the Fusion button.+            #+            # The socket is already bound above, so by the time the parent+            # prints, the URL is genuinely reachable.+            url = proxy_url(port)+            if hasattr(os, "fork"):+                if os.fork() > 0:+                    print(url, flush=True)+                    os._exit(0)          # _exit: never run atexit / close the fd+                os.setsid()+                # Detach stdio or the exec's pipe stays open and it keeps waiting+                # on a command that has, as far as it can tell, not finished.+                _null = os.open(os.devnull, os.O_RDWR)+                for _fd in (0, 1, 2):+                    try:+                        os.dup2(_null, _fd)+                    except Exception:+                        pass+            else:+                # No fork (Windows): print and serve in the foreground. Honest+                # fallback - the dock runs this in a Linux container.+                print(url, flush=True)         log(f"kicad-dashboard {VERSION} serving on {port} (target={target or 'auto'})")         try:             srv.serve_forever()
dock.json+15−8
@@ -1,18 +1,25 @@ {   "dock_manifest": "1.1.0",-  "webview": { "title": "KiCad Dashboard", "favicon": "docs/img/dock-kicad.svg" },+  "webview": {+    "title": "KiCad Dashboard",+    "favicon": "docs/img/dock-kicad.svg"+  },   "launch": {     "mode": "container_command",     "console": "show",     "steps": [-      { "label": "Installing the KiCad bridge",+      {+        "label": "Installing the KiCad bridge",         "run": "adom-wiki pkg install adom/kicad-bridge",-        "skip_if": "command -v kicad-dashboard",-        "timeout_seconds": 180 },-      { "label": "Starting the KiCad Dashboard",-        "run": "kicad-dashboard serve --print-url",+        "skip_if": "sh -c 'PATH=\"$HOME/.local/bin:$PATH\"; command -v kicad-dashboard'",+        "timeout_seconds": 180+      },+      {+        "label": "Starting the KiCad Dashboard",+        "run": "sh -c 'PATH=\"$HOME/.local/bin:$PATH\"; exec kicad-dashboard serve --print-url'",         "await": "url",-        "timeout_seconds": 60 }+        "timeout_seconds": 60+      }     ],     "on_ready": "navigate_placeholder",     "ai": {@@ -23,4 +30,4 @@       "typed": false     }   }-}+}\ No newline at end of file
install.sh+32
@@ -12,4 +12,36 @@ cp -f "$H/skills/kicad-tour/tour_runner.py" "$D/kicad-tour/tour_runner.py" cp -f "$H/skills/kicad-bridge-hero/compose_hero.py" "$D/kicad-bridge-hero/compose_hero.py" cp -f "$H/skills/kicad-bridge-test/run_verb_tests.py" "$D/kicad-bridge-test/run_verb_tests.py" rm -rf "$D/adom-desktop-kicad-bridge"   # legacy install dir from pre-rename versions+# ---------------------------------------------------------------------------+# The DASHBOARD and its launcher (wiki issue #43, John).+#+# dock.json runs `kicad-dashboard serve --print-url`, and this package never+# installed that command - it only delivered skills. It looked fine from a+# developer container because a hand-written 104-byte wrapper pointing at a+# local dev clone happened to exist there, so `skip_if: command -v+# kicad-dashboard` reported SKIP on the maintainer's machine and RUN on every+# user's. Clicking KiCad in the dock died with exit 127.+#+# The page repo already ships the dashboard, so this installs what it carries.+APPDIR="$HOME/.local/share/adom/kicad-bridge"+BINDIR="$HOME/.local/bin"+mkdir -p "$APPDIR/dashboard/ui" "$BINDIR"+cp -f "$H/dashboard/kicad_dashboard.py" "$APPDIR/dashboard/kicad_dashboard.py"+for asset in index.html kicad-logo.png; do+  [ -f "$H/dashboard/ui/$asset" ] && cp -f "$H/dashboard/ui/$asset" "$APPDIR/dashboard/ui/$asset"+done++cat > "$BINDIR/kicad-dashboard" <<LAUNCHER+#!/usr/bin/env bash+# Installed by adom/kicad-bridge. Points at the INSTALLED dashboard, never a+# developer's working copy - that distinction is the whole of wiki issue #43.+exec python3 "$APPDIR/dashboard/kicad_dashboard.py" "\$@"+LAUNCHER+chmod +x "$BINDIR/kicad-dashboard"++case ":$PATH:" in+  *":$BINDIR:"*) ;;+  *) echo "[kicad-bridge] NOTE: $BINDIR is not on your PATH; the dock passes it explicitly." ;;+esac+echo "[kicad-bridge] dashboard installed -> $BINDIR/kicad-dashboard" echo "[kicad-bridge] skills installed."
package.json+5−2
@@ -1,6 +1,6 @@ {   "slug": "kicad-bridge",-  "version": "1.0.33",+  "version": "1.0.34",   "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": [@@ -36,6 +36,9 @@     "skills/kicad-bridge-hero/compose_hero.py",     "skills/kicad-bridge-test/SKILL.md",     "skills/kicad-bridge-test/run_verb_tests.py",-    "skills/kicad-bridge-background/SKILL.md"+    "skills/kicad-bridge-background/SKILL.md",+    "dashboard/kicad_dashboard.py",+    "dashboard/ui/index.html",+    "dashboard/ui/kicad-logo.png"   ] }\ No newline at end of file