refactor(terminal): one isRemoteExecutionHostPtyId, on prefix semantics (#30232)

The shared copy parsed remote: ids fully, so a malformed or newer-format id read as local
to pty-running-work-probe. The renderer copy already used the prefix check; it is now the
only definition, in src/shared.
This commit is contained in:
Neil
2026-10-18 00:15:22 -07:00
committed by GitHub
parent 3767047db0
commit e1eef1f162
12 changed files with 26 additions and 32 deletions
@@ -1,4 +1,4 @@
import { isRemoteExecutionHostPtyId } from './remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../shared/remote-execution-host-pty-id'
/**
* Whether one cadence process inspection for this pane is expensive enough that
@@ -19,7 +19,7 @@ import {
setCommandCodeDoneSettleExecutor
} from './command-code-done-settle'
import { canCommandCodeOutputOwnPane } from './command-code-output-ownership'
import { isRemoteExecutionHostPtyId } from './remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../shared/remote-execution-host-pty-id'
export type ParkedTerminalCommandStatusPolicy = {
onCommandFinished: (bestEffortExitCode: number | null) => void
@@ -1,7 +1,7 @@
import { useAppStore } from '@/store'
import type { RecognizedAgentProcess } from '../../../../../shared/agent-process-recognition'
import { resolveCompatibleAgentTypeForOwner } from '../../../../../shared/agent-title-owner'
import { isRemoteExecutionHostPtyId } from '../remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../../shared/remote-execution-host-pty-id'
import type { ConnectPanePtySession } from './connect-pane-pty-session'
@@ -2,7 +2,7 @@ import { isRemoteRuntimePtyId } from '../../../../../shared/remote-runtime-pty-i
import { recordTerminalFreezeBreadcrumb } from '../terminal-freeze-breadcrumbs'
import { redactPtyIdForDiagnostics } from '../../../../../shared/pty-delivery-diagnostics'
import { cancelScheduledHiddenOutputRestore } from '../hidden-output-restore-scheduler'
import { isRemoteExecutionHostPtyId } from '../remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../../shared/remote-execution-host-pty-id'
import {
HIDDEN_OUTPUT_RESTORE_FOREGROUND_TIMEOUT_MS,
@@ -8,7 +8,7 @@ import {
} from '@/lib/pane-manager/windows-pty-compatibility'
import { createTerminalCommandLifecycle } from '../terminal-command-lifecycle'
import { createPaneForegroundAgentTracker } from '../pane-foreground-agent-tracker'
import { isRemoteExecutionHostPtyId } from '../remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../../shared/remote-execution-host-pty-id'
import { inspectRuntimeTerminalProcess } from '@/runtime/runtime-terminal-inspection'
import { parseAppSshPtyId } from '../../../../../shared/ssh-pty-id'
import { dispatchTerminalCommandFinishedEvent } from '@/hooks/terminal-command-finished-event'
@@ -13,7 +13,7 @@ import { registerTerminalSideEffectFactConsumer } from '../terminal-side-effect-
import { isAgentTaskCompleteTrackingEnabled } from './agent-task-complete-settings'
import { isAgentProcessInspectionCostly } from '../agent-process-inspection-cost'
import { isRemoteExecutionHostPtyId } from '../remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../../shared/remote-execution-host-pty-id'
import { retireLiveAgentRowOnConfirmedProcessExit } from './confirmed-process-exit-row-retire'
import type { ConnectPanePtySession } from './connect-pane-pty-session'
@@ -1,14 +0,0 @@
import { isRemoteRuntimePtyId } from '../../../../shared/remote-runtime-pty-id'
import { parseAppSshPtyId } from '../../../../shared/ssh-pty-id'
// Why: both remote shapes are answered across a link — paired runtimes
// ("remote:", host-owned buffer) and direct SSH ("ssh:<target>@@<id>", main's
// relay-fed model, whose serialize can block on host RPCs). Silence from either
// is `unverifiable`, never proof of death (docs/reference/ssh-execution-boundary.md).
export function isRemoteExecutionHostPtyId(ptyId: string | null | undefined): boolean {
if (typeof ptyId !== 'string') {
return false
}
return isRemoteRuntimePtyId(ptyId) || parseAppSshPtyId(ptyId) !== null
}
@@ -1,5 +1,5 @@
import { isRemoteRuntimePtyId } from '../../../../shared/remote-runtime-pty-id'
import { isRemoteExecutionHostPtyId } from './remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../shared/remote-execution-host-pty-id'
import { getRemoteRuntimePtyEnvironmentId } from '@/runtime/runtime-terminal-stream'
import { PTY_SESSION_ID_SEPARATOR } from '../../../../shared/pty-session-id-format'
import { parseAppSshPtyId } from '../../../../shared/ssh-pty-id'
@@ -1,5 +1,5 @@
import { isRemoteRuntimePtyId } from '../../../../shared/remote-runtime-pty-id'
import { isRemoteExecutionHostPtyId } from './remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../shared/remote-execution-host-pty-id'
import { PTY_SESSION_ID_SEPARATOR } from '../../../../shared/pty-session-id-format'
import { terminalProviderHasAuthoritativeSnapshot } from '../terminal/terminal-provider-snapshot-capability'
import {
@@ -7,7 +7,7 @@
*/
import { isTerminalLeafId } from '../../../../shared/stable-pane-id'
import { useAppStore } from '@/store'
import { isRemoteExecutionHostPtyId } from './remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from '../../../../shared/remote-execution-host-pty-id'
import { discardPreHandlerPtyState } from './pty-pre-handler-buffer'
import { terminalProviderHasAuthoritativeSnapshot } from '../terminal/terminal-provider-snapshot-capability'
import {
@@ -1,9 +1,9 @@
import { describe, expect, it } from 'vitest'
import { toRemoteRuntimePtyId } from '../../../../shared/remote-runtime-pty-id'
import { toAppSshPtyId } from '../../../../shared/ssh-pty-id'
import { toRemoteRuntimePtyId } from './remote-runtime-pty-id'
import { toAppSshPtyId } from './ssh-pty-id'
import { isRemoteExecutionHostPtyId } from './remote-execution-host-pty'
import { isRemoteExecutionHostPtyId } from './remote-execution-host-pty-id'
describe('isRemoteExecutionHostPtyId', () => {
it('accepts paired-runtime ptys with and without an owner environment', () => {
@@ -11,6 +11,12 @@ describe('isRemoteExecutionHostPtyId', () => {
expect(isRemoteExecutionHostPtyId(toRemoteRuntimePtyId('term_1'))).toBe(true)
})
// Why: decoding fails on a malformed owner, but the id still names a remote pty.
it('keeps a malformed or newer-format remote id remote', () => {
expect(isRemoteExecutionHostPtyId('remote:%E0%A4%A@@term_1')).toBe(true)
expect(isRemoteExecutionHostPtyId('remote:v2|env|term_1')).toBe(true)
})
it('accepts direct-SSH app pty ids', () => {
expect(isRemoteExecutionHostPtyId(toAppSshPtyId('target-1', 'pty-1'))).toBe(true)
})
+8 -6
View File
@@ -1,14 +1,16 @@
import { parseRemoteRuntimePtyId } from './remote-runtime-pty-id'
import { isRemoteRuntimePtyId } from './remote-runtime-pty-id'
import { parseAppSshPtyId } from './ssh-pty-id'
/**
* Whether the process behind this pty runs on an execution host other than this machine —
* a paired runtime environment or an app SSH target.
*
* Deliberately broader than the inspection module's private remote check, which only counts a
* `remote:` id that carries an owner environment id. An owner-less `remote:<handle>` still runs
* somewhere else, and treating it as local is how remote work becomes invisible to a guard.
* Why prefix-only for `remote:`: a malformed, owner-less or newer-format id still runs off
* this host, so silence from it is `unverifiable`, never local (docs/reference/ssh-execution-boundary.md).
*/
export function isRemoteExecutionHostPtyId(ptyId: string): boolean {
return parseRemoteRuntimePtyId(ptyId) !== null || parseAppSshPtyId(ptyId) !== null
export function isRemoteExecutionHostPtyId(ptyId: string | null | undefined): boolean {
if (typeof ptyId !== 'string') {
return false
}
return isRemoteRuntimePtyId(ptyId) || parseAppSshPtyId(ptyId) !== null
}