dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Worktree Space:将一个可包含多个 Git 仓库的工作区任务放进独立的任务空间目录——参与的每个仓库使用同一个任务分支各开一个 worktree;空间自动注册为 DSH 工作区,会话直接在其中开工,多个任务并行推进、互不干扰。收尾时可合并回各仓库目标分支、移除 worktree,并把 Git 未跟踪的文件归档到指定目录;结束任务时可选把未提交的变更和合并冲突交给 agent 处理。
简体中文 · English · 更新日志
Worktree Space:一任务一空间,工作多路并行。把一个涉及一个或多个 Git 仓库的工作任务放进独立的任务空间目录——参与的每个仓库都在同一个任务分支上各开一个 worktree;任务空间自动注册为 DSH 工作区,会话直接在任务空间里开工;多个任务各建一个任务空间并行推进、互不干扰。建空间时可以定下这个任务要不要部署验收,勾了它,一条通过的冒烟记录就是收尾合并的闸门。任务结束时把任务分支合并回目标分支、移除 worktree,并把空间里遗留的文档归档到指定目录;也可以把未处理的提交和合并冲突交给一个 agent 会话处理。
两条路各有侧重,可以只看其中一条:在面板上手动点完全程(使用),或者让 Agent 用工具自动编排(高级用法)。完整步骤、异常流程与错误码都在 《Worktree Space 使用指南》。
📺 视频介绍:Worktree Space 插件介绍(B 站)
[!IMPORTANT]
Beta(实验性):把提交和合并冲突交给 agent 处理的功能处于实验性验证阶段,行为可能继续调整;它**默认
显示**,如需隐藏这两个入口,将插件配置里的「交由 agent 解决冲突入口」设为「隐藏」(见实验性一节);
本文档其余部分描述的是不借助 agent 的标准流程。遇到问题请在
GitHub Issues 里反馈。
网页端,从命令行安装:
dsh plugin --profile web add dsh-worktree-space卸载:dsh plugin --profile web remove dsh-worktree-space;更新时先卸载再重新安装。
桌面端在插件管理页里操作:侧边栏 → 插件,在「插件包名」填 dsh-worktree-space,点「安装」; 卸载时在插件列表里点开 Worktree Space,进「插件详情」页,右上方点「卸载」按钮。
每个参与的仓库都会得到一份位于 ` 的 worktree(前缀默认 task/`),起点可以是各仓库 当前的 HEAD,也可以指定某个在所有选中仓库里都存在的分支或提交。
勾上后会多出一个 部署脚本 输入框(留空则用 工作区/.worktree-space/deploy/deploy.sh)。 它之所以在建的时候就问,是因为交付策略只在创建时落一次,事后没有入口能加、能改:没勾等于定了 「这个任务不做验收」,之后也不会有任何东西再提起这件事。反过来,勾了却找不到可用的入口脚本时 创建会被直接拒绝,而不是留一个永远部署不起来的任务空间。 其余收尾时的决定 —— 合到哪条分支、要不要删分支、冲突怎么办、遗留文档怎么处理 —— 都不在这里预定, 留给结束任务那一刻当场决定。
.worktree-space/deploy/ 会被复制进来,入口脚本提供 up(起环境、写验收地址)与 smoke(跑冒烟、把结果写进 .state.json)。 每个任务的环境身份互不相同,任务之间不会互相顶掉。合并之前有一道闸门:/.state.json 里没有一条 result: "pass" 的 lastSmoke,合并就被拒;面板会问「冒烟还没过,仍要结束吗?」, 这份豁免只有人能给。
/,同时开一个会话,工作目录就是这个任务空间 —— 在任务空间里改代码,不会动到源码检出。
任务行下面就是它的部署卡片。
那一列,任务已经有的不会重复列出;也可以直接填一个仓库目录,它会注册成工作区,因此同样进入 Git 仓库视图。 新仓库在任务现有分支上开 worktree,起点默认各仓库当前的 HEAD,也可指定分支或提交。新仓库可以位于不同目录 甚至不同磁盘;只有在把提交交给 agent 时才可能需要批准提权(见使用指南)。本版本不支持从任务里移除仓库。
空间里的文档归档到选定的目录,最后注销这个工作区;任务空间里还有会话在干活时先拒绝。合并往哪儿做、 冲突怎么办,见「结束 Worktree Space」。
⋯ 菜单里 —— 前者只对包含代码仓库的工作区显示,后者只对确属任务空间的目录显示,点开的就是同一个对话框。
勾了「部署到 Docker」的任务另有一层前提:这台机器上要有可用的容器引擎,见部署验收。
术语:Worktree Space 容器(下称容器)=插件存放任务空间的专用目录,也就是容器根目录
worktree-space/。下文每段第一次提到容器时写全称,同段之后用简称。容器根是容器根目录的简称,指同一个目录:既指那个目录本身(区域),也指设置项里要填的路径(路径)。
~/workspace/ 根工作空间:项目都挂在这一层,也存放 Worktree Space 容器根目录
├── repo-x/ 项目 x 的主工作区(本身就是仓库)
├── project1/ 项目 1 的主工作区(下面若干仓库)
│ ├── repo-a/
│ └── repo-b/
├── deep-path/project2/ 项目 2 的主工作区,目录位置埋得更深
│ ├── repo-c/
│ └── repo-d/
└── worktree-space/ 容器根目录:插件专用区
├── repo-x/ 项目层,名字就是源工作区目录名
│ └── task-x/ 任务空间 —— 同时是会话的工作目录
│ ├── .worktree-space/ 插件专属目录:插件自己的东西全在这里
│ │ ├── worktree-space.json 任务的记录:分支、起点、项目、仓库、部署策略与创建时间
│ │ ├── worktree-space.md 由上面的记录渲染出来,给人读的分支、起点与约定
│ │ └── deploy/ 部署根:源码根 .worktree-space/deploy/ 的副本,.state.json 在这里
│ └── repo-x/ 位于 <分支前缀>task-x 的 worktree
├── project1/
│ ├── hotfix/
│ │ ├── repo-a/ 都以 <分支前缀>hotfix 开 worktree
│ │ └── repo-b/
│ └── task-a/
│ ├── repo-a/
│ └── repo-b/
├── project2/ 目录位置埋得深不影响它落在同一个容器里
│ └── task-b/
│ ├── repo-c/
│ └── repo-d/
├── archived-docs/ 归档根(默认):非 Git 产物收在这里
│ └── project1/ 按项目归档
│ └── hotfix-20260926-020933/ 「任务名-YYYYMMDD-HHMMSS」,每个任务一层
├── README.md 第一次使用时由插件写入:这里是 Worktree 专用区
└── worktree-space-log.jsonl 操作日志:插件发的每条 git 命令、每个错误与警告
~/my-archive/ 归档根:可以在插件设置改成指定的目录
└── project2/ 结构一样:项目一层,任务名加时间戳一层
└── task-b-20260926-020933/Worktree Space 容器根推荐落在根工作空间的下一层(~/workspace/worktree-space),放在哪儿只看路径上盘根下面的 第一个目录:所以 ~/workspace/project1 和 ~/workspace/deep-path/project2 推荐的是同一个 容器,项目各自埋多深都不影响。创建时仍可指定其它路径,但容器根与源码根必须互不包裹。
项目名就是源工作区目录名,插件自动分层,无需填写:同一个 Worktree Space 容器里跑多个项目时,各项目下同名的任务 (都叫 hotfix)因此各占一层,不会挤在一起。源工作区本身就是仓库时(工作区目录 = ~/workspace/repo-x), 项目层与仓库层同名,得到 repo-x/task-x/repo-x —— 这处重复是有意接受的:布局深度恒定为三层,插件与 客户端都不需要额外信息就知道哪一层是哪一层。
Worktree Space 容器根是插件的专用区:第一次在这底下建任务空间时,插件会写一份 README.md 说明这里是 Worktree 专用区、 不要直接 git init 或 clone(已经有了就不覆盖)。反过来说,容器根本身要已经是 Git 仓库(下面有 .git), 创建会被拒绝,且一个目录都不会建出来。
归档根底下再分两层:/-/。归档结构因此与 Worktree Space 容器结构同形,一个项目的归档收在自己 那一层里;默认档就在容器根下,整块只多出 archived-docs 这一个目录和操作日志那个文件(见操作日志)。删掉 worktree 不会删除对应的 Git 分支;结束任务会先把分支合并回去,再删 worktree。
>=22.19.0PATH 上>=0.2.0-rc.1 <0.3.0-0,即 0.2.x(下界自 0.2.0-rc.1 起,不含 0.3.0 线的预发布)五个官方版本逐个实测通过:0.2.0-rc.1、0.2.0-rc.2、0.2.1-rc.1、0.2.1-rc.2、0.2.1-rc.3, 每个版本都用该版本自己的 DSH CLI 在一次性 profile 里跑通了安装、启动、卸载、回滚。这套验证覆盖的是 命令行与网页端的路径;桌面端(Electron)只做了人工安装可用性确认,未纳入脚本矩阵。逐条记录见 docs/store-evidence.md。
DSH 会强制校验清单里 peerDependencies 声明的 DSH 版本范围:运行时的版本不满足,就在安装前或启动时 拒绝加载,并给出 dsh plugin allow-version 的精确豁免命令。engines.dsh 之类的字段只是声明,不会阻止加载。 实测范围之外的版本一律按未知处理,不拿宽泛范围冒充证据;遇到版本相关的问题请到 Issues 反馈。
本插件在运行时会读写文件、并调用 git;这两类权限就是它的功能本身,无法裁剪为零。运行期依赖都由 DSH profile 提供,不随插件分发 —— 安装本插件不会引入新的运行期第三方依赖,也不连接任何外部服务、不上报遥测。
权限一览:
权限 · 范围 文件读取 · 所选工作区目录(广度优先扫描,跳过 node_modules、dist、build、vendor 与隐藏目录,.worktrees 除外);任务空间与 Worktree Space 容器根下的记录文件;各 worktree 的 .git 标记文件;结束任务时为判断合并是否仍留冲突而读回变更文件的内容 文件写入 · 只写任务空间与 Worktree Space 容器根下的文件,以及配置选定的归档目录(见配置),结束时删除的是插件自己创建的 worktree 与文档;合并时另在系统临时目录里建一份临时检出,用完即删。不写源码仓库检出里的文件,也不写 DSH 数据目录 命令执行 · 只调用 git(git -C ,固定参数、不经 shell,全部走同一处 runGit);部署勾了时才另跑任务自己的入口脚本(up / smoke)。`add` 与 `commit` 不在其中:插件不代写提交,未提交的改动会让该仓库停下(见下表);交给 agent 的提交由宿主里的那个会话自己执行 操作日志 · 容器根下的 worktree-space-log.jsonl,默认开启:改动仓库状态的 git 命令、任何失败的 git 命令、每个操作的结论、每个错误与警告(带错误码)。可在插件设置里关掉,关掉不影响已有文件。不含任何文件内容,URL 里的凭据写入前抹掉;不发送到任何地方,不离开这台机器 网络 · 无:插件自身不发任何 HTTP 请求,也不执行任何 git push;它发出的 git 子命令全是本地操作 凭据 · 不读取、不保存、不转发;插件不接触密钥 全局资源 · 不装全局包、不起常驻进程或服务、不写系统目录
逐条说明(读什么、写什么、执行哪些子命令、失败时怎么办)见 PERMISSIONS.md; 一次性 Profile 的安装、启动、卸载与回滚验收证据见 docs/store-evidence.md。
失败边界(绝不静默):
情形 · 行为 扫描目录数超过上限 · 不再抛错丢掉全部结果:停在上限处并提示哪些更深的仓库没看到,请提高上限或换一个更具体的工作区 任一 git 命令失败 · 抛出 git failed (exit N): ,把 Git 自己的诊断原样带出 结束任务时任务空间里还有会话在干活 · 拒绝整次收尾并点名那几个会话;先让它们停下来或结束它们 结束任务时某仓库还有未提交的改动 · 停下该仓库(force 才丢弃):uncommitted work is waiting in ; commit it before the task can be finished;插件不代写提交,其余仓库继续,结果里逐条报出 合并已解决但没有提交 · the merge in is resolved but not committed,现场原样保留 解决后的文件里仍有冲突标记 · the resolved merge still has conflict markers in ,原样保留,不替任何一方取舍 试合并撞上冲突 · 不自动 merge --abort,保留合并现场(mergeSite 与 conflictedFiles),待解决并提交后可继续 真合并撞上期间的新提交 · 试合并通过后,真合并时目标分支出现新提交,插件撤销本次合并(merge --abort,分支恢复原状)并原样带出 Git 的诊断;worktree 与任务分支保留,再次点「继续结束任务」会重新试合并 部署验收没通过就想合并 · 拒绝合并并说明缺什么(up 还是 smoke);冒烟通过后直接重试即可 worktree 删除失败 · 报 failed to remove the worktree (uncommitted changes? force it deliberately),保留该 worktree 并报告,可用 git worktree prune 清理 任务目录非空 · 保留目录与工作区注册,不强行删除 无法确认的事实 · 在文档里写「未知」,不把「没有搜到」推断成「不访问」
本节是面板手动流程的简述:从配置、创建、干活、部署验收到结束任务,全程在界面上点完, 不需要「队长 / 队员」或工具调用那一套。每一步的完整说明、会遇到的异常与被拒之后怎么办, 见 《Worktree Space 使用指南》。 另一条路 —— 让一个 Agent 用 wts_worktree_space 把整条链自动跑完 —— 见 高级用法:让 Agent 全自动编排。
在界面里改(推荐):侧边栏 →「插件」→ Worktree Space →「插件详情」页的配置区,和其它插件的配置在同一处, 保存后立即生效,无需重启。也可以直接改配置文件:DSH 数据目录下 profiles//cordis.patch.yml 里这个插件的 config: 区块,改完重启 DSH 生效。
设置 · 取值 · 默认 · 说明 面板入口(「新会话」下方) · 显示 / 隐藏 · 隐藏 · 侧边栏面板列表里那一行,整页打开管理页面(页面自带左侧导航和「返回会话」);默认隐藏 侧边栏底部快捷入口 · 显示 / 隐藏 · 显示 · 侧边栏底部那个快捷入口,以对话框打开同一个管理页面 交由 agent 解决冲突入口 · 显示 / 隐藏 · 显示 · 结束任务对话框里「交由 agent 提交」「交由 agent 解决冲突」两个实验性入口;隐藏时走标准流程:自己提交、自己解决冲突,再点继续结束任务 交由 agent 处理冲突和提交的会话使用完全权限 · 关 / 开 · 关 · 打开后,这两个会话开在任务空间上并立即置为「完全权限」(danger-full-access);代价是该会话此后可以写到这台机器上 DSH 进程能写的任何位置,不再逐次询问。只影响之后开起的会话,结束任务对话框里可以就地切换。 操作日志 · 开 / 关 · 开 · 容器根下 worktree-space-log.jsonl 的开关。关掉只是不再写新记录,磁盘上已有的日志原样保留 扫描深度 · 1–5 层 · 3 层 · 从工作区目录(第 0 层)往下找 Git 仓库的层级数 最大遍历目录数 · 500 / 1000 / 2000 / 3000 / 5000 / 10000 · 2000 · 一次扫描最多读取的目录数;超了会停下来并提示哪些没看到 工作区仓库扫描忽略目录 · 任意目录名列表 · 内置 25 个 · 扫描永远不会进入这些名字的目录。插件自带 25 个:各语言的依赖与编译输出目录(node_modules、target、__pycache__、Pods 等),加上插件自己的任务容器名 worktree-space、dsh-worktree-space。可以添加自己的,也可以把内置的放回来 —— 放回内置项需要二次确认,因为代价落在下一次扫描上。名字不区分大小写;点右侧「编辑」打开对话框,可搜索、增删,保存后才写入配置 默认分支前缀 · 任意文本 · task/ · 新建任务空间时默认用的前缀;在新建对话框里改动并勾选「设为默认分支前缀」,点创建时一并写回这里 Worktree Space 容器根目录 · 默认 / 指定目录 · 默认 · 新建任务空间默认放哪。推荐用默认:它按下面的规则从源码根推导,落在根工作空间的下一层,因此同一根工作区下的所有项目——无论各自埋得多深——都会落进同一个容器。若改用指定目录,而它与仓库目录没有公共祖先,agent 处理提交与冲突的会话需要手动提权 指定 Worktree Space 容器根目录 · 任意路径 · 留空 · 只在「指定目录」这一档生效;留空则按推荐规则推导。新建对话框里改动容器根并勾选「设为默认 Worktree Space 容器根目录」,点创建时把这两项一并写回 归档文档位置 · 跟随容器根 / 指定目录 · 跟随容器根 · 遗留文档存到哪个根目录下;两档都在该根目录下再建一层 /-,时间戳是归档那一刻的本地时间,精确到秒。默认档收在容器根自己的 archived-docs 里,与任务空间建在哪一层无关 指定归档目录 · 任意路径 · 留空 · 只在「指定目录」这一档生效;留空则收在容器根的 archived-docs 里
扫描覆盖全部工作区;按广度优先逐层进行,每层最多同时读 8 个目录。任何一层只要发现 .git 目录就认定是 仓库(git 的链接 worktree 里 .git 是文件,不重复计入);node_modules、dist、build、vendor 等目录 和隐藏目录会跳过(.worktrees 除外)。
术语:源码根=交给插件的工作区目录:它自己是一个 Git 仓库,或者它作为顶层目录装着若干 Git 仓库。
四个入口都能到这里:会话输入框旁的插件图标、管理页面里工作区或仓库行的 新建 Worktree Space、 工作区列表里的 ⋯ 菜单。对话框从上到下:
全选 / 清空 和「已选择 N / M 个仓库」。至少要选一个。
它同时是任务空间的目录名和分支后缀。不合法时直接说出违反了哪一条。
task/)。改成与当前默认不同的值时,下面出现设为默认分支前缀 —— 勾选后,点「创建并打开会话」时把这次的值写回插件设置。
worktree-space),通常无需修改;改动时同样出现 设为默认…,勾选后把这次的路径写回设置。容器根自身是 Git 仓库会被拒绝。
工作区/.worktree-space/deploy/deploy.sh。这一格定的是「合并要不要冒烟这道闸门」, 只在创建时这一回落一次,之后没有入口能补。
选中的仓库里都存在,缺一个就被拒。
如果任务空间已经建好、但工作区注册失败,对话框说明原因,并提供重新注册的入口;注册之后它就是一个正常的 任务空间,可以按「结束任务」正常收掉。注册之外的步骤失败时,建出来的那部分会被回滚掉 —— 目录、 worktree 与分支一起,不会留半个任务在那儿。