fix(desktop): scope registered ssh primary gateway

This commit is contained in:
Ahmett101
2026-08-24 23:46:40 +03:00
committed by Teknium
parent 4fc4da2531
commit 1b8f3eda38
3 changed files with 51 additions and 6 deletions
@@ -18,6 +18,7 @@ import {
} from '@/store/boot'
import {
$gateway,
activeGatewayConnectionId,
closeLegacySecondaryGateways,
closeSecondaryGateways,
configureGatewayRegistry,
@@ -31,6 +32,7 @@ import {
reportPrimaryGatewayState,
setPrimaryGateway,
setPrimaryGatewayConnection,
setPrimaryGatewayConnectionId,
touchSecondaryGateways
} from '@/store/gateway'
import { registerGatewayReconnect } from '@/store/gateway-reconnect'
@@ -185,6 +187,7 @@ export function useGatewayBoot({
}
: null
)
setPrimaryGatewayConnectionId(next?.connectionId)
}
if (!desktop) {
@@ -737,9 +740,17 @@ export function useGatewayBoot({
const sourceProfile = normalizeProfileKey($activeGatewayProfile.get())
const offEvent = gateway.onEvent(event =>
callbacksRef.current.handleGatewayEvent({ ...event, profile: sourceProfile })
)
const offEvent = gateway.onEvent(event => {
const connectionId = activeGatewayConnectionId()
const scopedEvent = {
...event,
profile: sourceProfile,
...(connectionId ? { connectionId } : {})
}
recordSessionEventScope(scopedEvent)
callbacksRef.current.handleGatewayEvent(scopedEvent)
})
// Wake signals: power resume (macOS/Windows), network coming back, and the
// window regaining focus/visibility. Each nudges an immediate reconnect.
@@ -40,14 +40,17 @@ vi.mock('@/store/session', () => ({
vi.mock('@/store/notify-baseline', () => ({ markNativeNotifyBaseline: vi.fn() }))
const {
activeGatewayConnectionId,
closeLegacySecondaryGateways,
closeSecondaryGateways,
configureGatewayRegistry,
ensureGatewayForAgent,
openGatewayForAgent,
pruneSecondaryGateways,
setPrimaryGateway
setPrimaryGateway,
setPrimaryGatewayConnectionId
} = await import('./gateway')
const { setApiRequestConnection } = await import('@/hermes')
function installDesktop(): void {
;(window as unknown as { hermesDesktop: unknown }).hermesDesktop = {
@@ -85,6 +88,25 @@ afterEach(() => {
delete (window as unknown as { hermesDesktop?: unknown }).hermesDesktop
})
describe('primary gateway registry scope', () => {
it('publishes a registered primary connection id for ambient API/WebSocket helpers', () => {
setPrimaryGateway({ connectionState: 'open' } as never, 'default')
setPrimaryGatewayConnectionId(' homelab-ssh ')
expect(activeGatewayConnectionId()).toBe('homelab-ssh')
expect(setApiRequestConnection).toHaveBeenLastCalledWith('homelab-ssh')
})
it('clears primary connection scope when the primary becomes legacy/local again', () => {
setPrimaryGateway({ connectionState: 'open' } as never, 'default')
setPrimaryGatewayConnectionId('homelab-ssh')
setPrimaryGateway({ connectionState: 'open' } as never, 'default')
expect(activeGatewayConnectionId()).toBeNull()
expect(setApiRequestConnection).toHaveBeenLastCalledWith(null)
})
})
describe('pruneSecondaryGateways with registry-scoped entries', () => {
it('keeps the previous source socket open when Sessions switches backends', async () => {
await ensureGatewayForAgent('work', 'default')
+14 -2
View File
@@ -226,11 +226,23 @@ export function setPrimaryGateway(gateway: HermesGateway | null, profile = 'defa
g.primaryGateway = gateway
g.primaryProfile = next
if (g.activeKey === g.primaryProfile) {
setApiRequestConnection(g.primaryConnectionId)
}
}
export function setPrimaryGatewayConnectionId(connectionId: null | string | undefined): void {
g.primaryConnectionId = (connectionId ?? '').trim() || null
if (g.activeKey === g.primaryProfile) {
setApiRequestConnection(g.primaryConnectionId)
}
}
/** Publish the registry source owned by the window primary socket. */
export function setPrimaryGatewayConnection(connection: Pick<HermesConnection, 'connectionId'> | null): void {
g.primaryConnectionId = connection?.connectionId?.trim() || null
setPrimaryGatewayConnectionId(connection?.connectionId)
}
function isPrimaryRegistryRoute(connectionId: null | string, profile: string): boolean {
@@ -276,7 +288,7 @@ export function activeGateway(): HermesGateway | null {
*/
export function activeGatewayConnectionId(): null | string {
if (g.activeKey === g.primaryProfile) {
return null
return g.primaryConnectionId
}
return g.secondaries.get(g.activeKey)?.connectionId ?? null