Don't show local Windows shells for serve-runtime worktrees (#5947)

* Don't show local Windows shells for serve-runtime worktrees

The Windows shell menu (PowerShell/CMD/Git Bash) was offered for a
serve/remote-runtime worktree whose host is not Windows (e.g. a Linux
orca serve), where those local shell choices are meaningless and the
plain New Terminal already opens the runtime's default shell. AND a new
runtimeHostIsNonWindows exclusion into the existing shouldShowWindowsShellMenu
gate, keyed on the probed runtime host platform so a LOCAL Windows-WSL
project runtime (hostPlatform === win32) keeps its shell menu. Adds
regression tests.

Rebased onto current main (was 75 commits stale); net delta unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Hide runtime Windows shells until host is known

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Lesley Murfin
2026-06-22 13:35:32 -07:00
committed by GitHub
co-authored by Claude Opus 4.8 Orca Jinwoo-H
parent 65e2bd0557
commit 28824cda78
4 changed files with 150 additions and 9 deletions
+11 -9
View File
@@ -76,6 +76,7 @@ import { TabStripScrollIndicator } from './TabStripScrollIndicator'
import { getTabStripScrollMaskClassName } from './tab-strip-scroll-metrics'
import { useTabStripOverflowNavigation } from './tab-strip-overflow-navigation'
import { useTabStripDragScrollHandlers } from './tab-strip-drag-scroll'
import { shouldShowWindowsShellMenu } from './windows-shell-menu-visibility'
const isWindows = navigator.userAgent.includes('Windows')
const isMacOs = navigator.userAgent.includes('Mac')
@@ -374,13 +375,14 @@ function TabBarInner({
windowsTerminalCapabilityOwnerKey,
runtimeTarget
)
// Why: SSH-backed PTYs ignore local Windows shell overrides; showing these
// entries there promises PowerShell/CMD/Git Bash but opens the remote shell.
const shouldShowWindowsShellMenu =
(isWindows || windowsTerminalCapabilities.hostPlatform === 'win32') &&
!worktreeHasRemoteConnection
const showWindowsShellMenu = shouldShowWindowsShellMenu({
activeRuntimeEnvironmentId,
hostPlatform: windowsTerminalCapabilities.hostPlatform,
isWindowsClient: isWindows,
worktreeHasRemoteConnection
})
const localProjectRuntime = useMemo(() => {
if (!shouldShowWindowsShellMenu || activeRuntimeEnvironmentId?.trim()) {
if (!showWindowsShellMenu || activeRuntimeEnvironmentId?.trim()) {
return undefined
}
return getLocalProjectExecutionRuntimeContext(
@@ -410,7 +412,7 @@ function TabBarInner({
projects,
repos,
settings,
shouldShowWindowsShellMenu,
showWindowsShellMenu,
windowsTerminalCapabilities.isLoading,
windowsTerminalCapabilities.wslAvailable,
windowsTerminalCapabilities.wslDistros,
@@ -491,7 +493,7 @@ function TabBarInner({
pendingNewTabMenuFocusRef.current = () => focusTerminalTabSurface(tabId)
}
const windowsShellEntries = useMemo(() => {
if (!shouldShowWindowsShellMenu || !onNewTerminalWithShell) {
if (!showWindowsShellMenu || !onNewTerminalWithShell) {
return undefined
}
const includeHostShells = projectRuntimeShellMenuMode !== 'wsl'
@@ -538,7 +540,7 @@ function TabBarInner({
defaultWindowsShell,
onNewTerminalWithShell,
projectRuntimeShellMenuMode,
shouldShowWindowsShellMenu,
showWindowsShellMenu,
windowsTerminalCapabilities.gitBashAvailable,
windowsTerminalCapabilities.wslAvailable
])
@@ -751,4 +751,68 @@ describe('TabBar PowerShell launch wiring', () => {
expect(findDropdownMenuItemByText(expandNode(element), 'New Terminal: PowerShell')).toBeNull()
expect(findDropdownMenuItemByText(expandNode(element), 'New Terminal')).not.toBeNull()
})
it('hides local Windows shell rows for a non-Windows serve runtime', async () => {
// Why: a Windows desktop client paired to a Linux `orca serve` runs its PTY on
// the serve host. The local Windows shell choices (PowerShell/CMD/WSL) are
// meaningless there; the plain "New Terminal" already opens the serve's default
// shell. Sibling tests above assert that a win32 remote host still shows the
// rows, so the LOCAL Windows-WSL project-runtime menu (hostPlatform 'win32')
// is unaffected by this suppression.
vi.stubGlobal('navigator', { userAgent: 'Windows' })
vi.stubGlobal('__ORCA_WEB_CLIENT__', false)
vi.stubGlobal('window', {
api: {
wsl: {
isAvailable: vi.fn().mockResolvedValue(false),
listDistros: vi.fn().mockResolvedValue([])
},
pwsh: { isAvailable: vi.fn().mockResolvedValue(false) },
gitBash: { isAvailable: vi.fn().mockResolvedValue(false) },
runtime: { getStatus: vi.fn().mockResolvedValue({ hostPlatform: 'linux' }) }
}
})
appStoreSnapshot.activeRuntimeEnvironmentId = 'serve-env-1'
const capabilities = await import('@/lib/windows-terminal-capabilities')
await capabilities.loadWindowsTerminalCapabilities({
force: true,
ownerKey: 'runtime:serve-env-1'
})
const tabBarModule = await import('./TabBar')
const candidate = tabBarModule.default ?? tabBarModule
const TabBar =
typeof candidate === 'function'
? candidate
: typeof (candidate as { type?: unknown }).type === 'function'
? (candidate as { type: (props: Record<string, unknown>) => unknown }).type
: null
expect(TabBar).not.toBeNull()
const element = TabBar!({
tabs: [],
activeTabId: null,
worktreeId: 'wt-1',
expandedPaneByTabId: {},
onActivate: () => {},
onClose: () => {},
onCloseOthers: () => {},
onCloseToRight: () => {},
onNewTerminalTab: () => {},
onNewTerminalWithShell: vi.fn(),
onNewBrowserTab: () => {},
onSetCustomTitle: () => {},
onSetTabColor: () => {},
onTogglePaneExpand: () => {}
})
expect(
findDropdownMenuItemByText(expandNode(element), 'New Terminal: PowerShell')
).toBeNull()
expect(
findDropdownMenuItemByText(expandNode(element), 'New Terminal: CMD Prompt')
).toBeNull()
expect(findDropdownMenuItemByText(expandNode(element), 'New Terminal: WSL')).toBeNull()
expect(findDropdownMenuItemByText(expandNode(element), 'New Terminal')).not.toBeNull()
})
})
@@ -0,0 +1,59 @@
import { describe, expect, it } from 'vitest'
import { shouldShowWindowsShellMenu } from './windows-shell-menu-visibility'
describe('shouldShowWindowsShellMenu', () => {
it('shows local Windows shells for a local Windows client without a runtime owner', () => {
expect(
shouldShowWindowsShellMenu({
activeRuntimeEnvironmentId: null,
hostPlatform: null,
isWindowsClient: true,
worktreeHasRemoteConnection: false
})
).toBe(true)
})
it('keeps the menu hidden while a runtime host platform is unknown', () => {
expect(
shouldShowWindowsShellMenu({
activeRuntimeEnvironmentId: 'serve-env-1',
hostPlatform: null,
isWindowsClient: true,
worktreeHasRemoteConnection: false
})
).toBe(false)
})
it('shows runtime Windows shells only after the runtime host is known to be Windows', () => {
expect(
shouldShowWindowsShellMenu({
activeRuntimeEnvironmentId: 'serve-env-1',
hostPlatform: 'win32',
isWindowsClient: false,
worktreeHasRemoteConnection: false
})
).toBe(true)
})
it('hides local Windows shells for a non-Windows runtime host', () => {
expect(
shouldShowWindowsShellMenu({
activeRuntimeEnvironmentId: 'serve-env-1',
hostPlatform: 'linux',
isWindowsClient: true,
worktreeHasRemoteConnection: false
})
).toBe(false)
})
it('hides local Windows shells for SSH worktrees', () => {
expect(
shouldShowWindowsShellMenu({
activeRuntimeEnvironmentId: null,
hostPlatform: 'win32',
isWindowsClient: true,
worktreeHasRemoteConnection: true
})
).toBe(false)
})
})
@@ -0,0 +1,16 @@
export function shouldShowWindowsShellMenu(args: {
activeRuntimeEnvironmentId: string | null | undefined
hostPlatform: NodeJS.Platform | null
isWindowsClient: boolean
worktreeHasRemoteConnection: boolean
}): boolean {
// Why: runtime terminals execute on the runtime host. Until that host is known
// to be Windows, local Windows shell choices would advertise the wrong target.
const runtimeHostIsNotKnownWindows =
Boolean(args.activeRuntimeEnvironmentId?.trim()) && args.hostPlatform !== 'win32'
return (
(args.isWindowsClient || args.hostPlatform === 'win32') &&
!args.worktreeHasRemoteConnection &&
!runtimeHostIsNotKnownWindows
)
}