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

Git 工作树隔离 wloops/dsh-git-worktree

DeepSeek Harnessv0.11.0
wloops15 天前有提交已提供中文文档扫描:含敏感能力

让智能体在独立 Git Worktree 中完成任务,你看过修改后再决定是否保存。

45.4/100
综合分
20
GitHub 星标
510
npm 周下载
—/5
用户评分

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-git-worktree
npm 源 · dsh-git-worktree 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · market
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 15 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-git-worktree @ 0.11.0
✓Node 引擎要求 ^22.19.0 || >=24.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/31 02:18:37

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件
查看扫描证据(共 156 处,展示前 95 条)
  • 写入本地文件
    lib/index.js:70
    mkdirSync(stateDir, { recursive: true });
  • 写入本地文件
    lib/index.js:72
    mkdirSync(hooksPath, { recursive: true });
  • 读取本地文件
    lib/adapters/project-skills.js:20
    const stat = await lstat(path, { bigint: true });
  • 读取本地文件
    lib/adapters/project-skills.js:31
    const stat = await lstat(current);
  • 读取本地文件
    lib/adapters/project-skills.js:58
    const named = await lstat(path);
  • 读取本地文件
    lib/adapters/project-skills.js:75
    if ((await lstat(join(root, path))).isDirectory()) {
  • 读取本地文件
    lib/adapters/project-skills.js:76
    for (const name of await readdir(join(root, path)))
  • 读取本地文件
    lib/adapters/project-skills.js:98
    const stat = await lstat(path);
  • 写入本地文件
    lib/adapters/project-skills.js:221
    await mkdir(this.directory, { recursive: true });
  • 写入本地文件
    lib/adapters/project-skills.js:224
    await writeFile(manifestPath, JSON.stringify(manifest), { flag: 'wx', mode: 0o600 });
  • 删除本地文件
    lib/adapters/project-skills.js:232
    await unlink(path);
  • 写入本地文件
    lib/adapters/project-skills.js:245
    await writeFile(temporary, JSON.stringify(manifest), { flag: 'wx', mode: 0o600 });
  • 写入本地文件
    lib/adapters/project-skills.js:246
    await rename(temporary, manifestPath);
  • 删除本地文件
    lib/adapters/project-skills.js:340
    async forget(root) { await rm(this.file(root), { force: true }); }
  • 读取本地文件
    lib/adapters/project-skill-provider.js:17
    const canonical = await realpath(cwd);
  • 读取本地文件
    lib/adapters/project-skill-provider.js:26
    const rootStat = await lstat(root);
  • 读取本地文件
    lib/adapters/project-skill-provider.js:27
    if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || relative(root, await realpath(root)) !== '')
  • 读取本地文件
    lib/adapters/project-skill-provider.js:29
    const stat = await lstat(marker);
  • 读取本地文件
    lib/adapters/project-skill-provider.js:32
    const text = (await readFile(marker, 'utf8')).trim();
  • 读取本地文件
    lib/adapters/project-skill-provider.js:33
    if (!text.startsWith('gitdir: ') || await realpath(resolve(root, text.slice(8))) !== await realpath(record.gitDir))
  • 读取本地文件
    lib/adapters/git.js:184
    await lstat(join(directory, '.git'));
  • 读取本地文件
    lib/adapters/git.js:239
    root: await realpath(resolve(topLevel.stdout)),
  • 读取本地文件
    lib/adapters/git.js:240
    commonDir: await realpath(resolve(commonDir)),
  • 读取本地文件
    lib/adapters/git.js:241
    gitDir: await realpath(resolve(gitDir)),
  • 读取本地文件
    lib/adapters/git.js:254
    return realpath(resolve(topLevel.stdout));
  • 读取本地文件
    lib/adapters/git.js:272
    const gitRoot = await realpath(await runSessionGitChecked(localRoot, ['rev-parse', '--show-toplevel']));
  • 读取本地文件
    lib/adapters/files.js:14
    if (!existsSync(path))
  • 读取本地文件
    lib/adapters/files.js:16
    const stat = await lstat(path);
  • 读取本地文件
    lib/adapters/files.js:22
    for (const entry of await readdir(path))
  • 读取本地文件
    lib/adapters/files.js:27
    if (!existsSync(path))
  • 读取本地文件
    lib/adapters/files.js:29
    const stat = lstatSync(path);
  • 读取本地文件
    lib/adapters/files.js:32
    for (const entry of readdirSync(path)) {
  • 删除本地文件
    lib/adapters/files.js:36
    rmdirSync(path);
  • 写入本地文件
    lib/adapters/files.js:63
    await rename(path, quarantinePath);
  • 写入本地文件
    lib/adapters/files.js:69
    await rename(quarantinePath, path);
  • 删除本地文件
    lib/adapters/files.js:82
    await rm(path, {
  • 写入本地文件
    lib/adapters/files.js:95
    ensureDirectory: (path) => mkdirSync(path, { recursive: true }),
  • 读取本地文件
    lib/adapters/registry.js:392
    if (!existsSync(this.path))
  • 写入本地文件
    lib/adapters/registry.js:397
    mkdirSync(dirname(this.path), { recursive: true });
  • 执行外部命令固定命令
    lib/session-checkout-apply.js:24
    const child = spawn('git', [
  • 写入本地文件
    lib/session-checkout-apply.js:219
    await mkdir(mergePath, { recursive: true });
  • 写入本地文件
    lib/session-checkout-apply.js:220
    await mkdir(hooksPath, { recursive: true });
  • 写入本地文件
    lib/session-checkout-apply.js:282
    await mkdir(mergePath, { recursive: true });
  • 写入本地文件
    lib/session-checkout-apply.js:283
    await mkdir(hooksPath, { recursive: true });
  • 读取本地文件
    lib/session-checkout-apply.js:496
    return (await readFile(markerPath, 'utf8')).trim() === commitOid;
  • 删除本地文件
    lib/session-checkout-apply.js:506
    await unlink(path);
  • 写入本地文件
    lib/session-checkout-apply.js:588
    await writeFile(indexLockMarker, `${commitOid}\n`, { flag: 'wx' });
  • 写入本地文件
    lib/session-checkout-apply.js:592
    await copyFile(finalIndexPath, adjacentIndex);
  • 删除本地文件
    lib/session-checkout-apply.js:708
    await unlink(indexLockPath);
  • 删除本地文件
    lib/session-checkout-apply.js:711
    await unlink(indexLockMarker);
  • 读取本地文件
    lib/session-checkout-apply.js:1152
    const originalIndexBytes = await readFile(realIndexPath);
  • 读取本地文件
    lib/session-checkout-apply.js:1185
    const intendedIndexBytes = await readFile(finalIndexPath);
  • 读取本地文件
    lib/session-checkout-apply.js:1207
    const finalIndexBytes = await readFile(realIndexPath);
  • 读取本地文件
    lib/session-checkout-apply.js:1231
    const committedIndexBytes = await readFile(realIndexPath);
  • 读取本地文件
    lib/session-checkout-apply.js:1271
    const backupBytes = await readFile(backupIndex);
  • 删除本地文件递归
    lib/session-checkout-apply.js:1518
    await rm(path, { recursive: true, force: true, maxRetries: 2 });
  • 执行外部命令固定命令
    lib/console-host/review-diff.js:17
    const child = spawn('git', ['-c', 'core.quotePath=false', ...(process.platform === 'win32' ? ['-c', 'core.longpaths=true'] : []), ...args], {
  • 写入本地文件
    lib/console-host/review-diff.js:105
    await mkdir(objectDirectory, { recursive: true });
  • 删除本地文件递归
    lib/console-host/review-diff.js:198
    await rm(tempRoot, { recursive: true, force: true });
  • 读取本地文件
    lib/adapters/project-skill-io.js:7
    const stat = await lstat(root, { bigint: true });
  • 写入本地文件
    lib/adapters/project-skill-io.js:21
    await mkdir(current).catch(error => { if (error.code !== 'EEXIST')
  • 读取本地文件
    lib/adapters/project-skill-io.js:25
    const stat = await lstat(current);
  • 读取本地文件
    lib/adapters/project-skill-io.js:46
    const pathStat = await lstat(join(root, file.path), { bigint: true });
  • 读取本地文件
    lib/adapters/project-skill-io.js:62
    const named = await lstat(join(root, file.path), { bigint: true });
  • 读取本地文件
    lib/adapters/project-skill-snapshot.js:12
    const root = await realpath(boundary.root);
  • 读取本地文件
    lib/adapters/project-skill-snapshot.js:13
    if (await realpath(source) !== root)
  • 读取本地文件
    lib/adapters/project-skill-snapshot.js:15
    const metadata = await Promise.all(boundary.metadata.map(path => realpath(path)));
  • 读取本地文件
    lib/adapters/project-skill-snapshot.js:40
    stat = await lstat(path);
  • 读取本地文件
    lib/adapters/project-skill-snapshot.js:66
    const target = await readlink(current);
  • 读取本地文件
    lib/adapters/project-skill-snapshot.js:104
    links.push({ path: logical, target: await readlink(physical) });
  • 读取本地文件
    lib/adapters/worktree-creation.js:27
    const commonDir = await realpath(await checked(localRoot, ['rev-parse', '--path-format=absolute', '--git-common-dir']));
  • 读取本地文件
    lib/adapters/worktree-creation.js:28
    const parent = await realpath(dirname(target));
  • 读取本地文件
    lib/adapters/worktree-creation.js:36
    originalMetadata = (await readdir(join(commonDir, 'worktrees'))).sort();
  • 写入本地文件
    lib/adapters/worktree-creation.js:42
    await mkdir(target);
  • 读取本地文件
    lib/adapters/worktree-creation.js:50
    const gitDir = await realpath(await checked(target, ['rev-parse', '--absolute-git-dir']));
  • 读取本地文件
    lib/adapters/worktree-creation.js:74
    evidence = { ...evidence, indexFingerprint: createHash('sha256').update(await readFile(join(gitDir, 'index'))).digest('hex') };
  • 读取本地文件
    lib/adapters/worktree-creation.js:90
    metadata = (await readdir(join(evidence.commonDir, 'worktrees'))).sort();
  • 删除本地文件
    lib/adapters/worktree-creation.js:102
    await rmdir(target);
  • 读取本地文件
    lib/adapters/initial-commit.js:16
    const stat = await lstat(path, { bigint: true });
  • 读取本地文件
    lib/adapters/initial-commit.js:23
    return (await readFile(join(gitDir, 'index'))).toString('base64');
  • 读取本地文件
    lib/adapters/initial-commit.js:37
    const entries = await readdir(snapshot.root);
  • 读取本地文件
    lib/adapters/initial-commit.js:47
    head: (await readFile(join(snapshot.gitDir, 'HEAD'))).toString('base64'),
  • 删除本地文件
    lib/adapters/initial-commit.js:106
    await unlink(lock.path);
  • 写入本地文件
    lib/adapters/safe-file.js:27
    renameSync(source, target);
  • 读取本地文件
    lib/adapters/safe-file.js:48
    if (!skipBackup && existsSync(filePath)) {
  • 写入本地文件
    lib/adapters/safe-file.js:50
    copyFileSync(filePath, bakPath);
  • 写入本地文件
    lib/adapters/safe-file.js:57
    writeFileSync(tmpPath, JSON.stringify(data, null, 2), 'utf-8');
  • 写入本地文件
    lib/adapters/safe-file.js:64
    writeFileSync(tmpPath, content, 'utf-8');
  • 读取本地文件
    lib/adapters/safe-file.js:75
    if (existsSync(filePath)) {
  • 读取本地文件
    lib/adapters/safe-file.js:77
    const raw = readFileSync(filePath, 'utf-8');
  • 读取本地文件
    lib/adapters/safe-file.js:87
    if (existsSync(tmpPath)) {
  • 读取本地文件
    lib/adapters/safe-file.js:89
    const raw = readFileSync(tmpPath, 'utf-8');
  • 删除本地文件
    lib/adapters/safe-file.js:103
    unlinkSync(tmpPath);
  • 读取本地文件
    lib/adapters/safe-file.js:108
    if (existsSync(bakPath)) {
  • 读取本地文件
    lib/host-compat.js:19
    const agent = JSON.parse(readFileSync(require.resolve('@deepseek-ai/dsh-agent/package.json'), 'utf8'));
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

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

依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/cordis-plugin-include@deepseek-ai/cordis-plugin-loader@deepseek-ai/dsh-agent@deepseek-ai/dsh-api-gateway@deepseek-ai/dsh-api-remote-access@deepseek-ai/dsh-api-session-controller@deepseek-ai/dsh-api-workspace-controller@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-modules
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

2 张 · 点击查看大图

功能亮点

  • 任务会话相互隔离
  • 本地预览可回退
  • 交付需人工确认

DeepSeek Harness 的 Git worktree 会话目标:任务会话相互隔离,本地预览可回退,交付需人工确认,支持恢复和同会话迭代。

v0.11.02026-10-18
· v0.11.0 — DSH 0.2.1-rc.2 基线适配与验收体验修复 本版将 DSH 基线从 0.2.0-rc.2 精确切换到 0.2.1-rc.2,修复新版 Cordis/Loader 下的 Provider 生命周期,取消提交信息 500 字符限制,并精简验收冲突展示。本版完整包含 tag v0.10.1 的全部变更;v0.10.1 有 Git tag 与 GitHub Release 但从未发布到 npm。 · 主要更新 · DSH peers/devDependencies 精确锁定 0.2.1-rc.2(Cordis 4.0.5、loader 1.0.6、include 1.0.10、schemastery 3.18.5);Workspace 版本/SHA 门禁与 Fork mandatory seam 对齐新源码,保留 allowMigration、agentPreset 与官方草稿初始化;新派生不复用于 0.2.0 Host,历史 alpha/next 别名保持。 · 修复 Cordis 4.0.5 / Loader 1.0.6 下插件 Provider 生命周期:显式释放 marker、等待禁用 fiber 真正结束、以公开 entry.init() 替换已销毁的官方 fiber、按身份撤回失败/禁用的 replacement fiber;保留非阻塞启动、超时/在途保护与根卸载语义。 · 提交信息不再截断为 500 字符:前端、RPC、Host 与 checkpoint 全链路保留完整正文,统一非空与 NUL 校验,保持身份与幂等门禁。 · 验收冲突展示精简:摘要与操作统一为顶部布局,冲突提示独立紧凑,冲突文件列表移入验收详情并复用展开;冲突时隐藏不可用的预览按钮。 · 兼容与迁移 DSH peers 从 0.2.0-rc.2 切换到 0.2.1-rc.2(精确版本);0.1.x Host 继续使用 0.9.x 插件线,其兼容记录不变。无 Worktree registry、Review 或 Recovery 数据迁移。minimumReleaseAgeExclude 覆盖 0.2.1-rc.2 精确锁定依赖(延续既有精确锁定豁免惯例);受 minimumReleaseAge 供应链防护影响的环境请显式指定 dsh-git-worktree@0.11.0 安装。 · 验证与发布状态 精确提交 9708a61e17518460027bfe3bc8be6da6962ccf98 在 clean 检出通过 typecheck、43 个测试文件(607 项通过、1 项跳过)、Workspace Sidebar 版本/SHA 门禁、build、clean-tree publish gate 与 tarball dry-run;GitHub Actions CI 在同一提交通过(run 39113832512)。0.2.1-rc.2 适配此前在新鲜隔离环境完成源码级验证(详见 验证报告);真实浏览器、AI 对话、桌面端与 Windows 全流程仍未验收。 npm 状态:已发布 dsh-git-worktree@0.11.0,latest 指向 0.11.0,Registry gitHead 为 9708a61e17518460027bfe3bc8be6da6962ccf98,下载 tarball 摘要与 Registry 记录一致。v0.10.1 从未进入 npm;只需安装 0.11.0。
v0.10.12026-10-07
· v0.10.1 — 托管侧栏操作恢复、状态展示收敛与验收详情折叠 本版恢复托管会话被过度屏蔽的官方侧边栏操作,收敛行内状态展示,并让验收详情的长列表默认折叠;是无数据迁移的补丁版。 · 主要更新 · 恢复托管会话行的官方重命名、归档与归档恢复:pin、rename、archive 在 alpha、next、modern 三版 Workspace Client 派生中保持原生菜单与回调,guard 改为保存在 uiWorkspace 实例上,避免 Cordis Context 派生丢失引用;Fork 等可能破坏托管归属的操作继续被阻止,安全操作不再依赖拓扑加载完成。 · 托管会话处于 working 状态时仅隐藏行内 Worktree 文字标签;Worktree 图标、官方运行指示器、完整悬停状态及其他状态标签保留。 · 验收详情的修改文件与验证记录超过 5 项时默认折叠为前 5 项,可独立展开全部/收起;重新打开详情或切换验收(checkout/review/revision)时重置折叠状态,附中英文文案与无障碍属性。 · README 与使用指南的安装/排错示例更新到 0.10.0,环境要求按 Host 版本分线,并说明 minimumReleaseAge 供应链防护下的精确版本安装。 · 兼容与迁移 无 Worktree registry、Review 或 Recovery 数据迁移。peer 仍精确锁定 DSH 0.2.0-rc.2:0.2.x Host 使用本版,0.1.x Host 继续使用 0.9.x 插件线,其兼容记录见 兼容性说明。刚发布的版本可能被 Profile 的 minimumReleaseAge 供应链防护静默回退到旧版,安装时请显式指定 dsh-git-worktree@0.10.1。 · 验证与发布状态 精确提交 cf57c3784da9e689f3b0850378d2ed74a02dec53 在 clean Local 通过 typecheck、42 个测试文件(592 项通过、1 项跳过)、Workspace Sidebar 版本/SHA 门禁、build、clean-tree publish gate 与 tarball dry-run;GitHub Actions CI 在同一提交通过。本机未安装 dsh CLI,未完成 npm 包在 scratch Harness Profile 的真实安装与浏览器端到端 smoke。 npm 状态(2026-10-18 更新):0.10.1 最终从未发布到 npm(发布时 npm 认证持续失败)。本版全部内容已完整包含在 dsh-git-worktree@0.11.0,请直接安装 0.11.0 或更高版本,不要等待 0.10.1。
v0.10.02026-09-30
· v0.10.0 — 适配 DSH 0.2.0-rc.2 0.10.0 将插件整体切换到 DSH 0.2.0-rc.2 运行时:修复桌面端插件安装因旧版 peerDependencies 声明被拒绝的问题,并解决新版 Host 上的三个阻断性缺陷(Web 启动死锁、strict codec 世代判定、派生 seam 失配)。 · 主要更新 · DSH Host/Client 依赖、插件兼容声明和发布版本切换到 0.2.0-rc.2;支持现代 Workspace Browser、懒加载 Typert codec 和 Skill locator,保留旧 codec 字段的运行时兼容。 · 修复 0.2.0 Web 启动死锁:入口 inject 过滤 remote.directoryPicker(其提供者条目等待 uiWorkspace,形成三方循环等待,插件卡 loading、12 条目 pending);目录选择器改在托管上下文中延迟解析。 · sidebarTopologyResponseSchema 补充 modern flavor,修复 strict codec 拒绝 Host 世代判定。 · 对齐 0.2.0 Workspace 派生 seam(protectedManagedWorkspace 定义、托管行 drag/new-session 抑制),修复渲染抛 ReferenceError 导致整个会话列表变为空白死格;托管行徽章图标改用 IconBranchOutlineRegular。新增 WT_DEBUG_SEAMS=1 派生 seam 审计开关。 · 宿主端插件启动不再被 Workspace Provider 选举阻塞:Provider 生命周期非阻塞执行,Loader 禁用/恢复操作限时、防重入,避免与新版 cordis-plugin-loader 并发启动互等。 · 兼容与迁移 · 插件 peers 精确锁定 0.2.0-rc.2:0.1.x Host 请继续使用 0.9.x 插件线,旧组合的支持记录不受影响。 · 0.1.x 各代(rc.1 / alpha.2 / 0.1.7-rc.2)的兼容记录见 docs/COMPATIBILITY.md,不因本版本撤销。 · 升级前建议备份环境;测试新版本请使用隔离 DSH_HOME。 · 验证摘要 · typecheck 通过;40 个测试文件 552 passed / 1 skipped;check:publish:release(clean tree)与 CI 通过。 · 真实 Chromium 端到端:隔离 DSH_HOME + 源码 Host(dsh-v0.2.0-rc.2)完成安装、Web 启动、会话创建、Worktree 开关、预会话创建与托管行「进行中」标记。 · 未验收:API Key 下真实 AI 对话、Review/预览/交付/回滚/恢复/清理全流程、Windows、npm 安装版 Host 与桌面端。 · npm 发布状态 · 本 Release 与 npm dsh-git-worktree@0.10.0 同步发布。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-git-worktree 让智能体在独立 Git Worktree 中完成任务,你看过修改后再决定是否保存。 dsh-git-worktree 是 DeepSeek Harness 的 Git Worktree 插件。它为隔离任务创建独立的 Worktree(工作目录),智能体的代码修改和测试在其中进行;只有你发起预览或确认保存时,插件才会把任务改动写回当前项目。任务完成后,你可以先预览结果,再选择保存、退回修改或放弃。 这套 Git Worktree 工作方式最初来自基于 Pi Agent Runtime 的开源桌面 coding 工作台 Domi,本插件是针对 DeepSeek Harness 独立适配的版本,可以单独安装和使用。 English · 完整使用指南 · 架构说明 为什么使用它? 让智能体直接修改当前项目时,它的改动可能与你尚未提交的内容混在一起;同时运行多个任务时,也更容易互相影响。使用本插件后: - 每个任务都在自己的 Git Worktree(独立工作目录)中修改和测试; - 多个隔离任务可以同时开发,各自使用独立工作目录;同一项目一次只允许一个任务进入验收写回流程; - 智能体完成后,你可以先把修改临时显示在当前项目中查看; - 只有确认后才会保存本轮修改,遇到冲突时不会自动覆盖你的内容。
展开完整文档(README 剩余 1 节)
dsh-git-worktree

让智能体在独立 Git Worktree 中完成任务,你看过修改后再决定是否保存。

dsh-git-worktree 是 DeepSeek Harness 的 Git Worktree 插件。它为隔离任务创建独立的 Worktree(工作目录),智能体的代码修改和测试在其中进行;只有你发起预览或确认保存时,插件才会把任务改动写回当前项目。任务完成后,你可以先预览结果,再选择保存、退回修改或放弃。

这套 Git Worktree 工作方式最初来自基于 Pi Agent Runtime 的开源桌面 coding 工作台 Domi,本插件是针对 DeepSeek Harness 独立适配的版本,可以单独安装和使用。

English · 完整使用指南 · 架构说明

为什么使用它?

让智能体直接修改当前项目时,它的改动可能与你尚未提交的内容混在一起;同时运行多个任务时,也更容易互相影响。使用本插件后:

- 每个任务都在自己的 Git Worktree(独立工作目录)中修改和测试;
- 多个隔离任务可以同时开发,各自使用独立工作目录;同一项目一次只允许一个任务进入验收写回流程;
- 智能体完成后,你可以先把修改临时显示在当前项目中查看;
- 只有确认后才会保存本轮修改,遇到冲突时不会自动覆盖你的内容。

核心能力

- Git Worktree 隔离:每个任务都有独立的工作目录和智能体对话。
- 多个 Worktree 并行:可以同时开发多个任务;为了避免混入修改,同一项目每次只验收一个任务。
- 提交前预览:先在当前项目中查看真实效果,不会立即创建 Git 提交。
- 不满意可以退回:撤回本次预览,继续让智能体修改,不影响其他本地改动。
- 只保存本轮任务:确认后只提交这个任务的修改,不把无关内容一起带入。
- 长任务可分阶段:先保存当前阶段的进度,再继续开发;最终仍合并为一次交付。
- 出错时保护现场:检测到分支变化、内容冲突或中断时停止操作,保留现场供你处理。
- 集中查看任务:同一项目的当前及历史 Worktree 会按 Host 导航归属聚合到侧边栏,归属不明确时保守保留原位置。
- 验收详情集中查看:从验收条打开只读详情,查看文件列表、验证记录与版本信息,不必翻找聊天工具记录。
- 空仓库安全起步:无提交仓库可在明确确认后创建不包含用户文件的空首次提交,再建立隔离 Worktree。
- 携带项目 Skills:首次及下一轮 Worktree 创建时一次性携带 .dsh/skills、.agents/skills 和 .claude/skills,辅助文件与 Git 交付隔离。
- 原对话继续下一轮:任务交付后,无需新开对话即可继续下一项修改。

当前版本管理单个项目中的 Git Worktree,暂不提供跨项目的全局管理界面。

工作流

flowchart LR
A[当前项目] -->|创建隔离任务| B[独立 Git Worktree]
B --> C[Agent 修改并测试]
C --> D[查看验收结果]
D -->|预览修改| E[在当前项目中查看效果]
E -->|确认并保存| F[创建本轮提交]
F --> G[在原对话继续下一轮]

D -.->|保存阶段进度| H[继续开发] E -.->|撤回本次预览| I[返回修改] D -.->|跳过预览| F

怎么选?

| 目标 | 操作 |
| 先在当前项目中查看效果 | 预览修改 |
| 预览结果没有问题 | 确认并保存 |
| 任务很长,先固定当前进度 | 保存阶段并继续 |
| 还要让智能体改代码 | 继续修改或撤回本次预览 |
| 不需要先查看效果 | 跳过预览并保存 |

详细的操作、恢复场景和命令见完整使用指南。

快速开始

环境要求

- Node.js ^22.19.0 || >=24.0.0
- DeepSeek Harness Web Client
- Git Workspace
- 与 Harness 版本匹配的插件版本,见下表

版本选择

| DeepSeek Harness | 插件版本 |
| 0.2.1-rc.2 | 0.11.0 |
| 0.2.0-rc.2 | 0.10.0 |
| 0.1.x | 请参考 0.9.x 的历史兼容记录,不代表所有 0.1.x 版本均已验证 |

插件版本与 Harness 版本需要匹配,不建议在旧版 Harness 上直接安装最新版插件。

0.11.0 对应的 DSH 0.2.1-rc.2 适配已通过发布前源码兼容检查,但尚未完成该组合的浏览器、真实 AI 对话、桌面端和 Windows 全流程验收。详细验证范围见兼容性说明与验证报告;旧组合的验证记录仍保留,不自动转为新组合的验收证据。

安装

以下命令适用于 DSH 0.2.1-rc.2,通过 dsh 的 Web Profile 安装:

dsh plugin --profile web add dsh-git-worktree@0.11.0

如果使用其他 Harness 版本,请先按上表选择匹配的插件版本。

安装后打开 Git Workspace,在新建 Session 时启用 Worktree;已有 Local Session 也可以让 Agent 调用 worktree_create 创建独立的隔离 Session。

第一次使用建议先完成一次「创建 → 预览修改 → 确认并保存 → 清理 Worktree」的完整流程。

升级与排错

- 升级 Harness 前,请先备份数据并检查版本兼容性;旧版数据迁移要求见升级与回退。
- 出现 Failed to load plugins 时,先确认插件与 Harness 版本匹配,再按使用指南排查。
- 刚发布的版本可能被 Harness 的供应链防护(minimumReleaseAge)暂时跳过而回退旧版;可显式指定匹配的精确版本,或待防护窗口过后重试。

Git 源安装方式、pnpm build approval 及其他排错步骤见安装与排错。

界面预览

项目聚合与任务状态

Managed Worktree 聚合到原 Local 项目

准备验收

Agent 完成任务并准备预览修改

完整操作步骤见完整使用指南。

安全边界

每次把任务修改写回当前项目之前,插件都会重新确认任务版本、项目位置和文件状态仍与验收时一致。如果你切换了分支、修改发生冲突,或上一次操作意外中断,插件会停止写入并保留现场,而不是猜测后继续覆盖。

Worktree 隔离主要用于避免任务之间误改文件,不是用来运行不受信任代码的系统沙箱。

更详细的状态检查与恢复规则见:

- Worktree Console 架构
- Session Target 迁移说明

当前限制

- 只有归属关系明确的任务才会聚合到原项目;无法确认时仍保留原位置,避免任务被隐藏。
- 隔离任务可以重命名和归档,暂不支持从任务对话直接复制出新任务(Fork)。
- 子 Agent 与父任务使用同一个工作目录,不会再为每个子 Agent 创建新的 Worktree。
- 已保存的阶段记录暂不支持编辑、删除、调整顺序或回退到任意阶段。
- Domi 中更完整的跨项目管理、直接修复当前项目、依赖复用和协作交接能力不在本插件当前范围内。

本地开发

pnpm install
pnpm run typecheck
pnpm test
pnpm run build
pnpm run check:publish

端到端启动:

pnpm run dev:dsh

更多开发命令见完整使用指南,发布前检查见发布清单。

文档

- 完整使用指南
- Worktree Console 架构
- Session Target 迁移说明
- UI 开发说明
- 发布清单
- 变更记录

许可证

MIT

界面语言

插件跟随 DSH 的中英文选择,不提供独立语言开关。请在 DSH 中明确选择 English,以便界面、工具和 /worktree 消息都使用英文;自动浏览器语言尚未写入 DSH 偏好时,工具和命令会回退中文。详见 语言传递与文案贡献说明。
预览分享卡片长什么样 ↓wloops/dsh-git-worktree
分享 · DeepSeek Harness Hub
wloops/dsh-git-worktree

让智能体在独立 Git Worktree 中完成任务,你看过修改后再决定是否保存。

回到顶部