Files
herdr-session-switch/README.md
T

255 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
检查当前环境:
```bash
./bin/herdr-hub doctor
```
## 安装
直接从仓库运行:
```bash
./bin/herdr-hub
```
或把启动器链接到 `~/.local/bin`:
```bash
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 退出后没有本地记录,因此直接使用:
```bash
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:
```bash
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`;最后一个 Tab 会保留为断线状态 |
| 修改 Tab 显示名称 | Sessions 弹窗 → `管理 Session 显示名称…` |
| detach Hub | `Ctrl+A d` |
| 重新进入 Hub | `herdr-hub` |
| 停止 Hub clients | `herdr-hub stop` |
## 远端 Session 弹窗
弹窗由 tmux `display-popup` 和 Hub 内置选择器组成,不依赖 fzf。它会立即显示已打开的
window,同时在后台并行查询所有已登记远端;每台机器的结果就绪后原地更新。
状态与选择行为:
| 状态 | 选择后的行为 |
| --- | --- |
| `▶` 当前 / `●` 已打开 | 跳转到已有 window |
| `×` 已断线 | 自动重连并跳转 |
| `○` 远端运行 | 新建 attach window 并跳转 |
| `■` 远端已停止 | Enter/单击启动;命名 Session 可按 `d` 或 `D` 删除 |
| `↻` Windows 旧窗口 | 原地切换为 SSH TTY 模式并重连 |
弹窗靠前位置提供“关闭当前 Tab”;它只结束该 Tab 中的 Hub client,底层 Herdr
Session 和工作现场继续运行。当前 Tab 是远端 Session 时还会显示“关闭并停止当前
Session”;二次确认后会在后台停止远端 Herdr Session、中断其中正在运行的任务并关闭
对应 Tab,但保留为 `■ 已停止`,以后仍可从弹窗重新启动。若它是 Hub 中最后一个 Tab,
停止后会保留该 Tab 为断线状态,避免销毁承载弹窗的最后一个 window。
“管理 Session 显示名称”可给已打开的本地或远端 Tab
设置最多 48 字符的名称;输入留空可恢复默认。每个远端下方都有“新建 Session”入口。
弹窗底部还可添加普通远端、明确添加“Windows/SSH 远端”,或管理已登记远端;移除远端只删除
记忆记录,不关闭已有 window,也不停止远端 Herdr server。手机端单击条目即可执行,
键盘支持上下键、Enter、输入搜索、Backspace、`Ctrl+R` 刷新和 Esc 返回/关闭。
远端查询失败时,该远端行支持 Enter 重试,也支持按 `d` 或 `D` 二次确认后从 Hub 的
历史列表移除。这只删除本机保存的远端登记,不会连接或修改不可达主机上的数据;需要时
可再次通过“添加远端”登记。
选中已停止的命名远端 Session 后,按 `d` 或 `D` 会进入二次确认;无论是否仍有关联
Hub Tab 都可以删除。可点击“确认删除”、按 Enter,或再按一次 `d`/`D`。确认后在后台
通过 SSH 执行 `herdr session delete`,永久删除该 Session 的工作现场和历史数据;若仍有
关联 Tab,也会一并关闭,然后留在弹窗中继续管理。运行中的 Session 不允许删除;Herdr
自身不支持删除永久保留的 `default` Session。若关联 Tab 是 Hub 的最后一个 Tab,Session
仍会成功删除,但该 Tab 会保留为断线状态,以免整个 Hub 随弹窗一起退出。
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 管理远端:
```bash
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 并使用终端原生复制。
当访问端宽度小于 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
```text
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 --remote` processes。
发现或手动添加一次后,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。
## 开发与测试
```bash
make test
```
测试使用伪造的 `/proc` 和 Herdr executable;tmux 集成测试使用唯一 socket 和
`/dev/null` 配置,不接触真实 Herdr sessions 或现有 tmux server。