wire/answer/release.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! Which version this city runs, and what each installation registry offers.
7//!
8//! **A reading of right now, never folded from the Ledger**, on the
9//! same grounds as `McpHealth` and `Toolkits` (`crates/wire/spec/Answer/McpHealth.lean`
10//! ยง8-34): which release is newest is a fact about this minute, and a
11//! recorded copy would still name last month's release as the newest
12//! one. It is also the reason this answer is never sent unasked - the
13//! city reaches the registry when somebody presses the button and at no
14//! other time.
15//!
16//! **Two renderings rather than the six numbers behind them.** A page
17//! draws `0.0.5-pre.260912` and `2026-09-12`; the arithmetic that
18//! decides which of two releases is newer is `kernel::Release`'s and
19//! stays there, so the client has nothing to get wrong and no second
20//! ordering rule to keep in step.
21
22use kernel::{AxError, ReleaseVerdict};
23use serde::{Deserialize, Serialize};
24
25/// One release, in the two spellings a person reads.
26#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
28pub struct ReleaseLine {
29 /// The registry's version spelling: dated npm semver or a bare crates.io version.
30 pub version: String,
31 /// The release date when the registry's spelling carries one; empty when unknown.
32 pub released: String,
33}
34
35/// Where this city stands against the release channel.
36///
37/// A comparison, an unreleased build, an origin requiring confirmation, or a refusal.
38/// The selected registry supplies both the displayed version and the comparison.
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(rename_all = "snake_case")]
41#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
42pub enum ReleaseAnswer {
43 /// This binary can be compared with its installation registry.
44 /// `newest` and `verdict` come from the registry this channel updates from.
45 Stands {
46 mine: ReleaseLine,
47 /// The exact registry version used for `verdict`, selected by the server.
48 newest: ReleaseLine,
49 registries: Vec<RegistryNewest>,
50 verdict: ReleaseVerdict,
51 update: UpdateHint,
52 },
53 /// This binary was built from a working tree, so it is none of the
54 /// published releases. Reporting it as out of date would be
55 /// answering about a binary the person is not running.
56 Unreleased {
57 registries: Vec<RegistryNewest>,
58 update: UpdateHint,
59 },
60 /// A published binary whose installation origin needs the person to confirm it.
61 Unconfirmed {
62 mine: ReleaseLine,
63 registries: Vec<RegistryNewest>,
64 update: UpdateHint,
65 },
66 /// The check could not be made. Carries why, because "could not
67 /// check" leaves a person believing they checked.
68 Refused { refusal: AxError },
69}
70
71/// What one registry said about the newest release
72/// (`crates/wire/spec/Answer/Release.lean` D24).
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
75pub struct RegistryNewest {
76 pub registry: Registry,
77 pub reading: RegistryReading,
78}
79
80/// A registry this project publishes to.
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
82#[serde(rename_all = "snake_case")]
83#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
84pub enum Registry {
85 Npm,
86 CratesIo,
87 Github,
88}
89
90/// What one registry answered.
91#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
92#[serde(rename_all = "snake_case")]
93#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
94pub enum RegistryReading {
95 Read { newest: ReleaseLine },
96 Refused { refusal: AxError },
97}
98
99/// How this binary was installed, which decides the command that
100/// updates it.
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
102#[serde(rename_all = "snake_case")]
103#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
104pub enum InstallChannel {
105 Npm,
106 Bun,
107 Binstall,
108 Unknown,
109 Package,
110 CargoOrBinstall,
111 Cargo,
112 Archive,
113 Aur,
114 Source,
115}
116
117/// The command a person runs to update, printed and never run: the
118/// channel that installed the binary owns updating it.
119#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
120#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
121pub struct UpdateHint {
122 pub channel: InstallChannel,
123 /// `None` for a binary built from source, which nothing updates.
124 pub command: Option<String>,
125 /// Exact commands requiring explicit choice when the path cannot identify an installer.
126 pub alternatives: Vec<String>,
127}