跳转至

Windows 终端 shell 选择

在 Windows 终端上,有两种不同的东西可能让 cmd.exe 出现在终端中,而其中只有一种会让终端 成为 cmd。

  • --shell / shellOverride 指定 PTY 以哪个可执行文件启动。终端自身的进程在其整个生命周期内就是该 shell。
  • --command / startupCommand 是 provider 输入到它启动的任意 shell 中的文本。因此 --command cmd.exe 会将 cmd 作为宿主默认 shell 的 子进程 启动。

在子进程退出之前,这种差异是不可见的。当那个 cmd 退出后,调用者的句柄会回到一个它从未要求的 Git Bash 或 PowerShell 提示符,而任何依赖“这个终端是 cmd”的逻辑现在都是错误的——尽管 terminal list 仍然显示一个已连接且健康的终端,因为 PTY 从未改变。

为什么运行时路径需要单独修复

有两个 spawn 预检,它们是孪生实现:

  • src/main/ipc/pty/ipc/spawn-preflight.ts — renderer/IPC 启动(应用中的终端标签页)。
  • src/main/ipc/pty/runtime/spawn-preflight.ts — 运行时启动:来自 CLI 的 terminal.create、无头 orca serve,以及所有配对的远程环境。

只有 IPC 孪生实现读取了调用者请求的 shell。运行时孪生实现传递了字面量 undefined,因此运行时创建的终端只能始终是宿主的默认 shell。针对 Windows 环境的 orca terminal create --command cmd.exe 没有办法表示“成为 cmd”——它只能将 cmd.exe 输入到 Git Bash 中。src/main/ipc/pty/pty-spawn-shell-override-parity.test.ts 锁定这对实现的一致性。

规则

  • 选择 shell 的调用者传递 --shell;运行程序的调用者传递 --command。不要通过 command 路由 shell 选择——它看起来像是成功了。
  • 允许列表是 src/shared/windows-terminal-shell.ts 中的 isSupportedWindowsShellOverride,这也是 --shell 不能指定任意可执行文件的原因。CLI、terminal.create RPC schema 和 relay 都检查同一集合;只在一个地方添加 shell。
  • 仅允许裸 shell 名称。路径或任何带参数的内容都会被拒绝,因此 --shell 永远无法将命令行带入 pty.spawn。
  • 早于 --shell 的宿主会剥离它(terminal.create 参数是一个 zod 对象,它会丢弃未知键),并回复一个运行其默认 shell 的健康终端——一个读起来像成功的回复。因此 CLI 以 TERMINAL_CREATE_SHELL_SELECTION_RUNTIME_CAPABILITY 为门控,并在创建任何内容之前拒绝,而不是悄悄地创建错误的 shell。
  • --shell 仅限 Windows,且无法应用它的宿主会拒绝创建(terminalShellOverrideRefusal)。macOS 和 Linux 执行宿主启动登录 shell,而通过 SSH 路由的终端会在 SSH 宿主上解析其 shell,该运行时无法看到其平台和已安装的 shell。拒绝正是重点:启动默认 shell 并报告成功是 --shell 旨在消除的失败。
  • 项目的执行运行时决定 shell 运行在哪台机器上,因此它优先于每个终端的选择——但它通过拒绝来优先,而不是通过重写。与项目运行时矛盾的 --shell(WSL 项目上的 Windows shell,或 Windows 宿主项目上的 WSL 名称)会被拒绝。否则 resolveLocalWindowsTerminalRuntimeOptions 会重写该值——WSL 项目强制使用 wsl.exe,Windows 宿主项目会丢弃 WSL 名称而改用 COMSPEC——并返回一个运行调用者从未要求的内容的终端。它还会将 agent 启动的引号处理与接收它的 shell 分开:将 POSIX 引号参数输入 cmd,或将 cmd 引号参数输入 WSL shell。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 orca48/orca