DeepSeek Harness Plugin Hub

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

探索

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

社区

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

相关链接

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

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

Git Flow — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
G

dsh-git-flow

Git Flow

DeepSeek Harness 的工作区 Git 分支切换、使用 AI 编写提交消息的提交编辑器以及推送功能

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

npx -y @deepseek-ai/dsh plugin --profile web add github:hunan36/dsh-git-flow#fdba659f5031603a380b1da36a24c1099dbb965b
README兼容性版本

兼容性与来源证明

Git Flow 以 dsh-git-flow 发布,当前版本为 0.3.0-rc.3。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

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

版本

0.3.0-rc.3prerelease
2026/9/26
查看其余 1 个版本收起版本
0.3.0-rc.2prerelease
2026/9/24

相关插件

正在加载相关插件…

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

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

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

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

认领这个 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

dsh-git-flow

English | 中文

A DeepSeek Harness workspace git plugin: a branch chip in the composer tool row. Open it to browse branches, switch branches, create one, and commit a checked subset of files — the commit message is written by the session's own model from the diff.

composer tool row:  [⑂ feature/login  3]  ← click
                      ├ Search branches
                      ├ Local branches · 2   ✓ feature/login
                      │                        main
                      ├ New branch…
                      ├ Commit…                (enabled while the tree is dirty)
                      └ Refresh status

Install

Two ways in; either one is enough.

From the plugin page (GUI)

Sidebar → Plugins → Add plugin, then put this in "Package or address":

https://github.com/hunan36/dsh-git-flow

Press Install and enable it afterwards ("Enable"). That path runs pnpm add <spec> in the profile serving the page (usually web) and writes this package into dsh.profile.bundles for you — you do neither by hand. The URL is accepted with or without the .git suffix.

Reload the page (⌘⇧R) afterwards so the browser fetches the new client bundle; if that profile does not have patchReload: live, restart dsh web once for the host side.

From the CLI (a dedicated profile is recommended)

# 1. Create a dedicated profile (leaves your existing web profile alone)
dsh --profile gitflow-web --from-default-profile web

# 2. Add the plugin — a git URL, or the absolute path of a local checkout
dsh plugin --profile gitflow-web add https://github.com/hunan36/dsh-git-flow
# dsh plugin --profile gitflow-web add "$PWD"

# 3. Enable it on the plugin page ("Enable"), or edit the bundle list directly:
#    dsh.profile.bundles += "dsh-git-flow"
#    The package declares dsh.bundle.patch, so enabling it mounts the GitFlow
#    service from the bundle's own cordis.patch.yml.

# 4. Boot
dsh --profile gitflow-web

The headless profile installs too, but it has no webServer: no /api/dsh-git-flow/* route is registered, the browser half does not exist there, and boot reports no error.

A machine without pnpm

dsh's plugin management — the plugin page's Install, and dsh plugin … — shells out to pnpm, and fails outright when there is none:

dsh: pnpm was not found; install pnpm and make it available on PATH.

Install one (Node ships npm):

npm install -g pnpm        # the latest 10.x
# or: corepack enable && corepack prepare pnpm@10 --activate

Do not let Corepack use its own default: after a bare corepack enable you get pnpm 8.15.7, which walks straight into the ERR_PNPM_ADDING_TO_ROOT failure below.

If you would rather not install pnpm at all, the plugin itself does not need it (its dependencies are empty):

  • Use Node's npm: cd ~/.dsh/profiles/<profile> && npm install https://github.com/hunan36/dsh-git-flow
  • Copy the directory: drop the whole dsh-git-flow folder (including lib/) into <profile>/node_modules/, for offline or fully manual setups

Both need one extra step: add dsh-git-flow to that profile's dsh.profile.bundles in its package.json, then restart dsh web. The plugin page and dsh plugin add do that for you; a manual install does not, and the package stays unloaded even though it sits in node_modules.

Point the plugin page at npm (a machine that only has npm)

The plugin page runs pnpm add <spec> by default, but the plugin manager's command is configurable — set it to npm in the profile's cordis.patch.yml and the page installs with npm:

# ~/.dsh/profiles/<profile>/cordis.patch.yml
- id: plugin-manager
  config:
    pnpmCommand: npm

Then use the plugin page exactly as usual (paste the address → Install → Enable). The CLI's dsh plugin … add does not honour this setting and still needs pnpm.

Three caveats:

  • This is an internal dsh setting and may move between versions; prefer installing pnpm when the machine allows it.
  • The arguments dsh passes are add <spec>, remove <name>, and view <spec> … --json, all of which npm accepts; but pnpm-specific semantics (-w, onlyBuiltDependencies, lockfiles) do not exist under npm, so do not mix both managers in one profile.
  • The command line shown in the UI and logs still reads pnpm add … (dsh builds that label literally). To tell which manager really ran, look for package-lock.json versus pnpm-lock.yaml in the profile directory.

Installation fails with ERR_PNPM_ADDING_TO_ROOT

A dsh profile directory is itself a pnpm workspace (pnpm-workspace.yaml with packages: [.]), and pnpm 8 treats pnpm add there as adding to a workspace root — which it refuses. When the profile has no packageManager field, Node's Corepack fills one in (commonly pnpm@8.15.7), and the install then dies on that check before it ever resolves this plugin, so the failure is not about this package.

Any one of these gets you through:

  1. Installing from the plugin page (GUI): that path runs pnpm add <spec> and cannot pass -w, so do step 2 first (write the .npmrc) and then press "Retry" in the dialog — the same command then succeeds under pnpm 8.

  2. Teach the profile to accept a root dependency, then install exactly as documented:

    echo 'ignore-workspace-root-check=true' >> ~/.dsh/profiles/gitflow-web/.npmrc
    
  3. From the CLI, pass -w through (dsh forwards extra arguments to pnpm):

    dsh plugin --profile gitflow-web add -w https://github.com/hunan36/dsh-git-flow.git
    
  4. Put the profile on pnpm 10 (the version this plugin is tested with): run corepack use pnpm@10 in the profile, or set the packageManager field Corepack added to pnpm@10.22.0.

Note that after the first failure Corepack has already written packageManager: pnpm@8.15.7+sha512… into that profile's package.json, so every later plugin operation there uses pnpm 8 — step 4 is the durable fix.

Requires Node ^22.19.0 || >=24.0.0 and pnpm 10; this repository pins it with packageManager: pnpm@10.22.0.

Configuration

Set in cordis.patch.yml:

KeyDefaultMeaning
timeoutMs15000Deadline for read-only and local git commands
pushTimeoutMs120000Deadline for git push, which waits on a remote
messageMaxDiffBytes65536Cap on the diff bytes handed to the model (truncated past it)
messageLanguageenDefault commit-message language, zh or en

The commit panel carries an English | 中文 switch beside "Draft message". It overrides messageLanguage for that call and remembers the choice in localStorage, so English stays the default until you pick otherwise.

Security boundaries

  • The browser sends only a sessionId. The host resolves the repository from that session's workspace, so a page can never name a directory for git to run in.
  • Arguments are always an array, never a shell string, with stdin: 'ignore' and GIT_TERMINAL_PROMPT=0, so a credential prompt can never hang a call.
  • push never passes --force or --force-with-lease, and only pushes the current branch's upstream (with --set-upstream <remote> HEAD:refs/heads/<branch> when it has none).
  • Commits stage only the files checked in the panel. An empty selection answers git/no-files-selected and never falls back to an implicit git add -A.
  • Switching branches on a dirty worktree fails by default (git/dirty-worktree). Only the user's second confirmation in the dialog sends --force.
  • Discarding runs only after the destructive action is picked in a confirmation dialog: tracked paths go back to HEAD with git restore --source=HEAD --staged --worktree, untracked paths are removed with git clean -fd (no -x, so ignored files stay), and a conflicted path is refused rather than guessed at.
  • workspaceRegistry is read lazily through ctx.get('workspaceRegistry') instead of being declared in static inject, so a profile without one (the shipped headless profile) still activates this entry rather than leaving a permanently pending plugin; every git call there answers git/not-a-repository.
  • A missing git, a non-repository workspace, a timeout, and every refusal travel as structured codes (git/not-installed, git/not-a-repository, git/timeout, …) that the UI renders as copy. Outside a repository — or without git — the chip renders nothing at all.

Layout

src/
├── index.ts       host entry (default-exports the GitFlow service)
├── service.ts     GitFlow: status / branches / checkout / createBranch / commit / discard / push / generateMessage
├── git.ts         GitRunner: subprocess + scrubbed env + timeout + porcelain v2 parsing
├── routes.ts      /api/dsh-git-flow/* (registered only where a webServer exists)
├── message.ts     commit message: ctx.llm.stream on the session's own provider/model, template fallback
├── contract.ts    host↔browser types only
└── client/
    ├── index.ts        slots.inject('conversation.input.left') + locale registration
    ├── BranchChip.tsx  container: status, menu, dialogs, toast
    ├── BranchMenu.tsx  the chip and its anchored menu
    ├── CommitDialog.tsx commit panel / new branch / forced-switch and discard confirmations
    ├── api.ts          fetch wrapper + error codes to copy
    ├── styles.ts       the few CSS rules the popover width and file-row ellipsis need
    └── locales.ts      zh/en dictionaries (en is typed against zh, so a missing key is a compile error)

Build

pnpm install
pnpm build       # tsc -> lib/types/**, tsdown -> lib/index.js + lib/client.js

lib/ is committed to the repository (it is not in .gitignore) and the package no longer carries a prepare script, so installing from the git URL needs no build, no dev dependencies, and no entry in pnpm's onlyBuiltDependencies allowlist:

  • pnpm 10.34+ blocks a git dependency's prepare (ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED), and the allowlist entry it demands is dsh-git-flow@<spec>#<commit sha> — a string that goes stale on every upstream commit;
  • shipping the build instead makes dsh plugin add <spec> take lib/ as-is: measured at 263 ms under pnpm 10.34.5.

After editing src/, run pnpm build and commit lib/ along with it, or everyone installing from git gets the previous build.

Artifact contract:

  • lib/index.js: Node ESM, imported directly by the cordis loader.
  • lib/client.js: a CJS factory wrapped as window.__ModuleLoader__.load({ id: "dsh-git-flow", factory: (require) => … }); react, react/jsx-runtime, and @deepseek-ai/dsh-client-ui-primitives stay external and come from the page's static module table.

Compatibility

Developed and verified against @deepseek-ai/dsh@0.1.6-alpha.2, with peer and dev dependencies pinned to it. dsh is still alpha, so contracts such as conversation.input.left, ctx.webServer.register, and ctx.slots.inject may drift between minor versions. After upgrading dsh, rebuild and confirm the first line of lib/client.js is still window.__ModuleLoader__.load({ id: "dsh-git-flow".

Known limits

  • An AI commit message needs one turn already sent in the session (the provider/model recorded in request/header). Without a route the panel answers git/no-route and tells you to send one message first; when the model fails or returns nothing usable, the chore: update N files template fills in and says so.
  • Messages default to English. The panel's language switch (remembered per browser) and the messageLanguage config are the only two inputs; the template fallback follows the same choice.
  • Remote branches appear only once refs/remotes/** exists locally (the plugin never fetches in the background); "Refresh status" makes no network call.
  • Conflicted files cannot be checked; resolve the conflict in the conversation first.
  • git switch --force discards all local changes, not just the conflicting ones — the confirmation copy says exactly that. To drop a single file's changes instead, use that file's Discard action in the commit panel.
  • Switching to a ref that exists nowhere fails inside git and is reported as git/failed with git's own text. Only stale UI state can reach that path, since the menu lists branches that exist.

Verification (0.1.6-alpha.2)

Measured on an isolated DSH_HOME with profile gitflow-web (dsh-git-flow appended to dsh.profile.bundles): the chip text equals git branch --show-current; the menu lists every local branch plus each remote-only one; search filters rows; switching moves both the chip and the worktree files; a dirty switch is refused and only confirms --force after a second dialog; an invalid branch name errors while a valid one is created and switched to; with a single file checked, the model returned a feat: … message and git log -1 --name-only showed only that file; commit-and-push made the branch appear in git ls-remote with its upstream set; a session whose workspace is not a repository renders no chip; the headless profile boots with no warning and no routes.