dsh-worktree
开发工具 活跃维护

dsh-worktree

Jiazliang/dsh-worktree

轻量级类fork Git工作区管理工具,支持从现有工作区快速创建隔离副本,自动关联新会话,可选择性复制历史对话,无需手动切换分支即可并行推进多任务开发。

0
Stars 标星
0
Forks 分支
0
Watchers 关注
0
Open Issues
JavaScript
主要语言
MIT
开源协议
24 KB
仓库大小
1 个月前
最后推送
一键安装扩展 / 插件指令
dsh plugin --profile web add github:Jiazliang/dsh-worktree
git clone https://github.com/Jiazliang/dsh-worktree.git
git clone git@github.com:Jiazliang/dsh-worktree.git
README.md main

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