From 923911ae1deff5890551d24a67c098a5c38c3760 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Tue, 26 May 2026 07:58:40 -0500 Subject: [PATCH] fix: use semver comparison for version-update hint Replaced naive with parse_semver tuple comparison so dev builds (e.g. "0.8.46-pre") don't trigger false update hints. Falls back to string compare when either side is non-semver. Caught by Gemini Code Assist review on PR #2181. --- crates/tui/src/tui/ui.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/tui/src/tui/ui.rs b/crates/tui/src/tui/ui.rs index 552f302b..316bbd34 100644 --- a/crates/tui/src/tui/ui.rs +++ b/crates/tui/src/tui/ui.rs @@ -916,7 +916,14 @@ async fn run_event_loop( let json: serde_json::Value = resp.json().await.ok()?; let tag = json["tag_name"].as_str()?; let latest = tag.trim_start_matches('v'); - if latest != current { + // Compare semver so dev builds (e.g. "0.8.46-pre") don't + // trigger false hints. Falls back to string compare on + // unparseable versions. + let newer = match (parse_semver(latest), parse_semver(¤t)) { + (Some(l), Some(c)) => l > c, + _ => latest != current, + }; + if newer { Some(format!( "v{latest} available — run `codewhale update` and restart" )) @@ -7984,5 +7991,15 @@ fn extract_reasoning_header(text: &str) -> Option { } } +/// Parse a `major.minor.patch` version string into a comparable tuple. +/// Returns `None` on any parse failure (non-semver, dev suffixes, etc.). +fn parse_semver(v: &str) -> Option<(u32, u32, u32)> { + let mut parts = v.splitn(3, '.'); + let major = parts.next()?.parse::().ok()?; + let minor = parts.next()?.parse::().ok()?; + let patch = parts.next().unwrap_or("0").parse::().ok()?; + Some((major, minor, patch)) +} + #[cfg(test)] mod tests;