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.45: 1.0.45: the Adom taskbar badge always expires. It means Adom is controlling this app right now, so five minutes after the last verb that acts on KiCad every badge comes off, swept across every KiCad window (not only the ones this process remembers badging) and logged. A fresh bridge process also clears any badge a previous one left behind, since an update restarts the bridge and it forgets what it badged. Read-only polls never reset the clock.
4 files changed
+36−11
rust/Cargo.lock+3−3@@ -244,7 +244,7 @@ dependencies = [ [[package]] name = "kicad-bridge"-version = "1.0.44"+version = "1.0.45" dependencies = [ "kicad-core", "kicad-platform",@@ -255,7 +255,7 @@ dependencies = [ [[package]] name = "kicad-core"-version = "1.0.44"+version = "1.0.45" dependencies = [ "kicad-ipc-rs", "kicad-platform",@@ -281,7 +281,7 @@ dependencies = [ [[package]] name = "kicad-platform"-version = "1.0.44"+version = "1.0.45" dependencies = [ "serde", "serde_json",
rust/Cargo.toml+1−1@@ -3,7 +3,7 @@ resolver = "2" members = ["crates/*"] [workspace.package]-version = "1.0.44"+version = "1.0.45" edition = "2021" license = "MIT" publish = false
rust/crates/kicad-bridge/src/main.rs+1@@ -114,6 +114,7 @@ fn main() { kicad_platform::native().init_process(); kicad_platform::native().etiquette_start(); verbs_libraries::apply_background_guard();+ taskbar::boot_sweep(); // The white taskbar icon (kicad_taskbar_repair): KiCad's own AUMID onto its standalone // shortcuts, once per boot, off the request path. Idempotent and never fatal. std::thread::spawn(|| {
rust/crates/kicad-bridge/src/taskbar.rs+31−7@@ -153,6 +153,31 @@ fn clear_badge(h: u64) { with_badged(|b| b.remove(&h)); } +/// Take the badge off every KiCad window: the ones remembered plus everything listed now.+fn clear_all_badges() -> usize {+ let mut all: HashSet<u64> = kicad_hwnds().into_iter().collect();+ all.extend(with_badged(|b| b.iter().copied().collect::<Vec<_>>()).unwrap_or_default());+ let n = all.len();+ for h in all {+ clear_badge(h);+ }+ n+}++/// At bridge start nothing is being driven, but a previous bridge process (an update restarts it)+/// may have left badges it can no longer clear. Sweep once, off the boot path.+pub fn boot_sweep() {+ let _ = std::thread::Builder::new().name("kicad-taskbar-boot".into()).spawn(|| {+ std::thread::sleep(Duration::from_secs(4));+ if ab::available() && INFLIGHT.load(Ordering::SeqCst) == 0 && since_last_drive().is_none() {+ let n = clear_all_badges();+ if n > 0 {+ eprintln!("[taskbar] boot: cleared any badge a previous bridge process left on {n} KiCad window(s)");+ }+ }+ });+}+ /// Called after a settings write: the switch takes effect at once in both directions. pub fn settings_changed() { if !setting_bool("overlayBadges", true) {@@ -216,13 +241,12 @@ fn ticker() { } idle_ticks += 1; if since_last_drive().is_some_and(|d| d >= IDLE_CLEAR) {- let mut all: HashSet<u64> = kicad_hwnds().into_iter().collect();- all.extend(with_badged(|b| b.iter().copied().collect::<Vec<_>>()).unwrap_or_default());- let had = with_badged(|b| !b.is_empty()).unwrap_or(false);- if had {- for h in all {- clear_badge(h);- }+ // A badge means "Adom is controlling this app RIGHT NOW" (John, 2026-09-21). Five minutes+ // with no verb acting on KiCad: every badge comes off. Sweep every KiCad window, not only+ // the ones this process remembers badging, so nothing is left behind.+ let n = clear_all_badges();+ if n > 0 {+ eprintln!("[taskbar] no KiCad verb for {} s: badge cleared on {n} window(s), KiCad is yours again", IDLE_CLEAR.as_secs()); } if idle_ticks > 5 { TICKER_ON.store(false, Ordering::SeqCst);