DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
W

@achasoft/dsh-worktree

Worktree

DeepSeek Harness Web Client 的 Git work树和分支:编辑器上方显示会话检出位置的分支和工作树行、分支和工作树切换,以及将工作树作为 harness 工作区采用

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:navid-kianfar/dsh-worktree#015f6c7884b9d7be82489e49898cf39521544342
README兼容性版本

说明

DeepSeek Harness Web Client 的 Git 工作树和分支:编辑器上方显示会话检出位置的分支和工作树行、分支和工作树切换,以及将工作树作为 harness 工作区采用

兼容性与来源证明

Worktree 以 @achasoft/dsh-worktree 发布,当前版本为 0.3.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/9/15

版本

0.3.0stable
2026/9/15
0.2.1stable
2026/9/15
0.2.0stable
2026/9/14
查看其余 1 个版本收起版本
0.1.0stable
2026/8/26

相关插件

正在加载相关插件…

最新版
0.3.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/9/15
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题
Worktree — DeepSeek Harness 插件(DSH Plugin)

相关插件

继续浏览 developer-tools 分类下经过校验的插件。

Web App@deepseek-ai/dsh-web-appdsh 浏览器界面捆绑包:位于 dsh-base 之上的 Web 补丁层,加上运行时粘合插件(提供前端 dist、Web 界面提示符、bash 运行时变量和 URL 行)Sdk Minimal@deepseek-ai/dsh-sdk-minimal独立的最小 SDK 配置包:JSON-RPC、一个 DeepSeek 适配器、持久化 Shell 和 JSONL 会话Sdk App@deepseek-ai/dsh-sdk-appdsh SDK 配置包:基于 dsh-base 提供 stdio JSON-RPC 服务和进程生命周期管理Subagent Codex@deepseek-ai/dsh-subagent-codex基于官方 app-server 协议的一次性 Codex 子代理提供程序

README

@achasoft/dsh-worktree

Git branches and worktrees for the DeepSeek Harness (dsh) Web Client. On the new-session screen it adds a project switcher and a branch pill with a worktree checkbox. Tick it and your first message runs in a fresh git worktree on a new branch named after that message. Once a session is running, a slim row above the composer shows the branch and worktree it is in, and lets you switch, create, rename, delete, lock, and prune them. git runs on the host. The browser never runs a git command itself.

New-session toolbar: project switcher, mode chip, and the branch pill with the worktree checkbox above the composer

Features

New-session toolbar

On a blank new chat, the row above the composer reads: project switcher, the harness's own mode chip, and a branch pill holding the branch and a worktree checkbox.

Project switcher. Opens a searchable list of your workspaces with Browse for folder… at the bottom. That entry opens the host's folder chooser, registers the folder as a workspace, and moves the new session there. If you have no workspaces yet, opening the switcher goes straight to the chooser.

Project picker dropdown with a search field, the workspace list, and "Browse for folder…"

Branch pill. Shows the branch the session will start on.

  • Worktree unticked. The session runs in the project folder, so picking a branch switches that folder to it. A switch that would overwrite uncommitted changes is refused, and git's message appears in the dropdown.
  • Worktree ticked. Nothing is created yet. The branch you pick is the base the new worktree will start from, and the project folder is left alone.

When a repository has more branches than maxBranches, the list says so. Typing a search then also asks the host, so a branch past the limit can still be found.

Branch picker dropdown under the pill, with a search field and local and remote branches

First send with the worktree ticked. When you press Enter or the send button, the plugin:

  1. locks the composer;
  2. asks the deployment's current model for a branch name based on your message. With no model, or if the call fails, it uses a slug of the message. branchPrefix is prepended, and a taken name gets a -2, -3, … suffix;
  3. runs git worktree add -b <name> from the chosen base branch, at the path worktreePathTemplate gives;
  4. registers the worktree as a workspace named after the branch, moves the draft and its attachments there, and sends it.

If you leave the session before the worktree is ready, or the move does not finish in time, the workspace, the worktree, and the new branch are removed again. Your message stays unsent in the composer, and you get a notice.

Pill states. Whenever a project is selected, the pill keeps its place in the row:

Pill readsMeaning
grey placeholderThe first reading has not arrived yet.
no git (disabled)The folder is not a git repository, git cannot run on the host, or showChip is off. The tooltip says which.
git error (disabled)The reading failed, for example on a timeout. The tooltip shows git's message, and the reading is retried with backoff.

Disabled "no git" pill on the new-session screen for a folder that is not a git repository

Branch and worktree row (active session)

After the first message, a row directly above the composer shows ⑂ branch ↑ahead ↓behind • and the current worktree's name with a count of worktrees. The dot means uncommitted changes. A + button next to it creates a new worktree. The row re-reads the repository every refreshIntervalMs. The popovers open upward.

The row is hidden in sessions whose folder is not a git repository, when git is unavailable, and when showChip is off.

Branch popover opened from the row above the composer, listing local branches with their tip commits, fetch and refresh buttons, and a search field

Worktree popover listing the repository's worktrees, with New worktree at the bottom

Branch popover. Local and remote-tracking branches, each with its tip commit, author, age, and ahead/behind counts, plus a search field.

  • Switch to a branch. When the worktree has uncommitted changes, a Carry uncommitted changes switch appears. It runs git switch --merge, which aborts on conflict. Without it, git refuses a switch that would overwrite changes.
  • Picking a remote branch creates the matching local branch that tracks it. If the local branch already exists, the plugin switches to it.
  • A branch already checked out in another worktree offers to open that worktree instead, because git will not check one branch out twice.
  • Create a branch from the search text, open a new worktree for a branch, or rename or delete a local branch.
  • Fetch and prune remotes runs git fetch --all --prune.

Worktree popover. Every worktree of the repository, marked main, current, detached, locked, or prunable.

  • Open a session here registers the worktree as a workspace and opens a session in it.
  • Show in file manager appears only when the host supports revealing a path.
  • Lock / Unlock and Remove… are available for linked worktrees. The main worktree cannot be locked or removed, and neither can the worktree the current session runs in.
  • Prune stale records runs git worktree prune.

New worktree dialog (the + button). Choose a new or existing branch and an optional start point. The directory is prefilled from worktreePathTemplate and can be edited. It must not exist, or must be an empty directory. Register as a workspace and Open a session after creating default to registerWorkspace and openSession.

Destructive actions.

  • A force-delete of an unmerged branch, or a force-remove of a worktree with uncommitted changes, needs the name typed to confirm while confirmDestructive is on.
  • git worktree remove deletes ignored files (a .env, a build directory) even without force. So the remove dialog lists them first and needs its own checkbox before removing them, whatever confirmDestructive is set to. The host refuses such a removal without that acknowledgement.
  • Remote branches are never deleted.
  • Removing a worktree does not unregister its workspace. Remove the workspace from the sidebar yourself.

Settings card

Settings → Plugins → Worktrees and branches shows whether git was found on the host, with its version, and edits the preferences. See Configuration.

Worktrees and branches settings card, expanded

Requirements

  • DeepSeek Harness 0.1.5-rc.2, with the web profile. This is the version the plugin is tested against. Node ^22.19 || >=24, as in engines.
  • git 2.23 or newer on the host process PATH, because the plugin uses git switch. With git 2.36 or newer, the plugin reads the worktree list in NUL-separated form and also reads the locked and prunable flags. With older git it reads the plain listing, which does not show those two flags.
  • pnpm on PATH, because dsh plugin runs pnpm.
  • Harness capabilities, all mounted by the base bundle:
    • @deepseek-ai/dsh-subprocess and @deepseek-ai/dsh-fs, required to run git. Without either, the row stays hidden, the pill reads no git, and the settings card names what is missing.
    • A directory picker (dsh-client-ui-directory-picker-native or -browse) for Browse for folder…. Without one, that entry reports that no chooser exists.
    • Optional: llm and agentDefaultModel for model-written branch names. Without them the name is a slug of the message.
    • Optional: the settings service. Without it, the values from cordis.patch.yml apply and the card cannot save changes.
  • OS: developed and tested on macOS. The code has no platform-specific git handling. Linux and Windows are not verified.

Install

dsh plugin --profile web add @achasoft/dsh-worktree
dsh web

dsh plugin --profile <name> … runs pnpm with the remaining arguments in $DSH_HOME/profiles/<name> (default ~/.dsh/profiles/web), creating the profile first if it does not exist. After pnpm succeeds, dsh adds every dependency whose package.json declares dsh.bundle to that profile's dsh.profile.bundles list. This package declares "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }, so it becomes a profile layer with no manual edit. Restart dsh web after installing.

To uninstall, remove the package. dsh also drops it from dsh.profile.bundles:

dsh plugin --profile web remove @achasoft/dsh-worktree

How cordis.patch.yml is applied

At boot, dsh builds the configuration from patch layers, in this order:

  1. Each bundle's cordis.patch.yml, in dsh.profile.bundles order. This package's file inserts two rows.
  2. The profile's own $DSH_HOME/profiles/<name>/cordis.patch.yml.
  3. $DSH_HOME/cordis.patch.yml, which applies to every profile.
  4. Any --patch <file> overlays.

A later layer overrides an earlier one by row id. The two rows this package inserts:

idnameRole
worktree@achasoft/dsh-worktree/hostHost service: git over RPC, and the worktree settings section.
worktree-ui@achasoft/dsh-worktreeBrowser half. It must be the bare package name, because the Web Client finds browser code by resolving <row name>/package.json.

To see the composed result:

dsh --profile web --dump-config

Configuration

Every key lives in the config of the worktree row. To override keys, add the row to your profile's cordis.patch.yml by id. Restate every key, because a patch replaces the row's whole config:

- id: worktree
  config:
    showChip: true
    worktreePathTemplate: '{repoParent}/{repo}-worktrees/{branch}'
    branchPrefix: 'feature/'
    registerWorkspace: true
    openSession: true
    includeRemoteBranches: true
    maxBranches: 200
    refreshIntervalMs: 15000
    gitTimeoutMs: 20000
    networkTimeoutMs: 120000
    maxOutputBytes: 1048576
    graceMs: 5000
    confirmDestructive: true

The host schema declares no defaults, and every key except branchPrefix is required. The defaults below are the values cordis.patch.yml ships. Values saved from the settings card are stored as a user layer over the patch value. The host reads settings on each request, so changes need no restart.

KeyDefaultCardWhat it does
showChiptrueyesShows the row above the composer and an enabled new-session pill. When off, the pill reads no git and the RPC endpoints and settings card stay available.
worktreePathTemplate{repoParent}/{repo}-worktrees/{branch}yesDirectory for a new worktree. See Path template.
branchPrefix''yesPrefix added to new branch names: first-send names, and branches created from the branch popover or the create dialog. Example: feature/.
registerWorkspacetrueyesDefault for Register as a workspace in the create dialog.
openSessiontrueyesDefault for Open a session after creating. Requires registerWorkspace.
includeRemoteBranchestrueyesLists remote-tracking branches next to local ones.
maxBranches200yesMost branches returned per reading (minimum 1). The list says when it was cut.
refreshIntervalMs15000yes, in secondsHow often the row re-reads. 0 means read only on explicit refresh.
gitTimeoutMs20000yes, in secondsTime limit for a local git command (minimum 1000).
networkTimeoutMs120000yes, in secondsTime limit for fetch (minimum 1000). Must not be less than gitTimeoutMs.
maxOutputBytes1048576noMemory cap for each captured git output stream (minimum 4096).
graceMs

The host refuses a configuration at load, and the card refuses to save it, when:

  • worktreePathTemplate is empty or contains neither {branch} nor {branchPath};
  • networkTimeoutMs is less than gitTimeoutMs;
  • openSession is true while registerWorkspace is false.

Path template

The template expands against the repository being acted on. A relative result resolves against {repoRoot}.

PlaceholderExpands to
{repoRoot}The repository's main worktree directory.
{repoParent}Its parent directory.
{repo}Its directory name.
{branch}The branch name with / replaced by -, so feature/login becomes one directory.
{branchPath}The branch name with slashes kept, so feature/login nests.

RPC and model-facing surface

The plugin registers no model tools, prompt content, or session events. The browser half calls one Typert Remote namespace, worktree, over the harness's own client connection:

EndpointPurpose
describeWhether git is available, its version, and the preferences the browser draws from.
overviewHEAD, dirty counts, branches, and worktrees for one workspace directory.
searchBranchesCase-insensitive branch-name search past maxBranches.
fetchgit fetch --all --prune --quiet.
checkout, createBranch, renameBranch, deleteBranchBranch changes.
suggestBranchNameBranch name from a prompt, written by the model or as a slug.
suggestPath, addWorktree, inspectWorktree, removeWorktree, lockWorktree, pruneWorktreesWorktree changes.

Every endpoint returns a result value with a failure code (no-git, not-a-repository, refused, timeout, …) instead of throwing. The root export @achasoft/dsh-worktree re-exports these types for other packages.

Security notes

  • git runs only on the host, through ctx.subprocess, with GIT_TERMINAL_PROMPT=0, GIT_PAGER=cat, and LC_ALL=C. The plugin registers no HTTP routes. All calls go through the harness's own client connection.
  • Opening a folder runs nothing the folder configures.
    • Every invocation passes -c core.fsmonitor=false.
    • Background readings (the status poll) also switch off every filter.<driver>.clean/process defined in the repository's local or per-worktree config, including include.path files. They also pass --no-optional-locks and --ignore-submodules=dirty.
    • Filters from your global or system config, such as git-lfs, keep working.
    • A repository whose filter driver name contains = cannot have that filter disabled on the command line, so it is not read automatically.
  • Browser input is checked before it reaches git.
    • Branch names must pass git's ref-name rules, and a leading - is refused.
    • Start points are verified with rev-parse --verify.
    • Worktree paths must appear in git's own worktree list.
    • -- ends the options wherever git's parser accepts it.
    • A new worktree's destination must be absent or an empty directory.
  • No uncommitted work is thrown away without a prompt. Checkouts never use --force. Force-delete and force-remove are separate, confirmed actions. Ignored files need an explicit acknowledgement that the host enforces.
  • Cleanup deletes only a branch that holds no work. When a first send is abandoned, the new branch is deleted only while its tip is still the commit it was created at. The host checks this with expectedTip.

Known limitations

  • The first send is intercepted in the composer. The harness has no pre-send hook for a plain prompt, because input triggers only handle drafts that start with /. A hidden element in the composer's tool row (conversation.input.left) listens, in the capture phase, for Enter and for clicks on the send button. It acts only while a worktree is ticked, the draft does not start with /, no trigger menu owns Enter, no IME composition is in progress, and the send button is enabled. A future change to the composer's DOM, such as the send button no longer being the card's last button, would need this updated.
  • The worktree is created on the first message, not when you tick the box, because its branch is named from that message.
  • The project folder's branch switch is refused on a dirty tree. The new-session pill never carries changes. Use the row's Carry uncommitted changes switch in a running session, or commit first.
  • Folders that are not repositories show a disabled no git pill on the new-session screen, and no row in a running session.
  • Shadowed seat. The new-session toolbar replaces the harness's workspace picker by registering conversation.hero.workspace at priority -1. The lowest priority renders, and the core picker is at 0. The core menu's Add workspace… entry is replaced by Browse for folder…. Uninstalling returns the core picker.
  • The row mirrors the shell's session phase. The composer dock is also drawn on the blank screen, so the row reproduces the conversation shell's phase rule (checked against @deepseek-ai/dsh-client-ui-conversation 0.1.5-rc.2) to decide when to show.
  • Branch names from a model use a model call (up to 32 output tokens, 20 s timeout) against the deployment's provider for each worktree created on first send.

Development

The dev dependencies are link: specifiers to a DeepSeek Harness source checkout at ../../deepseek-harness, relative to this directory. Clone the harness there before installing.

pnpm install
pnpm run typecheck
pnpm test              # checks generated/ against src/host, then runs vitest
pnpm run build         # tsc -p tsconfig.build.json, then tsdown -> lib/

generated/ holds the Typert RPC contract and is committed source. The harness's generator only runs inside a harness checkout, so scripts/emit-typert.mjs writes the contract in that generator's format. If you change src/host/types.ts or the @Remote methods in src/host/index.ts, update the spec in that script and regenerate:

pnpm run regen:typert  # rewrites generated/ and generated/.fingerprint
pnpm run check:typert  # the same check pnpm test runs first

To load your checkout into a local profile, build it, then add it by path. dsh resolves a relative path against the directory you run it from:

pnpm run build
dsh plugin --profile web add "$(pwd)"
dsh web

The profile loads the built lib/ output, not src/, so build before adding the checkout. After changing browser code, rebuild and reload the page. After changing anything under src/host/, or regenerating generated/, restart dsh web.

License

MIT

5000
no
Delay between TERM and KILL when a git command is stopped.
confirmDestructivetrueyesRequires typing the name before a force-delete or force-remove.