🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

工作区分支副本 Bainianzzz/dsh-fork-worktree

DeepSeek Harness
Bainianzzz17 天前有提交已提供中文文档扫描:含敏感能力

把工作区复制成独立 Git 分支目录

29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/15 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Bainianzzz/dsh-fork-worktree
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · dev
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 17 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件
查看扫描证据(共 71 处,展示前 23 条)
  • 读取本地文件
    impl.js:172
    const info = lstatSync(path);
  • 读取本地文件
    impl.js:205
    for (const entry of await readdir(root, { withFileTypes: true })) {
  • 读取本地文件
    impl.js:215
    if (existsSync(to)) return true;
  • 读取本地文件
    impl.js:237
    if (!existsSync(source)) return { kind: 'error', code: 'source-missing', text: `workspace directory does not exist: ${source}` };
  • 读取本地文件
    impl.js:238
    if (!statSync(source).isDirectory()) return { kind: 'error', code: 'source-not-directory', text: `workspace path is not a directory: ${source}` };
  • 读取本地文件
    impl.js:251
    if (existsSync(target)) return { kind: 'error', code: 'target-exists', text: `worktree target already exists: ${target}` };
  • 删除本地文件递归
    impl.js:374
    rmSync(source, { recursive: true, force: true });
  • 写入本地文件
    verify-host.mjs:22
    mkdirSync(root, { recursive: true });
  • 执行外部命令固定命令
    verify-host.mjs:24
    const git = (args, cwd) => execFileSync('git', args, { cwd, encoding: 'utf8' }).trim();
  • 写入本地文件
    verify-host.mjs:57
    mkdirSync(repo);
  • 写入本地文件
    verify-host.mjs:59
    writeFileSync(join(repo, 'README.md'), '# scratch\n');
  • 读取本地文件
    verify-host.mjs:66
    check('fork path exists', first.kind === 'success' && existsSync(join(first.path, 'README.md')));
  • 读取本地文件
    verify-host.mjs:67
    check('fork is a linked worktree', first.kind === 'success' && readFileSync(join(first.path, '.git'), 'utf8').startsWith('gitdir:'));
  • 写入本地文件
    verify-host.mjs:75
    mkdirSync(plain);
  • 写入本地文件
    verify-host.mjs:76
    writeFileSync(join(plain, 'notes.txt'), 'x\n');
  • 读取本地文件
    verify-host.mjs:84
    check('source became a repository', existsSync(join(plain, '.git')) && git(['rev-parse', '--show-toplevel'], plain) === plain);
  • 读取本地文件
    verify-host.mjs:86
    check('init fork carries the directory content', initialized.kind === 'success' && existsSync(join(initialized.path, 'notes.txt')));
  • 写入本地文件
    verify-host.mjs:91
    mkdirSync(empty);
  • 读取本地文件
    verify-host.mjs:182
    check('copy mode keeps tracked files at HEAD', readFileSync(join(copyFork.path, 'src', 'tracked.ts'), 'utf8') === 'HEAD\n');
  • 读取本地文件
    verify-host.mjs:183
    check('copy mode brings untracked files', readFileSync(join(copyFork.path, 'src', 'untracked.ts'), 'utf8') === 'UNTRACKED\n');
  • 删除本地文件递归
    verify-host.mjs:314
    rmSync(gone, { recursive: true, force: true });
  • 删除本地文件递归
    verify-host.mjs:319
    rmSync(unrelated, { recursive: true, force: true });
  • 删除本地文件递归
    verify-host.mjs:369
    rmSync(root, { recursive: true, force: true });
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DeepSeek Harness 插件:把工作区行 fork 成 git worktree,或删除工作区文件夹

README

由 DeepSeek 最新模型翻译生成
dsh-fork-worktree 给 dsh 侧边栏的工作区行加两个按钮(在 … 和 + 之间,fork 在左、垃圾桶在右): - fork:确认后基于该工作区所在的 git 仓库建一个新 worktree,并把 worktree 目录注册成新的 dsh 工作区(并在新工作区里开会话)。 - 垃圾桶:确认后删掉该工作区的目录,并移除它的登记。 两个按钮都不会在点击时直接动手,都必须先在弹窗里确认。 位置与实现 - 两个按钮都只在行 hover 时显示(和 + 一样)。 - dsh 的工作区行没有 slot 扩展点(…、+ 都是 ui-workspace 写死的行内 UI),所以按钮是通过 shell.overlay 里挂一个 React 组件、再用 createPortal portal 进行动区的(见 client.js 的 WorkspaceRowActions)。用 data-row-key="workspace:<id>" 找行、data-slot="sidebar.workspaces" 作为只监听侧边栏的 MutationObserver 根(不监听整帧,流式输出不会触发重扫)。
展开完整文档(README 剩余 1 节)
dsh-fork-worktree

给 dsh 侧边栏的工作区行加两个按钮(在 … 和 + 之间,fork 在左、垃圾桶在右):

- fork:确认后基于该工作区所在的 git 仓库建一个新 worktree,并把 worktree 目录注册成新的 dsh 工作区(并在新工作区里开会话)。
- 垃圾桶:确认后删掉该工作区的目录,并移除它的登记。

两个按钮都不会在点击时直接动手,都必须先在弹窗里确认。

位置与实现

- 两个按钮都只在行 hover 时显示(和 + 一样)。
- dsh 的工作区行没有 slot 扩展点(…、+ 都是 ui-workspace 写死的行内 UI),所以按钮是通过 shell.overlay 里挂一个 React 组件、再用 createPortal portal 进行动区的(见 client.js 的 WorkspaceRowActions)。用 data-row-key="workspace:<id>" 找行、data-slot="sidebar.workspaces" 作为只监听侧边栏的 MutationObserver 根(不监听整帧,流式输出不会触发重扫)。
- 图标取自 Lucide(ISC):fork 用 git-fork(v1.57.0),垃圾桶用 trash 的无竖线画法(v0.400.0)、描边 1.8 —— v1.57.0 里 trash 与 trash-2 的 path 相同,那两道内线在 16px 下挤成一块、看着比 fork 粗,所以取无竖线版本并把描边调到 1.8,两个图标视觉粗细一致(约 1.2px)。都按原样的 24 单位 viewBox、currentColor、round caps/joins 内联在 client.js 里(本 bundle 不引入图标包),显示尺寸 16px。
- 风险:dsh 改版若改了这两个 DOM 钩子,按钮会消失(不会报错);那时需要跟着改选择器。

fork 流程

1. 点 fork:只弹确认框。
2. 确认 → POST dsh-fork-worktree/fork {source, init:false}(Host 的 forkRoute):
- 是 git 仓库 → git worktree add -b wt/ <仓库名>-wt- HEAD,注册工作区。
- 不是 git 仓库 → 返回 not-a-git-repo,同一个弹窗切成"初始化"模式。
3. 初始化模式确认 → init:true:git init + 把目录当前内容提交成第一个提交(空目录则空提交),再建 worktree。
4. 成功 → ctx.workspaces.create({path})(幂等,把新工作区并进 Client 模型)→ ctx.uiWorkspace.startSession(id) 在新工作区打开会话 → toast 显示路径。

/fork-worktree [name] [--init] 命令是同一套逻辑的第二个入口,可在该工作区的会话里手敲。

垃圾桶流程与删除语义

1. 点垃圾桶:只弹确认框,写明将删除的确切路径(还会写明会话记录保留)。
2. 确认 → POST dsh-fork-worktree/remove {source, force:false}(Host 的 removeRoute → removeWorkspaceFolder):
- linked worktree(.git 是文件)→ 走 git worktree remove,仓库的 worktrees/ 元数据跟着走(不留脏数据)。
- 有未提交修改或未跟踪文件 → 返回 worktree-dirty,弹窗切成"强制删除"模式,再确认才 --force。
- 其他目录 → 直接 rm -rf。
- 删完移除工作区登记;即使这一步失败,2 秒后的扫描也会把登记收掉。
3. 护栏:拒绝删除 $HOME 和文件系统根;目录不存在/不是目录都返回明确错误码。
4. 删除故意没有命令入口:命令会默认取当前会话的工作区,删掉自己正在用的目录不该只是一条命令的距离。

worktree 命名

- 目录:与仓库根同级,<仓库名>-wt-;label 是 <name>(若给)或 6 位随机 hex。
- 分支:wt/,基于当前 HEAD。

工作区自动消失

Host 每 2 秒扫一次注册表(watchRemovedWorktrees):

- 目录存在且 .git 是文件(linked worktree)→ 记为跟踪对象。
- 被跟踪对象连续两次扫描都目录缺失 → 静默删除该工作区注册(不动文件和会话,不报错)。
- 进程重启后不丢:目录已消失、但名字是 -wt-<6位hex>,或同级还有同名仓库目录时,同样会被清掉。
- 不动普通目录、不动 bg-switcher--worktrees/xxx--worktree 这类别的命名。

开发迭代

改 Host 侧(impl.js)后,让这一行重新加载即可,不用重启 dsh:插件页把 fork-worktree 关掉再打开,或调 plugin_manager 的 set_plugin(target: include:fork-worktree,先 enabled:false 再 enabled:true)。

原理:ES 模块按解析后的 URL 缓存,所以 Loader 那一行导入的 index.js 是个极小且不再改动的壳,它的 apply 里用 ?load=<时间戳> 动态 import 真正的实现 impl.js——每次重新加载都拿到新副本。

client.js 改了要刷新页面(F5)才生效。bundle 是 link: 安装时,pnpm 层面不用重装。

node verify-host.mjs:不依赖 dsh 的 Host 侧验证(61 项),覆盖 worktree 创建/分支/初始化、两种删除(worktree / 普通目录)、dirty 拒绝与强删、路径护栏、两个路由的信任校验与 JSON 契约、以及自动清理的各分支。临时仓库建在系统临时目录并在结束时删除,不会污染本目录。

安装

dsh plugin add github:Bainianzzz/dsh-fork-worktree

或者用 GitHub Release 上的预构建 tarball:

dsh plugin add https://github.com/Bainianzzz/dsh-fork-worktree/releases/latest/download/dsh-fork-worktree.tgz

装好后,鼠标悬停在侧边栏的工作区行上,就会出现两个按钮。本插件只用 Node 内置模块,不需要构建授权。

文件

- index.js:包入口,也是 Loader 那一行导入的壳(name/inject/apply)。
- impl.js:Host 实现——createWorktreeFork、removeWorkspaceFolder、两个路由、/fork-worktree 命令、工作区清理扫描。
- client.js:浏览器侧——工作区行两个按钮(React portal)、四种弹窗、toast。
- cordis.patch.yml:bundle 的 patch,插入 id 为 fork-worktree 的这一行。
- verify-host.mjs:Host 侧离线验证脚本。
- 依赖:只用 Node 内置模块,不 import 任何 @deepseek-ai/ 包,所以 dependencies 与 peerDependencies 都是空的。
预览分享卡片长什么样 ↓Bainianzzz/dsh-fork-worktree
分享 · DeepSeek Harness Hub
Bainianzzz/dsh-fork-worktree

把工作区复制成独立 Git 分支目录

回到顶部