

























@@ -5,6 +5,7 @@ import { formatCliCommand } from "../cli/command-format.js";
55import { resolveStateDir } from "../config/paths.js";
66import type { OpenClawConfig } from "../config/types.openclaw.js";
77import { runCommandWithTimeout } from "../process/exec.js";
8+import { asDateTimestampMs, timestampMsToIsoString } from "../shared/number-coercion.js";
89import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
910import { VERSION } from "../version.js";
1011import { isTruthyEnvValue } from "./env.js";
@@ -188,6 +189,18 @@ function resolveStableJitterMs(params: {
188189return bucket % (Math.floor(params.jitterWindowMs) + 1);
189190}
190191192+function resolveUpdateCheckNowMs(valueMs: unknown): number {
193+return asDateTimestampMs(valueMs) ?? asDateTimestampMs(Date.now()) ?? 0;
194+}
195+196+function resolveUpdateCheckTimestamp(valueMs: unknown): string {
197+return (
198+timestampMsToIsoString(valueMs) ??
199+timestampMsToIsoString(resolveUpdateCheckNowMs(Date.now())) ??
200+new Date().toISOString()
201+);
202+}
203+191204function resolveStableAutoApplyAtMs(params: {
192205state: UpdateCheckState;
193206nextState: UpdateCheckState;
@@ -208,16 +221,17 @@ function resolveStableAutoApplyAtMs(params: {
208221if (!matchesExisting) {
209222params.nextState.autoFirstSeenVersion = params.version;
210223params.nextState.autoFirstSeenTag = params.tag;
211-params.nextState.autoFirstSeenAt = new Date(params.nowMs).toISOString();
224+params.nextState.autoFirstSeenAt = resolveUpdateCheckTimestamp(params.nowMs);
212225} else {
213226params.nextState.autoFirstSeenVersion = params.state.autoFirstSeenVersion;
214227params.nextState.autoFirstSeenTag = params.state.autoFirstSeenTag;
215228params.nextState.autoFirstSeenAt = params.state.autoFirstSeenAt;
216229}
217230218-const firstSeenMs = params.nextState.autoFirstSeenAt
231+const parsedFirstSeenMs = params.nextState.autoFirstSeenAt
219232 ? Date.parse(params.nextState.autoFirstSeenAt)
220233 : params.nowMs;
234+const firstSeenMs = Number.isFinite(parsedFirstSeenMs) ? parsedFirstSeenMs : params.nowMs;
221235const baseDelayMs = Math.max(0, params.stableDelayHours) * ONE_HOUR_MS;
222236const jitterWindowMs = Math.max(0, params.stableJitterHours) * ONE_HOUR_MS;
223237const jitterMs = resolveStableJitterMs({
@@ -327,7 +341,9 @@ export async function runGatewayUpdateCheck(params: {
327341328342const statePath = path.join(resolveStateDir(), UPDATE_CHECK_FILENAME);
329343const state = await readState(statePath);
330-const now = Date.now();
344+const rawNow = Date.now();
345+const now = resolveUpdateCheckNowMs(rawNow);
346+const rawNowIsValid = asDateTimestampMs(rawNow) !== undefined;
331347const lastCheckedAt = state.lastCheckedAt ? Date.parse(state.lastCheckedAt) : null;
332348if (shouldRunUpdateHints) {
333349const persistedAvailable = resolvePersistedUpdateAvailable(state);
@@ -344,7 +360,7 @@ export async function runGatewayUpdateCheck(params: {
344360const checkIntervalMs = shouldRunAutoUpdate
345361 ? resolveCheckIntervalMs(params.cfg)
346362 : UPDATE_CHECK_INTERVAL_MS;
347-if (lastCheckedAt && Number.isFinite(lastCheckedAt)) {
363+if (rawNowIsValid && lastCheckedAt && Number.isFinite(lastCheckedAt)) {
348364if (now - lastCheckedAt < checkIntervalMs) {
349365return;
350366}
@@ -364,7 +380,7 @@ export async function runGatewayUpdateCheck(params: {
364380365381const nextState: UpdateCheckState = {
366382 ...state,
367-lastCheckedAt: new Date(now).toISOString(),
383+lastCheckedAt: resolveUpdateCheckTimestamp(now),
368384};
369385370386if (status.installKind !== "package") {
@@ -451,7 +467,7 @@ export async function runGatewayUpdateCheck(params: {
451467params.log.info("auto-update deferred (stable rollout window active)", {
452468version: resolved.version,
453469 tag,
454-applyAfter: applyAfterMs ? new Date(applyAfterMs).toISOString() : undefined,
470+applyAfter: applyAfterMs ? resolveUpdateCheckTimestamp(applyAfterMs) : undefined,
455471});
456472} else if (recentAttemptForSameVersion) {
457473params.log.info("auto-update deferred (recent attempt exists)", {
@@ -460,15 +476,15 @@ export async function runGatewayUpdateCheck(params: {
460476});
461477} else {
462478nextState.autoLastAttemptVersion = resolved.version;
463-nextState.autoLastAttemptAt = new Date(now).toISOString();
479+nextState.autoLastAttemptAt = resolveUpdateCheckTimestamp(now);
464480const outcome = await runAuto({
465481 channel,
466482timeoutMs: AUTO_UPDATE_COMMAND_TIMEOUT_MS,
467483root: root ?? undefined,
468484});
469485if (outcome.ok) {
470486nextState.autoLastSuccessVersion = resolved.version;
471-nextState.autoLastSuccessAt = new Date(now).toISOString();
487+nextState.autoLastSuccessAt = resolveUpdateCheckTimestamp(now);
472488params.log.info("auto-update applied", {
473489 channel,
474490version: resolved.version,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。