From 3e4b0d05052c64f489545ec4a8021fb2cc52f4aa Mon Sep 17 00:00:00 2001 From: zerone0x Date: Sun, 18 Jan 2026 00:31:20 +0800 Subject: [PATCH] fix(macos): parse semver patch correctly when version has prerelease suffix Strip prerelease (`-beta.1`) and build (`-4`) suffixes from the patch component before parsing as integer. Previously `2026.1.11-4` parsed to `patch: 0` because `Int("11-4")` returns nil; now correctly yields `patch: 11`. Fixes #1107 Co-Authored-By: Claude --- apps/macos/Sources/Clawdbot/GatewayEnvironment.swift | 6 ++++-- .../Tests/ClawdbotIPCTests/GatewayEnvironmentTests.swift | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/macos/Sources/Clawdbot/GatewayEnvironment.swift b/apps/macos/Sources/Clawdbot/GatewayEnvironment.swift index 1e7bfd98e..6560b1870 100644 --- a/apps/macos/Sources/Clawdbot/GatewayEnvironment.swift +++ b/apps/macos/Sources/Clawdbot/GatewayEnvironment.swift @@ -25,8 +25,10 @@ struct Semver: Comparable, CustomStringConvertible, Sendable { let major = Int(parts[0]), let minor = Int(parts[1]) else { return nil } - let patch = Int(parts[2]) ?? 0 - return Semver(major: major, minor: minor, patch: patch) + // Strip prerelease suffix (e.g., "11-4" → "11", "5-beta.1" → "5") + let patchRaw = String(parts[2]) + let patchNumeric = patchRaw.split { $0 == "-" || $0 == "+" }.first.flatMap { Int($0) } ?? 0 + return Semver(major: major, minor: minor, patch: patchNumeric) } func compatible(with required: Semver) -> Bool { diff --git a/apps/macos/Tests/ClawdbotIPCTests/GatewayEnvironmentTests.swift b/apps/macos/Tests/ClawdbotIPCTests/GatewayEnvironmentTests.swift index 20d5b5973..0c62bb031 100644 --- a/apps/macos/Tests/ClawdbotIPCTests/GatewayEnvironmentTests.swift +++ b/apps/macos/Tests/ClawdbotIPCTests/GatewayEnvironmentTests.swift @@ -6,7 +6,8 @@ import Testing @Test func semverParsesCommonForms() { #expect(Semver.parse("1.2.3") == Semver(major: 1, minor: 2, patch: 3)) #expect(Semver.parse("v2.0.0") == Semver(major: 2, minor: 0, patch: 0)) - #expect(Semver.parse("3.4.5-beta.1") == Semver(major: 3, minor: 4, patch: 0)) // patch drops trailing text + #expect(Semver.parse("3.4.5-beta.1") == Semver(major: 3, minor: 4, patch: 5)) // prerelease suffix stripped + #expect(Semver.parse("2026.1.11-4") == Semver(major: 2026, minor: 1, patch: 11)) // build suffix stripped #expect(Semver.parse(nil) == nil) #expect(Semver.parse("invalid") == nil) }