From 5eb0ed45319e8ec49480fc523dd0ca0d97ee907e Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Tue, 15 Sep 2026 14:48:30 -0700 Subject: [PATCH] fix(desktop): Vault settings tab dials its scoped profile foreground requestGatewayForProfile always dialed with the 'background' spawn priority, so the Vault tab under the Settings 'Applies to' selector kept the #111651 infinite-spinner path on a cold profile even after the REST side moved to scopedDialPriority. Let requestGatewayForProfile take a spawnPriority option and pass 'foreground' from the Vault panel; ambient callers are unchanged. Part of #111651 --- .../src/app/settings/vault-settings.test.tsx | 23 +++++++++++++++---- .../src/app/settings/vault-settings.tsx | 2 +- .../src/store/gateway-profile-request.test.ts | 13 +++++++++++ apps/desktop/src/store/gateway.ts | 8 +++++-- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/apps/desktop/src/app/settings/vault-settings.test.tsx b/apps/desktop/src/app/settings/vault-settings.test.tsx index ba355d0aa9..487f5c0796 100644 --- a/apps/desktop/src/app/settings/vault-settings.test.tsx +++ b/apps/desktop/src/app/settings/vault-settings.test.tsx @@ -5,16 +5,20 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { stubResizeObserver } from '@/test/jsdom' -const { requestGateway } = vi.hoisted(() => ({ - requestGateway: vi.fn() +const { requestGateway, requestGatewayForProfile } = vi.hoisted(() => ({ + requestGateway: vi.fn(), + requestGatewayForProfile: vi.fn() })) // The panel routes every RPC through the owner profile's socket (never the ambient gateway); // the mock receives (method, params) after the profile argument. vi.mock('@/store/gateway', async importActual => ({ ...(await importActual>()), - requestGatewayForProfile: (_profile: string, method: string, params?: Record) => - requestGateway(method, params ?? {}) + requestGatewayForProfile: (...args: [string, string, Record?, ...unknown[]]) => { + requestGatewayForProfile(...args) + + return requestGateway(args[1], args[2] ?? {}) + } })) import { queryClient } from '@/lib/query-client' @@ -45,6 +49,7 @@ const LOGIN_ITEM = { beforeEach(() => { requestGateway.mockReset() + requestGatewayForProfile.mockReset() queryClient.clear() $gatewayState.set('open') }) @@ -61,6 +66,16 @@ describe('VaultSettings', () => { await waitFor(() => expect(screen.getByText('Nothing saved yet')).toBeTruthy()) expect(requestGateway).toHaveBeenCalledWith('vault.list', {}) + // The scoped Settings dial must be foreground so a cold profile spawn is not + // queued behind background work (#111651). + expect(requestGatewayForProfile).toHaveBeenCalledWith( + expect.any(String), + 'vault.list', + {}, + undefined, + undefined, + { spawnPriority: 'foreground' } + ) }) it('lists items with label, kind badge, identifier, and origin — never passwords', async () => { diff --git a/apps/desktop/src/app/settings/vault-settings.tsx b/apps/desktop/src/app/settings/vault-settings.tsx index f6e63f4476..3c1457bd42 100644 --- a/apps/desktop/src/app/settings/vault-settings.tsx +++ b/apps/desktop/src/app/settings/vault-settings.tsx @@ -165,7 +165,7 @@ export function VaultSettings() { const requestGateway = useCallback( (method: string, params: Record = {}) => - requestGatewayForProfile(scopeProfile, method, params), + requestGatewayForProfile(scopeProfile, method, params, undefined, undefined, { spawnPriority: 'foreground' }), [scopeProfile] ) diff --git a/apps/desktop/src/store/gateway-profile-request.test.ts b/apps/desktop/src/store/gateway-profile-request.test.ts index 04fcc88741..27d1b1c4f2 100644 --- a/apps/desktop/src/store/gateway-profile-request.test.ts +++ b/apps/desktop/src/store/gateway-profile-request.test.ts @@ -111,6 +111,19 @@ describe('requestGatewayForProfile', () => { expect($gateway.get()).toBe(primary) }) + it('dials the profile with foreground priority when a Settings-scoped caller asks for it (#111651)', async () => { + setPrimaryGateway(makePrimary() as never, 'default') + const getConnection = vi.fn(async (profile: null | string) => + profile ? { port: 5151, profile, token: 'secondary-token' } : { port: 4242, token: 'primary-token' } + ) + installDesktop(getConnection) + await ensureGatewayForProfile('default') + + await requestGatewayForProfile('worker', 'vault.list', {}, undefined, undefined, { spawnPriority: 'foreground' }) + + expect(getConnection).toHaveBeenCalledWith('worker', { priority: 'foreground' }) + }) + it('uses the primary socket and adds profile scope for a shared global remote route', async () => { const primary = makePrimary() setPrimaryGateway(primary as never, 'default') diff --git a/apps/desktop/src/store/gateway.ts b/apps/desktop/src/store/gateway.ts index a150bf680e..3045835fa6 100644 --- a/apps/desktop/src/store/gateway.ts +++ b/apps/desktop/src/store/gateway.ts @@ -991,9 +991,13 @@ export async function requestGatewayForProfile( method: string, params: Record = {}, timeoutMs?: number, - signal?: AbortSignal + signal?: AbortSignal, + { spawnPriority = 'background' }: { spawnPriority?: SpawnPriority } = {} ): Promise { - const route = await gatewayForProfile(profile, true) + // A user-initiated Settings-scoped RPC (the Vault tab's "Applies to" pick) + // dials `foreground` so a cold profile spawn is not queued behind background + // work (#111651); ambient callers keep the background default. + const route = await gatewayForProfile(profile, true, spawnPriority) try { if (!route.gateway) {