← Commit history

0.9.278: Wiki #72: kicad_install_library handed a single-part .kicad_sym now returns singlePartFile:true plus a hint naming kicad_install_symbol {filePath}, on both the fresh and already-registered success paths; a real multi-symbol library gets no hint. The verb still does what it did (registers the file as its own library); it just stops being silent about the shared Adom library being untouched.

John Lauer ·bcbc9bd47d ·1mo ago ·parent d486f48
4 files changed +44−4
BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.9.277\ No newline at end of file+0.9.278\ No newline at end of file
SKILL.md+1
@@ -38,6 +38,7 @@ A fresh machine can be missing KiCad, or the reverse-bridge plugin auto-installs  - **Install scope is mandatory in silent mode.** KiCad 10's installer is NsisMultiUser: bare `/S` exits instantly with **`rc=666660`** ("invalid command-line parameters") and installs nothing. The bridge auto-picks the scope: **`/allusers`** when the Bridge process is elevated (installs to Program Files), else **`/currentuser`** (installs to `%LOCALAPPDATA%\Programs\KiCad` — **no admin, no UAC prompt at all**). Force it with `kicad_upgrade '{"scope":"user"}'` — that's your answer to *"install KiCad without a UAC prompt."* (Elevation note: on a VM/kiosk the Bridge process may already be elevated even though nobody clicked UAC — an elevated installer that launches the app hands down its admin token. `kicad_upgrade '{"diagnoseOnly":true}'` reports the real token/UAC facts.) - **Library installs work before KiCad's first launch.** `%APPDATA%/kicad/<ver>/` (the per-user lib tables) doesn't exist until KiCad's first GUI run, so `kicad_install_library`/`_footprint` used to fail *"config directory not found."* The bridge now bootstraps that config (seeding the lib tables from the install template) automatically — installs just work on a never-launched KiCad.+  - From 0.9.278: handed a single-part `.kicad_sym`, it still succeeds but returns `singlePartFile: true` and a hint naming `kicad_install_symbol {"filePath": ...}`, because that call registers the PART as its own library and leaves Adom untouched (wiki #72).  **GPU-less hosts (VM/RDP/server):** KiCad pops a blocking *"Could not use OpenGL"* dialog and the heavy editors may not render. The bridge auto-expires that dialog and switches KiCad to the Cairo software canvas — see **[kicad-interaction](skills/kicad-interaction/SKILL.md)** for the dialog/canvas details. 
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "kicad",   "displayName": "KiCad EDA",-  "version": "0.9.277",+  "version": "0.9.278",   "description": "Reverse bridge for KiCad \u2014 board/schematic introspection, lint via kicad-cli, plugin install, multi-instance probe, in-process DRC.",   "homepage": "https://wiki.adom.inc/adom/adom-bridge",   "author": "Adom Inc.",
handlers/install_library.py+41−2
@@ -276,6 +276,13 @@ def handle_install_library(kicad_info: dict, args: dict) -> dict:     if not lib_name:         lib_name = source.stem +    # Wiki #72: a caller who wants "put this part into the Adom library" often+    # reaches for install_library with a single-part .kicad_sym. This verb then+    # registers that PART as its own library and the shared Adom library stays+    # empty, and every call says ok. Say so on the success path and name the+    # right verb; do not refuse, because what this verb did is not wrong.+    wrong_tool = _single_part_hint(source, lib_name)+     type_config = LIB_TYPE_CONFIG.get(lib_type)     if not type_config:         return {@@ -342,7 +349,9 @@ def handle_install_library(kicad_info: dict, args: dict) -> dict:             "success": True,             "alreadyRegistered": True,             "output": f"Library '{lib_name}' already registered in {type_config['table_file']} (file refreshed at {dest}).",-            "_hint": "Library was already present — nothing to change. This is a successful no-op.",+            "_hint": "Library was already present — nothing to change. This is a successful no-op."+                     + (" " + wrong_tool["_hint"] if wrong_tool else ""),+            **(wrong_tool or {}),         }      table.add_library(entry)@@ -363,5 +372,35 @@ def handle_install_library(kicad_info: dict, args: dict) -> dict:             f".kicad_sym surprises in ~100ms — much faster than discovering a broken "             f"library inside the GUI later. Any KiCad windows already open need to be "             f"closed + reopened to pick up the new library entry (sym-lib-table is read at startup)."-        ),+        ) + ((" " + wrong_tool["_hint"]) if wrong_tool else ""),+        **(wrong_tool or {}),     }+++def _single_part_hint(source: Path, lib_name: str) -> dict | None:+    """Return {'singlePartFile', 'symbolNames', '_hint'} when `source` is one+    .kicad_sym holding a single symbol (or a symbol named after the file), the+    shape that means the caller wanted kicad_install_symbol. None otherwise."""+    try:+        if source.is_dir() or source.suffix.lower() != ".kicad_sym":+            return None+        from adom_library import list_symbols+        names = list_symbols(Path(source)) or []+    except Exception:+        return None+    if not names or len(names) > 3:+        return None+    if len(names) == 1 or lib_name in names:+        shown = ", ".join(names)+        return {+            "singlePartFile": True,+            "symbolNames": names,+            "_hint": (+                f"NOTE: this file holds {len(names)} symbol(s) ({shown}), so KiCad now has a whole "+                f"library named '{lib_name}' containing only that part, and the shared Adom library was NOT touched. "+                f"If you meant 'put this part into the Adom library', the verb is kicad_install_symbol "+                f"'{{\"filePath\":\"{str(source).replace(chr(92), '/')}\"}}' (then kicad_show_library Adom). "+                f"Both are valid; only one matches what a shared-library caller usually means."+            ),+        }+    return None