diff --git a/CHANGELOG.md b/CHANGELOG.md index b44611a765d..25add7a3d71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Docs: https://docs.openclaw.ai - ACP/session history: persist transcripts for successful ACP child runs, preserve exact transcript text, record ACP spawned-session lineage, and keep spawn-time transcript-path persistence best-effort so history storage failures do not block execution. (#40137) thanks @mbelinky. - Browser/CDP: normalize loopback direct WebSocket CDP URLs back to HTTP(S) for `/json/*` tab operations so local `ws://` / `wss://` profiles can still list, focus, open, and close tabs after the new direct-WS support lands. (#31085) Thanks @shrey150. - Browser/CDP: rewrite wildcard `ws://0.0.0.0` and `ws://[::]` debugger URLs from remote `/json/version` responses back to the external CDP host/port, fixing Browserless-style container endpoints. (#17760) Thanks @joeharouni. +- Browser/extension relay: wait briefly for a previously attached Chrome tab to reappear after transient relay drops before failing with `tab not found`, reducing noisy reconnect flakes. (#32461) Thanks @AaronWander. - Context engine registry/bundled builds: share the registry state through a `globalThis` singleton so duplicated bundled module copies can resolve engines registered by each other at runtime, with regression coverage for duplicate-module imports. (#40115) thanks @jalehman. ## 2026.3.7 diff --git a/src/browser/server-context.ensure-tab-available.prefers-last-target.test.ts b/src/browser/server-context.ensure-tab-available.prefers-last-target.test.ts index 0f6a5e99a9f..10de9ee18bc 100644 --- a/src/browser/server-context.ensure-tab-available.prefers-last-target.test.ts +++ b/src/browser/server-context.ensure-tab-available.prefers-last-target.test.ts @@ -151,4 +151,29 @@ describe("browser server-context ensureTabAvailable", () => { vi.useRealTimers(); } }); + + it("still fails after the extension-tab grace window expires", async () => { + vi.useFakeTimers(); + try { + const responses = [ + [{ id: "A", type: "page", url: "https://a.example", webSocketDebuggerUrl: "ws://x/a" }], + [{ id: "A", type: "page", url: "https://a.example", webSocketDebuggerUrl: "ws://x/a" }], + ...Array.from({ length: 20 }, () => []), + ]; + stubChromeJsonList(responses); + const state = makeBrowserState(); + + const ctx = createBrowserRouteContext({ getState: () => state }); + const chrome = ctx.forProfile("chrome"); + await chrome.ensureTabAvailable(); + + const pending = expect(chrome.ensureTabAvailable()).rejects.toThrow( + /no attached Chrome tabs/i, + ); + await vi.advanceTimersByTimeAsync(3_500); + await pending; + } finally { + vi.useRealTimers(); + } + }); }); diff --git a/src/infra/git-commit.test.ts b/src/infra/git-commit.test.ts index be89c5444b4..26be4322ad8 100644 --- a/src/infra/git-commit.test.ts +++ b/src/infra/git-commit.test.ts @@ -65,7 +65,9 @@ describe("git commit resolution", () => { const repoHead = execFileSync("git", ["rev-parse", "--short=7", "HEAD"], { cwd: repoRoot, encoding: "utf-8", - }).trim(); + }) + .trim() + .slice(0, 7); const temp = await makeTempDir("git-commit-cwd"); const otherRepo = path.join(temp, "other"); @@ -81,7 +83,9 @@ describe("git commit resolution", () => { const otherHead = execFileSync("git", ["rev-parse", "--short=7", "HEAD"], { cwd: otherRepo, encoding: "utf-8", - }).trim(); + }) + .trim() + .slice(0, 7); process.chdir(otherRepo); const { resolveCommitHash } = await import("./git-commit.js"); @@ -95,7 +99,9 @@ describe("git commit resolution", () => { const repoHead = execFileSync("git", ["rev-parse", "--short=7", "HEAD"], { cwd: repoRoot, encoding: "utf-8", - }).trim(); + }) + .trim() + .slice(0, 7); const { resolveCommitHash } = await import("./git-commit.js"); const entryModuleUrl = pathToFileURL(path.join(repoRoot, "src", "entry.ts")).href; @@ -161,7 +167,9 @@ describe("git commit resolution", () => { const repoHead = execFileSync("git", ["rev-parse", "--short=7", "HEAD"], { cwd: repoRoot, encoding: "utf-8", - }).trim(); + }) + .trim() + .slice(0, 7); const { resolveCommitHash } = await import("./git-commit.js");