Files
orca/src/shared/vscode-remote-ssh-launcher.ts
Jinjing adc020393e feat(ssh): open SSH workspaces in VS Code Remote-SSH (#10005)
Allow the existing "Open in" entries to launch a configured VS Code
launcher against an SSH-backed worktree via Remote-SSH:

    code --remote ssh-remote+<authority> <remote-path>

- Split the blanket SSH/runtime block into a capability model: file
  managers and non-VS Code launchers stay local-only (disabled with
  "Local only" metadata); a recognized VS Code command is enabled and
  forwarded with connectionId over a typed object IPC.
- Main process stays authoritative: rejects active/owned runtimes,
  resolves the SshTarget from the persisted Store, derives the authority
  (config alias, or username@host on port 22, or ssh-alias-required on a
  non-default port), validates POSIX/Windows absolute remote paths without
  local stat/normalize, and rejects non-VS Code and compound commands
  before spawn.
- Authority and remote path are passed as separate argv; getSpawnArgsForWindows
  remains the cmd/bat shim boundary and fails closed on metacharacters.
- Same capability rules across the worktree menu, Explorer overflow, and
  the source-control entry context menu.

Refs STA-2386
Closes #9999
2026-07-22 17:17:59 -07:00

31 lines
1.1 KiB
TypeScript

const VSCODE_LAUNCHER_NAMES = new Set(['code', 'code-insiders', 'code - insiders'])
const WINDOWS_ABSOLUTE_PATH = /^(?:[a-z]:[\\/]|\\\\)/i
function stripMatchingQuotes(value: string): string {
const trimmed = value.trim()
const quote = trimmed[0]
if ((quote === '"' || quote === "'") && trimmed.endsWith(quote)) {
return trimmed.slice(1, -1)
}
return trimmed
}
export function isVsCodeLauncherExecutable(command: string): boolean {
const unquoted = stripMatchingQuotes(command)
const segments = unquoted.split(/[\\/]/)
const fileName = segments.at(-1) ?? ''
const launcherName = fileName.replace(/\.(?:cmd|exe|bat)$/i, '').toLowerCase()
return VSCODE_LAUNCHER_NAMES.has(launcherName)
}
export function isVsCodeRemoteSshCommand(command: string | undefined): boolean {
const trimmed = command?.trim() || 'code'
const unquoted = stripMatchingQuotes(trimmed)
if (!/\s/.test(unquoted)) {
return isVsCodeLauncherExecutable(unquoted)
}
const isAbsolutePath = unquoted.startsWith('/') || WINDOWS_ABSOLUTE_PATH.test(unquoted)
return isAbsolutePath && isVsCodeLauncherExecutable(unquoted)
}