diff --git a/scripts/e2e/lib/agent-turn-output.mjs b/scripts/e2e/lib/agent-turn-output.mjs index 12838da9a470..db4e1753b91f 100644 --- a/scripts/e2e/lib/agent-turn-output.mjs +++ b/scripts/e2e/lib/agent-turn-output.mjs @@ -1,5 +1,6 @@ // Helpers for extracting agent turn output from E2E protocol events. import fs from "node:fs"; +import { isRecord } from "../../lib/record-shared.mjs"; import { readTextFileTail, tailText } from "./text-file-utils.mjs"; const ERROR_DETAIL_TAIL_BYTES = 64 * 1024; @@ -150,10 +151,6 @@ function textValues(values) { return values.filter((value) => typeof value === "string" && value.length > 0); } -function isRecord(value) { - return value !== null && typeof value === "object" && !Array.isArray(value); -} - function isFailureStatus(value) { return ( typeof value === "string" && diff --git a/scripts/e2e/lib/auth-profile-store-assertions.mjs b/scripts/e2e/lib/auth-profile-store-assertions.mjs index c7a643361e5e..5fe6853a36e0 100644 --- a/scripts/e2e/lib/auth-profile-store-assertions.mjs +++ b/scripts/e2e/lib/auth-profile-store-assertions.mjs @@ -1,7 +1,5 @@ // Shared auth profile store assertions for install/onboard E2E proof. -function isRecord(value) { - return value !== null && typeof value === "object" && !Array.isArray(value); -} +import { isRecord } from "../../lib/record-shared.mjs"; function hasExpectedOpenAiEnvRef(profile) { if (!isRecord(profile)) { diff --git a/scripts/e2e/lib/bundled-plugin-install-uninstall/runtime-smoke.mjs b/scripts/e2e/lib/bundled-plugin-install-uninstall/runtime-smoke.mjs index 5fafb657ddc5..30c1912ac149 100644 --- a/scripts/e2e/lib/bundled-plugin-install-uninstall/runtime-smoke.mjs +++ b/scripts/e2e/lib/bundled-plugin-install-uninstall/runtime-smoke.mjs @@ -6,6 +6,7 @@ import path from "node:path"; import process from "node:process"; import { setTimeout as delay } from "node:timers/promises"; import { fileURLToPath } from "node:url"; +import { isRecord } from "../../../lib/record-shared.mjs"; import { resolveWindowsTaskkillPath } from "../../../lib/windows-taskkill.mjs"; import { readBoundedResponseText } from "../bounded-response-text.mjs"; @@ -993,10 +994,6 @@ function hasOwnPayloadField(raw, field) { ); } -function isRecord(value) { - return value !== null && typeof value === "object" && !Array.isArray(value); -} - export function unwrapRpcPayload(raw) { if (raw?.ok === false) { throw new Error(`gateway RPC failed: ${JSON.stringify(raw.error ?? raw)}`); diff --git a/scripts/e2e/lib/gateway-network/client.mjs b/scripts/e2e/lib/gateway-network/client.mjs index 92d25e586dfe..0d15c731adf4 100644 --- a/scripts/e2e/lib/gateway-network/client.mjs +++ b/scripts/e2e/lib/gateway-network/client.mjs @@ -4,6 +4,7 @@ import { readFile, writeFile } from "node:fs/promises"; import { request as httpRequest } from "node:http"; import { pathToFileURL } from "node:url"; import { WebSocket } from "ws"; +import { isRecord } from "../../../lib/record-shared.mjs"; import { sleep as delay } from "../../../lib/sleep.mjs"; import { waitForWebSocketOpen } from "../websocket-open.mjs"; import { readGatewayNetworkClientConnectTimeoutMs } from "./limits.mjs"; @@ -24,10 +25,6 @@ async function openSocket(url, timeoutMs = 10_000) { return ws; } -function isRecord(value) { - return value !== null && typeof value === "object" && !Array.isArray(value); -} - function hasGatewayHealthSummaryPayload(response) { if (!isRecord(response) || !isRecord(response.payload)) { return false; diff --git a/scripts/e2e/lib/live-plugin-tool/assertions.mjs b/scripts/e2e/lib/live-plugin-tool/assertions.mjs index 7312f1cfe2f1..fcfae06c27f6 100644 --- a/scripts/e2e/lib/live-plugin-tool/assertions.mjs +++ b/scripts/e2e/lib/live-plugin-tool/assertions.mjs @@ -2,6 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import { DatabaseSync } from "node:sqlite"; +import { isRecord } from "../../../lib/record-shared.mjs"; import { extractAgentReplyTexts } from "../agent-turn-output.mjs"; import { readPluginInstallRecords } from "../plugin-index-sqlite.mjs"; import { readTextFileTail, tailText } from "../text-file-utils.mjs"; @@ -64,10 +65,6 @@ function agentErrorPath() { return process.env.OPENCLAW_LIVE_PLUGIN_TOOL_AGENT_ERROR_PATH || "/tmp/openclaw-agent.err"; } -function isRecord(value) { - return Boolean(value && typeof value === "object" && !Array.isArray(value)); -} - function readNonEmptyString(value) { return typeof value === "string" && value.trim() ? value.trim() : undefined; } diff --git a/scripts/validate-qa-runtime-pair-summary.mjs b/scripts/validate-qa-runtime-pair-summary.mjs index cae57eaedd70..103e96e2c119 100644 --- a/scripts/validate-qa-runtime-pair-summary.mjs +++ b/scripts/validate-qa-runtime-pair-summary.mjs @@ -4,6 +4,7 @@ import fs from "node:fs"; import process from "node:process"; import { pathToFileURL } from "node:url"; +import { isRecord } from "./lib/record-shared.mjs"; const RUNTIME_IDS = ["openclaw", "codex"]; const HARD_RUNTIME_ERROR_CLASSES = new Set([ @@ -60,10 +61,6 @@ const FROZEN_RUNTIME_PAIR_MANIFESTS = new Map([ ["c37af96b18776fecc9e24268f27fc89b563481bf:core", FROZEN_CORE_RUNTIME_PAIR_MANIFEST], ]); -function isRecord(value) { - return value !== null && typeof value === "object" && !Array.isArray(value); -} - function isPassableCell(cell) { if (!isRecord(cell) || typeof cell.transportErrorClass === "string") { return false;