herdr-hub

herdr-hub 是一个 Linux 下的 Herdr session 切换器。它让 tmux 做最外层路由, 把每个本地或 herdr --remote attach 放进独立 tmux window,并在 Herdr 画面顶部 显示可点击的 Sessions 条。

它不是 Herdr 插件,也不会修改 Herdr core。Herdr 0.8.2 的插件 API 不能向原生 sidebar 插入 UI,也不能让 thin client 从一个 server 原地改连另一个 server; 所以顶部状态栏横跨整个终端,而不是只嵌在 Spaces 上方。

功能

  • 自动读取 herdr session list --json,导入本机正在运行的 sessions。
  • 记住使用过的远端,并通过 SSH 实时读取运行中及已停止的 Herdr sessions。
  • 在 Linux /proc/*/cmdline 中查找仍在运行的 herdr --remote … clients,并自动记住目标。
  • 首次接管已有 remote client 时安全地再 attach,不结束原进程。
  • 一个 endpoint 对应一个 tmux window,隐藏 window 中的连接继续在线。
  • 顶部 Sessions 条在窄屏下也为每个 Tab 显示 Session 优先的短名称,并支持鼠标点击、数字切换和无需 fzf 的动态 popup 选择。
  • 可隐藏不再需要的 Tab,而不停止底层本地或远端 Herdr Session。
  • dead window 留在顶栏,可原地重连。
  • 不修改 ~/.tmux.conf,不保存 SSH 凭据或远端 Session 缓存。

依赖

  • Linux
  • Python 3.11+
  • tmux 3.4+
  • Herdr 0.8.2+
  • OpenSSH client

检查当前环境:

./bin/herdr-hub doctor

安装

直接从仓库运行:

./bin/herdr-hub

或把启动器链接到 ~/.local/bin:

make install
herdr-hub doctor

安装脚本只创建一个指向本仓库的符号链接。移动或删除仓库后需重新安装。

第一次接管

如果本地和 remote Herdr clients 已经分别开在其他终端中:

  1. 保持这些 clients 运行。
  2. 从一个新的、未嵌套在 tmux 中的终端执行 herdr-hub。
  3. Hub 扫描现有 clients,并为每个 endpoint 创建一个新的 attach window。
  4. 确认 Hub 中可以正常操作后,手动退出原来的 clients。

tmux 不能把另一个终端里已经运行的进程搬进 window,所以首次接管会短暂存在两个 clients;它们连接的是同一个 Herdr server,不会复制 server 或 panes。

只有一个终端时,本地 Herdr 可以先 detach,因为 herdr session list 仍能发现后台 server。remote target 在 client 退出后没有本地记录,因此直接使用:

herdr-hub open --remote orangepi
herdr-hub open --remote orangepi --session work
herdr-hub open --remote ssh://me@server:2222 --remote-keybindings server

打开本地 named session:

herdr-hub open --session work

open 会把 endpoint 保存在当前 tmux hub 的 window metadata 中。远端 target 还会 同时加入 ~/.config/herdr-hub/remotes.json,以后可直接从 Sessions 弹窗浏览这台机器上的其他 Session。

日常操作

Hub 使用独立 tmux socket herdr-hub,不会接管普通 tmux server。外层前缀固定为 Ctrl+A,Herdr 原来的 Ctrl+B 可以直接使用。

操作 快捷键 / 命令
点击切换 鼠标点击顶部 session
打开 Session 弹窗 点击左上角 Sessions 或 Ctrl+A g
上一个/下一个 window Ctrl+A p / Ctrl+A n
按编号切换 Ctrl+A 0..9
扫描新增 sessions Ctrl+A r 或 herdr-hub refresh
强制重连当前 window Ctrl+A R
关闭/隐藏当前 Tab Ctrl+A &,确认 y;也可在 Sessions 弹窗中选择
detach Hub Ctrl+A d
重新进入 Hub herdr-hub
停止 Hub clients herdr-hub stop

远端 Session 弹窗

弹窗由 tmux display-popup 和 Hub 内置选择器组成,不依赖 fzf。它会立即显示已打开的 window,同时在后台并行查询所有已登记远端;每台机器的结果就绪后原地更新。

状态与选择行为:

状态 选择后的行为
▶ 当前 / ● 已打开 跳转到已有 window
× 已断线 自动重连并跳转
○ 远端运行 新建 attach window 并跳转
■ 远端已停止 启动该 Session、attach 并跳转

弹窗靠前位置提供“关闭当前 Tab”;它只结束该 Tab 中的 Hub client,底层 Herdr Session 和工作现场继续运行。每个远端下方都有“新建 Session”入口。弹窗底部还可添加或管理远端;移除远端只删除 记忆记录,不关闭已有 window,也不停止远端 Herdr server。手机端单击条目即可执行, 键盘支持上下键、Enter、输入搜索、Backspace、Ctrl+R 刷新和 Esc 返回/关闭。

也可通过 CLI 管理远端:

herdr-hub remote list
herdr-hub remote add orangepi
herdr-hub remote add ssh://me@server:2222 --remote-keybindings server
herdr-hub remote remove orangepi

注册表默认位于 ~/.config/herdr-hub/remotes.json(遵循 $XDG_CONFIG_HOME),权限为 0600。它只保存 SSH target 和 remote keybinding 模式。

复制与剪贴板

Hub 启用 tmux 的 OSC 52 剪贴板透传。Herdr 触发的自动复制,以及 tmux 接管后的 鼠标拖选,都会尝试写入当前 Hub 访问端的本地剪贴板。远程 session 中复制的 文本也回到访问端,不是远程机器的剪贴板。

访问端的终端需要支持并允许 OSC 52。如果终端或 Web terminal 禁止了这项能力, 可按住 Shift 再拖选,绕过 tmux 并使用终端原生复制。

当访问端宽度小于 80 列时,Hub 会自动进入窄屏模式:隐藏右侧快捷键说明, 所有 Tab 都显示状态和最多 12 列的短名称,并优先显示主机:默认 Session 的本地与 远端分别显示 local、host,非默认 Session 才显示 local/work、host/work。 宽度小于 50 列时左上角标题会缩成 S,继续给 Tab 留空间。点击 Sessions/S 可打开占 90% 屏幕的完整选择器。

refresh 是 add-only:它添加新发现的 endpoint,不自动删除已有 window,也不会改变 当前焦点。通过 Ctrl+A & 或弹窗关闭的 endpoint 会在当前 Hub 生命周期内记为已隐藏, 刷新和断开终端后重新进入都不会让它自动回来。要恢复它,打开 Sessions 弹窗并重新选择; 也可以执行对应的 herdr-hub open 命令。远端通过 SSH 目录重新选择,本地隐藏的运行中 Session 会列在“本机”下。Hub 至少保留一个 Tab;要全部退出请使用 herdr-hub stop。

当 endpoint 连接进程退出时,window 会保留:顶栏将它标记为 × [断开], 当前 pane 底部会显示退出状态和 Ctrl+A R 重连提示。这与正常 detach Hub 不同;仅关闭外层终端后,直接再次执行 herdr-hub 即可。

herdr-hub stop 只结束 tmux 中的 client processes。本地及远端 Herdr servers 和 它们的 panes 会继续运行。

CLI

herdr-hub
herdr-hub start
herdr-hub refresh
herdr-hub open [--session NAME]
herdr-hub open --remote TARGET [--session NAME]
               [--remote-keybindings local|server]
herdr-hub choose
herdr-hub remote list
herdr-hub remote add TARGET [--remote-keybindings local|server]
herdr-hub remote remove TARGET
herdr-hub reconnect [--window ID]
herdr-hub close [--window ID]
herdr-hub doctor
herdr-hub stop

自动发现与远端查询的边界

零配置的首次发现只覆盖:

  • 当前用户正在运行的本地 Herdr servers;
  • 当前用户、同一 PID namespace 中仍然存活的 herdr --remote processes。

发现或手动添加一次后,remote target 会被记住,不再要求本地 client 持续存活。弹窗使用 非交互 SSH 查询 $HOME/.local/bin/herdr session list --json;SSH key/passphrase 应已由 ssh-agent 处理。未知 host key、需要密码或远端不可达时会显示可重试的错误,不会卡住 整个弹窗。首次安装或 host-key 确认仍可在实际新建的 Herdr window 中交互完成。

首次使用且尚未登记时,以下情况仍无法自动找回 remote target:

  • remote client 已经退出,但远端 server 仍在后台运行;
  • client 位于另一个 container/PID namespace;
  • /proc 使用了阻止读取同用户 argv 的安全配置;
  • 可执行文件不叫 herdr。

这些场景可在弹窗中选择“添加远端”,或使用 herdr-hub open --remote …。为了避免嵌套 tmux 与前缀冲突, herdr-hub 应从普通终端启动;若当前已经在另一个 tmux server 中,它会拒绝再次 attach。

开发与测试

make test

测试使用伪造的 /proc 和 Herdr executable;tmux 集成测试使用唯一 socket 和 /dev/null 配置,不接触真实 Herdr sessions 或现有 tmux server。

S
Description
Responsive local and remote Herdr session switcher built on tmux
Readme
168 KiB
Languages
Python 99.9%
Shell 0.1%