diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bfbe123ff7..843436f473e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Browser/Extension startup: stop failing browser startup when relay is reachable but no tab is attached yet; tab attachment is now required only when a tab action actually runs. (#28855) Thanks @Sid-Qin. - Browser/Remote CDP ownership checks: skip local-process ownership errors for non-loopback remote CDP profiles when HTTP is reachable but the websocket handshake fails, and surface the remote websocket attach/retry path instead. (#15582) Landed from contributor (#28780) Thanks @stubbi, @bsormagec, @unblockedgamesstudio and @vincentkoc. - Docker/Image health checks: add Dockerfile `HEALTHCHECK` that probes gateway `GET /healthz` so container runtimes can mark unhealthy instances without requiring auth credentials in the probe command. (#11478) Thanks @U-C4N and @vincentkoc. - Daemon/systemd checks in containers: treat missing `systemctl` invocations (including `spawn systemctl ENOENT`/`EACCES`) as unavailable service state during `is-enabled` checks, preventing container flows from failing with `Gateway service check failed` before install/status handling can continue. (#26089) Thanks @sahilsatralkar and @vincentkoc. 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 b3f15680def..2dc00cf5292 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 @@ -1,5 +1,7 @@ import { describe, expect, it, vi } from "vitest"; import { withFetchPreconnect } from "../test-utils/fetch-mock.js"; +import * as chromeModule from "./chrome.js"; +import * as extensionRelayModule from "./extension-relay.js"; import type { BrowserServerState } from "./server-context.js"; import "./server-context.chrome-test-harness.js"; import { createBrowserRouteContext } from "./server-context.js"; @@ -120,4 +122,21 @@ describe("browser server-context ensureTabAvailable", () => { const chrome = ctx.forProfile("chrome"); await expect(chrome.ensureTabAvailable()).rejects.toThrow(/no attached Chrome tabs/i); }); + + it("starts relay without requiring an attached tab during browser availability checks", async () => { + const isChromeReachableMock = vi.mocked(chromeModule.isChromeReachable); + const ensureRelaySpy = vi + .spyOn(extensionRelayModule, "ensureChromeExtensionRelayServer") + .mockResolvedValue(undefined as never); + isChromeReachableMock.mockResolvedValueOnce(false).mockResolvedValueOnce(true); + + const state = makeBrowserState(); + const ctx = createBrowserRouteContext({ getState: () => state }); + const chrome = ctx.forProfile("chrome"); + + await expect(chrome.ensureBrowserAvailable()).resolves.toBeUndefined(); + expect(ensureRelaySpy).toHaveBeenCalledWith({ cdpUrl: "http://127.0.0.1:18792" }); + + ensureRelaySpy.mockRestore(); + }); });