fix: gateway summary lookup + test browser opens
This commit is contained in:
@@ -44,6 +44,7 @@ Docs: https://docs.clawd.bot
|
|||||||
- Docs: fix gog auth services example to include docs scope. (#1454) Thanks @zerone0x.
|
- 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.
|
- 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: 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).
|
- Providers: improve GitHub Copilot integration (enterprise support, base URL, and auth flow alignment).
|
||||||
|
|
||||||
## 2026.1.21-2
|
## 2026.1.21-2
|
||||||
|
|||||||
@@ -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)
|
.font(.caption)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
|
|
||||||
|
|||||||
@@ -248,12 +248,11 @@ final class GatewayProcessManager {
|
|||||||
guard let linkId else {
|
guard let linkId else {
|
||||||
return "port \(port), health probe succeeded, \(instanceText)"
|
return "port \(port), health probe succeeded, \(instanceText)"
|
||||||
}
|
}
|
||||||
let linked = linkId.flatMap { snap.channels[$0]?.linked } ?? false
|
let linked = snap.channels[linkId]?.linked ?? false
|
||||||
let authAge = linkId.flatMap { snap.channels[$0]?.authAgeMs }.flatMap(msToAge) ?? "unknown age"
|
let authAge = snap.channels[linkId]?.authAgeMs.flatMap(msToAge) ?? "unknown age"
|
||||||
let label =
|
let label =
|
||||||
linkId.flatMap { snap.channelLabels?[$0] } ??
|
snap.channelLabels?[linkId] ??
|
||||||
linkId?.capitalized ??
|
linkId.capitalized
|
||||||
"channel"
|
|
||||||
let linkText = linked ? "linked" : "not linked"
|
let linkText = linked ? "linked" : "not linked"
|
||||||
return "port \(port), \(label) \(linkText), auth \(authAge), \(instanceText)"
|
return "port \(port), \(label) \(linkText), auth \(authAge), \(instanceText)"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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";
|
import { openUrl, resolveBrowserOpenCommand, resolveControlUiLinks } from "./onboard-helpers.js";
|
||||||
|
|
||||||
@@ -21,9 +21,14 @@ vi.mock("../infra/tailnet.js", () => ({
|
|||||||
pickPrimaryTailnetIPv4: mocks.pickPrimaryTailnetIPv4,
|
pickPrimaryTailnetIPv4: mocks.pickPrimaryTailnetIPv4,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.unstubAllEnvs();
|
||||||
|
});
|
||||||
|
|
||||||
describe("openUrl", () => {
|
describe("openUrl", () => {
|
||||||
it("quotes URLs on win32 so '&' is not treated as cmd separator", async () => {
|
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 =
|
const url =
|
||||||
"https://accounts.google.com/o/oauth2/v2/auth?client_id=abc&response_type=code&redirect_uri=http%3A%2F%2Flocalhost";
|
"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,
|
timeoutMs: 5_000,
|
||||||
windowsVerbatimArguments: true,
|
windowsVerbatimArguments: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
platformSpy.mockRestore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("resolveBrowserOpenCommand", () => {
|
describe("resolveBrowserOpenCommand", () => {
|
||||||
it("marks win32 commands as quoteUrl=true", async () => {
|
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();
|
const resolved = await resolveBrowserOpenCommand();
|
||||||
expect(resolved.argv).toEqual(["cmd", "/c", "start", ""]);
|
expect(resolved.argv).toEqual(["cmd", "/c", "start", ""]);
|
||||||
expect(resolved.quoteUrl).toBe(true);
|
expect(resolved.quoteUrl).toBe(true);
|
||||||
|
platformSpy.mockRestore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ function resolveSshTargetHint(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function openUrl(url: string): Promise<boolean> {
|
export async function openUrl(url: string): Promise<boolean> {
|
||||||
|
if (shouldSkipBrowserOpenInTests()) return false;
|
||||||
const resolved = await resolveBrowserOpenCommand();
|
const resolved = await resolveBrowserOpenCommand();
|
||||||
if (!resolved.argv) return false;
|
if (!resolved.argv) return false;
|
||||||
const quoteUrl = resolved.quoteUrl === true;
|
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> {
|
export async function openUrlInBackground(url: string): Promise<boolean> {
|
||||||
|
if (shouldSkipBrowserOpenInTests()) return false;
|
||||||
if (process.platform !== "darwin") return false;
|
if (process.platform !== "darwin") return false;
|
||||||
const resolved = await resolveBrowserOpenCommand();
|
const resolved = await resolveBrowserOpenCommand();
|
||||||
if (!resolved.argv || resolved.command !== "open") return false;
|
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: {
|
export async function probeGatewayReachable(params: {
|
||||||
url: string;
|
url: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user