Files
orca/src/main/remote-ssh-editor-launch.ts
T
Neilandzerone0x 4fda57bb11 feat(open-in): open SSH workspaces in Cursor and Zed (#33877)
* feat(open-in): open SSH workspaces in Cursor and Zed

Cursor shares VS Code's Remote-SSH argv and now opens SSH and SSH-reached
server workspaces the same way, in a new window like its local launch.
Zed opens them through its ssh://[user@]host[:port]/path URL, so manual
custom-port hosts work without a local SSH config alias.

Co-authored-by: zerone0x <soberzml2333@gmail.com>

* fix(open-in): keep manual Zed targets on their saved route

Always send the saved port for manual targets so a matching ssh config Port
cannot redirect them, ask for an ssh config alias when a manual host needs a
key, agent or proxy the URL cannot carry, reject option-like hosts, and accept
the zeditor CLI name.

* refactor(open-in): move the remote SSH editor launch into its own module

Keeps external-editor-launch.ts under the max-lines limit after the main merge,
and moves main's new macOS CLI fallback test onto the remote launch API.

---------

Co-authored-by: zerone0x <soberzml2333@gmail.com>
2026-10-26 06:28:29 -07:00

48 lines
1.8 KiB
TypeScript

import { getRemoteSshEditorKind } from '../shared/remote-ssh-editor-launcher'
import type { ShellOpenExternalEditorResult } from '../shared/shell-open-types'
import type { SshTarget } from '../shared/ssh-types'
import { getLauncherBaseName } from './editor-launcher-name'
import {
resolveExternalEditorExecutable,
type ExternalEditorLaunchSpec
} from './external-editor-launch'
import { resolveVsCodeSshAuthority } from './ssh/config/vscode-ssh-authority'
import { resolveZedSshUrl } from './ssh/config/zed-ssh-url'
export function resolveRemoteSshEditorLaunchSpec(
command: string | undefined,
pathValue: string,
target: SshTarget,
options: { platform?: NodeJS.Platform; fileExists?: (path: string) => boolean } = {}
):
| { ok: true; launchSpec: ExternalEditorLaunchSpec }
| Exclude<ShellOpenExternalEditorResult, { ok: true }> {
const editorCommand = resolveExternalEditorExecutable(command, options)
const editorKind = editorCommand ? getRemoteSshEditorKind(editorCommand) : null
if (!editorCommand || !editorKind) {
return { ok: false, reason: 'remote-editor-unsupported' }
}
let spawnArgs: string[]
if (editorKind === 'zed') {
const zedUrl = resolveZedSshUrl(target, pathValue)
if (!zedUrl.ok) {
return zedUrl
}
spawnArgs = [zedUrl.url]
} else {
const authority = resolveVsCodeSshAuthority(target)
if (!authority.ok) {
return authority
}
spawnArgs = ['--remote', `ssh-remote+${authority.authority}`, pathValue]
// Cursor may reuse the last workbench; a new window preserves this workspace target.
if (getLauncherBaseName(editorCommand) === 'cursor') {
spawnArgs.unshift('--new-window')
}
}
return {
ok: true,
launchSpec: { kind: 'executable', hideWindowsConsole: true, spawnCmd: editorCommand, spawnArgs }
}
}