From 2060bbd23ab7720b2e5a90501182f4a9b2b92135 Mon Sep 17 00:00:00 2001 From: laily Date: Wed, 16 Sep 2026 21:44:25 +0800 Subject: [PATCH] feat: udpate fish --- fish/functions/ff.fish | 7 ++- git/.gitconfig | 2 + herdr/README.md | 57 ++++++++++++++++++++++ herdr/config.toml | 106 +++++++++++++++++++++++++++++++++++++++++ script/herdr-init.sh | 69 +++++++++++++++++++++++++++ 5 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 herdr/README.md create mode 100644 herdr/config.toml create mode 100755 script/herdr-init.sh diff --git a/fish/functions/ff.fish b/fish/functions/ff.fish index e4c3ec6..074c061 100644 --- a/fish/functions/ff.fish +++ b/fish/functions/ff.fish @@ -32,8 +32,13 @@ function ff for __f in ~/.dotfile/fish/functions/*.fish functions -e (basename $__f .fish) 2>/dev/null end - set -e __f source ~/.config/fish/config.fish + # fish 对已加载过的 autoload 函数不会在 functions -e 后重新加载, + # 必须显式 source 一遍,否则函数(含 ff 自身)会丢失 + for __f in ~/.dotfile/fish/functions/*.fish + source $__f + end + set -e __f echo "Fish configuration reloaded!" case edit vim ~/.config/fish/custom.fish diff --git a/git/.gitconfig b/git/.gitconfig index 67aa1c3..940ad3a 100644 --- a/git/.gitconfig +++ b/git/.gitconfig @@ -53,6 +53,8 @@ path = ~/.dotfile/git/.gitconfig.personal [includeIf "gitdir:~/workrepo/"] path = ~/.gitconfig.work +[includeIf "gitdir:~/repo/"] + path = ~/.gitconfig.work [rebase] autoSquash = true autoStash = true diff --git a/herdr/README.md b/herdr/README.md new file mode 100644 index 0000000..a071202 --- /dev/null +++ b/herdr/README.md @@ -0,0 +1,57 @@ +# herdr + +个人 herdr 配置与迁移笔记。配置由 `tmux/.tmux.conf` 映射而来。 + +- `config.toml` — 真实配置,经 `script/herdr-init.sh` 软链到 `~/.config/herdr/config.toml` +- 校验:`herdr config check` +- 热重载:`prefix+shift+r`(本配置改为 `prefix+r`)或 `herdr server reload-config` +- 默认值参考:`herdr --default-config` +- 官方速查:https://herdr.dev/docs/concepts/ ,给 agent 看的:`herdr --skill` + +## 概念对照 + +| tmux | herdr | 说明 | +|---|---|---| +| session | workspace | herdr 的 workspace 对应“一个项目/任务”,侧栏按 workspace 汇总 agent 状态 | +| (无对应) | session | herdr 的 named session 是**独立的 server 命名空间**(`herdr session attach work`),跟 tmux 的 session 不是一回事 | +| window | tab | | +| pane | pane | 只能向右(right)或向下(down)切 | +| prefix mode | prefix mode (`ctrl+b`) | 相同;另有 terminal mode / navigate mode | +| status bar + 脚本 | sidebar | 鼠标可点、可拖分隔条、右键菜单 | +| (无对应) | agent | herdr 识别 pane 里的 coding agent,状态 `working`/`blocked`/`done`/`idle`/`unknown` | +| tmux-resurrect | session.json + `[experimental] pane_history` | 布局自动持久化,agent 原生会话恢复需要装 integration | +| tpm 插件 | 无插件系统 | fzf 类能力内建(`prefix+w` workspace picker、`prefix+g` goto);自定义动作用 `[[keys.command]]` | +| tmux over ssh | `herdr --remote ` | 远端跑 server,本地 attach | + +## 和 tmux 的主要差异 + +1. **鼠标优先**。所有交互都能用鼠标完成;键位是可选层。`prefix+?` 可实时列出当前所有有效绑定。 +2. **agent 感知**。侧栏能看到每个 pane 里的 agent 状态,`blocked`(等你审批/回答)会被顶到前面。tmux 只能靠 pane 标题自己写。 +3. **CLI + 本地 socket API**。`herdr pane split/run/read/wait-output`、`herdr agent prompt/wait` 这类命令可以从脚本或 agent 内部驱动布局和读输出,tmux 的 `send-keys` 做不到等待与状态判定。 +4. **配置是单个 TOML**,没有插件系统,也没有 `run-shell` 状态栏脚本;但支持 + `[[keys.command]]` 自定义命令(`type = "shell"` / `"pane"` / `"popup"`,可指定宽高百分比),基本能覆盖原来用插件/脚本做的事。 +5. **直接快捷键**。除 `prefix+...` 外还支持 `ctrl+alt+...` 这类直通键位(适合想摆脱 prefix 的用法)。反过来,被 OS 或外层终端占用的组合 herdr 收不到,表现为“绑了没反应”。 +6. **没有 `escape-time` / `terminal-overrides` / 真彩色开关**。那些是 tmux 作为终端适配层才需要的,herdr 自己处理能力协商。通知走 `[ui.toast] delivery`,剪贴板走 `[ui] copy_on_select`。 +7. **不支持嵌套启动**(`experimental.allow_nested = false`):herdr pane 里再跑 `herdr` 会被拒绝。tmux 里 `tmux` 是能套的。 +8. `[remote] manage_ssh_config` 默认开启:`herdr --remote` 会生成一份私有 ssh config,**先 include 你的 `~/.ssh/config`**,再补 `ServerAliveInterval`/`ServerAliveCountMax` 兜底,并用私有 control socket 复用连接。所以 `~/.ssh/config` 里已有的 keepalive 仍然优先,我们的 `Include ~/.ssh/config.d/*` 也照常生效。 + +## 切换时的注意事项 + +- **分屏按分隔线的形状记**:`|` 是竖线 → 切成左右;`-` 是横线 → 切成上下。herdr 就是按形状命名的(`split_vertical` = 竖线 = 向右切,`split_horizontal` = 横线 = 向下切),而 tmux 的 `splitw -v/-h` 按“排列方向”命名,两者相反:tmux `splitw -v`(上下堆叠)对应 herdr `split_horizontal`,tmux `splitw -h`(左右并排)对应 `split_vertical`。本配置按形状对齐(`-` 上下、`|` 左右)。 +- **`herdr` 裸跑会 attach;`herdr server` 是前台 headless server**。别为了“看看帮助”敲 `herdr server`——它不返回,会把调用它的地方永久挂住(踩过一次:pi 的 bash 工具卡了 46 分钟)。要看帮助用 `herdr --help`、`herdr `(如 `herdr pane`);停 server 用 `herdr server stop`。 +- **prefix 都是 `ctrl+b`**,两套配置不冲突,但同时开难免按错。切过去之前建议先退掉 tmux,避免双层状态栏/双层 prefix。 +- **没有 `-c '#{pane_current_path}'` 这个开关**:新建 pane/tab 的目录策略在 `[terminal] new_cwd`(`follow` / `home` / `current` / 固定路径),本配置是 `follow`。 +- **resize 步长不可配**。tmux 那边是固定 10 格;herdr 直接绑定(本配置 `prefix+shift+hjkl`)用默认步长,或 `prefix+r` 进 resize mode 再动。 +- **`mouse on/off` 没有运行时快捷键**:由 `[ui] mouse_capture` 决定,运行时去 `prefix+s` 设置面板改。用 `copy_on_select = false` 可以在拖选后保留选区,等 `Ctrl+C` 再复制。 +- **复制模式**:`mode-keys vi` 在 herdr 没有等价配置。本配置给 `copy_mode` 绑了 `prefix+[`(herdr 0.8.2 支持该校验通过,但未写进 `--default-config`),复制模式的内部键位不可配;平时直接鼠标拖选即可。想把 scrollback 丢进 `$EDITOR` 用 `prefix+e`。 +- **中文/IME**:如果你在 pane 里用 pi/claude/codex 这类自绘光标的 TUI 遇到输入法候选框错位,可试开 + `[experimental] reveal_hidden_cursor_for_cjk_ime = true`(可用 `cjk_ime_agents` 限定只对某些 agent 生效)。默认关闭。 +- **别再跑 tpm**:`script/tmux-init.sh` 会克隆 tpm 并装插件,那是 tmux 的;herdr 不需要。两套可以并存,但别指望插件搬到 herdr。 +- **升级**:`herdr update`(stable 通道);0.8.2 → 0.9.0 已经可用。用包管理器装的则走包管理器。 + +## 迁移状态 + +- [x] `herdr/config.toml`(tmux 键位/UI 行为映射,`herdr config check` 通过) +- [x] `script/herdr-init.sh`(软链 + 备份 + 幂等 + 校验) +- [ ] 装 agent integration(`herdr integration install claude` 等),才有原生会话恢复与状态上报 +- [ ] 需要时启用 `reveal_hidden_cursor_for_cjk_ime` diff --git a/herdr/config.toml b/herdr/config.toml new file mode 100644 index 0000000..ebde744 --- /dev/null +++ b/herdr/config.toml @@ -0,0 +1,106 @@ +# herdr 配置 —— 由 ~/.dotfile/tmux/.tmux.conf 映射而来 +# +# 仓库内真实文件: ~/.dotfile/herdr/config.toml +# 由 script/herdr-init.sh 软链到: ~/.config/herdr/config.toml +# +# 校验: herdr config check +# 热重载: prefix+shift+r,或 herdr server reload-config +# 默认值: herdr --default-config +# +# 这里只写与 herdr 默认值不同(或需要显式强调)的键,未写到的沿用默认。 +# 概念对照: tmux session → herdr workspace,tmux window → herdr tab,tmux pane → herdr pane + +[keys] +# ---------------------------------------------------------------- 前缀 +# tmux 里的 prefix 相关行都被注释掉了,所以沿用 ctrl+b(herdr 默认值,无需显式设置) +# prefix = "ctrl+b" + +# tmux: bind r source-file ~/.tmux.conf \; display-message "Config reloaded" +reload_config = "prefix+r" # herdr 默认是 prefix+shift+r + +# ---------------------------------------------------------------- 分屏 +# 按“分隔线的形状”对齐: +# | 是竖线 → 把 pane 切成左右 +# - 是横线 → 把 pane 切成上下 +# herdr 就是按分隔线形状命名的,而 tmux 的 -v/-h 按“排列方向”命名,所以二者相反: +# tmux splitw -v(上下堆叠)= 横线 = herdr split_horizontal(向下切) +# tmux splitw -h(左右并排)= 竖线 = herdr split_vertical (向右切) +# tmux: bind - splitw -v -c '#{pane_current_path}' → 切成上下 +split_horizontal = "prefix+minus" +# tmux: bind | splitw -h -c '#{pane_current_path}' → 切成左右 +split_vertical = "prefix+|" +# tmux 的 -c '#{pane_current_path}' 对应 [terminal] new_cwd = "follow"(默认值) + +# ---------------------------------------------------------------- pane 切换 +# 注释写的是“绑定 hjkl 键为面板切换”,其中 h/l 两行被注释掉了,这里按原意启用 +focus_pane_left = "prefix+h" +focus_pane_down = "prefix+j" +focus_pane_up = "prefix+k" +focus_pane_right = "prefix+l" + +# tmux: bind -r K/J/H/L resizep -U/-D/-L/-R 10 +# herdr 可直接绑定 resize,不必先进入 resize mode;步长不可配(tmux 那边是 10 格) +resize_pane_up = "prefix+shift+k" +resize_pane_down = "prefix+shift+j" +resize_pane_left = "prefix+shift+h" +# 注: tmux 里 prefix+shift+l 被后面的 `bind L switch-client -l` 覆盖,此处留给“回上一个” +# 向右 resize 用 prefix+r 进 resize mode,或在此写回 "prefix+shift+l" + +# tmux: bind L switch-client -l (注释写“返回上一个窗口”) +previous_tab = "prefix+shift+l" +# 想要真正的“来回切换”(不按顺序),可改为 last_pane = "prefix+shift+l" + +# tmux: bind M command-prompt -p "插入窗口到位置:" "move-window -b -t ':%%'" +# herdr 没有“输入索引插入”这种交互,改成相邻平移 +move_tab_previous = "alt+shift+left" +move_tab_next = "alt+shift+right" + +# ---------------------------------------------------------------- 复制模式 +# tmux: setw -g mode-keys vi(tmux 默认用 prefix+[ 进入 copy mode) +# herdr 0.8.2 支持 copy_mode 键(未写进 --default-config,但 herdr config check 认可) +copy_mode = "prefix+[" +# tmux 里没有的: 把 scrollback 丢给 $EDITOR(herdr 默认 prefix+e) +# edit_scrollback = "prefix+e" + +# ---------------------------------------------------------------- 故意不复刻的 tmux 绑定 +# tmux: bind -r j select-pane -t .+1 \; resize-pane -Z +# 它覆盖了上面的 `bind j select-pane -D`,含义是“切到下一个 pane 且每次都 toggle zoom”, +# 语义含糊,不复刻。循环切换用 herdr 默认的 prefix+tab / prefix+shift+tab, +# zoom 用 prefix+z。 +# tmux: bind m (切换鼠标模式) +# herdr 没有鼠标开关的运行时按键: 行为由 [ui] mouse_capture 决定, +# 运行时可开 prefix+s(设置)面板调整。 +# herdr 自带、tmux 那边靠插件实现的能力(均为默认键): +# prefix+w workspace picker(≈ tmux-fzf) +# prefix+g goto +# prefix+? 列出所有有效绑定 + +[terminal] +# tmux 新建 pane/window 都带 -c '#{pane_current_path}' +new_cwd = "follow" + +[ui] +# tmux: set -g mouse on +mouse_capture = true +# tmux: set -s set-clipboard on +copy_on_select = true +# tmux: set-titles on / set-titles-string "#{session_name}" +window_title = "{workspace}" +# tmux: automatic-rename on(窗口名跟随当前目录)→ 关掉 herdr 的新 tab 命名询问 +prompt_new_tab_name = false +# tmux 风格: 只要内部分隔线,不要外面那圈边框 +pane_outer_borders = false + +# tmux: set -as terminal-features ",*:osc9" + allow-passthrough,让外层终端弹通知 +# herdr 直接把 pane 里的通知转发给外层终端(Ghostty) +[ui.toast] +delivery = "terminal" + +[session] +# 近似替代 tmux-resurrect 的会话恢复 +# (原生会话恢复需要对应 agent 装了 herdr integration,如 herdr integration install claude) +resume_agents_on_restore = true + +[experimental] +# 近似替代 tmux-resurrect 的 scrollback 恢复: 重启 server 后保留 pane 屏幕历史 +pane_history = true diff --git a/script/herdr-init.sh b/script/herdr-init.sh new file mode 100755 index 0000000..e329dd2 --- /dev/null +++ b/script/herdr-init.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# 将 herdr 配置链接到 dotfile + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common/help.sh" + +usage() { + cat <<'EOF' +用法: herdr-init + +将 ~/.dotfile/herdr/config.toml 软链接到 herdr 配置路径: + $XDG_CONFIG_HOME/herdr/config.toml(默认 ~/.config/herdr/config.toml) + +已有配置会备份为 *.backup.<时间戳>。 + +选项: + -h, --help 显示此帮助 +EOF +} + +dotfile_help_requested "${1:-}" && dotfile_show_help + +set -e + +SRC="$HOME/.dotfile/herdr/config.toml" +CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" +DEST_DIR="$CONFIG_HOME/herdr" +DEST="$DEST_DIR/config.toml" + +if [ ! -f "$SRC" ]; then + echo "错误: 未找到 $SRC" >&2 + exit 1 +fi + +echo "初始化 herdr 配置..." +echo "目标路径: $DEST" + +mkdir -p "$DEST_DIR" + +if [ -L "$DEST" ] && [ "$(readlink -f "$DEST")" = "$(readlink -f "$SRC")" ]; then + echo "软链接已存在且指向正确位置,无需操作。" + exit 0 +fi + +if [ -e "$DEST" ] || [ -L "$DEST" ]; then + BACKUP="$DEST.backup.$(date +%Y%m%d%H%M%S)" + mv "$DEST" "$BACKUP" + echo "已将现有配置备份到 $BACKUP" +fi + +ln -s "$SRC" "$DEST" + +if [ -L "$DEST" ] && [ "$(readlink -f "$DEST")" = "$(readlink -f "$SRC")" ]; then + echo "软链接创建成功: $DEST -> $SRC" +else + echo "软链接创建失败,请检查路径和权限。" >&2 + exit 1 +fi + +if command -v herdr >/dev/null 2>&1; then + echo "校验配置:" + herdr config check || true + if pgrep -x herdr >/dev/null 2>&1; then + echo "herdr 正在运行,可在 herdr 内用 prefix+shift+r 热重载" + fi +else + echo "未找到 herdr,跳过配置校验" +fi