mirror of
https://github.com/stablyai/orca.git
synced 2026-09-30 16:02:56 +00:00
* docs: design SSH relay PTY backpressure * fix(ssh): bound relay frame decoding * fix(relay): bound PTY output publication * fix(ssh): bound PTY model admission * fix(ssh): settle closed model admissions * feat(ssh): negotiate bounded PTY consumer sessions * fix(ssh): fence exit on renderer settlement * feat(ssh): track PTY source credit end to end * fix(ssh): recover bounded PTY output across reconnect * feat(ssh): complete relay PTY output backpressure * fix(ssh): close final PTY source credit races * docs(ssh): record final backpressure validation * feat(ssh): complete relay PTY source-credit lifecycle * test(ssh): complete provider notification fixture * fix(ssh): preserve terminal source credit across rotation * fix(ssh): fail closed on recovery cancellation * fix(ssh): prioritize mux control writes after drain * fix(ssh): retire canceled relay restore deliveries * fix(ssh): order exit cancellation cleanup * fix(ssh): gate provisional source activation * test(ssh): register mux drain-priority coverage * fix(ssh): type stale owner recovery mismatches * fix(ssh): close projection replacement races * fix(relay): contain streaming edge failures * fix(ssh): secure relay endpoint credentials * docs(ssh): reconcile final backpressure lifecycle * fix(ssh): bound main IPC output lifecycle * fix(ssh): close recovery ownership gaps * docs(ssh): record exact artifact validation * fix(ssh): reject reclaimed snapshot replacements * fix(ssh): fence model admission across reconnect * fix(ssh): contain migration failure per PTY * docs(ssh): record final exact-head validation * test(ssh): align deploy fixtures with credential publication * feat(ssh): add per-target bounded output setting * fix(ssh): close source recovery review gaps * fix(ssh): latch source credit environment override * feat(ssh): make PTY source credit the default * docs(ssh): record always-on relay validation * docs(ssh): bind validation to current main * test(ssh): grant source credit in IPC fixture * test(ssh): grant source credit in fake relay --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
248 lines
8.8 KiB
TypeScript
248 lines
8.8 KiB
TypeScript
import type { RemoteHostPlatform } from './ssh-remote-platform'
|
|
import { isWindowsRemoteHost, joinRemotePath } from './ssh-remote-platform'
|
|
import { powerShellCommand, powerShellLiteral, powerShellNativeArg } from './ssh-remote-powershell'
|
|
|
|
type RemoteCliInstallEnv = {
|
|
binDir: string
|
|
relayDir: string
|
|
nodePath: string
|
|
sockPath: string
|
|
credentialFile?: string
|
|
hostPlatform: RemoteHostPlatform
|
|
}
|
|
|
|
type RemoteCliInstallFile = {
|
|
path: string
|
|
contents: string
|
|
}
|
|
|
|
export type RemoteCliInstallPlan = {
|
|
launcherPath: string
|
|
files: RemoteCliInstallFile[]
|
|
postWriteCommands: string[]
|
|
}
|
|
|
|
const WINDOWS_REMOTE_CLI_LAUNCHER_SOURCE = String.raw`using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
internal static class OrcaRemoteCliLauncher
|
|
{
|
|
private static int Main(string[] args)
|
|
{
|
|
try
|
|
{
|
|
string nodePath = RequireEnvironmentVariable("ORCA_RELAY_NODE_PATH");
|
|
string relayDirectory = RequireEnvironmentVariable("ORCA_RELAY_DIR");
|
|
string socketPath = RequireEnvironmentVariable("ORCA_RELAY_SOCKET_PATH");
|
|
string credentialFile = Environment.GetEnvironmentVariable("ORCA_RELAY_CREDENTIAL_FILE");
|
|
if (String.IsNullOrEmpty(credentialFile))
|
|
{
|
|
credentialFile = socketPath + ".credential";
|
|
}
|
|
string relayPath = Path.Combine(relayDirectory, "relay.js");
|
|
|
|
if (!File.Exists(nodePath))
|
|
{
|
|
Console.Error.WriteLine("Orca SSH CLI bridge cannot find Node.js at \"{0}\"", nodePath);
|
|
return 1;
|
|
}
|
|
if (!File.Exists(relayPath))
|
|
{
|
|
Console.Error.WriteLine("Orca SSH CLI bridge cannot find the relay at \"{0}\"", relayPath);
|
|
return 1;
|
|
}
|
|
|
|
ProcessStartInfo startInfo = new ProcessStartInfo
|
|
{
|
|
FileName = nodePath,
|
|
Arguments = BuildArguments(relayPath, socketPath, credentialFile, args),
|
|
UseShellExecute = false
|
|
};
|
|
|
|
using (Process child = Process.Start(startInfo))
|
|
{
|
|
child.WaitForExit();
|
|
return child.ExitCode;
|
|
}
|
|
}
|
|
catch (Exception error)
|
|
{
|
|
Console.Error.WriteLine("Unable to start the Orca SSH CLI bridge: {0}", error.Message);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
private static string RequireEnvironmentVariable(string name)
|
|
{
|
|
string value = Environment.GetEnvironmentVariable(name);
|
|
if (String.IsNullOrEmpty(value))
|
|
{
|
|
throw new InvalidOperationException(name + " is not set.");
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private static string BuildArguments(string relayPath, string socketPath, string credentialFile, string[] args)
|
|
{
|
|
StringBuilder commandLine = new StringBuilder();
|
|
AppendArgument(commandLine, relayPath);
|
|
AppendArgument(commandLine, "--sock-path");
|
|
AppendArgument(commandLine, socketPath);
|
|
AppendArgument(commandLine, "--credential-file");
|
|
AppendArgument(commandLine, credentialFile);
|
|
AppendArgument(commandLine, "--orca-cli");
|
|
foreach (string arg in args)
|
|
{
|
|
AppendArgument(commandLine, arg);
|
|
}
|
|
return commandLine.ToString();
|
|
}
|
|
|
|
private static void AppendArgument(StringBuilder commandLine, string value)
|
|
{
|
|
if (commandLine.Length > 0)
|
|
{
|
|
commandLine.Append(' ');
|
|
}
|
|
commandLine.Append(QuoteArgument(value));
|
|
}
|
|
|
|
private static string QuoteArgument(string value)
|
|
{
|
|
bool requiresQuotes = value.Length == 0;
|
|
for (int index = 0; index < value.Length && !requiresQuotes; index += 1)
|
|
{
|
|
requiresQuotes = value[index] == '"' || Char.IsWhiteSpace(value[index]);
|
|
}
|
|
if (!requiresQuotes)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
StringBuilder quoted = new StringBuilder("\"");
|
|
int backslashCount = 0;
|
|
foreach (char character in value)
|
|
{
|
|
if (character == '\\')
|
|
{
|
|
backslashCount += 1;
|
|
continue;
|
|
}
|
|
if (character == '"')
|
|
{
|
|
quoted.Append('\\', backslashCount * 2 + 1);
|
|
quoted.Append('"');
|
|
}
|
|
else
|
|
{
|
|
quoted.Append('\\', backslashCount);
|
|
quoted.Append(character);
|
|
}
|
|
backslashCount = 0;
|
|
}
|
|
|
|
quoted.Append('\\', backslashCount * 2);
|
|
quoted.Append('"');
|
|
return quoted.ToString();
|
|
}
|
|
}
|
|
`
|
|
|
|
function quoteSh(value: string): string {
|
|
return `'${value.replaceAll("'", `'\\''`)}'`
|
|
}
|
|
|
|
function createWindowsLauncherCompileCommand(
|
|
binDir: string,
|
|
sourceFileName: string,
|
|
launcherFileName: string,
|
|
launcherPath: string,
|
|
sourcePath: string,
|
|
legacyShimPath: string
|
|
): string {
|
|
// Why: legacy csc.exe mis-parses space-bearing absolute paths handed to it by
|
|
// Windows PowerShell 5.1's native-argument quoting, so compile from the bin
|
|
// directory and pass only the bare, space-free launcher file names.
|
|
const compilerArgs = [
|
|
'/nologo',
|
|
'/target:exe',
|
|
'/optimize+',
|
|
'/warnaserror+',
|
|
`/out:${launcherFileName}`,
|
|
sourceFileName
|
|
]
|
|
.map(powerShellNativeArg)
|
|
.join(' ')
|
|
return powerShellCommand(
|
|
[
|
|
`Set-Location -ErrorAction Stop -LiteralPath ${powerShellLiteral(binDir)}`,
|
|
'$windowsDirectory = if ($env:WINDIR) { $env:WINDIR } else { $env:SystemRoot }',
|
|
`$compilerCandidates = @((Join-Path $windowsDirectory 'Microsoft.NET\\Framework64\\v4.0.30319\\csc.exe'), (Join-Path $windowsDirectory 'Microsoft.NET\\Framework\\v4.0.30319\\csc.exe'))`,
|
|
'$compiler = $compilerCandidates | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | Select-Object -First 1',
|
|
"if (-not $compiler) { Write-Error 'Unable to find the .NET Framework C# compiler required for the Orca SSH CLI launcher.'; exit 1 }",
|
|
`& $compiler ${compilerArgs}`,
|
|
'if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }',
|
|
`if (-not (Test-Path -LiteralPath ${powerShellLiteral(launcherPath)} -PathType Leaf)) { Write-Error 'The Orca SSH CLI launcher compiler produced no executable.'; exit 1 }`,
|
|
// Why: remove the legacy %* bridge only after a successful compile, so a
|
|
// host missing csc.exe keeps its existing CLI (orca.exe shadows orca.cmd).
|
|
`Remove-Item -LiteralPath ${powerShellLiteral(legacyShimPath)} -Force -ErrorAction SilentlyContinue`,
|
|
`Remove-Item -LiteralPath ${powerShellLiteral(sourcePath)} -Force`
|
|
].join('; ')
|
|
)
|
|
}
|
|
|
|
export function createRemoteCliInstallPlan(env: RemoteCliInstallEnv): RemoteCliInstallPlan {
|
|
if (isWindowsRemoteHost(env.hostPlatform)) {
|
|
const launcherFileName = 'orca.exe'
|
|
const sourceFileName = 'orca-launcher.cs'
|
|
const launcherPath = joinRemotePath(env.hostPlatform, env.binDir, launcherFileName)
|
|
const sourcePath = joinRemotePath(env.hostPlatform, env.binDir, sourceFileName)
|
|
const legacyShimPath = joinRemotePath(env.hostPlatform, env.binDir, 'orca.cmd')
|
|
const binDir = joinRemotePath(env.hostPlatform, env.binDir)
|
|
return {
|
|
launcherPath,
|
|
files: [{ path: sourcePath, contents: WINDOWS_REMOTE_CLI_LAUNCHER_SOURCE }],
|
|
// Why: compiling on the Windows target avoids shipping an unsigned
|
|
// cross-host binary while ensuring argv never crosses cmd.exe's parser.
|
|
postWriteCommands: [
|
|
createWindowsLauncherCompileCommand(
|
|
binDir,
|
|
sourceFileName,
|
|
launcherFileName,
|
|
launcherPath,
|
|
sourcePath,
|
|
legacyShimPath
|
|
)
|
|
]
|
|
}
|
|
}
|
|
|
|
const launcherPath = joinRemotePath(env.hostPlatform, env.binDir, 'orca')
|
|
return {
|
|
launcherPath,
|
|
files: [
|
|
{
|
|
path: launcherPath,
|
|
contents: [
|
|
'#!/usr/bin/env sh',
|
|
'set -eu',
|
|
`ORCA_RELAY_NODE_PATH=\${ORCA_RELAY_NODE_PATH:-${quoteSh(env.nodePath)}}`,
|
|
`ORCA_RELAY_DIR=\${ORCA_RELAY_DIR:-${quoteSh(env.relayDir)}}`,
|
|
`ORCA_RELAY_SOCKET_PATH=\${ORCA_RELAY_SOCKET_PATH:-${quoteSh(env.sockPath)}}`,
|
|
`ORCA_RELAY_CREDENTIAL_FILE=\${ORCA_RELAY_CREDENTIAL_FILE:-${quoteSh(env.credentialFile ?? `${env.sockPath}.credential`)}}`,
|
|
'if [ ! -S "$ORCA_RELAY_SOCKET_PATH" ]; then',
|
|
' echo "Orca SSH CLI bridge cannot find the relay socket: $ORCA_RELAY_SOCKET_PATH" >&2',
|
|
' exit 1',
|
|
'fi',
|
|
'exec "$ORCA_RELAY_NODE_PATH" "$ORCA_RELAY_DIR/relay.js" --sock-path "$ORCA_RELAY_SOCKET_PATH" --credential-file "$ORCA_RELAY_CREDENTIAL_FILE" --orca-cli "$@"',
|
|
''
|
|
].join('\n')
|
|
}
|
|
],
|
|
// Surface chmod failures: a non-executable launcher must fail install loudly, not silently.
|
|
postWriteCommands: [`chmod +x ${quoteSh(launcherPath)}`]
|
|
}
|
|
}
|