app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Drive your own KiCad from an AI, in the background: open every editor, read the whole board as data (the EDA Bridge Standard board model), stack-up, part heights, netlists, place, route, pour, DRC and exports.
← Commit history
1.0.36: 1.0.36: three more fixes from the full verb battery on a from-scratch Windows VM (KiCad 10.0.6). Stock libraries resolve on a fresh KiCad 10 install: its user sym-lib-table and fp-lib-table hold ONE row of type Table pointing at KiCad's template table, and the bridge only read the top level, so Device and every other stock library looked unregistered (kicad_list_symbols, kicad_sch_place_symbol and kicad_list_footprints now follow the nested table; the writers still never touch that row). kicad_open_symbol_editor and the other tree navigations wait for an editor that is busy loading libraries instead of giving up after 1.5 s. kicad_rescan_libraries gets the same foreground guard as the open verbs, so a footprint that finishes loading late no longer leaves the editor on top of the user's window.
4 files changed
+24−7
rust/Cargo.lock+3−3@@ -244,7 +244,7 @@ dependencies = [ [[package]] name = "kicad-bridge"-version = "1.0.35"+version = "1.0.36" dependencies = [ "kicad-core", "kicad-platform",@@ -255,7 +255,7 @@ dependencies = [ [[package]] name = "kicad-core"-version = "1.0.35"+version = "1.0.36" dependencies = [ "kicad-ipc-rs", "kicad-platform",@@ -281,7 +281,7 @@ dependencies = [ [[package]] name = "kicad-platform"-version = "1.0.35"+version = "1.0.36" dependencies = [ "serde", "serde_json",
rust/Cargo.toml+1−1@@ -3,7 +3,7 @@ resolver = "2" members = ["crates/*"] [workspace.package]-version = "1.0.35"+version = "1.0.36" edition = "2021" license = "MIT" publish = false
rust/crates/kicad-bridge/src/verbs_libraries.rs+1−1@@ -139,7 +139,7 @@ fn list_symbols(state: &mut State, args: &Value) -> Value { } } else { let table = match ctx.sym_lib_table() {- Some(t) => match LibTable::parse_file(&t) {+ Some(t) => match LibTable::parse_file_resolved(&t) { Ok(t) => Some(t), Err(e) => return json!({"success": false, "error": format!("Could not read sym-lib-table: {e}")}), },
rust/crates/kicad-bridge/src/verbs_windows.rs+19−2@@ -286,7 +286,9 @@ pub static VERBS: &[Verb] = &[ /// Verbs that may spawn or raise a KiCad window: they get the 5-round settle sweep and /// the foreground etiquette (server.py `_SPAWNS_WINDOW`, this group's members).-const SPAWNS_WINDOW: &[&str] = &["kicad_launch", "kicad_open_board", "kicad_open_schematic", "kicad_open_symbol_editor", "kicad_open_footprint_editor", "kicad_open_3d_viewer", "kicad_place_footprint"];+const SPAWNS_WINDOW: &[&str] = &["kicad_launch", "kicad_open_board", "kicad_open_schematic", "kicad_open_symbol_editor", "kicad_open_footprint_editor", "kicad_open_3d_viewer", "kicad_place_footprint",+ // loads a footprint into the editor, which KiCad may raise once the load finishes (a late raise on a slow box: winvm)+ "kicad_rescan_libraries"]; /// Verbs that touch no window at all (no sweep, no focus check). const NO_GUI: &[&str] = &["kicad_fix_keyboard", "kicad_enable_software_opengl"];@@ -1239,7 +1241,22 @@ fn navigate_tree(frame: u64, filter: &str, verify: Verify<'_>) -> (bool, Value, return (false, trace, mechanism); }; trace["editHwnd"] = json!(edit.hwnd);- match set_filter_text(edit.hwnd, filter) {+ let mut set = set_filter_text(edit.hwnd, filter);+ if let Err(e) = &set {+ // A slow box (2 cores, software rendering) spends many seconds loading every library the+ // first time an editor opens, and its UI thread answers nothing meanwhile: the text timed out+ // at 1.5 s and the verb gave up on a symbol that exists (winvm). Wait for the editor to answer+ // again, then set the text once more.+ steps.push(format!("filter text not accepted yet ({e}); waiting for the editor to become responsive"));+ let mut waited = 0;+ while waited < 40 && !native().responsive(frame, 500).unwrap_or(true) {+ sleep_ms(500);+ waited += 1;+ }+ sleep_ms(800);+ set = set_filter_text(edit.hwnd, filter);+ }+ match set { Ok(m) => { mechanism = m; steps.push(format!("filter text set via {m}"));