mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-23 02:45:38 -06:00
refactor: consolidate coercion contracts (#122458)
* refactor: consolidate coercion contracts Centralize exact string, record, numeric, date, Boolean, argument, and structured-error coercions while preserving call-site semantics. Migrate canonical-name collisions and deprecated internal SDK bypasses, deleting 55 net production/tooling lines. Expand declaration ownership enforcement to 101 allowed helpers and add a narrow export-completeness audit. * fix: preserve standalone script coercions Keep copied Control UI tooling self-contained and retain the trusted release harness module-relative source seam when the harness runs against an old target cwd.
This commit is contained in:
committed by
GitHub
parent
66fe424590
commit
b080dd1e76
@@ -2274,9 +2274,9 @@ function parsePosixProcessRows(stdout: string) {
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const processId = parseStrictPositiveInteger(pidRaw);
|
||||
const processId = parsePositivePosixProcessToken(pidRaw);
|
||||
const parentProcessId = parseStrictUnsignedInteger(ppidRaw);
|
||||
const rssKb = parseStrictPositiveInteger(rssKbRaw);
|
||||
const rssKb = parsePositivePosixProcessToken(rssKbRaw);
|
||||
const cpuPercent = parseStrictNonNegativeDecimal(cpuRaw);
|
||||
if (
|
||||
!Number.isInteger(processId) ||
|
||||
@@ -2320,7 +2320,7 @@ function parseStrictUnsignedInteger(raw: string | undefined) {
|
||||
return Number.isSafeInteger(parsed) ? parsed : null;
|
||||
}
|
||||
|
||||
function parseStrictPositiveInteger(raw: string | undefined) {
|
||||
function parsePositivePosixProcessToken(raw: string | undefined) {
|
||||
const parsed = parseStrictUnsignedInteger(raw);
|
||||
return parsed && parsed > 0 ? parsed : null;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ function parseExpectedStatus(raw) {
|
||||
return Number(raw);
|
||||
}
|
||||
|
||||
function resolveTimerTimeoutMs(valueMs, fallbackMs) {
|
||||
function resolveOpenWebUiHttpProbeTimeoutMs(valueMs, fallbackMs) {
|
||||
const value = Number.isFinite(valueMs) ? valueMs : fallbackMs;
|
||||
return Math.min(Math.max(Math.floor(value), 1), MAX_TIMER_TIMEOUT_MS);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export async function probeHttpStatus({
|
||||
throw new Error("usage: http-probe.mjs <url> [status|lt500]");
|
||||
}
|
||||
const expectedStatus = expectedRaw === "lt500" ? undefined : parseExpectedStatus(expectedRaw);
|
||||
const resolvedTimeoutMs = resolveTimerTimeoutMs(timeoutMs, 30_000);
|
||||
const resolvedTimeoutMs = resolveOpenWebUiHttpProbeTimeoutMs(timeoutMs, 30_000);
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), resolvedTimeoutMs);
|
||||
let res;
|
||||
|
||||
@@ -50,17 +50,17 @@ function readPositiveNumberEnv(name, fallback) {
|
||||
|
||||
const MAX_TIMER_TIMEOUT_MS = 2_147_000_000;
|
||||
|
||||
function clampTimerTimeoutMs(valueMs) {
|
||||
function clampPluginLifecycleTimerMs(valueMs) {
|
||||
return Math.min(Math.max(Math.floor(valueMs), 1), MAX_TIMER_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
const pollMs = clampTimerTimeoutMs(
|
||||
const pollMs = clampPluginLifecycleTimerMs(
|
||||
readPositiveIntEnv("OPENCLAW_PLUGIN_LIFECYCLE_METRIC_POLL_MS", 100),
|
||||
);
|
||||
const timeoutMs = clampTimerTimeoutMs(
|
||||
const timeoutMs = clampPluginLifecycleTimerMs(
|
||||
readPositiveIntEnv("OPENCLAW_PLUGIN_LIFECYCLE_PHASE_TIMEOUT_MS", 300000),
|
||||
);
|
||||
const timeoutKillGraceMs = clampTimerTimeoutMs(
|
||||
const timeoutKillGraceMs = clampPluginLifecycleTimerMs(
|
||||
readPositiveIntEnv("OPENCLAW_PLUGIN_LIFECYCLE_TIMEOUT_KILL_GRACE_MS", 2000),
|
||||
);
|
||||
const maxRssKbThreshold = readPositiveIntEnv(
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
||||
import type { QaProviderMode } from "../../extensions/qa-lab/src/run-config.ts";
|
||||
import type { QaSuiteRoundTripProbe } from "../../extensions/qa-lab/src/suite-round-trip.ts";
|
||||
|
||||
function parseBoolean(value: string | undefined) {
|
||||
function isTruthyNpmTelegramEnvValue(value: string | undefined) {
|
||||
const normalized = value?.trim().toLowerCase();
|
||||
return normalized === "1" || normalized === "true" || normalized === "yes";
|
||||
}
|
||||
@@ -147,7 +147,7 @@ async function shouldFailPackageTelegramRun(
|
||||
result: { summaryPath: string },
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
) {
|
||||
if (parseBoolean(env.OPENCLAW_NPM_TELEGRAM_ALLOW_FAILURES)) {
|
||||
if (isTruthyNpmTelegramEnvValue(env.OPENCLAW_NPM_TELEGRAM_ALLOW_FAILURES)) {
|
||||
return false;
|
||||
}
|
||||
const { readQaSuiteFailedOrSkippedScenarioCountFromFile } =
|
||||
@@ -224,7 +224,7 @@ async function main() {
|
||||
providerMode,
|
||||
primaryModel,
|
||||
alternateModel: process.env.OPENCLAW_NPM_TELEGRAM_ALT_MODEL,
|
||||
fastMode: parseBoolean(process.env.OPENCLAW_NPM_TELEGRAM_FAST),
|
||||
fastMode: isTruthyNpmTelegramEnvValue(process.env.OPENCLAW_NPM_TELEGRAM_FAST),
|
||||
scenarioIds,
|
||||
resolvedScenarioIds: prioritizeRoundTripProbeScenario(resolvedScenarioIds, rttOptions),
|
||||
roundTripProbe: createRoundTripProbe(rttOptions),
|
||||
|
||||
@@ -70,18 +70,18 @@ function readNonNegativeInt(name, fallback) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function clampTimerTimeoutMs(valueMs, minMs = 1) {
|
||||
function clampOpenWebUiTimerTimeoutMs(valueMs, minMs = 1) {
|
||||
const min = Math.max(0, Math.floor(minMs));
|
||||
const value = Number.isFinite(valueMs) ? valueMs : min;
|
||||
return Math.min(Math.max(Math.floor(value), min), MAX_TIMER_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
function readPositiveTimerMs(name, fallback) {
|
||||
return clampTimerTimeoutMs(readPositiveInt(name, fallback));
|
||||
return clampOpenWebUiTimerTimeoutMs(readPositiveInt(name, fallback));
|
||||
}
|
||||
|
||||
function readNonNegativeTimerMs(name, fallback) {
|
||||
return clampTimerTimeoutMs(readNonNegativeInt(name, fallback), 0);
|
||||
return clampOpenWebUiTimerTimeoutMs(readNonNegativeInt(name, fallback), 0);
|
||||
}
|
||||
|
||||
function createTimeoutError(label, timeoutMs) {
|
||||
@@ -91,7 +91,7 @@ function createTimeoutError(label, timeoutMs) {
|
||||
}
|
||||
|
||||
async function withRequestTimeout(label, timeoutMs, run) {
|
||||
const resolvedTimeoutMs = clampTimerTimeoutMs(timeoutMs);
|
||||
const resolvedTimeoutMs = clampOpenWebUiTimerTimeoutMs(timeoutMs);
|
||||
const controller = new AbortController();
|
||||
const timeoutError = createTimeoutError(label, resolvedTimeoutMs);
|
||||
let timer;
|
||||
@@ -156,7 +156,7 @@ function buildAuthHeaders(token, cookie) {
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, clampTimerTimeoutMs(ms, 0));
|
||||
setTimeout(resolve, clampOpenWebUiTimerTimeoutMs(ms, 0));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { clampTimerTimeoutMs } from "@openclaw/normalization-core/number-coercion";
|
||||
import { sliceUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
|
||||
import { parseStrictBooleanArg } from "../lib/arg-utils.mts";
|
||||
import { coerceErrorMessage } from "../lib/error-format.mts";
|
||||
import { sleep } from "../lib/sleep.mjs";
|
||||
import { resolveWindowsTaskkillPath } from "../lib/windows-taskkill.mjs";
|
||||
import { createPnpmRunnerSpawnSpec } from "../pnpm-runner.mts";
|
||||
@@ -303,16 +305,6 @@ function parseTcpPort(value: string, label: string) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function parseBoolean(value: string, label: string) {
|
||||
if (value === "true") {
|
||||
return true;
|
||||
}
|
||||
if (value === "false") {
|
||||
return false;
|
||||
}
|
||||
throw new Error(`${label} must be true or false.`);
|
||||
}
|
||||
|
||||
function createTelegramProofRunId() {
|
||||
return `${new Date().toISOString().replace(/[:.]/gu, "-")}-${randomUUID().slice(0, 8)}`;
|
||||
}
|
||||
@@ -417,7 +409,7 @@ export function parseArgs(argvInput: string[]): Options {
|
||||
} else if (arg === "--keep-box") {
|
||||
opts.keepBox = true;
|
||||
} else if (arg === "--link-preview") {
|
||||
opts.linkPreview = parseBoolean(readValue(), "--link-preview");
|
||||
opts.linkPreview = parseStrictBooleanArg(readValue(), "--link-preview");
|
||||
} else if (arg === "--mock-port") {
|
||||
opts.mockPort = parseTcpPort(readValue(), "--mock-port");
|
||||
} else if (arg === "--mock-response-file") {
|
||||
@@ -1656,9 +1648,7 @@ function destroyLocalSutRuntime(sut: { containerName?: string; tempRoot?: string
|
||||
}
|
||||
|
||||
function cleanupFailureMessage(message: string, cleanupErrors: unknown[]) {
|
||||
const details = cleanupErrors.map((error) =>
|
||||
error instanceof Error ? error.message : String(error),
|
||||
);
|
||||
const details = cleanupErrors.map(coerceErrorMessage);
|
||||
return [message, ...details.map((detail) => `Cleanup failure: ${detail}`)].join("\n");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user