2026-09-12 09:33:59 +08:00
2026-09-12 09:33:59 +08:00
2026-09-11 20:41:07 +08:00
2026-09-11 20:41:07 +08:00
2026-09-12 09:33:59 +08:00

ShellRS

基于 GPUI Kit 的中文 SSH 主机管理工具,提供持久化的主机与分组、可在多台主机间共用的登录凭据、本地终端、SSH 多终端、对标 WinSCP 的 SFTP 双栏浏览器和 SSH 端口转发。

标题栏「ShellRS」后面的三个图标切换左侧栏显示的内容:主机列表、端口转发列表或凭据列表。侧栏隐藏时点其中一个会把它重新展开。

ShellRS 同一时间只运行一个:已经开着时再打开一次,会把已有的窗口调到前面,新启动的那个随即退出。两个 ShellRS 各自把主机读进内存再写回同一个数据库,会互相覆盖对方的改动。(用 SHELLRS_DATA_DIR 指到不同数据目录的算不同的 ShellRS,可以同时运行。)要并排看两个终端或 SFTP,把标签拖成分栏即可。

主机列表

左侧栏里保存的每一项是一台主机:地址、端口和认证方式。同一台机器用不同用户登录,就保存成两台主机。

主机对话框的「认证方式」有三种:

  • 密码:填用户名和密码,密码保存在系统钥匙串;密码留空则每次连接时询问。只用密码登录,不会先拿 SSH Agent 或私钥去试。
  • 使用凭据:选一条保存好的凭据,用户名和登录方式都来自凭据(见下面「凭据」),对话框里不再填用户名和密码。「测试连接」同样使用凭据保存的密码。要用私钥登录,就建一条密钥凭据。
  • 无密码:只填用户名。依次尝试服务器免认证、SSH Agent 和 ~/.ssh 下的默认私钥(id_ed25519、id_ecdsa、id_rsa),和命令行 ssh 默认的做法一样。服务器要求密码时连接失败并说明原因,不会询问;服务器在密钥之后再要验证码时照样询问。

无论选哪种,连接时都先问服务器是否允许免认证登录,允许就直接登录。

主机对话框「分组」下面的「连接方式」决定怎么连到这台主机,终端、SFTP、端口转发、外部 CLI 和「测试连接」都照它走:

  • 直接连接:默认,本机直接连主机的地址和端口。
  • SSH 跳板:经过别的已保存主机连过去,支持多级。框里一排标签写出整条路(「本机 → 阿里云99 → 禅道 → 当前主机」),下面每台跳板一行,「×」移除,「添加跳板主机」可按名称或地址搜索;要调顺序就移除后重新添加。连接时先登录第 1 台,由它连第 2 台,依此类推,最后一台连到主机。每台跳板都用它自己的地址、端口、认证方式(密码、凭据或无密码)和主机信任记录,首次连接各问一次主机密钥,询问框里写明是哪台跳板主机;跳板主机自己的「连接方式」在这里不生效,要多级就在这里按顺序列出。主机的地址按跳板主机那边的网络来填,例如内网地址。
  • 代理连接:经由 HTTP 代理(CONNECT)或 SOCKS5 代理连接,在下拉框里选。填代理的地址和端口(例如本机的 127.0.0.1:7890);代理需要认证时再填用户名和密码,密码保存在系统钥匙串,经由同一个代理、同一个用户名的主机共用。主机的地址交给代理去解析。代理要求认证却没有密码、或者拒绝了用户名和密码时,连接失败并说明原因,不会询问。

改了一台主机的地址或认证方式,经由它跳转的主机也会重新连接(只改名称不会)。删除一台被别的主机用作跳板的主机,确认框写明有几台主机在用它;删除后那些主机的跳板列表里留下一行「已删除的主机」,连接时直接报错,不会悄悄改成直连或少跳一级,编辑时移除或换一台即可。已经打开的连接不受影响。

尚未实现:跳板和代理叠加使用、拖动调整跳板顺序、HTTPS 代理、在主机列表里标出连接方式。

对话框最后是「备注」,可以写多行(回车换行),记下机器的用途、负责人、到期时间之类,只保存在本地数据库里,不影响连接。

鼠标停在主机上,行的右侧会显示 用户@地址:端口,主机有备注时下面接着显示备注(太长的只显示前 6 行)。右键主机可连接、打开 SFTP、编辑、复制、复制 ID 或删除。「复制 ID」复制的是主机的 16 位随机标识(形如 Jwg5rHvXCxw89paM),供其他工具标识这台主机:它在主机创建时生成,改名、改地址都不变,复制出来的主机得到新的 ID,删掉的 ID 不会再分配。没有打开任何标签时,中间区显示「最近连接」列表,双击或回车连接;右键其中的主机弹出同一个菜单,并选中该主机。

拖动分组或主机到同类项目的上侧 / 下侧可调整同级顺序;主机拖到分组会移入该分组,分组拖到另一个分组的中部会成为子分组。拖到列表空白处可移回根层级。分组始终排在同级主机之前,顺序与分组的展开状态会保存到本地数据库。搜索时暂停拖动排序。

端口转发

点标题栏的端口转发图标,左侧栏换成转发列表。每条转发规则经由一台已保存的主机,启动时为自己建立一条 SSH 连接,不依赖该主机的终端或 SFTP 标签:关掉标签、对主机「断开连接」都不影响它,主机的连接状态也不把它算在内。有转发在运行时,标题栏的端口转发图标旁显示运行数量。

三种转发,都按「入口 → 出口 → 目标」理解,连接从入口进、经 SSH 隧道到出口、再由出口去连目标:

类型 入口(监听) 出口 用途
本地转发(ssh -L) 本机 服务器 在本机访问服务器那边的服务,例如用本机的客户端连只对服务器开放的数据库
远程转发(ssh -R) 服务器 本机 让服务器那边访问本机的服务,例如把本机开发中的站点给对方看、接收 Webhook
动态转发(ssh -D) 本机(SOCKS 代理) 服务器 把服务器当代理,目标由应用自己指定,例如让浏览器经由服务器上网
  • 新建和编辑:列表标题栏的「+」打开对话框。上方一行三张卡片选类型,中间的示意图随表单实时填入地址、标出入口在哪台机器上,下面一句话说明这条规则的效果(如「在本机连接 127.0.0.1:8080,就等于从 SSH 服务器连接 db.internal:3306。」)。示意图和这句话里的「SSH 服务器」就是「经由主机」选的那一台,图里按它扮演的角色称呼,不写主机的名称。示意图上有一个圆点沿连接方向缓缓移动:先过 SSH 隧道,再到目标,停一下,周而复始;切换类型时从新的入口重新出发。名称可以不填,列表里显示转发摘要(8080 → db.internal:3306、9000 ← localhost:3000、SOCKS 1080)。
  • 启动和停止:每行末尾的按钮,或双击该行、选中后回车;右键菜单里还有编辑和删除。「创建」只保存规则,不会自动启动。勾选「启动 ShellRS 时自动开启」的规则随应用启动。
  • 状态:行尾显示正在连接、运行中(及当前连接数)、正在重连或已停止的原因。某个连接转发不了(例如服务器连不上目标)只在该行提示,转发本身继续运行。
  • 登录:使用主机的配置、钥匙串里保存的密码和 ShellRS 自己的主机信任记录。首次连接的主机、需要输入的密码会弹出和终端一样的询问框,并注明是哪条转发在连接;取消询问等于停止这条转发。
  • 断线重连:连接中断后按 1、3、10 秒自动重连三次,重连期间本机监听端口保留,新进来的连接会被直接关闭。自动重连不弹任何询问:需要重新输入密码、确认主机密钥时停止并写明原因,手动启动即可。三次都失败也会停止,并弹出通知。
  • 修改后:编辑运行中规则的类型、主机、监听或目标,或编辑它所经由的主机的地址、认证方式和连接方式(包括这台主机所用凭据的用户名、类型或私钥文件,以及它的跳板主机),这条转发会按新设置重新启动;只改名称或自动开启不会。
  • 删除主机:删除主机(或包含它的分组)会连同经由它的转发规则一起删除,运行中的先停止,确认框里写明数量。
  • 动态转发支持 SOCKS5(无认证,CONNECT,IPv4、域名、IPv6)和 SOCKS4 / 4a。域名交给服务器解析。
  • 监听地址默认 127.0.0.1。填其他地址时,本地和动态转发会被同一网络中的其他设备使用;远程转发需要服务器的 sshd_config 设置 GatewayPorts clientspecified 或 yes,其他机器才连得上;默认是 no,这时转发照常运行、不报错,但只监听服务器自己的 127.0.0.1(和手写 ssh -R 一样)。对话框在填了非回环地址时会提示这一点。1024 以下的端口需要管理员(服务器上是 root)权限。不支持端口 0(由系统挑选端口)。

尚未实现:通过外部 CLI 管理转发、规则排序。系统的「减少动态效果」设置目前不会关掉示意图的动画。

凭据

点标题栏的凭据(钥匙)图标,左侧栏换成凭据列表。一条凭据是一套可以让多台主机共用的登录信息,包括名称、用户名和登录方式:

类型 保存什么 登录时
密码 用户名和密码 用凭据保存的密码;没存或被拒绝时询问
密钥 用户名、私钥和口令 只用这把私钥;口令按私钥文件保存,用同一个文件的凭据共用
SSH Agent 用户名 只用 SSH Agent 中的密钥:macOS / Linux 上是 SSH_AUTH_SOCK 指向的 Agent,Windows 上是 OpenSSH Authentication Agent 服务
  • 新建和编辑:列表标题栏的「+」、空列表里的「新建凭据…」或空白处的右键菜单打开对话框;双击凭据、选中后回车或右键「编辑凭据…」编辑。密码和私钥口令存进系统钥匙串,数据库里只有名称、用户名、类型和私钥路径。
  • 密钥从哪里来:密钥凭据的「私钥」有三种来源。
    • 本机文件:选一个私钥文件,只保存它的路径;文件移动或删除后需要重新选择。
    • 粘贴:贴进 OpenSSH、PEM 或 PuTTY 格式的私钥。贴成公钥或认不出的内容时会说明原因。私钥加了口令时才显示口令栏。
    • 生成新密钥:选 Ed25519(默认)或 RSA 4096,选中就生成;对话框里显示公钥,旁边可以复制。口令可留空;填了就用它加密私钥,口令存进钥匙串。生成的密钥以凭据名称作为注释。
    • 粘贴和生成的私钥由 ShellRS 写成数据目录下 keys/ 里的文件(随机文件名,只有自己的账户能读),凭据引用这个文件,编辑时显示为「本机文件」和它的路径。之后再粘贴或生成会直接覆盖这个文件,已连接的主机不会因此重连;改成别的文件或别的类型、或删除凭据时,这个文件连同它的口令一起删除,对话框会先提示。用户自己的私钥文件 ShellRS 从不改动或删除。
    • 空列表和空白处的右键菜单里另有「生成密钥…」,打开的是同一个对话框,已经选好「密钥 · 生成新密钥」。密钥凭据的右键菜单有「复制公钥」,用来把公钥加到服务器的 ~/.ssh/authorized_keys。
  • 主机跟着凭据变:改凭据的用户名,所有使用它的主机的用户名一起变。改用户名、类型或私钥文件时,使用它的已连接主机会重新连接(只改名称不会);对话框里写明有几台主机在用。
  • 删除:右键「删除」。有主机在用时确认框写明数量和它们之后怎么登录:用密码凭据的主机改为「密码」,连接时询问;用密钥或 SSH Agent 凭据的主机改为「无密码」。用户名不变,密码和私钥不会复制过去。已经打开的连接不受影响,凭据的密码随凭据一起从钥匙串删除。
  • SSH Agent 凭据连不上 Agent、Agent 里没有密钥或服务器不接受其中任何一把时,会直接说明原因,不会改为询问密码。「无密码」的主机也会尝试同一个 Agent,连不上时静默跳过,接着试默认私钥(Windows 上同样如此)。

尚未实现:在主机对话框里直接新建凭据、通过外部 CLI 管理凭据、凭据排序、自定义 SSH Agent 的套接字、把公钥自动装到主机上、导出 ShellRS 保存的私钥。

设置

侧栏最下方的「设置」按钮(或 ⌘,,其他平台 Ctrl+,)在中间区打开「设置」标签页;已经打开时切换到该标签,不会重复打开。设置页分两栏:左边是分类(外观、终端、外部 CLI、关于),上方可搜索,栏宽可拖动;右边是所选分类的设置。设置改动立即生效并保存在数据目录的 settings.json 里。

  • 外观 → 常规 → 界面语言:跟随系统、简体中文、English,默认简体中文。英文界面尚在翻译中,目前只有 GPUI Kit 组件自带的文字(如搜索框提示)会切换。
  • 外观 → 常规 → 应用外观:深色、浅色、跟随系统,默认跟随系统;选「跟随系统」时随系统的深浅色切换。标题栏的主题按钮也会改写这一项。
  • 终端 → 字体配置:字体(只列出本机安装的等宽字体,默认是系统的等宽字体,macOS 上为 Menlo)、字号(8–32 像素,默认 13)、行高(字号的 1.0–2.0 倍,默认 1.54,即原来的 20 像素行高)。改动立即作用于所有已打开的终端。下方的预览按终端的排法显示字母、数字、易混字符、符号、中文、制表符和一行命令。设置文件里的字体在本机没有安装时,使用默认字体。
  • 外部 CLI:见下一节。
  • 关于:「应用更新」一组:当前版本和检查更新、更新渠道、自动升级,见「下载与更新」。

外部 CLI

shellrs 命令让 Codex、Claude Code、OpenCode 等 AI Agent 在 ShellRS 里已保存的主机上执行远程命令、传输文件。命令本身不接触密码和私钥,也不读数据库:它把请求交给正在运行的 ShellRS,由 ShellRS 用保存的配置和钥匙串去连接。请求走本机的进程间通信:macOS、Linux 上是数据目录下的套接字 cli.sock,Windows 上是命名管道 \\.\pipe\shellrs-cli-<数据目录的散列>。

在 设置 → 外部 CLI 中:

  • 启用外部 CLI:默认关闭。关闭时 ShellRS 仍在监听,但拒绝所有请求,命令会提示去这里打开。开启后,本机当前用户下的任何程序都能这样使用已保存的主机。套接字只对当前用户可读写,连接时还会核对对方的用户身份;Windows 的管道同样只允许当前用户、只接受本机连接,命令在发请求之前还会确认管道属于当前用户(或管理员),防止别人抢注同名管道。
  • CLI 二进制:把 shellrs 放进 PATH。
    • macOS:链接到 /usr/local/bin/shellrs,目录不可写时弹系统授权框。
    • Linux:链接到 ~/.local/bin/shellrs。
    • macOS、Linux 上「移除」只删除指向 shellrs 的链接,同名的其他文件不会被改动。
    • Windows:图形程序没有控制台,命令是单独的控制台程序 shellrs-cli.exe(与 shellrs.exe 放在一起)。「安装」把它复制成 %LOCALAPPDATA%\ShellRS\bin\shellrs.exe,并把这个文件夹加入当前用户的 PATH(不需要管理员),重新打开的终端和 Agent 才能找到它。ShellRS 升级后启动时会自动更新这份副本;更新不了时显示「更新」。副本正被使用时也能更新。「移除」删掉副本并把文件夹移出 PATH。
  • Agent Skills:把教 Agent 使用 shellrs 的 skill 写到通用目录(~/.agents/skills)或 Codex、Claude Code、OpenCode 各自的 skills 目录;内容和当前版本不同时显示「更新」。「复制 skills」把 skill 全文复制到剪贴板。

命令(shellrs --help 查看完整说明):

shellrs list [--query <关键词>] [--json]       # 列出主机;输出不是终端时自动用 JSON
shellrs exec <ID> "<命令>"                     # 或 --stdin 从标准输入读命令
shellrs upload <ID> <本地路径> <远程路径>
shellrs download <ID> <远程路径> <本地路径>
  • <ID> 是 16 位的主机 ID,即 shellrs list 的 id,也就是主机右键「复制 ID」复制的内容。
  • exec 每次临时建立连接,执行完即断开。远程命令没有标准输入,退出码就是远程命令的退出码;被信号终止时是 128 加信号编号。
  • 上传和下载沿用 SFTP 标签的传输引擎(递归、.filepart、断线重连),目标路径按 scp 的规则:目标是已存在的目录就放进去并保留原名,否则目标就是副本自己的路径,其父目录必须存在。已存在的文件直接覆盖;新建的文件保留源文件的可执行权限。~ 表示登录目录。
  • 失败时在标准错误输出 shellrs: [错误码] 说明,退出码 255。错误码有 not_running(ShellRS 未运行)、not_enabled(未启用外部 CLI)、host_not_found、host_key_unknown(还没在 ShellRS 里连过这台主机)、host_key_changed、missing_credential(没有保存密码或口令)、connect_failed、transfer_failed、bad_request、version_mismatch。CLI 不弹任何询问:陌生主机、缺少密码都直接失败,请先在 ShellRS 里连接一次。传输完成但有项目失败时退出码为 1。
  • 支持 macOS、Linux 和 Windows。Windows 的 PowerShell 里,多行或带引号的命令用 here-string 经 --stdin 传入(@'…'@ | shellrs exec <ID> --stdin);输出有中文时先执行 $OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::new()。命令文本会去掉开头的 BOM、把 CRLF 换成 LF,远程 shell 不会看到多余的回车符。

标签页

远程终端标签和 SFTP 标签都以主机系统徽章为图标(与主机列表相同)。右键标签可重命名(仅本次运行有效,留空恢复为主机的名称,用于区分同一台主机的多个连接)、在新标签页中连接、打开 SFTP、复制 IP 地址 / 主机名、重新连接、编辑主机,以及关闭当前、左侧、右侧、其他或全部标签。SFTP 标签的菜单是「重命名标签…」(留空恢复为「主机的名称 · SFTP」)、打开 SFTP、复制 IP 地址 / 主机名、重新连接加关闭命令,标签栏右侧和远程终端一样有「SFTP」和「重新连接」按钮;本地终端标签是「重新启动」加关闭命令。标签栏右侧「…」按钮的菜单与当前标签的右键菜单相同。双击任一标签的标题可隐藏或显示左侧的侧栏(同 ⌘B 和标题栏的按钮)。远程终端运行时和 SFTP 标签已连接时,标签栏右侧显示这条 SSH 连接的往返延迟,每 5 秒更新一次:低于 100 ms 为绿色,100–200 ms 为黄色,高于 200 ms 或超时为红色。SFTP 传输进行中也照常测量,读数会随传输占满带宽而升高。批量关闭时,正在上传的 SFTP 标签仍会先确认。

终端

右键终端内容区可复制、粘贴、查找、清屏;远程终端另有打开 SFTP、重新连接和断开连接。断开连接只断开这一个标签,标签保留,可随时重新连接,同一台主机的其他标签和 SFTP 不受影响。

  • 查找(⌘F,其他平台 Ctrl+Shift+F):在终端右上角打开查找条,按字面量搜索屏幕和回滚历史。查询全为小写时不区分大小写,含大写字母时区分。所有匹配高亮显示,当前项颜色更深,查找条显示「当前项/总数」。回车或 ⌘G(F3)跳到下一项(更新的输出),Shift+回车或 ⌘⇧G(Shift+F3)跳到上一项(更早的输出),到头后循环。Esc 关闭。打开时如有选中文字,会作为查询词。
  • 清屏(⌘K,其他平台 Ctrl+Shift+K;焦点不在终端时 ⌘K 仍是聚焦侧栏的搜索框):清掉屏幕和回滚历史,只留下光标所在的提示符行,包括已输入但未回车的内容。清屏只在本地进行,不向服务器发送任何内容。vim、top 等全屏程序运行时不可用。

SFTP

打开主机的「SFTP」标签即可浏览本地与远程目录;和终端一样,每次「打开 SFTP」都新开一个标签,同一台主机可以开多个,各自独立连接、各看各的目录。操作方式对标 WinSCP Commander。SFTP 使用独立 SSH 连接,仅请求 SFTP 子系统,不要求服务器提供 Shell;关闭终端不会中止传输。

工具栏

每一侧面板都有两行工具栏,下方是路径标签。面板太窄放不下时,按钮从右往左整个隐藏,不会换行(对应的命令在右键菜单和快捷键里仍然可用)。新开的 SFTP 标签本地、远程两侧各占一半;两侧和队列之间的分隔线拖到哪里,在这个标签关闭之前都会记住,切到别的标签再回来也不变:

  • 第一行(导航):
    • 「目录列表」:列出从根到当前目录的每一级,本地另有主目录、桌面、文稿、下载,选中即前往。
    • 书签:点按钮打开「打开目录/书签」(见下);旁边的下拉箭头列出这台主机这一侧的书签,点击即前往,也可添加或移除当前路径。书签保存在本地数据库,删除主机时一并删除。
    • 上级目录、根目录、主目录、刷新、后退、前进。
  • 第二行(文件):
    • 远程是「下载…」,本地是「上传…」,下拉里还有「选择文件上传…」。
    • 删除、重命名…、属性…、新建(文件夹… / 文件…)。

路径标签

与 WinSCP 的路径标签相同:

  • 显示当前目录的完整路径,例如 /home/tester/。
  • 每一级都可以点:悬停时从根到该级高亮,单击即前往。
  • 当前使用的一侧(最近点过的一侧)底部有一条深蓝色线。
  • 路径放不下时保留根目录和末尾几级,中间折成 …,点 … 前往被折叠的最后一级。
  • 单击当前目录、双击路径右侧空白处打开「打开目录/书签」。
  • 右键:前往、刷新、添加路径到书签、复制路径、打开目录/书签…。

打开目录/书签

与 WinSCP 的「打开目录」对话框相同,可以从路径标签、书签按钮、⌘O(其他平台 Ctrl+O;macOS 另有 ⌘⇧G)或路径标签的右键菜单打开:

  • 「目录」预填当前目录并已选中,直接输入即可替换。~ 表示主目录,相对路径从当前目录算起。本地侧另有「浏览…」。
  • 下方是这台主机这一侧的书签。与目录相同的书签处于选中状态;单击书签把它填入目录,双击直接打开。
  • 「添加」把目录加入书签,「删除」(或在列表中按 Delete)删除选中的书签并选中相邻的一个,「上移」「下移」调整顺序。
  • 书签的改动立即保存,按「取消」也不会撤销,与 WinSCP 相同。
  • 回车或「打开」前往目录;Esc 或「取消」关闭。

列表下方的状态栏平时显示项目数和已选数量;连接中和读取目录超过 0.3 秒时显示「正在连接 SFTP…」或「正在读取目录…」。读不了目录或连接断开时,原因用红字显示在窗口最左下角(平时显示「已连接 主机的名称」的位置);空闲时断网也会自己发现,不用等到刷新,时机和同一台主机的终端一样;重新连接用标签栏的「重新连接」按钮或标签菜单;断开时在远程列表里做任何操作(刷新、打开目录、删除、上传下载等)会弹出「SFTP 连接已断开」对话框,说明原因,并可直接「重新连接」。这些都不会让列表移动。

列与 WinSCP 相同:本地为名称、大小、类型、修改时间,远程为名称、大小、修改时间、权限、所有者。

  • 大小默认以 KB 显示(4,008,960 KB,向上取整,只有空文件是 0 KB),与 WinSCP 相同。右键「大小」列标题可切换为「字节」(4,105,175,040 B)、「千字节(KB)」或「简短格式」(按大小用 B、KB、MB、GB,如 3.8 GB),对所有 SFTP 标签生效并保存在设置里。按大小排序始终按实际字节数。
  • 时间形如 2026/4/22 12:44:53。
  • 权限形如 rwxr-xr-x。
  • 所有者来自服务器的 ls -l 行。
  • 链接到目录的符号链接显示为带箭头的文件夹,可以双击进入。

选择与右键菜单

  • 与 WinSCP 关闭「整行选择」时相同,「名称」格才是项目:鼠标移上去时只有名称格变灰,单击、双击、右键都作用在名称格上,选中时整个名称格高亮;行里的其他列和列表下方都算空白处。
  • 鼠标:单击名称格选中(其他选择取消),⌘ 单击(其他平台 Ctrl 单击)增减,Shift 单击选取范围,双击打开。单击空白处取消全部选择(按住 ⌘ 或 Shift 时不取消)。
  • 框选:在名称右边的空白、大小、类型、时间等列或列表下方按下拖动,画出选框,框住的行被选中;按住 ⌘ 或 Shift 开始拖动则加到已有选择上。拖到列表上下边缘时自动滚动。拖动文件名才是把文件拖到另一侧传输:按下未选中的文件名时只选中它(其他选择取消),拖走的就是它一个;按下已选中的文件名则拖走全部已选。拖动时只有到了另一侧列表上才显示「上传 / 下载 N 个项目」,在自己的列表或其他不能放下的地方,指针显示为禁止。
  • 键盘:↑↓、Home、End、PageUp、PageDown 移动,加 Shift 扩展;空格或 Insert 切换当前行;⌘A 全选;Tab 切到另一侧。
  • 右键未选中的名称格会先选中它;右键空白处取消选择并弹出空白处菜单。
    • 文件名上的菜单:打开、上传… / 下载…、删除、重命名…、属性…。
    • 空白处的菜单:前往(上级 / 根 / 主目录 / 后退 / 前进)、刷新、添加路径到书签、新建。

快捷键

命令 快捷键
上传 / 下载(按所在面板) F5
重命名 F2
新建文件夹 F7
删除 F8、Delete;macOS 另有 ⌘⌫
属性 F9;macOS 另有 ⌘I
刷新 ⌘R / Ctrl+R
上级目录 Backspace;macOS 另有 ⌘↑
根目录 ⌘\ / Ctrl+\
主目录 macOS ⌘⇧H,其他平台 Ctrl+H
后退 / 前进 ⌥← / ⌥→;macOS 另有 ⌘[ / ⌘]
添加路径到书签 ⌘D / Ctrl+D
打开目录 Enter;macOS 另有 ⌘↓
打开目录/书签 ⌘O / Ctrl+O;macOS 另有 ⌘⇧G

文件操作

  • 删除前会确认,并写明对象和后果:
    • 本地项目移到废纸篓。
    • 远程项目永久删除,目录连同其中全部内容。
    • 删除符号链接只删除链接本身。
  • 重命名和新建:
    • 按当前列表检查名称;不能为空,不能是 . 或 ..,不能与已有项目同名。
    • 重命名不会覆盖已有项目。
  • 属性:
    • 显示位置、大小、修改时间,远程另有所有者和组。
    • 权限用 3×3 复选框和八进制数字编辑,两者同步。
    • 多选时,项目之间不一致的权限位保持原样,除非你改动它。
    • 含目录时可以递归应用;递归时默认「为目录添加执行权限(X)」,避免目录无法进入。
    • 符号链接不参与修改权限。

上传与下载

  • 入口:
    • 上传:「上传…」、本地列表中的 F5、「选择文件上传…」,或按住本地项目的文件名拖到远程列表,或把 Finder 中的文件拖到远程列表。
    • 下载:「下载…」、远程列表中的 F5,或按住远程项目的文件名拖到本地列表。
    • 拖到目录行时放进该目录,拖到其余区域时放进当前目录。
  • 所有入口都显示确认框,可以修改目标目录;下载可以用「浏览…」选择本机目录。确认框写明数量和种类(如「上传 2 个文件到 …」),来源的所在目录只写一次,每个项目占一行,悬停可看完整路径。
  • 确认后来源、端点和目标即固定。每个 SFTP 标签同时运行一个批次(上传和下载共用),批内依次处理;传输进行中还可以继续上传或下载,新的批次排进传输队列,前一批结束后自动开始。其他 SFTP 标签、主机和终端可以继续操作。
  • 递归传输包含空目录。符号链接原样创建,不跟随。默认二进制传输,保留普通文件的修改时间。
  • 新建项使用目标一侧的默认权限,覆盖时保留目标原有的基本权限。不复制所有者、ACL 或扩展属性。
  • 同名目录合并。文件或链接冲突时询问覆盖、跳过或取消,可以应用于本批剩余冲突;目录与非目录冲突不会自动删除。
  • 出错时可以重试、跳过或取消,完成后的汇总分别列出成功、跳过和失败。

传输队列

与 WinSCP 的队列面板相同,有传输时出现在双栏下方,高度可拖动,清除全部已结束的批次后收起。

  • 每一批一行:操作(上传 / 下载)、来源(一个项目时是它的路径,多个项目时是所在目录)、目标、已传输(单位与「大小」列相同)、时间(剩余时间)、速度(最近几秒)和进度。
  • 进行中的批次显示总进度条,下面一行是正在传的文件和它自己的进度条,对应 WinSCP 进度对话框里的两个进度条。
  • 进度列:等待中、正在扫描、百分比、等待回答、重连说明、已停止、已完成、部分失败(N 项)、已移出。
  • 点行首的箭头展开这一批的逐项结果(完成、已跳过、失败及原因),最新的在最上面。
  • 工具栏:继续(停止的批次)、停止(进行中的批次)、移出队列(选中的排队中或已结束的批次,或停止的批次)、丢弃续传进度、清除已完成。
  • 停止的批次留在队首,等你继续、丢弃续传进度或移出队列之后,后面的批次才会开始;移出队列不删除续传记录,下次传同样的文件仍会询问是否续传。
  • 队列只在本次运行中保留,关闭 SFTP 标签时一起清除;有未完成的批次时关闭标签会先确认。

断点续传和替换

文件先写入 <目标文件名>.filepart。写入请求采用有界流水线,收到每个写入确认并关闭成功后才发布正式文件;服务器支持时先调用 fsync@openssh.com。支持 posix-rename@openssh.com 的服务器使用原子替换;其他服务器先将旧文件移到 .shellrs-<UUID>.backup,再发布新文件,此兼容路径不保证原子性。发布响应丢失时根据受管理临时路径、阶段、类型和大小恢复,无法安全判断则保留恢复文件并报告。

续传记录保存在应用数据目录的 upload-resume/,采用版本化 JSON 和原子写入,不写入密码、口令或私钥,不改变数据库结构。记录用于绑定端点、主机指纹、来源、目标和安全替换阶段。续传方式与 WinSCP 相同:读取远端 .filepart 的当前大小,在本地文件中跳过相同长度并继续传输;使用者需确保来源仍是同一版本。上传过程不会为了校验而回读远端文件内容。

下载同样先写入本机的 <目标文件名>.filepart,完成后设置远程的修改时间、fsync,再在同一文件系统内重命名为正式文件(原子替换)。并发的读取请求可能乱序、短读返回,但临时文件严格按顺序写入,因为续传只信它的长度。下载续传记录保存在 download-resume/,绑定端点、主机指纹、远程来源及其大小与修改时间、本地目标;远程文件变化后不能续传,只能重新下载或跳过。

网络故障每批最多自动重连三次,间隔 1、3、10 秒。耗尽后使用「继续上传」或「继续下载」,手动恢复会重置次数。认证失败、主机密钥变化和主动取消需要用户处理。重连沿用原连接配置,编辑主机不会改变正在传输的目标。

取消、关闭标签、断开连接或退出时保留续传记录;关闭正在传输的标签会先确认。重启后不会自动继续,再次选择相同来源和目标时会询问续传。停止状态下可使用「丢弃续传进度」清理该批受管理的临时文件;存在无法判断的恢复备份时会保留文件并说明原因。成功发布的项目自动清理记录和备份。

文件名不能准确表示时会明确报错。当前 russh-sftp 3.0.0 的远端字符串解码会替换无效 UTF-8,浏览器因此拒绝包含替换字符 U+FFFD 的远端名称,避免访问错误路径。符号链接沿用 OpenSSH 的 SFTP v3 参数顺序。

尚未实现:目录同步、前台传输进度对话框、队列排序、过滤、查找文件、目录树和 Dock 布局持久化。

下载与更新

安装包在 shellrs.com/download:

系统 首次安装 自动更新
macOS(Apple Silicon 和 Intel 共用一个包) DMG,把 ShellRS 拖进「应用程序」 支持
Windows x64 安装程序,按当前用户安装到 %LOCALAPPDATA%\Programs\ShellRS,不需要管理员 支持
Linux x64 AppImage 支持

ShellRS 启动 30 秒后检查一次有没有新版本,之后每 6 小时检查一次。有新版本就在后台下载并校验,完成后标题栏右上角出现更新图标。点开可以看更新内容,点「重启并安装」就换成新版本并重新打开。重启会断开已打开的连接、停止传输(续传进度保留)和端口转发,对话框里会写明具体有哪些。

「设置 › 关于」里的「应用更新」只有三行:

  • 当前版本:下面写着现在的状态(已是最新、正在下载、已下载等),右边是版本号和一个按钮:平时是「检查更新」,下载好之后变成「重启并安装…」。构建号和平台在版本号的悬停提示里。

  • 更新渠道:稳定版适合日常使用;Beta 可以提前收到测试版本,稳定版发布时也会收到。切换后马上按新渠道检查(关掉自动升级时等你手动检查)。

  • 自动升级:关掉之后只在手动检查时才联网,发现新版本时由你决定是否下载。

  • 校验:更新清单由 ShellRS 的发布密钥签名,安装包按清单里的大小和 SHA-256 核对,任何一步对不上都不会安装。macOS 上还会核对新版本的开发者签名。

  • 隐私:检查更新只发送 ShellRS 的版本号、操作系统和 CPU 架构,不发送任何能识别这台电脑或用户的信息。

  • 不能自动更新的情况:从 DMG 里直接运行、没有放进「应用程序」文件夹、对安装位置没有写权限、Linux 上不是用 AppImage 运行,或者是自己编译的开发构建。这时「关于」页会说明原因,有新版本时给出「前往下载页」。

  • 退回旧版本:数据库在升级到新结构之前会备份成 shellrs.db.v<旧版本>.bak。旧版本打开新结构的数据库时会拒绝打开,以免把新版本保存的数据弄乱;需要退回时,把备份改名回 shellrs.db。

发布

在 CHANGELOG.md 里写好 ## [x.y.z] 一节,把 Cargo.toml 的版本改成 x.y.z,提交后推送 tag vx.y.z。.github/workflows/release.yml 依次:

  1. 核对 tag 与 Cargo.toml 一致,截出更新说明,确认代码里有发布公钥;
  2. 构建并打包:macOS 合成 universal,签名、公证、staple,产出升级用的 .app.zip 和首次安装用的 .dmg;Windows 用 Inno Setup 打安装程序;Linux 打 AppImage;
  3. 在 release 环境里人工批准后:给每个包签名,上传到 R2(dl.shellrs.com/releases/<版本>/),建 GitHub Release,最后才替换更新清单 dl.shellrs.com/update/v1/<通道>.json 并清 CDN 缓存。

版本号带 - 的(如 0.3.0-beta.1)只发到 beta 通道;正式版同时成为 beta 通道的最新版。在 Actions 里手动运行这个 workflow 只构建打包、不发布,用来演练。客户端只接受比自己新的版本,所以发错的版本撤不回来:把清单改回上一版能阻止更多人升级,修复要发新的补丁版。

一次性准备:

  • 更新签名密钥:minisign -G -p shellrs-update.pub -s shellrs-update.key 生成两对(一对日常用,一对离线保存备用),把两个公钥(.pub 文件的第二行)填进 src/update/build_info.rs 的 TRUSTED_KEYS。私钥和口令只放进 GitHub 的 release 环境,另外离线备份;丢了私钥,已发出去的 ShellRS 就再也收不到更新。换钥匙时先发一版带上新公钥,再换签名用的私钥。
  • Cloudflare:shellrs.com 的 DNS 托管在 Cloudflare;建 R2 bucket,绑定自定义域 dl.shellrs.com,关闭 r2.dev 地址;Cache Rules 让 /releases/* 和 /update/* 按源站的 Cache-Control 缓存(默认不缓存 .json、.AppImage);一个只能写这个 bucket 的 R2 API Token,一个只能清这个 zone 缓存的 API Token。
  • Apple:Developer ID Application 证书(导出 .p12)和 notarytool 用的 App Store Connect API Key。packaging/macos/Info.plist.in 里的 bundle id com.shellrs.ShellRS 和签名的 Team ID 一经发布就不能再改:钥匙串按它们授权,改了之后每条保存的密码都要重新允许。
  • 图标:assets/logo/ 里的 shellrs.icns(macOS)、shellrs.png(1024×1024,Linux,macOS 没有 icns 时也由它生成)和 shellrs.ico(Windows 安装程序)。
  • GitHub secrets:仓库级的 APPLE_CERTIFICATE_P12(base64)、APPLE_CERTIFICATE_PASSWORD、APPLE_SIGNING_IDENTITY、APPLE_TEAM_ID、APPLE_API_KEY_P8(base64)、APPLE_API_KEY_ID、APPLE_API_ISSUER;release 环境(设为需要审批)里的 MINISIGN_SECRET_KEY、MINISIGN_PASSWORD、R2_ACCOUNT_ID、R2_ACCESS_KEY_ID、R2_SECRET_ACCESS_KEY、R2_BUCKET、CF_ZONE_ID、CF_API_TOKEN。

清单格式见 packaging/manifest.example.json,由 packaging/make-manifest.sh 生成:一个文件里是清单原文和它的 minisign 签名,签名的 trusted comment 写明通道和版本。格式只增加字段、不改已有的;已发出去的 ShellRS 一直按 /update/v1/ 这个地址检查。

运行和验证

工具链固定 Rust 1.98.1,russh-sftp 固定 3.0.0;保持仓库锁定的 GPUI 与 russh 版本。

cargo run
cargo test
cargo clippy --all-targets -- -D warnings
cargo fmt --check

数据目录默认是系统应用数据目录中的 shellrs,可通过 SHELLRS_DATA_DIR 覆盖。主机、端口转发规则和凭据(不含密码)保存在 shellrs.db,主机信任记录保存在该目录的 known_hosts,凭据里粘贴或生成的私钥保存在该目录的 keys/ 下,密码和私钥口令使用系统钥匙串(服务名 shellrs;账户名是主机端点的 password:<用户>@<地址>:<端口>、私钥的 passphrase:<路径>、密码凭据的 credential:<随机 ID> 和代理的 proxy:<用户>@<代理地址>:<端口>)。

src/sftp/tests.rs 使用临时目录与故障注入覆盖上传和下载的文件内容、空目录、链接、覆盖、权限、取消、源文件变化、乱序与短读、续传及替换各阶段恢复,以及删除、重命名、新建和递归改权限不跟随链接。Unix 协议测试使用本机 OpenSSH sftp-server(macOS /usr/libexec/sftp-server,Linux /usr/lib/openssh/sftp-server);工作线程测试仅监听 127.0.0.1 的随机端口,使用测试凭据。限制本地套接字的沙箱会跳过该部分,需要在允许回环套接字的环境运行。

src/forward/protocol_tests.rs 用进程内的 SSH 服务器和本机的回显服务测试真实的转发工作线程:三种转发的往返、目标不可达、服务器禁止转发、端口被占用、空闲断线后重连、重试耗尽和停止后的清理,同样只监听 127.0.0.1 的随机端口。

tests/ui/ 里的 UI 测试驱动真实 Workspace,通过 Workspace::new_with_services 注入 SFTP、本地目录、终端和端口转发服务,不连接用户服务器或真实钥匙串;在线升级的测试给 workspace.updater() 注入假的更新服务器和安装器,不联网、不改任何安装。Finder 的系统原生拖放仍需在真实 macOS 窗口中补充人工验收;无头测试覆盖原生文件拖入事件和面板内部拖放。

开发构建(cargo run)不检查更新。要在本机走一遍更新流程,用 debug 构建加环境变量 SHELLRS_UPDATE_CHANNEL=beta 编译,运行时用 SHELLRS_UPDATE_URL=http://127.0.0.1:8000/{channel}.json 指向本地的静态服务器(python3 -m http.server),清单用 packaging/make-manifest.sh 和自己生成的测试密钥签名,测试公钥放在环境变量 SHELLRS_UPDATE_PUBLIC_KEY 里。release 构建不认这两个环境变量。

上传交互参考 WinSCP 上传流程,协议适配参考 russh-sftp 请求接口 与 OpenSSH 扩展规范。

S
Description
High-performance native SSH client in Rust, GPU-rendered with GPUI: host manager, terminal, WinSCP-style SFTP and port forwarding. Rust 编写、GPU 渲染的原生 SSH 客户端。
https://shellrs.com
Readme GPL-3.0
14 MiB
0 Stars 1 Watchers 0 Forks
ShellRS 0.1.8
Latest
2026-10-11 08:40:38 +00:00
Languages
Rust 99.8%
Shell 0.1%