fix: gateway summary lookup + test browser opens

This commit is contained in:
Peter Steinberger
2026-01-23 05:54:32 +00:00
parent bd7443b39b
commit 9f6ea67415
5 changed files with 27 additions and 9 deletions

View File

@@ -44,6 +44,7 @@ Docs: https://docs.clawd.bot
- Docs: fix gog auth services example to include docs scope. (#1454) Thanks @zerone0x.
- Slack: read thread replies for message reads when threadId is provided (replies-only). (#1450) Thanks @rodrigouroz.
- macOS: prefer linked channels in gateway summary to avoid false “not linked” status.
- macOS/tests: fix gateway summary lookup after guard unwrap; prevent browser opens during tests unless explicitly enabled. (ECID-1483)
- Providers: improve GitHub Copilot integration (enterprise support, base URL, and auth flow alignment).
## 2026.1.21-2

View File

@@ -102,7 +102,9 @@ struct DebugSettings: View {
}
}
Text("When enabled, Clawdbot won't install or manage \(gatewayLaunchdLabel). It will only attach to an existing Gateway.")
Text(
"When enabled, Clawdbot won't install or manage \(gatewayLaunchdLabel). " +
"It will only attach to an existing Gateway.")
.font(.caption)
.foregroundStyle(.secondary)

View File

@@ -248,12 +248,11 @@ final class GatewayProcessManager {
guard let linkId else {
return "port \(port), health probe succeeded, \(instanceText)"
}
let linked = linkId.flatMap { snap.channels[$0]?.linked } ?? false
let authAge = linkId.flatMap { snap.channels[$0]?.authAgeMs }.flatMap(msToAge) ?? "unknown age"
let linked = snap.channels[linkId]?.linked ?? false
let authAge = snap.channels[linkId]?.authAgeMs.flatMap(msToAge) ?? "unknown age"
let label =
linkId.flatMap { snap.channelLabels?[$0] } ??
linkId?.capitalized ??
"channel"
snap.channelLabels?[linkId] ??
linkId.capitalized
let linkText = linked ? "linked" : "not linked"
return "port \(port), \(label) \(linkText), auth \(authAge), \(instanceText)"
}

View File

@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import { openUrl, resolveBrowserOpenCommand, resolveControlUiLinks } from "./onboard-helpers.js";
@@ -21,9 +21,14 @@ vi.mock("../infra/tailnet.js", () => ({
pickPrimaryTailnetIPv4: mocks.pickPrimaryTailnetIPv4,
}));
afterEach(() => {
vi.unstubAllEnvs();
});
describe("openUrl", () => {
it("quotes URLs on win32 so '&' is not treated as cmd separator", async () => {
vi.spyOn(process, "platform", "get").mockReturnValue("win32");
vi.stubEnv("CLAWDBOT_ALLOW_TEST_BROWSER_OPEN", "1");
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const url =
"https://accounts.google.com/o/oauth2/v2/auth?client_id=abc&response_type=code&redirect_uri=http%3A%2F%2Flocalhost";
@@ -39,15 +44,18 @@ describe("openUrl", () => {
timeoutMs: 5_000,
windowsVerbatimArguments: true,
});
platformSpy.mockRestore();
});
});
describe("resolveBrowserOpenCommand", () => {
it("marks win32 commands as quoteUrl=true", async () => {
vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const resolved = await resolveBrowserOpenCommand();
expect(resolved.argv).toEqual(["cmd", "/c", "start", ""]);
expect(resolved.quoteUrl).toBe(true);
platformSpy.mockRestore();
});
});

View File

@@ -192,6 +192,7 @@ function resolveSshTargetHint(): string {
}
export async function openUrl(url: string): Promise<boolean> {
if (shouldSkipBrowserOpenInTests()) return false;
const resolved = await resolveBrowserOpenCommand();
if (!resolved.argv) return false;
const quoteUrl = resolved.quoteUrl === true;
@@ -218,6 +219,7 @@ export async function openUrl(url: string): Promise<boolean> {
}
export async function openUrlInBackground(url: string): Promise<boolean> {
if (shouldSkipBrowserOpenInTests()) return false;
if (process.platform !== "darwin") return false;
const resolved = await resolveBrowserOpenCommand();
if (!resolved.argv || resolved.command !== "open") return false;
@@ -308,6 +310,12 @@ export async function detectBinary(name: string): Promise<boolean> {
}
}
function shouldSkipBrowserOpenInTests(): boolean {
if (process.env.CLAWDBOT_ALLOW_TEST_BROWSER_OPEN) return false;
if (process.env.VITEST) return true;
return process.env.NODE_ENV === "test";
}
export async function probeGatewayReachable(params: {
url: string;
token?: string;