mirror of https://github.com/openclaw/openclaw.git
135 lines
3.5 KiB
TypeScript
135 lines
3.5 KiB
TypeScript
import {
|
|
comparePrereleaseIdentifiers,
|
|
normalizeLegacyDotBetaVersion,
|
|
} from "../infra/semver-compare.js";
|
|
|
|
export type OpenClawVersion = {
|
|
major: number;
|
|
minor: number;
|
|
patch: number;
|
|
revision: number | null;
|
|
prerelease: string[] | null;
|
|
};
|
|
|
|
const VERSION_RE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/;
|
|
|
|
export function parseOpenClawVersion(raw: string | null | undefined): OpenClawVersion | null {
|
|
if (!raw) {
|
|
return null;
|
|
}
|
|
const normalized = normalizeLegacyDotBetaVersion(raw.trim());
|
|
const match = normalized.match(VERSION_RE);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
const [, major, minor, patch, suffix] = match;
|
|
const revision = suffix && /^[0-9]+$/.test(suffix) ? Number.parseInt(suffix, 10) : null;
|
|
return {
|
|
major: Number.parseInt(major, 10),
|
|
minor: Number.parseInt(minor, 10),
|
|
patch: Number.parseInt(patch, 10),
|
|
revision,
|
|
prerelease: suffix && revision == null ? suffix.split(".").filter(Boolean) : null,
|
|
};
|
|
}
|
|
|
|
export function normalizeOpenClawVersionBase(raw: string | null | undefined): string | null {
|
|
const parsed = parseOpenClawVersion(raw);
|
|
if (!parsed) {
|
|
return null;
|
|
}
|
|
return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
|
|
}
|
|
|
|
export function isSameOpenClawStableFamily(
|
|
a: string | null | undefined,
|
|
b: string | null | undefined,
|
|
): boolean {
|
|
const parsedA = parseOpenClawVersion(a);
|
|
const parsedB = parseOpenClawVersion(b);
|
|
if (!parsedA || !parsedB) {
|
|
return false;
|
|
}
|
|
if (parsedA.prerelease?.length || parsedB.prerelease?.length) {
|
|
return false;
|
|
}
|
|
return (
|
|
parsedA.major === parsedB.major &&
|
|
parsedA.minor === parsedB.minor &&
|
|
parsedA.patch === parsedB.patch
|
|
);
|
|
}
|
|
|
|
export function compareOpenClawVersions(
|
|
a: string | null | undefined,
|
|
b: string | null | undefined,
|
|
): number | null {
|
|
const parsedA = parseOpenClawVersion(a);
|
|
const parsedB = parseOpenClawVersion(b);
|
|
if (!parsedA || !parsedB) {
|
|
return null;
|
|
}
|
|
if (parsedA.major !== parsedB.major) {
|
|
return parsedA.major < parsedB.major ? -1 : 1;
|
|
}
|
|
if (parsedA.minor !== parsedB.minor) {
|
|
return parsedA.minor < parsedB.minor ? -1 : 1;
|
|
}
|
|
if (parsedA.patch !== parsedB.patch) {
|
|
return parsedA.patch < parsedB.patch ? -1 : 1;
|
|
}
|
|
|
|
const rankA = releaseRank(parsedA);
|
|
const rankB = releaseRank(parsedB);
|
|
if (rankA !== rankB) {
|
|
return rankA < rankB ? -1 : 1;
|
|
}
|
|
|
|
if (
|
|
parsedA.revision != null &&
|
|
parsedB.revision != null &&
|
|
parsedA.revision !== parsedB.revision
|
|
) {
|
|
return parsedA.revision < parsedB.revision ? -1 : 1;
|
|
}
|
|
|
|
if (parsedA.prerelease || parsedB.prerelease) {
|
|
return comparePrereleaseIdentifiers(parsedA.prerelease, parsedB.prerelease);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
export function shouldWarnOnTouchedVersion(
|
|
current: string | null | undefined,
|
|
touched: string | null | undefined,
|
|
): boolean {
|
|
const parsedCurrent = parseOpenClawVersion(current);
|
|
const parsedTouched = parseOpenClawVersion(touched);
|
|
if (
|
|
parsedCurrent &&
|
|
parsedTouched &&
|
|
parsedCurrent.major === parsedTouched.major &&
|
|
parsedCurrent.minor === parsedTouched.minor &&
|
|
parsedCurrent.patch === parsedTouched.patch &&
|
|
parsedTouched.revision != null
|
|
) {
|
|
return false;
|
|
}
|
|
if (isSameOpenClawStableFamily(current, touched)) {
|
|
return false;
|
|
}
|
|
const cmp = compareOpenClawVersions(current, touched);
|
|
return cmp !== null && cmp < 0;
|
|
}
|
|
|
|
function releaseRank(version: OpenClawVersion): number {
|
|
if (version.prerelease?.length) {
|
|
return 0;
|
|
}
|
|
if (version.revision != null) {
|
|
return 2;
|
|
}
|
|
return 1;
|
|
}
|