dsh-worktree
DSH(DeepSeek Harness)的"fork 式"git worktree 插件:基于仓库创建独立的 git worktree(独立分支),并把新会话绑定到该 worktree 上打开。两个入口:
- 工作区(文件夹)⋯ 菜单「创建 Git worktree」:建 worktree + 空会话(复制副本图标);
- 会话 ⋯ 菜单「在 Worktree 中分叉」:建 worktree 并分叉该会话——新会话继承 全部对话历史,cwd 指向新 worktree(右上箭头图标,区别于"分叉会话"的分支图标)。
工作原理
[工作区 ⋯ 菜单] "创建 Git worktree" [会话 ⋯ 菜单] "在 Worktree 中分叉"
│ gitWorktree/create (basePath=工作区路径) │ gitWorktree/forkInto (sessionId)
▼ ▼
[Typert 网关] (/api 前缀,浏览器信任围栏保护)
│ 严格描述符 → GitWorktreeService
▼
[host 端 lib/index.js]
create: git -C <repo> worktree add -b <branch> <repo>.Worktree/<id>
forkInto: 同一 worktree 操作 + 复刻内置 session.fork 原子逻辑
(seed=截止最后完成回合、继承 preset/模型),但 meta.cwd = worktree 路径,
并 attach 到新 worktree 工作区 → 子会话继承全部对话且工作在独立 worktree
▼
[client 端复用现成 RPC]
create: workspace.create → session.create → sessions.open
forkInto: sessions.open(子会话)
菜单行的注入采用与 dsh-open-in-vscode 相同的双路径机制:优先注册进原生
sidebar.workspaces.row-menu 插槽(新版构建);当前构建无此插槽时,自动降级为
DOM 注入适配器(MutationObserver 定位打开的溢出菜单并挂载菜单行)——无需 patch
core 包。零 core 包改动:host 通过官方 Typert Remote 网关暴露 gitWorktree/*
端点,forkInto 只用公开服务(sessions/agents/workspaceRegistry/
agentPresets/agentDefaultModel + 公开导入 resolveSessionPreset /
installModelSelection / inspectApiRemoteSession)复刻 fork 语义。
安装
方式 A:本地目录(开发/自用)
# 在 dsh 的 web profile 目录里用 pnpm 安装(dsh plugin 即转发到 pnpm):
dsh plugin --profile web add file:D:/Documents/GitHub/dsh-plugins/dsh-worktree
# 或直接在 profile 目录执行:
cd "$env:APPDATA\io.github.hairyf.deepseek-harness-desktop\data\dsh\profiles\web"
pnpm add file:D:/Documents/GitHub/dsh-plugins/dsh-worktree
然后在 profiles/web/package.json 的 dsh.profile.bundles 追加
"dsh-worktree"(若 dsh plugin add 未自动追加),最后重启 dsh web 应用。
方式 B:GitHub 仓库(发布后)
dsh plugin --profile web add github:Jiazliang/dsh-worktree
dsh plugin add 会先执行 pnpm add,成功后自动把声明了 dsh.bundle 的包追加进
dsh.profile.bundles(无需手改 package.json),最后重启 dsh web 应用生效。
方式 C:npm(未发布)
dsh-worktree 这个 npm 包名已被其他项目占用,本插件暂不发布 npm;请使用
方式 A(本地目录)或方式 B(GitHub 仓库)安装。
发布
# 自检
pnpm check && pnpm verify
# 打包(dry-run 查看将发布的文件清单)
pnpm pack
# 发布到 npm(需 npm 账号)
npm publish
发布内容由 package.json 的 files 限定:lib/、cordis.patch.yml、
dsh.plugin.json、README.md、LICENSE。
验证方式
- 工作区 ⋯ 菜单:「创建 Git worktree」(复制副本图标)→ 建 worktree + 空会话;
- 会话 ⋯ 菜单:「在 Worktree 中分叉」(右上箭头图标)→ 建 worktree 并分叉会话, 新会话继承全部对话历史、cwd=worktree。
- worktree 落在仓库外层的
<仓库名>.Worktree/<id>容器里(与.git隔离, 主工作区零干扰);新工作区出现在侧栏,新会话自动打开(cwd = worktree,独立分支)。
自检(开发环境)
verify-host.mjs / verify-e2e.mjs / verify-fork.mjs 需要 DSH 的 peer 包
(@deepseek-ai/cordis、dsh-typert-registry 等)可解析。两种方式:
- 本机已有 DSH 安装:
pnpm link:deps(把zod与@deepseek-ai/*peer 包以 junction 链接到本仓库的node_modules,幂等;pnpm install剪除后可重跑); - 独立开发环境:
pnpm install后用 npm registry 安装对应 peer 版本。
node scripts/verify-git.mjs # git 逻辑(零依赖,随处可跑)
node scripts/verify-host.mjs # host 注册(真实 Cordis Context + TypertRegistry)
node scripts/verify-e2e.mjs # 端到端 create→list→remove(自建 scratch 仓库)
node scripts/verify-fork.mjs # forkInto 编排(seed 切割 / cwd=worktree / 继承 / attach)
安全说明
- RPC 走
/api前缀,与内置 RPC 同级,受浏览器信任围栏(DNS rebinding / 跨站 防御)保护;basePath取自会话cwd,host 侧经git rev-parse --show-toplevel解析仓库根,不执行用户提供的任意命令。 - worktree 目录固定放在仓库外层的
<repoRoot>.Worktree/<id>容器中(仓库根的同级 兄弟目录,带项目名前缀),不进入仓库、不触碰.git,主工作区 status 零噪音。 - 菜单行仅在有
cwd的工作区/会话显示;非仓库会报错并提示(详见浏览器控制台)。
排错
- host 插件已加载(
pluginInventory/list显示 active)但菜单行不出现 / bundle 404:package.json的exports必须包含"./package.json": "./package.json"——client-modules 用require.resolve("<pkg>/package.json")读包信息,exports 封锁会抛ERR_PACKAGE_PATH_NOT_EXPORTED并被静默跳过(本插件踩过这个坑)。 dsh.profile.bundles里的名字必须指向声明了dsh.bundle的包,否则启动直接 崩溃:profile bundle "..." declares no dsh.bundle in its package.json。- 插件集变更需重启 web 应用;host 代码与 client bundle 的改动同样以重启生效。
卸载
# 从 profiles/web/package.json 的 dsh.profile.bundles 移除 dsh-worktree
# 从 profiles/web 执行:
pnpm remove dsh-worktree
No comments yet. Be the first to write one.