- 开发工具
- 代码评审
- CLI
- AI 应用
【免费下载链接】hunk
Review-first terminal diff viewer for agentic coders
导读
Watch mode(--watch)是 Hunk 面向 Agent 化编码场景提供的一项核心工作流能力:它把一次性的 diff review 会话,升级为对不断变化的源码输入持续跟踪、自动刷新的连续视图。本指南将围绕 watch-mode.md 的官方用法展开,并结合 Hunk 仓库中packages/hunk/src/core/watch/的控制器、观察器、签名检测与 VCS 集成源码,讲清哪些输入可以被监听、底层如何以"事件提示 + 签名校验 + 周期轮询兜底"三层机制保持同步,以及r键与hunk session reload两种手动刷新方式的使用边界。读完你可以在自己的仓库里正确使用 watch mode,并理解它为什么会这样工作。
什么是 Watch Mode
Hunk 的定位是 review-first 的终端 diff 查看器(见 README.md 项目描述 "Review-first terminal diff viewer for agentic coders"),watch mode 则是把"评审一次快照"升级为"评审一条不断变化的流"。
它的核心语义可以用文档原句概括:
Watch mode turns a review into a continuous view of a changing source.
也就是说,当你用--watch启动一个 review 后,Hunk 会持续观察输入的来源(文件、补丁文件、仓库工作区或历史版本),一旦底层内容发生变化,就自动重新加载并刷新评审视图,无需你手动退出重进。这在"Agent 正在持续修改代码、评审者需要盯着最新差异"的场景下尤其有用——工作区里的文件一边被改写,diff 视图一边跟着更新。
启动一个被监听的评审
官方文档给出的最简启动方式是对工作区 diff 开启 watch:
hunk diff --watch该命令会同时观察直接文件输入与Git-backed 输入,用于在内容变化时触发刷新;同时保留周期轮询(periodic polling)作为兜底。而对 Jujutsu(jj)与 Sapling 输入,则直接使用轮询方式(详见下文"轮询兜底"一节)。
除了工作区 diff,所有**可重新打开(reopenable)**的输入都能进入 watch mode,官方示例包括:
hunk show HEAD~1 --watch hunk diff --files before.ts after.ts --watch hunk patch changes.patch --watch这些命令的共性在于:它们的输入在磁盘上有一个稳定、可重新读取的落点——一个 ref、两个具体文件路径、或一个补丁文件。在 CLI 参考实现 中,--watch被定义为:
export const WATCH_OPTION = { flag: "--watch", description: "auto-reload when the current diff input changes", } as const satisfies CliReferenceOption;并且diff、show、stash show、patch、difftool等 review 命令在命令规格上都声明了watch: true(见 cli.ts),意味着它们都共享同一个--watch标志并具备自动重载能力。
哪些输入可以被监听
watch mode 有一个硬性前提:输入的来源必须能被 Hunk 再次打开。换句话说,只有"可重开"的输入才谈得上持续观察;一次性、流式的输入则不行。
官方文档明确排除了一种典型场景——stdin 输入:
# Snapshot only; --watch would fail some-command | hunk patch -从源码看,这条规则在 resolveWatchPlan 中实现:当输入的 kind 为patch且文件参数缺失或为-(stdin)时,直接返回null,即无法构建 watch 计划:
case "patch": if (!input.file || input.file === "-") { return null; } fileTargets.push({ path: input.file, source: "content" }); break;同理,agentContext若来自 stdin(-)也无法被监听:
if (input.options.agentContext === "-") { return null; }为什么 stdin 不能 watch?因为 Hunk 的 watch 机制需要反复读取同一输入来计算"内容是否变化"的签名;stdin 是一次性管道,读完即尽,无法二次打开。文档给出的替代方案非常明确:把正在变化的输出落盘到文件,或者改用仓库-backed 命令(如hunk diff、hunk show),再对文件路径开启--watch。
底层同步机制:三层架构
watch mode 之所以能既灵敏又省资源,是因为它的同步不是单一的"纯事件"或"纯轮询",而是三层配合。对应的核心实现在 packages/hunk/src/core/watch/ 目录,由controller.ts(状态机控制器)、observer.ts(事件观察器)、signature.ts(签名检测)三个模块构成。
第一层:事件提示(Event Hints)
createWatchController(见 controller.ts)维护一个明确的状态机:
starting → idle → debouncing → checking → refreshing → closed当观察器(observer)报告底层文件发生变化时,控制器进入debouncing阶段——事件只被当作"提示",不会立即触发刷新,而是先进入防抖窗口,等安静下来再校验签名。控制器提供了一组可调参数(源码中的默认值):
| 参数 | 默认值 | 作用 |
|---|---|---|
quietDelayMs | 200ms | 防抖窗口:事件安静这么久后才做一次检查 |
maximumDelayMs | 1000ms | 事件洪泛时的最大延迟上限,保证检查不会无限推迟 |
healthyCheckMs | 10000ms | 健康状态下的兜底轮询间隔 |
degradedCheckMs | 2000ms | 降级状态下的快速轮询间隔 |
duplicateErrorIntervalMs | 10000ms | 同一错误在窗口内的去重上报间隔 |
startupTimeoutMs | 2000ms | 事件源启动超时(见下) |
第二层:签名校验(Signature Check)
防抖到期后,控制器调用getSignature计算当前输入的签名,与上一次应用过的签名比对:一致则什么都不做,不一致才触发 refresh(见 controller.ts)。这层校验过滤了大量"事件发生了但其实内容没变"的噪声(例如编辑器 touch 文件、无关元数据写入)。
签名由 computeWatchSignature 生成,不同输入类型采用不同签名策略:
diff/difftool(左右两个文件):对左右文件分别取path:size:mtimeMs:ino的 stat 签名;patch(补丁文件):对补丁文件取同样的 stat 签名;vcs/show/stash-show:委托给 VCS adapter 的watchSignature生成仓库态签名;- 若带有
--agent-context,还会把该 sidecar 文件的 stat 签名拼进签名串。
第三层:周期轮询兜底(Polling Fallback)
事件监听并不是所有输入都能提供的。在 createVcsWatchPlan 中可以看到:
return handler.watchPlan?.(operation.input, context) ?? { coverage: "poll-only", targets: [] };即:如果所选 VCS 操作的 adapter 没有实现watchPlan,就回退到poll-only轮询计划。这正是文档所说的"它轮询 Jujutsu 和 Sapling 输入"——这两类 VCS 适配器不提供文件系统事件计划,Hunk 便以轮询签名的方式来感知仓库变化。此外,当事件源因资源耗尽(ENOSPC、EMFILE)或启动超时而降级时,控制器也会把健康轮询间隔从 10s 收紧为 2s 的降级轮询,保证"事件不可用,同步仍不中断"(见 controller.ts 与L311-L325)。
观察器:原生递归与可移植树两种后端
事件从哪来?createWatchObserver 会按 watch 计划为每个目标构建底层 watcher,并根据平台选择后端(见 observer.ts):
- macOS(darwin)与 Windows:使用 Bun/Node 的原生递归 watcher(
fs.watch+recursive: true),注册完成后即视为 ready; - Linux 等可移植平台:使用 Chokidar 的分块树监听器(
createChunkedTreeWatcher,见 portableTree.ts)。
分块树监听器的设计很讲究:它按PORTABLE_TREE_BATCH_SIZE = 32个目录一批地注册深度为零的 Chokidar watcher,批与批之间让出 macrotask,从而在遍历超大工作区时避免一次性扫完整个目录树导致的卡顿;每批 watcher 会暴露独立的 ready 边界,全部就绪后才向控制器报告整体 ready。目录的新增(addDir)会被动态登记,删除(unlinkDir)会先注销旧批次再重新收编存活的兄弟目录。
在事件进入控制器前,观察器还会做一层忽略根(ignored roots)过滤:VCS adapter 可以在 watch 计划中声明忽略的目录(例如.git),观察器通过createIgnoredRootMatcher(observer.ts)做带缓存的祖先链判断,把无关目录的写事件直接丢弃,避免无谓刷新。
运行前提:Bun 版本要求
watch mode 依赖运行时(Bun)的文件系统 watcher,而这里有一个真实的历史坑:Bun 1.3.14 之前存在 watcher 关闭时的锁反转(deadlock)问题。因此 runtime.ts 定义了:
export const MINIMUM_RELIABLE_WATCH_BUN_VERSION = "1.3.14";assertReliableWatchRuntime会在旧版本上直接抛出用户可读错误,提示升级 Bun 或去掉--watch。这意味着:使用 watch mode 请确保 Bun ≥ 1.3.14(bun upgrade可升级)。
手动刷新:r键与hunk session reload
不是所有场景都需要常驻 watch。文档给了两种按需刷新的途径:
1. 终端内按r键
当 review 输入可重载(reloadable)时,直接按r立即刷新,无需开启持续的--watch。从测试用例看,r触发的是"软重载"(soft reload,resetApp: false):保留当前选区及其稳定 id,仅替换底层 review 文件对象(见 AppHost.extensions.test.tsx),所以刷新后你的阅读位置不会被打回原点。
2. 活体 Agent 用hunk session reload
如果评审会话运行在 Agent 会话场景中,Agent 可以通过hunk session reload命令替换会话的整个输入。其语法要求嵌套的 Hunk review 命令放在--之后(见 cli.ts 的解析实现):
hunk session reload session-1 -- show HEAD~1若--后缺失 review 命令,CLI 会报错:"Pass the replacement Hunk command after--"(见 cli.test.ts);session reload也不允许再嵌套另一个 session 命令或非 review 命令(见 cli.ts)。reload 在桥接层对应reloadSession处理器,可携带新的输入并保留或重置应用状态(见 bridge.test.ts)。
相比r键只重载当前输入,session reload是"整个会话换血":适合 Agent 需要切换到完全不同的评审目标(例如从 diff 切到某个历史提交)的场景。
总结:选择哪种同步方式
| 场景 | 推荐方式 | 说明 |
|---|---|---|
| Agent 持续改工作区文件 | hunk diff --watch | 事件提示 + 签名校验,变化即刷新 |
| 盯住某个历史提交/补丁 | hunk show HEAD~1 --watch/hunk patch changes.patch --watch | 输入可重开即可监听 |
| 输入来自 stdin 管道 | 先落盘再用--watch | stdin 输入无法二次打开,watch 会失败 |
| 只想偶尔手动刷新 | 按r | 软重载,保留阅读位置 |
| Agent 要整体替换会话输入 | hunk session reload <id> -- <review-command> | 换整个输入,需--分隔符 |
| jj / sapling 仓库 | hunk diff --watch(轮询兜底) | 事件计划缺省,靠签名轮询感知变化 |
更深一层的机制——状态机防抖参数、忽略根过滤、原生/可移植双后端、Bun 版本门禁——都可以在 packages/hunk/src/core/watch/ 的源码与controller.test.ts、observer.test.ts、plan.test.ts等测试中继续深入研读,作为把 watch mode 集成进自己工具链时的可靠参考。
- 开发工具
- 代码评审
- CLI
- AI 应用
【免费下载链接】hunk
Review-first terminal diff viewer for agentic coders
相关推荐
Hunk hunk-review Skill 完全指南:让编码 Agent 安全驱动实时终端 Diff 评审
Hunk hunk review Skill 完全指南:让编码 Agent 安全驱动实时终端 Diff 评审 导读 Hunk 是一个面向终端用户的交互式 dif
开发工具代码评审CLIAI 应用visual-explainer /diff-review 视觉化 Diff 审查指南:把 git 变更渲染成自包含 HTML 审查报告
visual explainer /diff review 视觉化 Diff 审查指南:把 git 变更渲染成自包含 HTML 审查报告 /diff revie
Understand Anything /understand-diff 实战指南:把 Git Diff 变成知识图谱上的结构化影响分析
Understand Anything /understand diff 实战指南:把 Git Diff 变成知识图谱上的结构化影响分析 本篇指南围绕 Unde
AI 技能AI 插件开发工具知识图谱
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考