diff --git a/CHANGELOG.md b/CHANGELOG.md index ece6bd939fd..d261965d9f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai - Telegram: detect polling stalls from `getUpdates` liveness only, so outbound API calls no longer mask dead inbound polling; log polling-cycle starts after transport rebuilds. Fixes #78473. - fix(plugins): scan installed dependency runtime code [AI]. (#81066) Thanks @pgondhi987. - Inherit tool restrictions for delegated sessions [AI]. (#80979) Thanks @pgondhi987. +- Codex harness: make the live test wrapper portable to Windows and defer locked temp cleanup so native Windows and WSL2 live runs complete. - Telegram: discard legacy long-poll update offsets that cannot be tied to the current bot token, so token rotation no longer leaves bots silently skipping new messages. (#80671) Thanks @sxxtony. - browser: enforce navigation checks for act interactions [AI]. (#81070) Thanks @pgondhi987. - Validate node exec event provenance [AI]. (#81071) Thanks @pgondhi987. diff --git a/package.json b/package.json index 45ca29d73c8..55556fc9fff 100644 --- a/package.json +++ b/package.json @@ -1643,7 +1643,7 @@ "test:install:smoke": "bash scripts/test-install-sh-docker.sh", "test:live": "node scripts/test-live.mjs", "test:live:cache": "node --import tsx scripts/check-live-cache.ts", - "test:live:codex-harness": "OPENCLAW_LIVE_CODEX_HARNESS=1 node scripts/test-live.mjs -- src/gateway/gateway-codex-harness.live.test.ts", + "test:live:codex-harness": "node scripts/test-live.mjs --codex-harness -- src/gateway/gateway-codex-harness.live.test.ts", "test:live:crestodian-rescue-channel": "OPENCLAW_LIVE_CRESTODIAN_RESCUE_CHANNEL=1 node scripts/test-live.mjs -- src/crestodian/rescue-channel.live.test.ts", "test:live:gateway-profiles": "node scripts/test-live.mjs -- src/gateway/gateway-models.profiles.live.test.ts", "test:live:media": "node --import tsx scripts/test-live-media.ts", diff --git a/scripts/test-live.mjs b/scripts/test-live.mjs index 22cf8e2c846..b34a8808996 100644 --- a/scripts/test-live.mjs +++ b/scripts/test-live.mjs @@ -2,11 +2,16 @@ import { spawnPnpmRunner } from "./pnpm-runner.mjs"; const forwardedArgs = []; let quietOverride; +let forceCodexHarness = false; for (const arg of process.argv.slice(2)) { if (arg === "--") { continue; } + if (arg === "--codex-harness") { + forceCodexHarness = true; + continue; + } if (arg === "--quiet" || arg === "--quiet-live") { quietOverride = "1"; continue; @@ -25,6 +30,7 @@ const env = { pnpm_config_verify_deps_before_run: process.env.pnpm_config_verify_deps_before_run || "false", OPENCLAW_LIVE_TEST: process.env.OPENCLAW_LIVE_TEST || "1", OPENCLAW_LIVE_TEST_QUIET: quietOverride ?? process.env.OPENCLAW_LIVE_TEST_QUIET ?? "1", + ...(forceCodexHarness ? { OPENCLAW_LIVE_CODEX_HARNESS: "1" } : {}), }; function parsePositiveInt(value, fallback) { diff --git a/src/gateway/gateway-codex-harness.live.test.ts b/src/gateway/gateway-codex-harness.live.test.ts index ce4b186b00d..5bbc0710c3a 100644 --- a/src/gateway/gateway-codex-harness.live.test.ts +++ b/src/gateway/gateway-codex-harness.live.test.ts @@ -162,6 +162,31 @@ async function createLiveWorkspace(tempDir: string): Promise { return workspace; } +async function removeLiveTempDir(dir: string): Promise { + let lastError: unknown; + for (let attempt = 0; attempt < 100; attempt += 1) { + try { + await fs.rm(dir, { recursive: true, force: true }); + return; + } catch (error) { + lastError = error; + const code = (error as { code?: unknown } | null)?.code; + if (code !== "EBUSY" && code !== "ENOTEMPTY" && code !== "EPERM" && code !== "EACCES") { + throw error; + } + await delay(100); + } + } + if (process.platform === "win32") { + logCodexLiveStep("temp-cleanup-deferred", { + dir, + error: lastError instanceof Error ? lastError.message : String(lastError), + }); + return; + } + await fs.rm(dir, { recursive: true, force: true }); +} + function parseModelKey(modelKey: string): { provider: string; modelId: string } { const [provider, ...modelParts] = modelKey.split("/"); const modelId = modelParts.join("/"); @@ -935,8 +960,15 @@ describeLive("gateway live (Codex harness)", () => { clearRuntimeConfigSnapshot(); await client.stopAndWait(); await server.close(); + const [{ resetTaskRegistryForTests }, { resetTaskFlowRegistryForTests }] = + await Promise.all([ + import("../tasks/runtime-internal.js"), + import("../tasks/task-flow-runtime-internal.js"), + ]); + resetTaskRegistryForTests({ persist: false }); + resetTaskFlowRegistryForTests({ persist: false }); restoreEnv(previousEnv); - await fs.rm(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); + await removeLiveTempDir(tempDir); } }, CODEX_HARNESS_TIMEOUT_MS,