fix(desktop): reuse primary during owned route activation

This commit is contained in:
arya
2026-08-26 02:13:34 +10:00
committed by Teknium
parent 6c0ddecf66
commit 1ec32e7385
3 changed files with 25 additions and 9 deletions
@@ -9,7 +9,7 @@ import {
selectConnection,
setConnectionsRegistry
} from '@/store/connections'
import { closeSecondaryGateways, isActivePrimary } from '@/store/gateway'
import { closeSecondaryGateways, isActivePrimary, requestGatewayForAgent } from '@/store/gateway'
import { reconnectGateway } from '@/store/gateway-reconnect'
import {
$gatewaySwitching,
@@ -869,6 +869,17 @@ describe('useGatewayBoot remote reconnect loop (real hook, fake socket)', () =>
expect(configPublications).toEqual(['settings-b'])
})
it('publishes the cold-boot primary registry identity for owned session RPCs', async () => {
render(<Harness />)
await flushAsync()
expect($gatewayState.get()).toBe('open')
expect(FakeWebSocket.instances).toHaveLength(1)
await expect(requestGatewayForAgent('primary-vps', 'default', 'ping')).resolves.toEqual({ pong: true })
expect(FakeWebSocket.instances).toHaveLength(1)
})
it('re-fetches the profile rail from the NEW backend after a connection apply (#85731)', async () => {
// The reported repro: connected to backend A, the rail shows A's named
// profiles; the user applies a different remote/Cloud connection (soft
@@ -42,7 +42,7 @@ vi.mock('@/hermes', () => ({
},
setApiRequestConnection: vi.fn()
}))
vi.mock('@/store/session', () => ({ setGatewayState: vi.fn() }))
vi.mock('@/store/session', () => ({ setConnection: vi.fn(), setGatewayState: vi.fn() }))
vi.mock('@/store/notify-baseline', () => ({ markNativeNotifyBaseline: vi.fn() }))
const {
@@ -213,6 +213,9 @@ describe('requestGatewayForAgent', () => {
}
await ensureGatewayForProfile('default')
await openGatewayForAgent('remote-primary', 'default')
await ensureGatewayForAgent('remote-primary', 'default')
const result = await requestGatewayForAgent('remote-primary', 'default', 'session.resume', {
session_id: 'stored-session'
})
+9 -7
View File
@@ -202,6 +202,12 @@ export function setPrimaryGatewayConnection(connection: Pick<HermesConnection, '
g.primaryConnectionId = connection?.connectionId?.trim() || null
}
function isPrimaryRegistryRoute(connectionId: null | string, profile: string): boolean {
const id = String(connectionId ?? '').trim()
return normKey(profile) === g.primaryProfile && Boolean(id) && Boolean(g.primaryConnectionId) && id === g.primaryConnectionId
}
export function isActivePrimary(): boolean {
return g.activeKey === g.primaryProfile
}
@@ -688,11 +694,7 @@ export async function requestGatewayForAgent<T>(
// "session not found" while REST history from the primary remains visible.
// Require both owner identities to agree before collapsing the route; a
// different source or profile must retain its isolated secondary.
if (
key === g.primaryProfile &&
Boolean(g.primaryConnectionId) &&
g.primaryConnectionId === String(connectionId).trim()
) {
if (isPrimaryRegistryRoute(connectionId, key)) {
return requestGatewayForProfile<T>(key, method, params, timeoutMs, signal)
}
@@ -907,7 +909,7 @@ export async function openGatewayForAgent(
): Promise<void> {
const scope = registryBackendScopeKey(connectionId, profile)
if (scope === normKey(profile)) {
if (scope === normKey(profile) || isPrimaryRegistryRoute(connectionId, profile)) {
return openGatewayForProfile(profile)
}
@@ -947,7 +949,7 @@ export async function ensureGatewayForAgent(
): Promise<boolean> {
const scope = registryBackendScopeKey(connectionId, profile)
if (scope === normKey(profile)) {
if (scope === normKey(profile) || isPrimaryRegistryRoute(connectionId, profile)) {
if (signal?.aborted) {
return false
}