feat: harden local shell, SFTP, and desktop session reliability

Finder-launched terminals now inherit a login PATH so tools like ollama resolve, destructive SFTP/editor actions require confirmation, and terminal search plus window dragging work again. SSH forwards and RDP sessions keep listeners and survive reconnect without FastPath crashes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Logan.LiandCursor committed 2026-08-16 16:08:11 +08:00
1 parent 188f3556ed
commit 08696896f9
223 files changed
+13493 -3423

No files matched your search

+291 -94
View File
@@ -1,16 +1,18 @@
import { useEffect, useRef, useState, type KeyboardEvent, type MouseEvent } from 'react'
import { useCallback, useEffect, useRef, useState, type KeyboardEvent, type MouseEvent } from 'react'
import { useTranslation } from 'react-i18next'
import {
Cast,
ClipboardPaste,
FolderInput,
FolderOpen,
Maximize2,
Minimize2,
Monitor,
RefreshCw,
Unplug,
} from 'lucide-react'
import { useTabStore } from '../../stores/tabStore'
import { useSessionStore } from '../../stores/sessionStore'
import { useDesktopFullscreenStore } from '../../stores/desktopFullscreenStore'
import type {
DesktopFrameEvent,
DesktopPointerButton,
@@ -28,6 +30,7 @@ import {
rdpDisconnect,
rdpInputKey,
rdpInputPointer,
rdpResize,
rdpUploadFile,
} from '../../platform/rdp'
import {
@@ -41,6 +44,7 @@ import {
vncInputPointer,
} from '../../platform/vnc'
import { sessionToRdpConfig, sessionToVncConfig } from '../../utils/sessionProtocol'
import { clampDesktopResolution } from '../../utils/desktopResolution'
interface DesktopSessionViewProps {
tabId: string
@@ -70,6 +74,7 @@ function decodeRgbaBase64(base64: string): Uint8ClampedArray<ArrayBuffer> {
export default function DesktopSessionView({ tabId, isActive }: DesktopSessionViewProps) {
const { t } = useTranslation('desktop')
const canvasRef = useRef<HTMLCanvasElement>(null)
const paneRef = useRef<HTMLDivElement>(null)
const canvasCtxRef = useRef<CanvasRenderingContext2D | null>(null)
const nativeSessionIdRef = useRef<string | null>(null)
const isActiveRef = useRef(isActive)
@@ -77,7 +82,11 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
const buttonsRef = useRef({ left: false, middle: false, right: false })
const pointerRafRef = useRef<number | null>(null)
const paintRafRef = useRef<number | null>(null)
const hideBarTimerRef = useRef<number | null>(null)
const pendingFramesRef = useRef<DesktopFrameEvent[]>([])
const lastRemoteResizeRef = useRef<{ width: number; height: number } | null>(null)
const remoteResizeTimerRef = useRef<number | null>(null)
const connectedRef = useRef(false)
const pendingPointerRef = useRef<{
x: number
y: number
@@ -87,10 +96,17 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
const tab = useTabStore((state) => state.tabs.find((item) => item.id === tabId))
const sessions = useSessionStore((state) => state.sessions)
const updateTabStatus = useTabStore((state) => state.updateTabStatus)
const fullscreenActive = useDesktopFullscreenStore(
(state) => state.active && state.tabId === tabId
)
const enterFullscreen = useDesktopFullscreenStore((state) => state.enter)
const exitFullscreen = useDesktopFullscreenStore((state) => state.exit)
const toggleFullscreen = useDesktopFullscreenStore((state) => state.toggle)
const [statusMessage, setStatusMessage] = useState<string>(() => t('status.connecting'))
const [error, setError] = useState<string | null>(null)
const [fbSize, setFbSize] = useState({ width: 1920, height: 1080 })
const [resolvedConfig, setResolvedConfig] = useState<RdpConfig | VncConfig | null>(null)
const [chromeVisible, setChromeVisible] = useState(true)
const protocol: DesktopProtocol = tab?.type === 'vnc' ? 'vnc' : 'rdp'
isActiveRef.current = isActive
@@ -203,6 +219,8 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
updateTabStatus(tabId, 'connecting')
setStatusMessage(t('status.connecting'))
setError(null)
connectedRef.current = false
lastRemoteResizeRef.current = null
void (async () => {
try {
@@ -210,13 +228,20 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
unlistenStatus = await onRdpStatus((payload) => {
if (nativeSessionIdRef.current && payload.sessionId !== nativeSessionIdRef.current) return
if (!nativeSessionIdRef.current) nativeSessionIdRef.current = payload.sessionId
if (payload.width && payload.height) {
setFbSize({ width: payload.width, height: payload.height })
lastRemoteResizeRef.current = { width: payload.width, height: payload.height }
}
if (payload.status === 'connected') {
connectedRef.current = true
updateTabStatus(tabId, 'connected')
setStatusMessage(payload.message || t('status.connected'))
} else if (payload.status === 'error') {
connectedRef.current = false
updateTabStatus(tabId, 'error')
setError(payload.message || t('status.connectFailed'))
} else if (payload.status === 'disconnected') {
connectedRef.current = false
updateTabStatus(tabId, 'disconnected')
setStatusMessage(t('status.disconnected'))
} else if (payload.message) {
@@ -288,6 +313,11 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
return () => {
disposed = true
connectedRef.current = false
if (remoteResizeTimerRef.current != null) {
window.clearTimeout(remoteResizeTimerRef.current)
remoteResizeTimerRef.current = null
}
if (paintRafRef.current != null) {
window.cancelAnimationFrame(paintRafRef.current)
paintRafRef.current = null
@@ -311,6 +341,123 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
canvasRef.current?.focus()
}, [isActive])
// Fit canvas to pane; for RDP also request remote dynamic resolution (mstsc / FreeRDP style).
useEffect(() => {
const pane = paneRef.current
const canvas = canvasRef.current
if (!pane || !canvas || fbSize.width <= 0 || fbSize.height <= 0) return
const updateFit = () => {
const availW = Math.max(1, pane.clientWidth)
const availH = Math.max(1, pane.clientHeight)
const scale = Math.min(availW / fbSize.width, availH / fbSize.height)
const displayW = Math.max(1, Math.floor(fbSize.width * scale))
const displayH = Math.max(1, Math.floor(fbSize.height * scale))
canvas.style.width = `${displayW}px`
canvas.style.height = `${displayH}px`
}
const requestRemoteResize = () => {
if (protocol !== 'rdp' || !connectedRef.current || !isActive) return
const sessionId = nativeSessionIdRef.current
if (!sessionId) return
const next = clampDesktopResolution(pane.clientWidth, pane.clientHeight)
const last = lastRemoteResizeRef.current
if (last && last.width === next.width && last.height === next.height) return
// Skip tiny panes (drawer/animation) that would thrash the session.
if (next.width < 640 || next.height < 480) return
lastRemoteResizeRef.current = next
void rdpResize(sessionId, next.width, next.height).catch(() => {
// Allow retry on next size change if Display Control was not ready.
lastRemoteResizeRef.current = last
})
}
const onPaneResize = () => {
updateFit()
if (remoteResizeTimerRef.current != null) {
window.clearTimeout(remoteResizeTimerRef.current)
}
remoteResizeTimerRef.current = window.setTimeout(requestRemoteResize, 280)
}
updateFit()
// After fullscreen / maximize layout settles, request matching remote size once.
remoteResizeTimerRef.current = window.setTimeout(requestRemoteResize, fullscreenActive ? 120 : 280)
const observer = new ResizeObserver(onPaneResize)
observer.observe(pane)
return () => {
observer.disconnect()
if (remoteResizeTimerRef.current != null) {
window.clearTimeout(remoteResizeTimerRef.current)
remoteResizeTimerRef.current = null
}
}
}, [fbSize.height, fbSize.width, fullscreenActive, isActive, protocol])
// Leave OS fullscreen when this tab is hidden or unmounted.
useEffect(() => {
if (!isActive && fullscreenActive) {
void exitFullscreen()
}
}, [exitFullscreen, fullscreenActive, isActive])
useEffect(() => {
return () => {
if (hideBarTimerRef.current != null) {
window.clearTimeout(hideBarTimerRef.current)
}
// Only exit when this session view is truly torn down (tab closed), not on HMR-only paths.
const state = useDesktopFullscreenStore.getState()
if (state.active && state.tabId === tabId) {
const stillOpen = useTabStore.getState().tabs.some((item) => item.id === tabId)
if (!stillOpen) void state.exit()
}
}
}, [tabId])
useEffect(() => {
if (!fullscreenActive) {
setChromeVisible(true)
if (hideBarTimerRef.current != null) {
window.clearTimeout(hideBarTimerRef.current)
hideBarTimerRef.current = null
}
return
}
// If the user leaves OS fullscreen via system UI, drop session chrome-hide.
const timer = window.setInterval(() => {
void (async () => {
try {
const state = useDesktopFullscreenStore.getState()
if (!state.active || state.tabId !== tabId) return
if (Date.now() - state.enteredAt < 1600) return
const osFs = await window.opsxApi?.isFullscreen?.()
if (osFs === false) {
useDesktopFullscreenStore.setState({ active: false, tabId: null, enteredAt: 0 })
}
} catch {
// ignore
}
})()
}, 1000)
return () => window.clearInterval(timer)
}, [fullscreenActive, tabId])
const scheduleHideChrome = useCallback(() => {
if (!fullscreenActive) return
if (hideBarTimerRef.current != null) window.clearTimeout(hideBarTimerRef.current)
hideBarTimerRef.current = window.setTimeout(() => {
setChromeVisible(false)
hideBarTimerRef.current = null
}, 1800)
}, [fullscreenActive])
const revealChrome = useCallback(() => {
setChromeVisible(true)
scheduleHideChrome()
}, [scheduleHideChrome])
const flushPointer = () => {
pointerRafRef.current = null
const sessionId = nativeSessionIdRef.current
@@ -383,6 +530,21 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
const onKey = (event: KeyboardEvent<HTMLCanvasElement>, pressed: boolean) => {
const sessionId = nativeSessionIdRef.current
if (!sessionId) return
// Local fullscreen controls — never forward to the remote desktop.
if (event.key === 'F11') {
event.preventDefault()
event.stopPropagation()
if (pressed) void toggleFullscreen(tabId)
return
}
if (fullscreenActive && event.key === 'Escape') {
event.preventDefault()
event.stopPropagation()
if (pressed) void exitFullscreen()
return
}
event.preventDefault()
const isPasteChord =
@@ -434,20 +596,6 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
}
}
const disconnectSession = async () => {
const sessionId = nativeSessionIdRef.current
if (!sessionId) return
try {
if (protocol === 'rdp') await rdpDisconnect(sessionId)
else await vncDisconnect(sessionId)
nativeSessionIdRef.current = null
updateTabStatus(tabId, 'disconnected')
setStatusMessage(t('status.disconnected'))
} catch (reason) {
setError(reason instanceof Error ? reason.message : String(reason))
}
}
const Icon = protocol === 'rdp' ? Monitor : Cast
const hostLabel =
resolvedConfig && 'host' in resolvedConfig
@@ -458,91 +606,140 @@ export default function DesktopSessionView({ tabId, isActive }: DesktopSessionVi
const toolBtn =
'inline-flex h-7 w-7 items-center justify-center rounded-md text-content-secondary transition-colors hover:bg-dark-700 hover:text-content-primary disabled:cursor-not-allowed disabled:opacity-40'
return (
<div className="h-full flex flex-col bg-dark-900">
<div className="flex items-center gap-2 border-b border-dark-700/50 bg-dark-800/80 px-2.5 py-1.5 text-xs">
<Icon className="h-3.5 w-3.5 flex-shrink-0 text-accent-blue" />
<span className="max-w-[10rem] truncate font-mono text-content-secondary" title={hostLabel}>
{hostLabel}
</span>
<span className="tabular-nums text-txt-faint">
{fbSize.width}×{fbSize.height}
</span>
{tab?.connectionStatus === 'connecting' ? (
<RefreshCw className="h-3 w-3 flex-shrink-0 animate-spin text-yellow-400" />
) : (
<span
className={`h-1.5 w-1.5 flex-shrink-0 rounded-full ${
connected ? 'bg-green-500' : tab?.connectionStatus === 'error' ? 'bg-red-500' : 'bg-dark-500'
}`}
/>
const toolbar = (
<div
className={`flex items-center gap-2 px-2.5 py-1.5 text-xs ${
fullscreenActive
? 'rounded-b-lg border border-t-0 border-dark-700/60 bg-dark-900/95 shadow-lg shadow-black/40 backdrop-blur'
: 'border-b border-dark-700/50 bg-dark-800/80'
}`}
onMouseEnter={() => {
if (fullscreenActive) {
setChromeVisible(true)
if (hideBarTimerRef.current != null) {
window.clearTimeout(hideBarTimerRef.current)
hideBarTimerRef.current = null
}
}
}}
onMouseLeave={() => {
if (fullscreenActive) scheduleHideChrome()
}}
>
<Icon className="h-3.5 w-3.5 flex-shrink-0 text-accent-blue" />
<span className="max-w-[10rem] truncate font-mono text-content-secondary" title={hostLabel}>
{hostLabel}
</span>
<span className="tabular-nums text-txt-faint">
{fbSize.width}×{fbSize.height}
</span>
{tab?.connectionStatus === 'connecting' ? (
<RefreshCw className="h-3 w-3 flex-shrink-0 animate-spin text-yellow-400" />
) : (
<span
className={`h-1.5 w-1.5 flex-shrink-0 rounded-full ${
connected ? 'bg-green-500' : tab?.connectionStatus === 'error' ? 'bg-red-500' : 'bg-dark-500'
}`}
/>
)}
<span className="min-w-0 flex-1 truncate text-txt-muted">{statusMessage}</span>
{error && <span className="max-w-[30%] truncate text-red-400">{error}</span>}
{fullscreenActive && (
<span className="hidden shrink-0 text-[10px] text-txt-faint sm:inline">{t('toolbar.exitFullscreenHint')}</span>
)}
<div className="ml-1 flex flex-shrink-0 items-center gap-0.5">
<button
type="button"
className={toolBtn}
disabled={!connected}
onClick={() => void pasteToRemote()}
title={t('toolbar.pasteClipboard')}
aria-label={t('toolbar.pasteAria')}
>
<ClipboardPaste className="h-3.5 w-3.5" />
</button>
{protocol === 'rdp' && (
<>
<button
type="button"
className={toolBtn}
disabled={!connected}
onClick={() => fileInputRef.current?.click()}
title={t('toolbar.shareDrive')}
aria-label={t('toolbar.shareDriveAria')}
>
<FolderInput className="h-3.5 w-3.5" />
</button>
<input
ref={fileInputRef}
type="file"
className="hidden"
onChange={(event) => {
void onShareFileSelected(event.target.files)
event.target.value = ''
}}
/>
<button
type="button"
className={toolBtn}
onClick={() => void openSharedFolder()}
title={t('toolbar.openShareDir')}
aria-label={t('toolbar.openShareDirAria')}
>
<FolderOpen className="h-3.5 w-3.5" />
</button>
</>
)}
<span className="min-w-0 flex-1 truncate text-txt-muted">{statusMessage}</span>
{error && <span className="max-w-[30%] truncate text-red-400">{error}</span>}
<div className="ml-1 flex flex-shrink-0 items-center gap-0.5">
<button
type="button"
className={toolBtn}
disabled={!connected}
onClick={() => void pasteToRemote()}
title={t('toolbar.pasteClipboard')}
aria-label={t('toolbar.pasteAria')}
>
<ClipboardPaste className="h-3.5 w-3.5" />
</button>
{protocol === 'rdp' && (
<>
<button
type="button"
className={toolBtn}
disabled={!connected}
onClick={() => fileInputRef.current?.click()}
title={t('toolbar.shareDrive')}
aria-label={t('toolbar.shareDriveAria')}
>
<FolderInput className="h-3.5 w-3.5" />
</button>
<input
ref={fileInputRef}
type="file"
className="hidden"
onChange={(event) => {
void onShareFileSelected(event.target.files)
event.target.value = ''
}}
/>
<button
type="button"
className={toolBtn}
onClick={() => void openSharedFolder()}
title={t('toolbar.openShareDir')}
aria-label={t('toolbar.openShareDirAria')}
>
<FolderOpen className="h-3.5 w-3.5" />
</button>
</>
)}
<button
type="button"
className={`${toolBtn} text-red-400 hover:bg-red-500/15 hover:text-red-300`}
disabled={!connected}
onClick={() => void disconnectSession()}
title={t('toolbar.disconnect')}
aria-label={t('toolbar.disconnectAria')}
>
<Unplug className="h-3.5 w-3.5" />
</button>
</div>
<button
type="button"
className={toolBtn}
onClick={(event) => {
event.preventDefault()
event.stopPropagation()
void (fullscreenActive ? exitFullscreen() : enterFullscreen(tabId))
}}
title={fullscreenActive ? t('toolbar.exitFullscreen') : t('toolbar.fullscreen')}
aria-label={fullscreenActive ? t('toolbar.exitFullscreenAria') : t('toolbar.fullscreenAria')}
>
{fullscreenActive ? <Minimize2 className="h-3.5 w-3.5" /> : <Maximize2 className="h-3.5 w-3.5" />}
</button>
</div>
</div>
)
<div className="flex min-h-0 flex-1 items-center justify-center overflow-auto bg-black p-2">
return (
<div
className={`relative flex h-full flex-col bg-dark-900 ${fullscreenActive ? 'bg-black' : ''}`}
onMouseMove={(event) => {
if (!fullscreenActive) return
if (event.clientY <= 56) revealChrome()
}}
>
{fullscreenActive ? (
<div
className={`pointer-events-none absolute inset-x-0 top-0 z-20 flex justify-center px-3 transition-opacity duration-200 ${
chromeVisible ? 'opacity-100' : 'opacity-0'
}`}
>
<div className="pointer-events-auto w-full max-w-5xl">{toolbar}</div>
</div>
) : (
toolbar
)}
<div
ref={paneRef}
className={`flex min-h-0 flex-1 items-center justify-center overflow-hidden bg-black ${
fullscreenActive ? 'p-0' : 'p-2'
}`}
>
<canvas
ref={canvasRef}
tabIndex={0}
className="max-h-full max-w-full cursor-default outline-none shadow-lg shadow-black/40"
className="cursor-default outline-none shadow-lg shadow-black/40"
onContextMenu={(event) => event.preventDefault()}
onMouseMove={(event) => mapPointer(event)}
onMouseDown={(event) => mapPointer(event, true)}