From 351d056ca64f19b23aa8b8e5aabf9947e102d478 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 29 May 2026 07:56:18 -0400 Subject: [PATCH] fix(update): centralize timeout seconds parsing --- src/cli/update-cli/shared.command-runner.test.ts | 6 ++++-- src/cli/update-cli/shared.ts | 10 +++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/cli/update-cli/shared.command-runner.test.ts b/src/cli/update-cli/shared.command-runner.test.ts index 2d097c3e010..9f17d1fadcc 100644 --- a/src/cli/update-cli/shared.command-runner.test.ts +++ b/src/cli/update-cli/shared.command-runner.test.ts @@ -57,14 +57,15 @@ describe("createGlobalCommandRunner", () => { try { expect(parseTimeoutMsOrExit("1.5")).toBeNull(); expect(parseTimeoutMsOrExit("10abc")).toBeNull(); + expect(parseTimeoutMsOrExit("0x10")).toBeNull(); expect(parseTimeoutMsOrExit("0")).toBeNull(); expect(parseTimeoutMsOrExit("-1")).toBeNull(); expect(parseTimeoutMsOrExit(" ")).toBeNull(); expect(parseTimeoutMsOrExit(String(Number.MAX_SAFE_INTEGER))).toBeNull(); - expect(error).toHaveBeenCalledTimes(6); + expect(error).toHaveBeenCalledTimes(7); expect(error).toHaveBeenCalledWith("--timeout must be a positive integer (seconds)"); - expect(exit).toHaveBeenCalledTimes(6); + expect(exit).toHaveBeenCalledTimes(7); expect(exit).toHaveBeenCalledWith(1); } finally { error.mockRestore(); @@ -78,6 +79,7 @@ describe("createGlobalCommandRunner", () => { try { expect(parseTimeoutMsOrExit(" 10 ")).toBe(10_000); + expect(parseTimeoutMsOrExit("+10")).toBe(10_000); expect(parseTimeoutMsOrExit("001")).toBe(1_000); expect(parseTimeoutMsOrExit()).toBeUndefined(); expect(error).not.toHaveBeenCalled(); diff --git a/src/cli/update-cli/shared.ts b/src/cli/update-cli/shared.ts index 9536513595a..b807771bb92 100644 --- a/src/cli/update-cli/shared.ts +++ b/src/cli/update-cli/shared.ts @@ -6,6 +6,7 @@ import { resolveRequiredHomeDir } from "../../infra/home-dir.js"; import { resolveOpenClawPackageRoot } from "../../infra/openclaw-root.js"; import { readPackageName, readPackageVersion } from "../../infra/package-json.js"; import { normalizePackageTagInput } from "../../infra/package-tag.js"; +import { parseStrictPositiveInteger } from "../../infra/parse-finite-number.js"; import { trimLogTail } from "../../infra/restart-sentinel.js"; import { parseSemver } from "../../infra/runtime-guard.js"; import { fetchNpmTagVersion } from "../../infra/update-check.js"; @@ -60,13 +61,8 @@ export function parseTimeoutMsOrExit(timeout?: string): number | undefined | nul return undefined; } const trimmed = timeout.trim(); - const seconds = Number(trimmed); - if ( - !/^\d+$/u.test(trimmed) || - !Number.isSafeInteger(seconds) || - seconds <= 0 || - seconds > MAX_SAFE_TIMEOUT_SECONDS - ) { + const seconds = parseStrictPositiveInteger(trimmed); + if (seconds === undefined || seconds > MAX_SAFE_TIMEOUT_SECONDS) { defaultRuntime.error(INVALID_TIMEOUT_ERROR); defaultRuntime.exit(1); return null;