Cline Git Worktree 开发中的依赖卫生:诊断与修复 node_modules 符号链接污染
在 Cline 这类使用 Bun workspaces 的多包 monorepo 中,git worktree 会让同一份仓库同时存在多个 checkout,而每个 checkout 下的 node_modules 符号链接一旦错误地指向另一个 checkout,就会导致"混合源码"的类型错误或运行期行为异常。本文基于仓库中的规则文件 worktree_dependency_hygiene.md 展开,讲清楚这条 Worktree 依赖卫生规则要解决什么问题、如何用一条 realpath 命令快速自检、发现污染后的修复流程,以及为什么 Cline 仓库自身(CLI 任务 worktree、VS Code worktree 控制器)使这条规则成为日常开发的高频实践。
规则背景:worktree 下的符号链接为什么会"串"
这条规则存放在 Cline 仓库自身的 agent 配置目录中,文件为 sdk/.cline/rules/worktree_dependency_hygiene.md。其原文给出的核心断言是:
当你在 git worktree 中工作时,在运行 CLI 复现、测试、hooks 或提交之前,必须先校验依赖链接。
node_modules符号链接可能意外指向另一个 checkout,从而造成混合源码的类型错误或运行期行为偏差。
为什么在 monorepo + worktree 的组合下会出现这种情况?从仓库结构看有两层原因:
- 工作区依赖通过符号链接解析。根目录 package.json(第 4–14 行)声明了
workspaces,包含sdk/packages/*、apps/*、apps/vscode/webview-ui、apps/examples/*等 8 个 glob 项;Bun 安装时会把工作区内的包以符号链接形式放入各级node_modules。 - SDK 包之间存在硬性的工作区依赖。以 sdk/packages/core/package.json 为例,其
dependencies中直接声明了:
"dependencies": {
"@cline/agents": "workspace:*",
"@cline/shared": "workspace:*",
"@cline/llms": "workspace:*",
...
}
workspace:* 协议意味着 node_modules/@cline/llms 这类路径是符号链接,指向仓库内某个 checkout 的 sdk/packages/llms 目录——而不是一个独立的实体拷贝。一旦这个链接指到了另一个 checkout(例如你在主 checkout 里做过 ln -s、或 worktree 复用了残留的链接状态),当前 worktree 的 @cline/core 就会解析到别的 checkout 的 @cline/llms 源码与构建产物,形成"一半代码来自 A、一半来自 B"的混合源码状态。
这也解释了规则中提到的两类症状:混合源码类型错误(两个 checkout 的 dist/ 类型声明不一致)与运行期行为异常(加载的运行时 JS 与当前 checkout 的源码不同步)。Cline 仓库的 AGENTS.md 中有一条相互印证的约束:SDK 包(@cline/shared|llms|agents|core|sdk)之间只通过编译后的 dist/ 互相解析,且不存在 development 源码条件——修改 SDK 源码后必须执行 bun run build:sdk,否则 import 会直接以缺少 @cline/* 或缺少 dist/ 的方式失败。也就是说,跨 checkout 的链接污染不仅会造成"行为不对",还可能让构建链直接断裂。
快速自检:一条 realpath 命令
规则给出的快速检查命令如下(原文照录):
realpath node_modules packages/core/node_modules packages/core/node_modules/@cline/llms
在存在 packages/core 的目录(本仓库中即 sdk/ 目录,packages/core 对应 sdk/packages/core/)执行这条命令,realpath 会解析并打印每个路径的真实物理位置。判定标准非常直接:
- 正常:三行输出全部落在当前 worktree 根目录之下;
- 异常:任一行输出指向了另一个 checkout 的绝对路径(例如你磁盘上另一个 clone 或另一个 worktree 的路径)。
选择这三个路径是有讲究的:node_modules 覆盖根层级的符号链接,packages/core/node_modules 覆盖核心包自己的安装层,packages/core/node_modules/@cline/llms 则精确命中一个 workspace:* 协议的工作区依赖——正是最容易跨 checkout 串链接的那类条目。
发现污染后的修复流程
当 realpath 检出任何一条路径指向其他 checkout 时,规则给出的处置动作是:
- 删除失效的
node_modules符号链接——只清理指向错误 checkout 的链接,而不是盲目删除整个目录; - 从 worktree 根目录重新执行
bun install,让 Bun 按当前 checkout 的 workspace 定义重建全部符号链接; - 在完成上述两步之前,不要信任任何测试或 hook 的结果——这是规则的原文要求("before trusting test or hook results")。
第 3 步尤其值得强调:Cline 仓库的工具链本身对"来源一致性"很敏感。例如根目录 package.json 中 "engines" 锁定 bun: 1.3.13、"packageManager": "bun@1.3.13",并要求 node >=22;overrides 中还固定了 @opentui/core、protobufjs 等 15 个包的版本。如果符号链接跨 checkout 混入,这些版本锁定就可能被另一个 checkout 的 node_modules 实质架空,测试"看似通过"其实验证的是别的代码——这正是该规则要求"先校验、再运行"的原因。
为什么 Cline 仓库会把这条规则写进 agent 配置
从源码结构看,worktree 是 Cline 的一等公民工作流,而不仅仅是开发者的个人习惯,这条规则针对的正是 agent 在 worktree 中自动工作的场景:
- CLI 内置任务 worktree 创建。apps/cli/src/utils/worktree.ts 实现了
createTaskWorktree()(第 71 行起):先git rev-parse --show-toplevel定位仓库根,再创建任务级 worktree;其存放位置由getTaskWorktreesHomePath()决定,即~/.cline/worktrees子目录(第 19–21 行,基于@cline/shared/storage的resolveClineDir())。对应的行为验证见 apps/cli/src/utils/worktree.test.ts。这意味着 agent 通过 CLI 并行开多个任务时,磁盘上天然存在多个 worktree checkout。 - VS Code 扩展提供完整的 worktree 控制面。apps/vscode/src/core/controller/worktree/ 下实现了
createWorktree.ts、listWorktrees.ts、switchWorktree.ts、mergeWorktree.ts、deleteWorktree.ts等控制器,配套 apps/vscode/src/utils/git-worktree.ts 与 apps/vscode/src/utils/worktree-include.ts 工具层。开发者在 IDE 内切换 worktree 工作时,同样是"多 checkout 并存"的常态。
在"同一仓库多 checkout 同时存在"成为常态的前提下,node_modules 符号链接的归属校验就从边角技巧变成了提交前的标准动作——这条规则本质上是在为 agent 自动化流程补上"环境可信度"这一环。
适用前提与注意事项
- 仅在 git worktree 工作流中适用:单一 checkout、无并行 worktree 的场景不存在跨 checkout 链接污染,无需执行该检查。
- 工具链前提:本仓库以 Bun 1.3.13 为包管理器兼任务运行器(AGENTS.md 明确"Do not use npm/yarn/pnpm"),Node >=22。修复动作中的
bun install依赖这一前提。 - 检查命令的工作目录:
realpath node_modules packages/core/node_modules ...中的相对路径以存在packages/core的目录为基准,在本仓库中应从 sdk/ 目录执行(packages/core即 sdk/packages/core/);如果你把该规则移植到其他仓库,请相应替换为你的核心包路径。 - 规则文件本身的位置:sdk/.cline/rules/worktree_dependency_hygiene.md 位于
sdk/.cline/rules/下,与同目录树中的 sdk/.cline/skills/plugin.md 并列,属于面向 agent 的规则/技能资产,供 Cline 系宿主(CLI、IDE 扩展、自定义 SDK 宿主)在会话中作为持久指令消费。
小结
Worktree 依赖卫生的完整工作流可以压缩为三步:
# 1. 自检(在 sdk/ 目录下,本仓库示例)
realpath node_modules packages/core/node_modules packages/core/node_modules/@cline/llms
# 2. 发现指向其他 checkout 时,删除对应失效的 node_modules 符号链接
# 3. 从 worktree 根目录重建
bun install
核心判断标准只有一条:所有 realpath 输出都必须落在当前 worktree 之下。在 Cline 这类"SDK 包只经 dist/ 互相解析 + worktree 并行任务"的仓库中,这一步能避免最隐蔽的一类事故——测试跑在别家 checkout 的依赖上,而你还以为自己在验证自己的代码。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00