dsh-plugin-worktrees
v0.1.2
Published
git worktree parallel write isolation + serial merge integration plugin for the DeepSeek Harness
Maintainers
Readme
dsh-worktrees
English | 简体中文
适用于 DeepSeek Harness (dsh)
0.1.0-rc.6/0.1.0-rc.7· Node ≥ 18 · PATH 上有 git · MIT
让多个 agent 并行写代码而互不打架。 每个任务拿到自己的目录 —— 一个挂在独立分支上的 git worktree —— 多个 agent 可以同时改代码而互不干扰。任务完成后,其分支经串行队列一次一个地合回可供审查的集成分支。如果两个任务改了同几行,冲突现场会原样保留给你 —— 绝不自动解决、绝不强推。
六件工具、零宿主补丁、不接管任何工具名 —— 装上即对所有会话可见 worktree_* 工具族。
为什么需要它
并行派几个带写权限的子代理,它们会互相踩脚:大家改的是同一个工作目录,每个文件都是一场竞态。经典解法就是 git worktree —— 本插件把它变成 agent 工作流里顺手的一步:
worktree_create("api-types")→ 在~/.dsh/worktrees/<repo>/<session>/api-types得到一个全新检出,分支dsh-wt/<session>/<api-types>。- 用
cwd把 agent 派进去(借助 dsh-plugin-subagents)—— 你自己进去改也行。 worktree_merge(id)→ 未提交的改动自动提交,然后分支合入dsh-wt/integration/<session>—— 严格一次一个合并,集成之间不会互相撞车。
安装
# 1. 安装进 dsh profile
dsh plugin --profile web add dsh-plugin-worktrees # 或者:add /path/to/本地检出
# 2. 重启并开一个新会话
dsh --profile web预期结果: 新会话里出现 worktree_create、worktree_list、worktree_status、worktree_merge、worktree_queue、worktree_cleanup 六个工具。
两种启动方式都支持(0.1.2 起)。 0.1.x 曾把 dsh-tools 双实例检查做成硬失败,现在是建议性告警:源码树(tsx)启动器下宿主加载 dsh-tools 的
src构建、插件拿到lib构建,旧版会被这个假阳性直接卡死启动。本插件只用公开的ctx.tools.registerAPI,两份拷贝可以安全共存;告警里指明的setup:peer只在工具调用真的报Cannot read properties of undefined (reading 'prepare')时才需要跑。
用本地检出而不是 npm? 先在仓库里跑
npm install && npm run setup:peer(避免出现第二份 dsh-tools,否则每次工具调用都可能崩),再dsh plugin --profile web add "$(pwd)"。
想让 agent 直接在 worktree 里干活? 官方宿主会静默丢弃子代理的
cwd。安装 dsh-plugin-subagents 并跑它的patches/install.sh(每次 dsh 升级后重跑)。
快速上手
完整闭环 —— 两个并行任务、一次干净合并、一次冲突:
worktree_create({ task: "api-types" }) // → { id: id1, path: P1, branch, base_commit, … }
worktree_create({ task: "docs-refresh" }) // → { id: id2, path: P2, … }
// 并行干活 —— 每个 agent(或你自己)在自己的 path 里改
subagent({ prompt: "实现新的 API 类型。", cwd: P1 })
subagent({ prompt: "刷新文档。", cwd: P2 })
worktree_merge({ worktree_id: id1 })
// → { state: "succeeded", integrated_commit, integration_branch }
worktree_merge({ worktree_id: id2 })
// → { state: "conflicted", conflict_files: [...],
// integration_worktree: "<保留的现场>", resolution_hint: "…" }
// 在保留的 worktree 里手工解决(冲突标记都在),然后:
worktree_queue({ action: "list" })
worktree_queue({ action: "resolve", job_id: "…" }) // 释放集成分支
worktree_cleanup({ worktree_id: id1 }) // 移除 worktree 和分支六个工具
| 工具 | 作用 |
| --- | --- |
| worktree_create | 为任务新建 worktree + 专属分支。返回 path(直接交给 cwd)、branch、base_commit、integration_branch。 |
| worktree_list | 列出某仓库的 worktree(可选包含保留的冲突现场),附合并队列摘要。 |
| worktree_status | 单个 worktree:HEAD、脏状态、逐文件变更、领先基线多少、当前合并作业。 |
| worktree_merge | 自动提交未提交改动,然后入队并合入集成分支。五种可能结果(见下)。 |
| worktree_queue | 查看队列;对作业 resolve / retry / cancel。 |
| worktree_cleanup | 移除 worktree(及分支,除非 keep_branch)。未经双重确认,拒绝销毁未合并的工作。 |
合并结果
| state | 含义 |
| --- | --- |
| succeeded | 合并成功;集成分支上出现 integrated_commit。 |
| conflicted | 有冲突。集成 worktree 连同冲突标记保留;该作业占住集成分支,直到你 resolve 或 retry。 |
| queued | 排在其他合并后面(queued_ahead 告诉你前面有几个)。 |
| no_changes | 工作树相对基线是干净的 —— 无可集成(正常,不是错误)。 |
| failed | 硬失败(如 autoCollect: false 时工作树脏 → dirty_not_collected)。 |
冲突处理,一句话版
不自动解决、不 rebase、不强推。冲突的合并保留现场(一个带冲突标记的 worktree),列出冲突文件,并占住集成分支,直到你:在保留的 worktree 里改完文件后 worktree_queue(action: "resolve");或 action: "retry" 重新排队;或放弃。
内建的安全机制
- 未合并的工作很难丢。 清理一个提交还没进集成分支的 worktree,需要两个独立确认(
force: true且acknowledge: true),否则带证据拒绝。已合并的 worktree 直接清理,没有仪式。 - 仓库门禁,从严失败。 只在会话 cwd 子树、已注册工作区或
allowedRoots里建 worktree —— 没有"任意根"开关。分支名由 git 本身校验。 - 只在本地。 插件会合并,但绝不 push/fetch/clone —— 结果留在本地集成分支上,等人审查后再推。
- 脏工作树有归宿。
autoCollect: true(默认)在合并前自动提交未提交改动(含未跟踪文件)。关掉它,脏树会以明确报错拦下合并,而不是硬来。 - 重启安全。 启动时,仓库/路径已消失的 worktree 标记为
orphaned,在途合并判失败并附说明 —— 只做标记,不做破坏性删除。
配置
全部可选 —— 下表每项都有可用默认值。配置写在 profile 的 cordis.patch.yml 中本插件的行上;写错的键会在启动时大声报错。
| 键 | 默认值 | 含义 |
| --- | --- | --- |
| worktreeRoot | ~/.dsh/worktrees/ | 所有任务 worktree 的根目录。 |
| maxWorktrees | 16 | 跨仓库的非终态 worktree 上限。 |
| defaultBaseRef | HEAD | 新任务分支的起点(总是解析成具体 commit)。 |
| autoCollect | true | 合并前自动提交未提交改动。 |
| gitTimeoutMs / mergeTimeoutMs | 15000 / 120000 | 单条 git 命令 / 合并步骤的超时。 |
| allowedRoots | [] | 门禁额外放行的仓库根。 |
| requireWorkspaceRegistration | true | 同时放行已注册工作区(关闭后仅靠会话 cwd + allowedRoots)。 |
| statePath | ~/.dsh/dsh-worktrees/state.json | 状态文件(原子写、仅所有者)。 |
| retainJobHistory | 200 | 保留的终态合并作业记录数。 |
| register.* | true | 按工具注册开关。 |
搭配使用
- dsh-plugin-subagents
—— 它的逐次调用
cwd就是接合点:把worktree_create返回的path直接交给子代理,它就写进 worktree。 - dsh-dag-orchestrator
—— 本插件对外暴露
worktreesEngine服务,编排器探测到即可用,DAG 里的worktree:任务隔离与merge节点零接线开启。
边界与常见问题
- 一个仓库的合并只走一个 dsh 会话。 队列是进程内的;不支持两个宿主并发合并同一仓库。
cwd被忽略了? 官方宿主会丢弃它 —— 装 dsh-plugin-subagents 并跑它的patches/install.sh。active_job_exists报错 —— 更早的一个冲突作业占着集成分支;worktree_queue(action: "list"),然后resolve或retry它。- 每次工具调用都报
Cannot read properties of undefined (reading 'prepare')—— 真正的第二份 dsh-tools 拷贝(典型:本地检出没跑npm run setup:peer);在本仓库npm install后、或 dsh 升级后重跑。仅启动时出现一条告警是预期且无害的 —— 见「安装」下的说明。
开发
npm install && npm run setup:peer # 链接正在运行的宿主的 peers
npm test # node --test,真实本地 git 夹具 —— 不碰网络与远端
npm run lint设计记录:docs/DESIGN.md。
参考与致谢
- git worktree —— 这一切所构建的底层机制。
- task-weaver(
packages/workspaces/)—— 核心引擎(git 端口、合并队列、冲突现场保留)移植自它。 - dsh-plugin-subagents 与 dsh-dag-orchestrator —— 为组合而生的伙伴插件。
安全
见 SECURITY.md。
