diff --git a/Cargo.lock b/Cargo.lock index c7208b0..f9ae3d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1320,6 +1320,7 @@ dependencies = [ "fieldcraft-parallel", "fieldcraft-render", "fieldcraft-solver", + "fieldcraft-update", "log", "png", "serde", diff --git a/THIRD-PARTY-LICENSES.txt b/THIRD-PARTY-LICENSES.txt index a04eee9..a576be9 100644 --- a/THIRD-PARTY-LICENSES.txt +++ b/THIRD-PARTY-LICENSES.txt @@ -1,6 +1,6 @@ Third-party software in FieldCraft -FieldCraft (the desktop app, fieldcraft-cli and the web app) is built from the 474 crates below. +FieldCraft (the desktop app, fieldcraft-cli and the web app) is built from the 477 crates below. Generated by `cargo xtask licences` from Cargo.lock and the crates' own licence files. FieldCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE. @@ -123,6 +123,7 @@ fastrand 2.5.0 (Apache-2.0 OR MIT) fax 0.2.7 (MIT) fdeflate 0.3.7 (MIT OR Apache-2.0) fearless_simd 0.4.1 (Apache-2.0 OR MIT) +filetime 0.2.29 (MIT/Apache-2.0) flate2 1.1.10 (MIT OR Apache-2.0) float-cmp 0.9.0 (MIT) foldhash 0.2.0 (Zlib) @@ -190,6 +191,7 @@ matext4cgmath 0.1.0 (Apache-2.0) memchr 2.8.3 (Unlicense OR MIT) memmap2 0.9.11 (MIT OR Apache-2.0) memoffset 0.9.1 (MIT) +minisign-verify 0.3.0 (MIT) miniz_oxide 0.8.9 (MIT OR Zlib OR Apache-2.0) miniz_oxide 0.9.1 (MIT OR Zlib OR Apache-2.0) moxcms 0.8.1 (BSD-3-Clause OR Apache-2.0) @@ -343,6 +345,7 @@ svgtypes 0.16.1 (Apache-2.0 OR MIT) syn 1.0.109 (MIT OR Apache-2.0) syn 2.0.119 (MIT OR Apache-2.0) syn 3.0.9 (MIT OR Apache-2.0) +tar 0.4.46 (MIT OR Apache-2.0) tempfile 3.27.0 (MIT OR Apache-2.0) termcolor 1.4.1 (Unlicense OR MIT) thiserror 1.0.69 (MIT OR Apache-2.0) @@ -781,21 +784,21 @@ ahash 0.8.12, arbitrary 1.5.0, arrayvec 0.7.8, async-channel 2.5.0, async-execut core-foundation 0.9.4, core-foundation-sys 0.8.7, core-graphics 0.23.2, core-graphics-types 0.1.3, crossbeam-deque 0.8.8, crossbeam-epoch 0.9.21, crossbeam-utils 0.8.23, data-url 0.3.2, derive_arbitrary 1.5.0, either 1.19.0, equivalent 1.0.2, errno 0.3.14, euclid 0.22.14, -event-listener 5.4.2, event-listener-strategy 0.5.4, fastrand 2.5.0, flate2 1.1.10, futures-lite -2.6.1, gethostname 1.1.0, glow 0.17.0, hashbrown 0.16.1, hashbrown 0.17.1, hermit-abi 0.5.3, -httparse 1.10.1, indexmap 2.14.2, itertools 0.13.0, itertools 0.15.0, js-sys 0.3.106, khronos-egl -6.0.0, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, lock_api 0.4.14, log 0.4.34, num-complex 0.4.6, -num-traits 0.2.19, once_cell 1.21.4, openssl-probe 0.2.1, ordered-stream 0.2.0, parking 2.2.1, -parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, plain 0.2.3, png -0.18.1, polling 3.11.0, pollster 0.4.0, pollster 1.0.1, rayon 1.12.0, rayon-core 1.13.0, -renderdoc-sys 1.1.0, robust 1.2.0, roxmltree 0.21.1, rustc-hash 1.1.0, rustix 0.38.44, rustix 1.1.5, -rustls 0.23.46, rustls-native-certs 0.8.5, scoped-tls 1.0.1, scopeguard 1.2.0, security-framework -3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, simd_cesu8 1.2.0, simplecss 0.2.2, -smallvec 1.16.3, smol_str 0.2.2, svgtypes 0.16.1, syn 1.0.109, tempfile 3.27.0, ttf-parser 0.25.1, -unicode-segmentation 1.13.3, unicode-width 0.2.2, uuid 1.28.0, wasi 0.11.1+wasi-snapshot-preview1, -wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.129, wasm-bindgen-futures 0.4.79, wasm-bindgen-macro -0.2.129, wasm-bindgen-macro-support 0.2.129, wasm-bindgen-shared 0.2.129, web-sys 0.3.106, weezl -0.1.12, wit-bindgen 0.57.1 +event-listener 5.4.2, event-listener-strategy 0.5.4, fastrand 2.5.0, filetime 0.2.29, flate2 1.1.10, +futures-lite 2.6.1, gethostname 1.1.0, glow 0.17.0, hashbrown 0.16.1, hashbrown 0.17.1, hermit-abi +0.5.3, httparse 1.10.1, indexmap 2.14.2, itertools 0.13.0, itertools 0.15.0, js-sys 0.3.106, +khronos-egl 6.0.0, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, lock_api 0.4.14, log 0.4.34, +num-complex 0.4.6, num-traits 0.2.19, once_cell 1.21.4, openssl-probe 0.2.1, ordered-stream 0.2.0, +parking 2.2.1, parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, +plain 0.2.3, png 0.18.1, polling 3.11.0, pollster 0.4.0, pollster 1.0.1, rayon 1.12.0, rayon-core +1.13.0, renderdoc-sys 1.1.0, robust 1.2.0, roxmltree 0.21.1, rustc-hash 1.1.0, rustix 0.38.44, +rustix 1.1.5, rustls 0.23.46, rustls-native-certs 0.8.5, scoped-tls 1.0.1, scopeguard 1.2.0, +security-framework 3.7.0, security-framework-sys 2.17.0, signal-hook-registry 1.4.8, simd_cesu8 +1.2.0, simplecss 0.2.2, smallvec 1.16.3, smol_str 0.2.2, svgtypes 0.16.1, syn 1.0.109, tar 0.4.46, +tempfile 3.27.0, ttf-parser 0.25.1, unicode-segmentation 1.13.3, unicode-width 0.2.2, uuid 1.28.0, +wasi 0.11.1+wasi-snapshot-preview1, wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.129, +wasm-bindgen-futures 0.4.79, wasm-bindgen-macro 0.2.129, wasm-bindgen-macro-support 0.2.129, +wasm-bindgen-shared 0.2.129, web-sys 0.3.106, weezl 0.1.12, wit-bindgen 0.57.1 ================================================================================ Apache License @@ -3154,9 +3157,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================================================ -cfg-if 1.0.5, js-sys 0.3.106, openssl-probe 0.2.1, scoped-tls 1.0.1, wasm-bindgen 0.2.129, -wasm-bindgen-futures 0.4.79, wasm-bindgen-macro 0.2.129, wasm-bindgen-macro-support 0.2.129, -wasm-bindgen-shared 0.2.129, web-sys 0.3.106 +cfg-if 1.0.5, filetime 0.2.29, js-sys 0.3.106, openssl-probe 0.2.1, scoped-tls 1.0.1, wasm-bindgen +0.2.129, wasm-bindgen-futures 0.4.79, wasm-bindgen-macro 0.2.129, wasm-bindgen-macro-support +0.2.129, wasm-bindgen-shared 0.2.129, web-sys 0.3.106 ================================================================================ Copyright (c) 2014 Alex Crichton @@ -8036,6 +8039,70 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +minisign-verify 0.3.0 +================================================================================ + +Copyright (c) 2019-2025 Frank Denis + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +-- + +Code in the src/crypto folder is derived from the rust-crypto project: +https://github.com/DaGenix/rust-crypto + +Original ISC license follows: + +Copyright (c) 2006-2009 Graydon Hoare +Copyright (c) 2009-2013 Mozilla Foundation + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ miniz_oxide 0.8.9, miniz_oxide 0.9.1 ================================================================================ @@ -11456,6 +11523,36 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +================================================================================ +tar 0.4.46 +================================================================================ + +Copyright (c) The tar-rs Project Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + ================================================================================ tempfile 3.27.0 ================================================================================ diff --git a/crates/engine/Cargo.toml b/crates/engine/Cargo.toml index f3d10e2..c0c3aae 100644 --- a/crates/engine/Cargo.toml +++ b/crates/engine/Cargo.toml @@ -25,6 +25,8 @@ serde = { workspace = true } serde_json = { workspace = true } thiserror = { workspace = true } log = { workspace = true } +# app.update.check (docs/updates.md); the browser build has no update check. +fieldcraft-update = { workspace = true } [dev-dependencies] png = { workspace = true } diff --git a/crates/engine/src/catalogue.rs b/crates/engine/src/catalogue.rs index 0b961ad..d4fd79a 100644 --- a/crates/engine/src/catalogue.rs +++ b/crates/engine/src/catalogue.rs @@ -597,7 +597,7 @@ pub static CATALOGUE: &[Capability] = &[ Tools, "Help", "Draft a GitHub bug report with the version, the OS and the last error; you review it, and nothing is sent until you submit it", - &["diagnostics.crash_reports", "diagnostics.crash_report", "diagnostics.crash_test"], + &["diagnostics.crash_reports", "diagnostics.crash_report", "diagnostics.crash_test", "app.update.check"], ), ]; diff --git a/crates/engine/src/cmd/forms.rs b/crates/engine/src/cmd/forms.rs index 9359c38..c1f03b7 100644 --- a/crates/engine/src/cmd/forms.rs +++ b/crates/engine/src/cmd/forms.rs @@ -1716,6 +1716,7 @@ mod tests { const STATE: &[&str] = &[ "open a design first", + "update checks are off", "`boundary_conditions` or `loads`", "give one of", "is not an explicit", diff --git a/crates/engine/src/cmd/mod.rs b/crates/engine/src/cmd/mod.rs index ead6954..77fa861 100644 --- a/crates/engine/src/cmd/mod.rs +++ b/crates/engine/src/cmd/mod.rs @@ -25,6 +25,7 @@ pub(crate) mod seeds; pub(crate) mod solve; mod symmetry; mod tags; +pub mod update; pub(crate) mod view; use crate::schema::ProblemKind; @@ -158,6 +159,7 @@ pub static ALL: &[CommandSpec] = &[ diagnostics::CRASH_REPORT, diagnostics::BUG_REPORT, diagnostics::CRASH_TEST, + update::CHECK, ]; /// The problem with required parameter `key`: [`ProblemKind::Required`] when it is left out, diff --git a/crates/engine/src/cmd/update.rs b/crates/engine/src/cmd/update.rs new file mode 100644 index 0000000..debfd5f --- /dev/null +++ b/crates/engine/src/cmd/update.rs @@ -0,0 +1,59 @@ +//! `app.update.check`: is a newer FieldCraft published? The same check as the desktop app's +//! Help › Check for Updates and `fieldcraft-cli update --check` (docs/updates.md). It only +//! reports: nothing is downloaded or installed, and no dialog opens. +//! +//! Checking reaches the network, so it is switched on only by the programs that may +//! ([`enable_checks`]: the desktop app and the CLI); everywhere else (tests, scratch sessions, +//! the browser) the command refuses without asking anything. + +use std::sync::atomic::{AtomicBool, Ordering}; + +use serde_json::Value; + +use crate::{CommandKind, CommandSpec, EngineError, Result, Session}; + +pub const CHECK: CommandSpec = CommandSpec { + id: "app.update.check", + label: "Check for Updates", + params: r#"{} — asks GitHub Releases for the latest published FieldCraft release and compares it with this version: current, latest, newer, url (its page and release notes), published, signed (whether it can be verified and installed from the app) and asset (the file this install would download; null when it cannot update itself). Reports only: nothing is downloaded or installed. Desktop app and fieldcraft-cli only"#, + form: Some(&[]), + kind: CommandKind::Session, + requires: &[], + run: check, +}; + +static ENABLED: AtomicBool = AtomicBool::new(false); + +/// Let `app.update.check` reach the release server (the desktop app and the CLI do). +pub fn enable_checks(on: bool) { + ENABLED.store(on, Ordering::SeqCst); +} + +#[cfg(target_arch = "wasm32")] +fn check(_: &mut Session, _: &Value) -> Result { + Err(EngineError::Params("not in the browser: the web app offers Reload to update when a new version is deployed".into())) +} + +#[cfg(not(target_arch = "wasm32"))] +fn check(_: &mut Session, _: &Value) -> Result { + if !ENABLED.load(Ordering::SeqCst) { + return Err(EngineError::Params("update checks are off in this session (the desktop app and fieldcraft-cli check for updates)".into())); + } + let check = fieldcraft_update::net::Client::from_env().check().map_err(|e| EngineError::Params(e.to_string()))?; + let asset = fieldcraft_update::install::here().asset_name(&check.latest.version, std::env::consts::ARCH); + Ok(check.to_json(asset.as_deref())) +} + +#[cfg(test)] +mod tests { + use serde_json::json; + + use super::*; + + /// Off unless a program switches it on: tests and scratch sessions never reach the network. + #[test] + fn checks_are_off_unless_enabled() { + let e = Session::default().execute("app.update.check", &json!({})).unwrap_err(); + assert!(e.to_string().contains("update checks are off"), "{e}"); + } +} diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index b9bb7ab..69523e0 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -21,6 +21,7 @@ pub mod logfile; pub use cmd::analytic_surfaces; pub use cmd::replace::{MESHERS, Replacement, replacement}; +pub use cmd::update::enable_checks as enable_update_checks; pub use fieldcraft_io::{Item as ViewItem, ItemKind}; pub mod history; pub mod progress; diff --git a/docs/features.md b/docs/features.md index e71c60c..13889b0 100644 --- a/docs/features.md +++ b/docs/features.md @@ -163,4 +163,4 @@ the control channel and AI agents over MCP (docs/mcp.md) run the same commands. | View | Show All — Show every item hidden in the viewport (hide, show and isolate items from the browser) | ready | `view.show_all`, (`view.hide`), (`view.show`), (`view.isolate`) | | History | Undo — Undo the last command that changed the model | ready | `edit.undo` | | History | Redo — Redo the command undone last | ready | `edit.redo` | -| Help | Report a Bug — Draft a GitHub bug report with the version, the OS and the last error; you review it, and nothing is sent until you submit it | ready | `diagnostics.bug_report`, `diagnostics.crash_reports`, `diagnostics.crash_report`, `diagnostics.crash_test` | +| Help | Report a Bug — Draft a GitHub bug report with the version, the OS and the last error; you review it, and nothing is sent until you submit it | ready | `diagnostics.bug_report`, `diagnostics.crash_reports`, `diagnostics.crash_report`, `diagnostics.crash_test`, `app.update.check` |