← Commit history

0.9.341: Release-day fixes: stock library path resolution (#80), screenshot_all sizeKB (#81), readiness re-detect (#82), routing DRC completeness (PR 82), verified source pushes (#79), full verb-test coverage (#78)

John Lauer ·f8dadf890f ·1mo ago ·parent ea38b79
2 files changed +27−5
kicad_detect.py+8−5
@@ -516,7 +516,7 @@ def _parse_lib_table_entries(table_path: Path) -> list[dict]:     return entries  -def _resolve_kicad_var(uri: str, version: str) -> Path:+def _resolve_kicad_var(uri: str, version: str, base_dir: str | None = None) -> Path:     """Resolve KiCad path variables in a library URI. KiCad uses     `${VAR_NAME}` syntax for things like `${KICAD_USER_TEMPLATE_DIR}`,     `${KIPRJMOD}`, `${KICAD9_FOOTPRINT_DIR}`, etc.@@ -528,12 +528,15 @@ def _resolve_kicad_var(uri: str, version: str) -> Path:     userprofile = os.environ.get("USERPROFILE", "")     documents = Path(userprofile) / "Documents" if userprofile else None     # Common KiCad path vars + their typical resolved values+    # The stock libraries live under the INSTALLED KiCad, which is not always+    # C:/Program Files (per-user installs sit in %LOCALAPPDATA%/Programs/KiCad).+    share = Path(base_dir) / "share" / "kicad" if base_dir else Path("C:/Program Files/KiCad") / version / "share" / "kicad"     substitutions = {-        "KICAD_USER_TEMPLATE_DIR": str(documents / "KiCad" / version) if documents else "",+        "KICAD_USER_TEMPLATE_DIR": str(documents / "KiCad" / version / "template") if documents else "",         "KICAD_3RD_PARTY": str(Path(os.environ.get("APPDATA", "")) / "kicad" / version / "3rdparty") if os.environ.get("APPDATA") else "",-        f"KICAD{version.split('.')[0]}_SYMBOL_DIR": str(Path("C:/Program Files/KiCad") / version / "share" / "kicad" / "symbols"),-        f"KICAD{version.split('.')[0]}_FOOTPRINT_DIR": str(Path("C:/Program Files/KiCad") / version / "share" / "kicad" / "footprints"),-        f"KICAD{version.split('.')[0]}_3DMODEL_DIR": str(Path("C:/Program Files/KiCad") / version / "share" / "kicad" / "3dmodels"),+        f"KICAD{version.split('.')[0]}_SYMBOL_DIR": str(share / "symbols"),+        f"KICAD{version.split('.')[0]}_FOOTPRINT_DIR": str(share / "footprints"),+        f"KICAD{version.split('.')[0]}_3DMODEL_DIR": str(share / "3dmodels"),     }     resolved = uri     for var, val in substitutions.items():
server.py+19
@@ -258,6 +258,7 @@ def _handle_list_versions(kicad_info: dict, args: dict) -> dict:     Returns: {success, versions:[full info dict + default flag], default,               activeVersion, count, runningInstances, _hint}     """+    _refresh_versions_if_stale()     if not all_kicad_versions:         return {             "success": True,@@ -298,6 +299,23 @@ def _handle_list_versions(kicad_info: dict, args: dict) -> dict:     }  +def _refresh_versions_if_stale() -> bool:+    """Re-detect when the startup cache names a kicad.exe that no longer exists+    (issue #82: KiCad uninstalled while the bridge ran kept readiness at+    detected:true until a bridge restart). Cheap: one stat per cached version,+    a full re-detect only when something is gone. Returns True if refreshed."""+    global all_kicad_versions+    stale = [v for v in all_kicad_versions+             if v.get("kicad_exe") and not os.path.isfile(str(v["kicad_exe"]))]+    if not stale:+        return False+    try:+        all_kicad_versions = detect_all_kicad_versions() or []+    except Exception:+        all_kicad_versions = [v for v in all_kicad_versions if v not in stale]+    return True++ def _handle_readiness(kicad_info: dict, args: dict) -> dict:     """Read-only readiness probe — 'is the KiCad host app present?' @@ -310,6 +328,7 @@ def _handle_readiness(kicad_info: dict, args: dict) -> dict:     for "what EDA tools do I have" across all bridges use the Bridge-level     `bridge_readiness`.     """+    _refresh_versions_if_stale()     detected = bool(all_kicad_versions)     default_version = all_kicad_versions[0]["version"] if detected else None     versions = [