Files
orca/src/shared/plain-ssh-terminal.ts
T
NeilandClaude 56143a9a5e feat(ssh): open a plain SSH terminal to a host whose move to its Orca server is blocked (#31716)
* feat(ssh): open a plain SSH terminal to a host whose move to its Orca server is blocked

A refused or unserved host fails the whole connect, so the user had no way to
reach their work there. The blocked-move banner and the SSH host row now offer
an unmanaged, unpersisted ssh login in a non-modal window. Main builds the argv
from the saved target (no -T, BatchMode or Orca multiplexing; the config alias
stays bare so ssh_config applies) and spawns ssh with an argv array through the
local PTY spawn primitive.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): claim a host before awaiting, wait for ssh on quit, and share the preview terminal's keys

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): give the plain SSH terminal Orca's Unicode widths, kitty flags and spawn-helper repair

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(terminal): one standalone terminal for the agent preview and plain SSH

Extracts the preview's xterm setup (Unicode widths, links, IME bridge, kitty
flags, copy/paste and shortcut policy, user-input routing) into
openStandaloneTerminal, so the plain SSH terminal reuses it instead of a second
copy. Plain SSH output is now acked once rendered, and main pauses ssh while too
much is unrendered.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): plain SSH answers terminal queries, keeps early exits, and ends a paused pty on Windows

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): plain SSH applies theme changes live and never refits while minimized

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): a native call on a just-exited plain SSH pty never crashes main

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ssh): give the plain SSH test's ResizeObserver stub unobserve, which Tooltip needs

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-21 19:35:32 -07:00

24 lines
1.1 KiB
TypeScript

/** The plain SSH terminal's IPC contract: open by saved target id, then talk by session id. */
export const PLAIN_SSH_TERMINAL_CHANNELS = {
open: 'plainSsh:open',
write: 'plainSsh:write',
resize: 'plainSsh:resize',
close: 'plainSsh:close',
/** Output the window has rendered, in UTF-16 units of `data`; ssh is paused while too much is unrendered. */
ack: 'plainSsh:ack',
event: 'plainSsh:event'
} as const
export type PlainSshTerminalOpenResult =
| { ok: true; sessionId: string; label: string }
/** `already-open`: another window holds this host's one session. */
| { ok: false; reason: 'unknown-target' | 'not-blocked' | 'already-open' }
/** A newer open from the same window, a reload or quit took this one's place. */
| { ok: false; reason: 'cancelled' }
| { ok: false; reason: 'ssh-missing' | 'spawn-failed'; message: string }
export type PlainSshTerminalEvent =
| { kind: 'data'; sessionId: string; data: string }
/** `signal`: set when ssh was killed, so a zero `exitCode` is not a clean logout. */
| { kind: 'exit'; sessionId: string; exitCode: number; signal?: number }