fix: prefer stable release when beta lags
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
|||||||
checkUpdateStatus,
|
checkUpdateStatus,
|
||||||
compareSemverStrings,
|
compareSemverStrings,
|
||||||
fetchNpmTagVersion,
|
fetchNpmTagVersion,
|
||||||
|
resolveNpmChannelTag,
|
||||||
} from "../infra/update-check.js";
|
} from "../infra/update-check.js";
|
||||||
import { parseSemver } from "../infra/runtime-guard.js";
|
import { parseSemver } from "../infra/runtime-guard.js";
|
||||||
import {
|
import {
|
||||||
@@ -411,10 +412,16 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
|
|||||||
const gitCheckout = await isGitCheckout(root);
|
const gitCheckout = await isGitCheckout(root);
|
||||||
const defaultChannel = gitCheckout ? DEFAULT_GIT_CHANNEL : DEFAULT_PACKAGE_CHANNEL;
|
const defaultChannel = gitCheckout ? DEFAULT_GIT_CHANNEL : DEFAULT_PACKAGE_CHANNEL;
|
||||||
const channel = requestedChannel ?? storedChannel ?? defaultChannel;
|
const channel = requestedChannel ?? storedChannel ?? defaultChannel;
|
||||||
const tag = normalizeTag(opts.tag) ?? channelToNpmTag(channel);
|
const explicitTag = normalizeTag(opts.tag);
|
||||||
|
let tag = explicitTag ?? channelToNpmTag(channel);
|
||||||
if (!gitCheckout) {
|
if (!gitCheckout) {
|
||||||
const currentVersion = await readPackageVersion(root);
|
const currentVersion = await readPackageVersion(root);
|
||||||
const targetVersion = await resolveTargetVersion(tag, timeoutMs);
|
const targetVersion = explicitTag
|
||||||
|
? await resolveTargetVersion(tag, timeoutMs)
|
||||||
|
: await resolveNpmChannelTag({ channel, timeoutMs }).then((resolved) => {
|
||||||
|
tag = resolved.tag;
|
||||||
|
return resolved.version;
|
||||||
|
});
|
||||||
const cmp =
|
const cmp =
|
||||||
currentVersion && targetVersion ? compareSemverStrings(currentVersion, targetVersion) : null;
|
currentVersion && targetVersion ? compareSemverStrings(currentVersion, targetVersion) : null;
|
||||||
const needsConfirm =
|
const needsConfirm =
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import path from "node:path";
|
|||||||
|
|
||||||
import { runCommandWithTimeout } from "../process/exec.js";
|
import { runCommandWithTimeout } from "../process/exec.js";
|
||||||
import { parseSemver } from "./runtime-guard.js";
|
import { parseSemver } from "./runtime-guard.js";
|
||||||
|
import { channelToNpmTag, type UpdateChannel } from "./update-channels.js";
|
||||||
|
|
||||||
export type PackageManager = "pnpm" | "bun" | "npm" | "unknown";
|
export type PackageManager = "pnpm" | "bun" | "npm" | "unknown";
|
||||||
|
|
||||||
@@ -315,6 +316,30 @@ export async function fetchNpmTagVersion(params: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function resolveNpmChannelTag(params: {
|
||||||
|
channel: UpdateChannel;
|
||||||
|
timeoutMs?: number;
|
||||||
|
}): Promise<{ tag: string; version: string | null }> {
|
||||||
|
const channelTag = channelToNpmTag(params.channel);
|
||||||
|
const channelStatus = await fetchNpmTagVersion({ tag: channelTag, timeoutMs: params.timeoutMs });
|
||||||
|
if (params.channel !== "beta") {
|
||||||
|
return { tag: channelTag, version: channelStatus.version };
|
||||||
|
}
|
||||||
|
|
||||||
|
const latestStatus = await fetchNpmTagVersion({ tag: "latest", timeoutMs: params.timeoutMs });
|
||||||
|
if (!latestStatus.version) {
|
||||||
|
return { tag: channelTag, version: channelStatus.version };
|
||||||
|
}
|
||||||
|
if (!channelStatus.version) {
|
||||||
|
return { tag: "latest", version: latestStatus.version };
|
||||||
|
}
|
||||||
|
const cmp = compareSemverStrings(channelStatus.version, latestStatus.version);
|
||||||
|
if (cmp != null && cmp < 0) {
|
||||||
|
return { tag: "latest", version: latestStatus.version };
|
||||||
|
}
|
||||||
|
return { tag: channelTag, version: channelStatus.version };
|
||||||
|
}
|
||||||
|
|
||||||
export function compareSemverStrings(a: string | null, b: string | null): number | null {
|
export function compareSemverStrings(a: string | null, b: string | null): number | null {
|
||||||
const pa = parseSemver(a);
|
const pa = parseSemver(a);
|
||||||
const pb = parseSemver(b);
|
const pb = parseSemver(b);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import { type CommandOptions, runCommandWithTimeout } from "../process/exec.js";
|
import { type CommandOptions, runCommandWithTimeout } from "../process/exec.js";
|
||||||
|
import { compareSemverStrings } from "./update-check.js";
|
||||||
import { DEV_BRANCH, isBetaTag, isStableTag, type UpdateChannel } from "./update-channels.js";
|
import { DEV_BRANCH, isBetaTag, isStableTag, type UpdateChannel } from "./update-channels.js";
|
||||||
import { trimLogTail } from "./restart-sentinel.js";
|
import { trimLogTail } from "./restart-sentinel.js";
|
||||||
|
|
||||||
@@ -143,8 +144,16 @@ async function resolveChannelTag(
|
|||||||
channel: Exclude<UpdateChannel, "dev">,
|
channel: Exclude<UpdateChannel, "dev">,
|
||||||
): Promise<string | null> {
|
): Promise<string | null> {
|
||||||
const tags = await listGitTags(runCommand, root, timeoutMs);
|
const tags = await listGitTags(runCommand, root, timeoutMs);
|
||||||
const predicate = channel === "beta" ? isBetaTag : isStableTag;
|
if (channel === "beta") {
|
||||||
return tags.find((tag) => predicate(tag)) ?? null;
|
const betaTag = tags.find((tag) => isBetaTag(tag)) ?? null;
|
||||||
|
const stableTag = tags.find((tag) => isStableTag(tag)) ?? null;
|
||||||
|
if (!betaTag) return stableTag;
|
||||||
|
if (!stableTag) return betaTag;
|
||||||
|
const cmp = compareSemverStrings(betaTag, stableTag);
|
||||||
|
if (cmp != null && cmp < 0) return stableTag;
|
||||||
|
return betaTag;
|
||||||
|
}
|
||||||
|
return tags.find((tag) => isStableTag(tag)) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveGitRoot(
|
async function resolveGitRoot(
|
||||||
|
|||||||
@@ -4,12 +4,8 @@ import path from "node:path";
|
|||||||
import type { loadConfig } from "../config/config.js";
|
import type { loadConfig } from "../config/config.js";
|
||||||
import { resolveStateDir } from "../config/paths.js";
|
import { resolveStateDir } from "../config/paths.js";
|
||||||
import { resolveClawdbotPackageRoot } from "./clawdbot-root.js";
|
import { resolveClawdbotPackageRoot } from "./clawdbot-root.js";
|
||||||
import { compareSemverStrings, fetchNpmTagVersion, checkUpdateStatus } from "./update-check.js";
|
import { compareSemverStrings, resolveNpmChannelTag, checkUpdateStatus } from "./update-check.js";
|
||||||
import {
|
import { normalizeUpdateChannel, DEFAULT_PACKAGE_CHANNEL } from "./update-channels.js";
|
||||||
channelToNpmTag,
|
|
||||||
normalizeUpdateChannel,
|
|
||||||
DEFAULT_PACKAGE_CHANNEL,
|
|
||||||
} from "./update-channels.js";
|
|
||||||
import { VERSION } from "../version.js";
|
import { VERSION } from "../version.js";
|
||||||
import { formatCliCommand } from "../cli/command-format.js";
|
import { formatCliCommand } from "../cli/command-format.js";
|
||||||
|
|
||||||
@@ -84,22 +80,22 @@ export async function runGatewayUpdateCheck(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const channel = normalizeUpdateChannel(params.cfg.update?.channel) ?? DEFAULT_PACKAGE_CHANNEL;
|
const channel = normalizeUpdateChannel(params.cfg.update?.channel) ?? DEFAULT_PACKAGE_CHANNEL;
|
||||||
const tag = channelToNpmTag(channel);
|
const resolved = await resolveNpmChannelTag({ channel, timeoutMs: 2500 });
|
||||||
const tagStatus = await fetchNpmTagVersion({ tag, timeoutMs: 2500 });
|
const tag = resolved.tag;
|
||||||
if (!tagStatus.version) {
|
if (!resolved.version) {
|
||||||
await writeState(statePath, nextState);
|
await writeState(statePath, nextState);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmp = compareSemverStrings(VERSION, tagStatus.version);
|
const cmp = compareSemverStrings(VERSION, resolved.version);
|
||||||
if (cmp != null && cmp < 0) {
|
if (cmp != null && cmp < 0) {
|
||||||
const shouldNotify =
|
const shouldNotify =
|
||||||
state.lastNotifiedVersion !== tagStatus.version || state.lastNotifiedTag !== tag;
|
state.lastNotifiedVersion !== resolved.version || state.lastNotifiedTag !== tag;
|
||||||
if (shouldNotify) {
|
if (shouldNotify) {
|
||||||
params.log.info(
|
params.log.info(
|
||||||
`update available (${tag}): v${tagStatus.version} (current v${VERSION}). Run: ${formatCliCommand("clawdbot update")}`,
|
`update available (${tag}): v${resolved.version} (current v${VERSION}). Run: ${formatCliCommand("clawdbot update")}`,
|
||||||
);
|
);
|
||||||
nextState.lastNotifiedVersion = tagStatus.version;
|
nextState.lastNotifiedVersion = resolved.version;
|
||||||
nextState.lastNotifiedTag = tag;
|
nextState.lastNotifiedTag = tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user