From eb61c59affad6b6a6dc31ecce80cfb4a294a9a2e Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Fri, 7 Aug 2026 19:07:11 -0400 Subject: [PATCH] fix(quick-commands): address remote host review --- .../settings/QuickCommandsPane.test.ts | 36 +++++++- .../components/settings/QuickCommandsPane.tsx | 74 ++++++++++++--- .../tab-bar/TabBarQuickCommandAddActions.tsx | 7 +- .../TerminalContextMenu.test.tsx | 11 +++ .../terminal-pane/TerminalContextMenu.tsx | 2 +- .../use-terminal-quick-command-hosts.test.ts | 90 ++++++++++++++++++- .../hooks/use-terminal-quick-command-hosts.ts | 5 +- src/renderer/src/i18n/locales/en.json | 30 ++++--- .../slices/terminal-quick-command-hosts.ts | 4 +- 9 files changed, 227 insertions(+), 32 deletions(-) diff --git a/src/renderer/src/components/settings/QuickCommandsPane.test.ts b/src/renderer/src/components/settings/QuickCommandsPane.test.ts index ac0689d9259..41af6d410ad 100644 --- a/src/renderer/src/components/settings/QuickCommandsPane.test.ts +++ b/src/renderer/src/components/settings/QuickCommandsPane.test.ts @@ -1,5 +1,9 @@ import { describe, expect, it } from 'vitest' -import { shouldOpenQuickCommandAddIntent } from './QuickCommandsPane' +import { + getAvailableQuickCommandHostId, + shouldOpenQuickCommandAddIntent, + shouldShowQuickCommandsRefreshError +} from './QuickCommandsPane' describe('QuickCommandsPane add-command intent', () => { it('opens the add flow once for each new intent signal', () => { @@ -10,3 +14,33 @@ describe('QuickCommandsPane add-command intent', () => { expect(shouldOpenQuickCommandAddIntent(2, 1)).toBe(true) }) }) + +describe('QuickCommandsPane host state', () => { + it('falls back to the local host when the selected remote host disappears', () => { + expect( + getAvailableQuickCommandHostId('runtime:removed', [ + { id: 'local' }, + { id: 'runtime:available' } + ]) + ).toBe('local') + }) + + it('keeps the selected host while it remains available', () => { + expect( + getAvailableQuickCommandHostId('runtime:available', [ + { id: 'local' }, + { id: 'runtime:available' } + ]) + ).toBe('runtime:available') + }) + + it('surfaces refresh failures only when cached commands remain usable', () => { + expect(shouldShowQuickCommandsRefreshError(true, { error: 'offline', ready: true })).toBe(true) + expect(shouldShowQuickCommandsRefreshError(true, { error: 'offline', ready: false })).toBe( + false + ) + expect(shouldShowQuickCommandsRefreshError(false, { error: 'offline', ready: true })).toBe( + false + ) + }) +}) diff --git a/src/renderer/src/components/settings/QuickCommandsPane.tsx b/src/renderer/src/components/settings/QuickCommandsPane.tsx index 1f98b1af361..55aef0a05a1 100644 --- a/src/renderer/src/components/settings/QuickCommandsPane.tsx +++ b/src/renderer/src/components/settings/QuickCommandsPane.tsx @@ -46,6 +46,22 @@ export function shouldOpenQuickCommandAddIntent( return Boolean(addCommandIntentSignal && consumedAddIntentSignal !== addCommandIntentSignal) } +export function getAvailableQuickCommandHostId( + selectedHostId: ExecutionHostId, + hostOptions: readonly { id: ExecutionHostId }[] +): ExecutionHostId { + return hostOptions.some((host) => host.id === selectedHostId) + ? selectedHostId + : LOCAL_EXECUTION_HOST_ID +} + +export function shouldShowQuickCommandsRefreshError( + commandsAreCurrent: boolean, + runtimeCommands: { error: string | null; ready: boolean } | undefined +): boolean { + return commandsAreCurrent && runtimeCommands?.ready === true && Boolean(runtimeCommands.error) +} + export function QuickCommandsPane({ settings, addCommandIntentSignal @@ -97,6 +113,12 @@ export function QuickCommandsPane({ const [scopeSelection, setScopeSelection] = useState | null>(null) const [scopePopoverOpen, setScopePopoverOpen] = useState(false) + const availableHostId = getAvailableQuickCommandHostId(selectedHostId, hostOptions) + if (availableHostId !== selectedHostId) { + setSelectedHostId(availableHostId) + setScopeSelection(null) + } + const hostRepos = useMemo( () => selectedEnvironmentId @@ -227,7 +249,9 @@ export function QuickCommandsPane({
- +