From b8f6e16ba5ec0c0952ff7d4dee8e56d90d849994 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 4 May 2026 03:05:39 -0700 Subject: [PATCH] fix(update): order stable correction releases after base --- CHANGELOG.md | 1 + src/infra/update-check.test.ts | 6 ++++++ src/infra/update-check.ts | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf39f378425..1fd9f349799 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ Docs: https://docs.openclaw.ai - Plugins/commands: scope QQBot framework slash commands to the QQBot channel so `/bot-*` command handlers and native specs do not leak onto unrelated chat surfaces. Thanks @vincentkoc. - fix: harden backend message action gateway routing [AI]. (#76374) Thanks @pgondhi987. - Gate QQBot streaming command auth [AI]. (#76375) Thanks @pgondhi987. +- CLI/update: treat OpenClaw stable correction versions like `2026.5.3-1` as newer than their base stable release, so package updates no longer ask for downgrade confirmation. - Plugins/install: suppress dangerous-pattern scanner warnings for trusted official OpenClaw npm installs, so installing `@openclaw/discord` no longer prints credential-harvesting warnings for the official package. - Plugins/release: make the published npm runtime verifier reject blank `openclaw.runtimeExtensions` entries instead of treating them as absent and passing via inferred outputs. Thanks @vincentkoc. - Plugins/security: ignore inline and block comments when matching source-rule context in plugin install scans, so comment-only `fetch`/`post` references near environment defaults do not block clean plugins. Thanks @vincentkoc. diff --git a/src/infra/update-check.test.ts b/src/infra/update-check.test.ts index ebc5bd3de3c..b85c620ae0f 100644 --- a/src/infra/update-check.test.ts +++ b/src/infra/update-check.test.ts @@ -29,6 +29,12 @@ describe("compareSemverStrings", () => { expect(compareSemverStrings("1.0.0", "1.0.0.beta.1")).toBe(1); }); + it("treats OpenClaw stable correction releases as newer than their base release", () => { + expect(compareSemverStrings("2026.5.3", "2026.5.3-1")).toBe(-1); + expect(compareSemverStrings("2026.5.3-1", "2026.5.3")).toBe(1); + expect(compareSemverStrings("2026.5.3-2", "2026.5.3-1")).toBe(1); + }); + it("returns null for invalid inputs", () => { expect(compareSemverStrings("1.0", "1.0.0")).toBeNull(); expect(compareSemverStrings("latest", "1.0.0")).toBeNull(); diff --git a/src/infra/update-check.ts b/src/infra/update-check.ts index 806c349023d..bf13cbb9207 100644 --- a/src/infra/update-check.ts +++ b/src/infra/update-check.ts @@ -3,6 +3,7 @@ import path from "node:path"; import { runCommandWithTimeout } from "../process/exec.js"; import { fetchWithTimeout } from "../utils/fetch-timeout.js"; import { detectPackageManager as detectPackageManagerImpl } from "./detect-package-manager.js"; +import { compareOpenClawReleaseVersions } from "./npm-registry-spec.js"; import { compareComparableSemver, parseComparableSemver } from "./semver-compare.js"; import { channelToNpmTag, type UpdateChannel } from "./update-channels.js"; @@ -384,6 +385,12 @@ export async function resolveNpmChannelTag(params: { } export function compareSemverStrings(a: string | null, b: string | null): number | null { + if (a && b) { + const openClawReleaseCmp = compareOpenClawReleaseVersions(a, b); + if (openClawReleaseCmp != null) { + return openClawReleaseCmp; + } + } return compareComparableSemver( parseComparableSemver(a, { normalizeLegacyDotBeta: true }), parseComparableSemver(b, { normalizeLegacyDotBeta: true }),