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.31: NATIVE (Rust) build. 1.0.31: the foreground toast is debounced (foregroundToastMinutes setting, default 10, 0 = off); the on-screen caption on the driven box is unchanged.
1 file changed
+28
rust/crates/kicad-core/src/settings.rs+28@@ -19,6 +19,12 @@ pub fn defaults() -> Vec<(&'static str, Value)> { // the measured verb timings and suppresses the OS flash; flash leaves the // Windows attention flash alone; both; none. ("activityIndicator", json!("progress")),+ // A foreground the calling AI asked for (foreground:true with a reason) announces+ // itself with a toast, which ab mirrors to the user's other boxes. One toast per+ // this many minutes; later foregrounds inside the window keep only the 3 s+ // on-screen caption on the driven box. 0 turns the toast off (John, 2026-09-19:+ // one per verb "makes them more disruptive than you foregrounding kicad").+ ("foregroundToastMinutes", json!(10)), ] } @@ -64,6 +70,18 @@ pub fn coerce(key: &str, raw: &Value) -> Result<Value, String> { return Ok(json!(v)); } let default = defaults().into_iter().find(|(k, _)| *k == key).map(|(_, v)| v).unwrap_or(Value::Null);+ if default.is_number() {+ let n = match raw {+ Value::Number(n) => n.as_f64(),+ Value::String(t) => t.trim().parse::<f64>().ok(),+ Value::Bool(false) | Value::Null => Some(0.0),+ _ => None,+ };+ return match n {+ Some(f) if f.is_finite() && f >= 0.0 => Ok(json!((f.min(1440.0)).round() as u64)),+ _ => Err(format!("{key} must be a number of minutes, 0 or more (0 turns it off)")),+ };+ } if default.is_boolean() { return Ok(json!(match raw { Value::String(s) => matches!(s.trim().to_lowercase().as_str(), "1" | "true" | "on" | "yes"),@@ -182,4 +200,14 @@ mod tests { assert_eq!(d.get("overlayBadges"), Some(&json!(true))); assert_eq!(d.get("activityIndicator"), Some(&json!("progress"))); }++ #[test]+ fn foreground_toast_minutes_is_a_clamped_count() {+ assert_eq!(coerce("foregroundToastMinutes", &json!("15")).unwrap(), json!(15));+ assert_eq!(coerce("foregroundToastMinutes", &json!(0)).unwrap(), json!(0));+ assert_eq!(coerce("foregroundToastMinutes", &json!(false)).unwrap(), json!(0));+ assert_eq!(coerce("foregroundToastMinutes", &json!(99999)).unwrap(), json!(1440));+ assert!(coerce("foregroundToastMinutes", &json!(-5)).is_err());+ assert!(coerce("foregroundToastMinutes", &json!("soon")).is_err());+ } }