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.47: 1.0.47: KiCad 10's Welcome to KiCad setup wizard no longer pops up. KiCad shows it in every editor start until kicad.json has system.first_run_shown true; cancelling the wizard does not set it and a force-closed KiCad never saves it, so on a machine the bridge drives it came back every time, in front of the user, and the bridge spent about 30 s per editor finding and cancelling it (open_board and open_schematic took 35 s instead of about 5 s on AdomLapper). Before starting any KiCad process, and only when none is running, the bridge now sets that one key, keeping every other; new installs are seeded with it.
1 file changed
+39−1
rust/crates/kicad-core/src/kicad_common.rs+39−1@@ -210,7 +210,7 @@ pub fn first_run_documents() -> Vec<(&'static str, Value)> { "kicad.json", json!({ "meta": {"filename": "kicad", "version": 0},- "system": {"check_for_kicad_updates": false},+ "system": {"check_for_kicad_updates": false, "first_run_shown": true}, "pcm": {"check_for_updates": false}, }), ),@@ -263,6 +263,29 @@ fn merge_into_pristine(path: &Path, seed: &Value) -> Result<bool, String> { Ok(true) } +/// KiCad 10 shows its "Welcome to KiCad" setup wizard in EVERY editor start until+/// `kicad.json` has `system.first_run_shown: true`. Cancelling the wizard does not set it, and+/// a force-closed KiCad never writes its settings, so on a box the bridge drives the flag stayed+/// false for good: every open paid ~30 s for the bridge to find and cancel the wizard, and the+/// user saw it pop up (AdomLapper, 2026-09-21). Set it, keeping every other key. Call ONLY while+/// no KiCad runs, or KiCad writes its in-memory false back on exit. Ok(true) = changed.+pub fn mark_first_run_done(config_dir: &Path) -> Result<bool, String> {+ let path = config_dir.join("kicad.json");+ let Ok(text) = std::fs::read_to_string(&path) else { return Ok(false) }; // no file: seed_first_run's job+ let mut doc: Value = serde_json::from_str(&text).map_err(|e| format!("{}: {e}", path.display()))?;+ if doc.pointer("/system/first_run_shown").and_then(Value::as_bool) == Some(true) {+ return Ok(false);+ }+ if !doc.get("system").is_some_and(Value::is_object) {+ doc["system"] = json!({});+ }+ doc["system"]["first_run_shown"] = json!(true);+ let tmp = path.with_extension("json.adom-tmp");+ std::fs::write(&tmp, serde_json::to_string_pretty(&doc).unwrap_or_default() + "\n").map_err(|e| e.to_string())?;+ std::fs::rename(&tmp, &path).map_err(|e| e.to_string())?;+ Ok(true)+}+ /// Seed the first-run settings files into a per-version config dir, each written ONLY /// if absent (never on a settings file the user already has). Creates the dir when /// missing. Never panics; failures land in `Seeded.errors`.@@ -319,6 +342,21 @@ mod tests { serde_json::from_str(&std::fs::read_to_string(p).unwrap()).unwrap() } + #[test]+ fn the_setup_wizard_flag_is_set_and_nothing_else_changes() {+ let t = tmp("wizard");+ let f = t.0.join("kicad.json");+ std::fs::write(&f, r#"{"meta":{"version":0},"system":{"first_run_shown":false,"check_for_kicad_updates":true},"pcm":{"x":1}}"#).unwrap();+ assert_eq!(mark_first_run_done(&t.0), Ok(true));+ let d = read_json(&f);+ assert_eq!(d["system"]["first_run_shown"], json!(true));+ assert_eq!(d["system"]["check_for_kicad_updates"], json!(true));+ assert_eq!(d["pcm"]["x"], json!(1));+ assert_eq!(mark_first_run_done(&t.0), Ok(false)); // already done: untouched+ let empty = tmp("wizard-none");+ assert_eq!(mark_first_run_done(&empty.0), Ok(false)); // no file: nothing to do+ }+ #[test] fn a_pristine_file_kicad_cli_wrote_is_merged_and_a_users_file_is_left_alone() { let t = tmp("pristine");