mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
* feat: add windows ssh relay base support * feat: support windows ssh relay runtime services * fix: default windows ssh pty cwd to user profile * fix: support windows hosts over system ssh * fix: preserve degraded windows relay native deps * fix: gate windows shell args by relay platform * fix: preserve windows relay fallback pipes * test: align windows native deps relay fixture * fix: build valid windows install lock command * fix: address windows SSH relay review findings Resolve correctness, efficiency, and reuse issues found reviewing the Windows SSH native-host support: - GC liveness on Windows now probes the actual named pipe (via node net.connect against markers + deterministic candidates) instead of substring-matching Win32_Process command lines, which could remove a live relay dir. Reports ALIVE conservatively only when there is no liveness signal at all (no markers and no seed pipes). - Resolve the remote node path once per deploy and thread it through install/repair/launch instead of re-resolving 3-7x. - Replace the 200ms node -e poll loop with a single long-lived remote wait process during Windows relay startup. - Skip the no-op executable command on Windows in uploadRelay. - Make the Windows fallback pipe name deterministic and recoverable (drop the global counter), with an extra reconnect attempt. - Normalize the prepended node bin dir to backslashes on Windows PATH. - Batch the system-SSH Windows directory upload into a single streamed JSON package instead of one ssh process per file. - Extract relay endpoint/marker helpers into ssh-relay-endpoints.ts and consolidate the PowerShell EncodedCommand encoding into the shared powershell-command-encoding module. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Support cancellation and timeouts in Windows port scanning - Propagate the request AbortSignal and a 5-second timeout to both PowerShell and netstat child processes during Windows port scanning. - Avoid spawning the netstat fallback process if the port scan has already been aborted. - Wrap the .NET OSArchitecture check in a try/catch block during SSH Windows platform detection to robustly fall back to environment variables if needed. --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
import type { SshConnection } from './ssh-connection'
|
|
import { parseUnameToRelayPlatform, type RelayPlatform } from './relay-protocol'
|
|
import { execCommand } from './ssh-relay-deploy-helpers'
|
|
import { getRemoteHostPlatform, type RemoteHostPlatform } from './ssh-remote-platform'
|
|
import { powerShellCommand } from './ssh-remote-powershell'
|
|
|
|
export async function detectRemoteHostPlatform(
|
|
conn: SshConnection
|
|
): Promise<RemoteHostPlatform | null> {
|
|
const unamePlatform = await detectUnamePlatform(conn)
|
|
if (unamePlatform) {
|
|
return getRemoteHostPlatform(unamePlatform)
|
|
}
|
|
const windowsPlatform = await detectWindowsPlatform(conn)
|
|
return windowsPlatform ? getRemoteHostPlatform(windowsPlatform) : null
|
|
}
|
|
|
|
async function detectUnamePlatform(conn: SshConnection): Promise<RelayPlatform | null> {
|
|
try {
|
|
const output = await execCommand(conn, 'uname -sm')
|
|
const parts = output.trim().split(/\s+/)
|
|
if (parts.length < 2) {
|
|
return null
|
|
}
|
|
return parseUnameToRelayPlatform(parts[0], parts[1])
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
async function detectWindowsPlatform(conn: SshConnection): Promise<RelayPlatform | null> {
|
|
try {
|
|
const script = [
|
|
'$arch = $env:PROCESSOR_ARCHITECTURE',
|
|
'try { $runtimeArch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString(); if ($runtimeArch) { $arch = $runtimeArch } } catch {}',
|
|
'if (-not $arch) { $arch = $env:PROCESSOR_ARCHITECTURE }',
|
|
'Write-Output ("Windows " + $arch)'
|
|
].join('; ')
|
|
const output = await execCommand(conn, powerShellCommand(script), { wrapCommand: false })
|
|
const parts = output.trim().split(/\s+/)
|
|
if (parts.length < 2 || parts[0].toLowerCase() !== 'windows') {
|
|
return null
|
|
}
|
|
return parseUnameToRelayPlatform('Windows', parts[1])
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|