mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
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:
co-authored by
Claude Opus 4.8
Orca
Jinwoo-H
parent
65e2bd0557
commit
28824cda78
@@ -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
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user