Engine: app.update.check reports whether a newer release is published (#231)

The same check as the app's Help › Check for Updates and fieldcraft-cli update --check: the
latest release, whether it is newer, its page, whether it is signed and the asset this install
would download. It only reports. Checking reaches the network, so only the desktop app and the
CLI switch it on; tests, scratch sessions and the browser build refuse without asking.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-15 01:48:30 -04:00
1 parent 8fe31545ea
commit 12487794a3
9 files changed
+184 -21

No files matched your search

Generated
+1
View File
@@ -1320,6 +1320,7 @@ dependencies = [
"fieldcraft-parallel",
"fieldcraft-render",
"fieldcraft-solver",
"fieldcraft-update",
"log",
"png",
"serde",
+116 -19
View File
@@ -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
================================================================================
+2
View File
@@ -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 }
+1 -1
View File
@@ -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"],
),
];
+1
View File
@@ -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",
+2
View File
@@ -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,
+59
View File
@@ -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<Value> {
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<Value> {
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}");
}
}
+1
View File
@@ -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;
+1 -1
View File
@@ -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` |