From 1767639226bb3177f9f2c771d39de16fef2563aa Mon Sep 17 00:00:00 2001 From: WhatsSkiLL Date: Sun, 2 Aug 2026 02:44:38 +0200 Subject: [PATCH] fix-onboarding-ignore-presence-heartbeats (#117431) Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com> --- src/commands/onboard-browser-handoff.test.ts | 66 ++++++++++++++++++++ src/commands/onboard-browser-handoff.ts | 10 ++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/commands/onboard-browser-handoff.test.ts b/src/commands/onboard-browser-handoff.test.ts index d66a81e944bd..fdffe572055c 100644 --- a/src/commands/onboard-browser-handoff.test.ts +++ b/src/commands/onboard-browser-handoff.test.ts @@ -1,8 +1,13 @@ import { describe, expect, it, vi } from "vitest"; +import { + GATEWAY_CLIENT_IDS, + GATEWAY_CLIENT_MODES, +} from "../../packages/gateway-protocol/src/client-info.js"; import { createWizardPrompter } from "../../test/helpers/wizard-prompter.js"; import { detectGraphicalSession, probeBrowserHatchGateway, + resolveConnectedControlUiPresenceKeys, runBrowserHatchHandoff, } from "./onboard-browser-handoff.js"; @@ -47,7 +52,68 @@ describe("detectGraphicalSession", () => { }); }); +const connectedControlUiPresence = { + host: GATEWAY_CLIENT_IDS.CONTROL_UI, + mode: GATEWAY_CLIENT_MODES.WEBCHAT, + reason: "connect", + deviceId: "same-device", + instanceId: "existing-tab", + text: "Control UI", + ts: 1, +}; + +describe("resolveConnectedControlUiPresenceKeys", () => { + it("uses connection identity instead of mutable presence freshness", () => { + const baseline = resolveConnectedControlUiPresenceKeys([connectedControlUiPresence]); + + expect( + resolveConnectedControlUiPresenceKeys([{ ...connectedControlUiPresence, ts: 2 }]), + ).toEqual(baseline); + expect( + resolveConnectedControlUiPresenceKeys([ + { ...connectedControlUiPresence, instanceId: "new-tab", ts: 2 }, + ]), + ).not.toEqual(baseline); + expect( + resolveConnectedControlUiPresenceKeys([ + { ...connectedControlUiPresence, reason: "disconnect", ts: 2 }, + ]), + ).toEqual([]); + }); +}); + describe("runBrowserHatchHandoff", () => { + it("does not hand off when only an existing Control UI heartbeat changes", async () => { + const prompter = createWizardPrompter(); + let elapsedMs = 0; + + const result = await runBrowserHatchHandoff( + { config: {}, prompter }, + { + env: { DISPLAY: ":0" }, + platform: "linux", + openBrowser: vi.fn(async () => true), + resolveTarget: async () => target, + probePresence: async () => ({ + reachable: true, + clientKeys: resolveConnectedControlUiPresenceKeys([ + { ...connectedControlUiPresence, ts: elapsedMs }, + ]), + }), + now: () => elapsedMs, + sleep: async (ms) => { + elapsedMs += ms; + }, + }, + ); + + expect(result).toEqual({ handedOff: false, reason: "timeout" }); + expect(prompter.note).not.toHaveBeenCalledWith( + "Dashboard connected — continuing in your browser.", + expect.anything(), + ); + }); + it.each([ { platform: "darwin" as const, env: {} }, { platform: "linux" as const, env: { DISPLAY: ":0" } }, diff --git a/src/commands/onboard-browser-handoff.ts b/src/commands/onboard-browser-handoff.ts index 963f3b3b1d3b..464cda5a37f3 100644 --- a/src/commands/onboard-browser-handoff.ts +++ b/src/commands/onboard-browser-handoff.ts @@ -172,8 +172,12 @@ function isConnectedControlUi(entry: SystemPresence): boolean { ); } -function dashboardPresenceKey(entry: SystemPresence): string { - return [entry.deviceId, entry.instanceId, entry.host, entry.mode, entry.ts].join("\0"); +export function resolveConnectedControlUiPresenceKeys( + entries: readonly SystemPresence[], +): string[] { + return entries + .filter(isConnectedControlUi) + .map((entry) => [entry.deviceId, entry.instanceId, entry.host, entry.mode].join("\0")); } async function probeDashboardPresence( @@ -203,7 +207,7 @@ async function probeDashboardPresence( }); return { reachable: true, - clientKeys: (presence ?? []).filter(isConnectedControlUi).map(dashboardPresenceKey), + clientKeys: resolveConnectedControlUiPresenceKeys(presence ?? []), }; } catch (error) { return {