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。
- 远端查询兼容 Windows OpenSSH 与 Linux/macOS shell;Windows target 自动改用并持久记住 SSH TTY 模式。
- 在 Linux
/proc/*/cmdline中查找仍在运行的herdr --remote …clients,并自动记住目标。 - 首次接管已有 remote client 时安全地再 attach,不结束原进程。
- 一个 endpoint 对应一个 tmux window,隐藏 window 中的连接继续在线。
- 顶部 Sessions 条在窄屏下也为每个 Tab 显示主机优先的短名称,并支持鼠标点击、数字切换和无需 fzf 的动态 popup 选择。
- 可隐藏不再需要的 Tab,而不停止底层本地或远端 Herdr Session。
- 可在 Sessions 管理弹窗中为 Tab 设置持久化显示名称,或恢复默认名称。
- 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 已经分别开在其他终端中:
- 保持这些 clients 运行。
- 从一个新的、未嵌套在 tmux 中的终端执行
herdr-hub。 - Hub 扫描现有 clients,并为每个 endpoint 创建一个新的 attach window。
- 确认 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
herdr-hub open --remote windows-host --transport ssh
打开本地 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 q,确认 y;也可在 Sessions 弹窗中选择 |
| 关闭并停止远端 Session | Sessions 弹窗 → 选中 Session → Space / [⋯] → 关闭并停止 Session |
| 修改 Tab 显示名称 | Sessions 弹窗 → 选中 Session → Space / [⋯] → 修改显示名称 |
| detach Hub | Ctrl+A d |
| 重新进入 Hub | herdr-hub |
| 停止 Hub clients | herdr-hub stop |
远端 Session 弹窗
弹窗由 tmux display-popup 和 Hub 内置选择器组成,不依赖 fzf。它会立即显示已打开的
window,同时在后台并行查询所有已登记远端;每台机器的结果就绪后原地更新。
主页面只显示 Session 和两个全局入口。大多数主机只有 default Session,因此默认只显示
主机名;有命名 Session 时显示为 主机 / Session。本机同样显示为“本机”或
“本机 / Session”。状态与主操作如下:
| 状态 | 选择后的行为 |
|---|---|
▶ 当前 / ● 已打开 |
跳转到已有 window |
× 已断线 |
自动重连并跳转 |
○ 远端运行 |
新建 attach window 并跳转 |
■ 远端已停止 |
Enter/单击启动并打开 |
↻ Windows 旧窗口 |
原地切换为 SSH TTY 模式并重连 |
Enter 或单击一行始终执行它的主操作。管理操作统一放在上下文菜单中:键盘选中一行后按
Space,或在手机端点击行尾 [⋯];右上角 [操作] 也会打开当前行的菜单。菜单会按
Session 当前状态提供修改显示名称、关闭 Hub Tab、关闭并停止 Session、永久删除已停止的
命名 Session、在此远端新建 Session、重试连接和移除远端记录等可用操作。Esc 逐层返回;
危险操作会二次确认并默认选中“取消”。关闭 Hub Tab 只结束该 Tab 中的 client,底层
Session 和工作现场保持运行;“关闭并停止”则会中断远端任务。若它是 Hub 中最后一个 Tab,
该 Tab 会保留为断线状态,避免销毁承载弹窗的最后一个 window。
主页面只有一个“新建 Session”入口,选择远端后再输入 Session 名;“添加远端”会先让你 选择“自动检测(Linux/macOS)”或“Windows/SSH”。修改显示名称支持最多 48 个字符,留空 保存可恢复默认名称,且不会修改底层 Session ID。移除远端记录只删除本机记忆,不关闭已有 Tab,也不停止远端 Herdr server。
搜索必须按 / 显式进入,因此普通字母不会误触命令;搜索页输入文字即可筛选,Esc 清空并
返回。键盘还支持上下键、Page Up/Down、Enter、Ctrl+R 刷新和 Esc 返回/关闭。窄屏会优先
显示主机和 Session 名,状态详情可在 [⋯] 菜单中查看。
永久删除只会出现在已停止的命名 Session 的菜单中,无论是否仍有关联 Hub Tab 都可执行。
确认后会在后台通过 SSH 执行 herdr session delete,永久删除工作现场和历史数据;关联 Tab
也会一并关闭。运行中的 Session 需先“关闭并停止”,Herdr 永久保留的 default Session
不能删除。
Herdr 0.8.2 不支持 Windows 作为原生 herdr --remote 的目标主机。Hub 查询到 Windows
Session 后会标记为“Windows · SSH 模式”,并自动改为 ssh -tt target herdr;命名
Session 会在远端运行 herdr --session NAME。这种模式仍支持 Tab 切换、detach、断线
重连和远端工作现场持久化,但使用远端 Herdr 的 keybindings,也没有原生 thin client
提供的本地图片剪贴板桥接。空 Windows 主机或平台检测失败时,可在“添加远端”中选择
“Windows / SSH”,也可手动执行 herdr-hub open --remote TARGET --transport ssh。
也可通过 CLI 管理远端:
herdr-hub remote list
herdr-hub remote add orangepi
herdr-hub remote add ssh://me@server:2222 --remote-keybindings server
herdr-hub remote add windows-host --transport ssh
herdr-hub remote remove orangepi
注册表默认位于 ~/.config/herdr-hub/remotes.json(遵循 $XDG_CONFIG_HOME),权限为
0600。它只保存 SSH target、remote keybinding 模式和首选 transport,不保存凭据。
Session 显示名称
Herdr 0.8.2 没有底层 Session rename 命令,因此 Hub 的“重命名”是安全的显示名称:
顶部 Tab 和 Sessions 弹窗显示新名称,attach、重连和工作现场仍绑定原来的 Session ID。
名称会跨终端断线、Hub detach 和 herdr-hub stop 保留,并在重新打开 endpoint 时自动
应用。配置保存在 ~/.config/herdr-hub/aliases.json(遵循 $XDG_CONFIG_HOME),
权限为 0600;留空保存会删除该 endpoint 的显示名称并恢复 local/work、
host/work 等默认格式。
复制与剪贴板
Hub 启用 tmux 的 OSC 52 剪贴板透传。Herdr 触发的自动复制,以及 tmux 接管后的 鼠标拖选,都会尝试写入当前 Hub 访问端的本地剪贴板。远程 session 中复制的 文本也回到访问端,不是远程机器的剪贴板。
访问端的终端需要支持并允许 OSC 52。如果终端或 Web terminal 禁止了这项能力,
可按住 Shift 再拖选,绕过 tmux 并使用终端原生复制。
Termux / 手机端复制
Termux 的原生长按选区只认识整个终端画面,不知道 Herdr pane 和左侧 sidebar 的边界。
跨行拖选时,中间行因此可能混入 sidebar 文本。优先使用 Herdr 自带的 Copy Mode:按
Ctrl+B [ 进入,用方向键或 h/j/k/l 移动,按 v 或空格开始选择,再按 y 或 Enter
复制。它只读取当前 pane,不会包含 sidebar;复制大段历史输出也可按 Ctrl+B e 在编辑器
中打开当前 pane 的 scrollback。这里的 Ctrl+B 是 Herdr 前缀,Hub 外层 tmux 前缀仍为
Ctrl+A。
如果更习惯 Termux 长按拖选,可在 ~/.config/herdr/config.toml 已有的 [ui] 段中加入:
[ui]
pane_scrollbars = false
sidebar_collapsed_mode = "hidden"
# sidebar_start_collapsed = true # 可选:下次启动时默认收起
不要重复创建 [ui] 段。执行 herdr config check 和 herdr server reload-config 后,按
Ctrl+B b 可在完整 sidebar 和零宽度隐藏之间切换;隐藏后再使用 Termux 原生选区即可。
pane_scrollbars = false 还会移除 pane 右侧滚动条并腾出一列空间。
当访问端宽度小于 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 q 或弹窗关闭的 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] [--transport native|ssh]
herdr-hub choose
herdr-hub remote list
herdr-hub remote add TARGET [--remote-keybindings local|server]
[--transport native|ssh]
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 --remoteprocesses。
发现或手动添加一次后,remote target 会被记住,不再要求本地 client 持续存活。弹窗先
通过非交互 SSH 执行跨平台的 herdr session list --json;Linux/macOS 的非交互 PATH
找不到 Herdr 时,再自动尝试 $HOME/.local/bin/herdr。Windows OpenSSH 返回的本地代码页
错误文本也会被容错解码。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。