Skip to content

第 8 章:SSH、WSL 与远程运行时 ​

目标:理解 Orca 如何让本地、WSL、SSH 和配对 runtime 共享同一产品语义,并在断线和滚动升级中保持资源所有权。

1. 四种执行位置 ​

位置控制通道PTY 所有者Git/文件执行者
本机 nativeElectron IPC / local calllocal/daemon providermain process
本机 WSL本机 provider + wsl.exeWSL shell/daemonWSL-aware runner
Direct SSHSSH multiplexremote relayremote relay
Paired runtimeencrypted WebSocket RPCremote Orca runtimeremote runtime

UI 希望它们“都像 workspace”,但实现不能抹掉差异。路径语法、Git 版本、shell、账户 home、延迟、断线语义都属于 host。

2. 先解析执行主机,再选择 provider ​

Repo/Workspace 保存 connectionId 与 executionHostId。请求进入 main/renderer 后,先解析:

  1. workspace 属于 local、SSH 还是 runtime;
  2. provider 当前是否注册且 generation 匹配;
  3. 若是 Windows local,是否实际路由到 WSL;
  4. 能力是否在该 host 可用;
  5. 是否允许 fallback。

fallback 不能跨越所有权。例如 SSH provider 暂时不可用时,绝不能在本机相同路径执行 git。

3. SSH 连接建立 ​

Orca 支持 ~/.ssh/config alias、ssh -G 解析、key、agent、ProxyCommand、ForwardAgent 与系统 SSH fallback。

显式 Orca 设置优先于 config;config alias 的默认 host/22 则允许被 ssh -G 的 HostName/Port 填充。

关键文件:ssh-connection.ts、ssh-connection-utils.ts。

4. Relay 的部署与发现 ​

连接成功后,Orca 在远端 home 下部署版本化 relay。部署需要处理:

  • OS/arch 与包版本;
  • 上传临时文件和原子替换;
  • SFTP namespace 与 shell home 不一致;
  • 多客户端同时部署锁;
  • 旧 relay 兼容和滚动更新;
  • 不可写 home 或缺失工具。

relay 不是长期开放端口;通常运行在 SSH channel 内,通过 framed protocol 提供服务。

5. Channel multiplexer ​

同一个 SSH 连接承载:

  • control request/response;
  • notifications;
  • PTY output;
  • Git 大结果流;
  • keepalive 与 ACK。

SshChannelMultiplexer 为 request 分配 id,设置 timeout,并按 lane 调度写入。Frame decoder 有最大消息、每 turn 帧数、字节数与时间预算,防止一个大 frame 长时间堵住 Electron event loop。

高优先级交互不能被后台 PTY 洪流淹没;同时 ordinary request 的 unacked timestamp 数量有界。

6. SSH PTY provider ​

SshPtyProvider 实现与 local provider 相同的 IPtyProvider,但行为是 RPC 翻译:

  • spawn -> relay pty.spawn;
  • write/resize -> notification;
  • attach -> replay / snapshot / live stream;
  • listProcesses -> 远端事实;
  • shutdown -> 带 deadline 的远端事务。

返回的 app-facing PTY id 必须全局可路由,不能直接泄漏 relay 内部 handle。

7. Connection generation 与迟到事件 ​

同一个 SSH target 断线重连后会产生新 generation。所有回调和 mutation expectation 都要带 generation:

text
target A generation 41 disconnects
target A generation 42 connects
late event from 41 arrives -> reject

如果不做这层隔离,旧连接的 exit、port list 或 repo catalog 会覆盖新连接事实。

8. 断线为何不等于退出 ​

Direct SSH 的断线只证明控制通道不可用,不能证明:

  • remote PTY 已退出;
  • Git worktree 已删除;
  • Agent provider session 已结束;
  • port forward 不再存在。

因此 UI 可以标 disconnected,metadata 可以保留,但不能释放唯一执行 claim。重连后先列举远端 process/lease,再决定 reattach 或清理。

9. Remote Agent Session Host Authority ​

最危险的场景:两个客户端同时恢复同一 Agent,会不会启动两个?Orca 的结构化流程使用 claim identity 和 operation replay。

claim 由 host-only signer 根据 agent/provider、worktree、machine/principal、runtime namespace 等生成摘要,不直接暴露原始 provider session id。

三个结果 ​

  • 无 owner:原子创建并登记;
  • 有 live owner:adopt / attach;
  • owner 未知或冲突:fail closed。

为什么 operation id 还不够 ​

operation id 只能让“同一次请求重试”幂等;两个不同客户端可能有两个 operation id。claim identity 才能表达“它们想运行的是同一个逻辑 Agent 会话”。

完整设计见 remote-agent-session-host-authority.md。

10. 能力协商与安全 fallback ​

新客户端面对旧 host/daemon/relay 时,先探测 agent-session.host-authority.v1 等 capability。

只在以下情况回退 legacy:

  • dispatch 前能力明确不可用;
  • host 在任何 side effect 前返回稳定 legacy_required;
  • 旧 host 返回 method_not_found。

timeout、malformed response、未知错误都不能 fallback,因为请求可能已经 spawn。此时再走 legacy 会复制 Agent。

11. Paired runtime 与 direct SSH 的区别 ​

Direct SSH ​

桌面 main 持有 SSH 连接,远端 relay 是能力代理。适合连接普通开发机。

Paired runtime ​

远端运行完整 Orca runtime,可在 headless serve 中维护 workspace graph、browser、automations 与 terminal model;客户端通过配对 token 和 WebSocket RPC 访问。

paired runtime 更像远程“Orca 主机”,direct SSH 更像把特定资源 provider 搬到远端。

12. WSL:本机中的另一个执行主机 ​

WSL 的难点与 SSH 类似:

  • Windows path 与 Linux path 转换;
  • WSL distro 是 capability/cache scope;
  • git, gh, Agent CLI 可能只存在某一侧;
  • managed CLI/hook 需要注入 guest;
  • sleep/wake 后 cwd 与 OSC 7 可能漂移。

Orca 不把 WSL 简化成 shell 参数,而是把 distro 贯穿 PTY、Git、hook 与账户 target。

13. 远程文件、Git 和端口 ​

relay/runtime 还提供:

  • 文件 list/read/write/watch;
  • Git status/diff/worktree/branch;
  • GitHub/GitLab CLI 的 host-aware 调用;
  • detected ports 与 forwarding;
  • remote browser/emulator 能力;
  • skills 与 AI Vault 扫描。

每类结果都要打 host stamp,renderer 合并时不能让不同 host 上相同 repo id 的数据碰撞。

14. 源码导航 ​