← 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.

John Lauer ·189fe8e72b ·1mo ago ·parent 74d31d3
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");