← Back to home@cherrchen

dsh-plugin-git

DSH Git 仓库服务与 Client UI 插件,依赖 Details Host;DeepSeek Harness Desktop 预装。 / DSH Git repository service and client UI; requires Details Host; pre-installed in DeepSeek Harness Desktop.

Stars
0
Language
TypeScript
Created
Aug 23, 2026
Updated
Sep 14, 2026
GitHub repo

Introduction


description: "Portable Git repository operations and Client UI for DeepSeek Harness Desktop and standard DSH Web profiles." kind: "package-bundle"

dsh-plugin-git

English | 中文

Summary

Standard DSH/Cordis Git plugin with one portable Host service, one Client bundle, and optional Desktop enhancement. The package runs unchanged in DeepSeek Harness Desktop and in a standard DSH Web host; the npm scope @dsh-electron/ identifies the publisher, not a runtime requirement.

Requires the upstream right sidebar. This package targets DeepSeek Harness ≥ v0.1.5-rc.2, whose Client UI ships the right sidebar (@deepseek-ai/dsh-client-ui-sidebar-right). Git registers three sidebar tab types through the standard two-stage path and navigates through ctx.sidebarRight; without the right sidebar the Client half cannot load. The third-party Details Host plugin is deprecated and no longer depended on.

DeepSeek Harness Desktop pre-installs this plugin and mirrors this repository with git subtree. Users may disable Git from the Plugins settings; the right sidebar is an upstream built-in.

Table of Contents

DSH compatibility

This repo targets DeepSeek Harness v0.1.5-rc.2.

Installation

The package is published to npm as @dsh-electron/dsh-plugin-git (current 0.2.1, MIT, with build provenance). It is still experimental development: the API and versioning remain pre-1.0 and may change between minor releases.

DeepSeek Harness Desktop — Git is pre-installed and enabled by default. Disable it from Settings → Plugins when you do not need repository UI.

DSH Web — the right sidebar ships with DeepSeek Harness ≥ v0.1.5-rc.2, so Git alone is enough. The shortest path is two commands:

dsh plugin --profile web add @dsh-electron/dsh-plugin-git
dsh --profile web

dsh plugin forwards to pnpm inside the profile directory: it installs the package and activates the bundled cordis.patch.yml layer that mounts the plugin. Four install sources are supported, shown here with the web profile:

SourceCommandNotes
npm registry (recommended)dsh plugin --profile web add @dsh-electron/dsh-plugin-gitPrebuilt artifact; no build authorization
tarballdsh plugin --profile web add ./dsh-electron-dsh-plugin-git-<version>.tgzPrebuilt offline package; no build authorization
local pathdsh plugin --profile web add /path/to/dsh-plugin-gitpnpm links the checkout; for development
GitHub / gitdsh plugin --profile web add github:cherrchen/dsh-plugin-gitFetches sources and builds them on install through prepare; needs allowBuilds, pin a tag

Whichever source you use, the Git client requires the host to already provide the ctx.sidebarRight and ctx.sidebarRightTabs services at load time; DeepSeek Harness ≥ v0.1.5-rc.2 provides both.

From the npm registry (recommended)

dsh plugin --profile web add @dsh-electron/dsh-plugin-git

The registry holds the prebuilt artifact, so no package code runs on your machine at install time.

From a tarball

pnpm pack --pack-destination dist
dsh plugin --profile web add ./dist/dsh-electron-dsh-plugin-git-0.2.1.tgz

pnpm pack produces that single tarball, and every tag's GitHub Release carries the same one — for 0.2.1, https://github.com/cherrchen/dsh-plugin-git/releases/download/v0.2.1/dsh-electron-dsh-plugin-git-0.2.1.tgz. It is prebuilt as well, which makes it the form to use for an offline or air-gapped profile.

From GitHub

dsh plugin --profile web add github:cherrchen/dsh-plugin-git

A git install fetches sources, not built artifacts, so the package's own prepare script builds the published entry points on your machine: pnpm run build emits the declarations with tsc and then bundles both faces with tsdown, using only this package's standalone tsconfigs, so no sibling checkout is assumed. pnpm ≥ 10 refuses to run that script until it is explicitly allowed, so the first add fails with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED. Copy the exact key pnpm prints into the profile's pnpm-workspace.yaml — for a git-hosted dependency that key is the package name plus the resolved git spec and commit, and a bare package name does not match it:

allowBuilds:
  # the key pnpm printed
  '@dsh-electron/dsh-plugin-git@git+<host>/<path>#<commit>': true

then run the add again. Moving the pin moves the commit, so the key moves with it. Treat that allowance as permission for the package to execute code on your machine at install time, outside any sandbox the agent runs under. Pin a tag so a later push cannot silently change what runs:

dsh plugin --profile web add github:cherrchen/dsh-plugin-git#v0.2.1

From a local checkout (development)

git clone https://github.com/cherrchen/dsh-plugin-git.git
cd dsh-plugin-git
pnpm install
pnpm build        # writes lib/, which Git ignores but the install reads
dsh plugin --profile web add "$PWD"

pnpm links the checkout, so a later pnpm build is picked up without reinstalling.

Note: if your DSH is a source checkout rather than a global install, dsh is not on PATH — replace dsh with pnpm dsh in every command above, for example pnpm dsh plugin --profile web add ….

Pairing with the upstream right sidebar

Git joins the tab-type system through the upstream right sidebar's standard two-stage registration. The Client manifest declares the service dependency only:

{
  "dsh": {
    "client": {
      "inject": [
        "@deepseek-ai/dsh-client-ui-sidebar-right"
      ]
    }
  }
}

Dynamic client plugins may not import runtime values from another plugin package — only import type — so the type references erase completely from the bundle and no external entry is needed.

Stage one — ctx.sidebarRightTabs.register(definition) registers three tab types: git.changes and git.graph are page types (opened by kind, one tab per pane) that each contribute one guide entry (Changes order: 10, Graph order: 11), replacing the old Details launcher cards on the guide page; git.diff is a resource type with pattern dsh-resource://git/diff/**, a canOpen that validates the address decodes, and a title taken from the decoded file name.

Stage two — each type's body component injects the sidebar.right.pane.tab seat under the definition's id; bodies read { address, params, revision } from useTabInfo().tab.navigation.

Unified navigation converges on ctx.sidebarRight:

ctx.sidebarRight.openTab('git.changes')
ctx.sidebarRight.openResource('dsh-resource://git/diff/<encodeURIComponent(path)>/<staged|worktree>', { params: { path, staged } })
ctx.sidebarRight.openTab('git.graph')

A diff tab's identity is its exact address: re-opening the same file and comparison side reveals the existing tab and bumps its revision (the body refetches on it), while a staged and a working-tree diff of one file are two addresses and sit side by side. Changes and Graph dedupe per pane by kind, owned by the sidebar. The changed-files indicator, the branch chip, and the guide entries open git.changes; clicking a file row opens the git.diff for that path.

Parameter typing augments the sidebar:

declare module '@deepseek-ai/dsh-client-ui-sidebar-right/client' {
  interface SidebarRightResourceParamsMap {
    git: GitDiffPayload
  }
}

Repository controls (refresh / reveal) render inside each Git frame through a local component. The tab bar, the guide page, docking geometry, and panel width are owned by the right sidebar (built on ui-dockkit), not this package.

User experience

In the conversation composer, Git contributes a branch selector and a changed-files indicator on the left of the input area. Clicking either control opens git.changes as a right-sidebar tab. Creating a branch opens a shared conversation Modal; after git init with no commits (unborn HEAD), the menu shows the symbolic default branch as disabled, explains that the first commit is required, and disables create until HEAD exists.

The Changes surface shows the current branch beside refresh, then a single-line auto-growing commit message field with a wand Generate control and a split Commit button (Commit, Amend, Commit & Push, Commit & Sync). Staged, unstaged, and untracked paths follow as icon-action sections: plus or minus toggles the index, undo discards after a two-step confirm, and a porcelain letter badges the row. Clicking a path opens the matching diff. The Diff surface shows refresh in the top-right and renders one file's working-tree or staged diff per tab. The Graph surface shows Auto / All / First parent beside refresh, then the commit history as a canvas-drawn lane graph — one continuous coordinate space, so rails and merge edges never break at row boundaries — with subject, author, date, hash, and HEAD/branch/tag decoration badges, paged incrementally with a load-more control. When the host exposes an LLM runtime, a staged diff is sent to the session model — or to a custom provider/model configured under Settings → Plugins → Plugin configuration → Git — and the streamed suggestion is written into the editable input. That same card also edits the generation system message. Generation never stages, commits, or pushes anything. On Electron, optional Desktop enhancement adds reveal-in-folder and open-path actions when the Desktop provider is present.

Composition

The Host plugin requires ctx.subprocess, provides ctx.git, and starts Git with an executable plus separate argv values. It never invokes a shell. When a DSH Web Host is present, an optional Connection child registers the loopback /git RPC channel.

The Client plugin requires Connection, locale, renderer, conversation UI, primitives, session UI, and the upstream right sidebar (ctx.sidebarRight / ctx.sidebarRightTabs, type-only imports). Business components receive a controller and openDetails() through slot injection and do not access Cordis context.

When ctx.settingsScope is present, the Client also registers a card into Settings → Plugins → Plugin configuration under the git-commit-message namespace. The card is absent in hosts that do not serve that namespace.

The Client main fiber does not require desktop. A child ctx.inject(['desktop'], ...) fiber accepts only shell.showItemInFolder, shell.openPath, and notification.show; without them, repository, status, diff, stage, commit, and branch operations remain available and native actions are not shown.

No runtime invariant companion is published because Cordis owns the service, RPC registration, and child-fiber lifetimes this package uses.

Configuration

FieldDefaultMeaning
executablegitGit executable name or absolute path resolved by ctx.subprocess.
maxOutputBytes8 MiBPer-stream collection cap for one Git command.
graceMs3000Managed subprocess termination grace period.
commitMessage.provider—Provider route registered with the DSH LLM runtime. Required when commitMessage.mode is custom.
commitMessage.model—Model id resolved by the provider route. Required when commitMessage.mode is custom.
commitMessage.modeinheritinherit uses the host session model; custom pins provider/model.
commitMessage.systemPromptbuilt-inSystem prompt for commit-message generation. Empty/absent uses the package default.
commitMessage.maxDiffBytes48 KiBStaged-diff byte cap applied before the generation prompt is built (validated minimum 1024).

The whole commitMessage section is optional and is also the git-commit-message settings namespace. Edit it from Settings → Plugins → Plugin configuration → Git, or as a composition entry. When the host exposes no LLM runtime, or no session model and no custom route resolve, commit message generation is unavailable and the Client reports git/generation-unavailable.

Git operations

The first release supports repository discovery, Git version, current branch and HEAD, staged/unstaged/untracked status, local branches, working and staged diffs, stage/unstage, commit, amend, push to origin, rebase-then-push sync, branch creation, and branch switching. Status uses porcelain v2 with NUL path separators; branches use for-each-ref; every caller-supplied path, branch, and message remains one argv value.

Discard restores one staged, unstaged, or untracked change, including an addition or rename edited after staging, through explicit index, worktree, and clean operations. It is destructive: the Client always asks for a second, explicit confirmation before sending the RPC, and the surface names the path in the confirm body.

Commit history is read with a paged git log (GIT_LOG_FORMAT, one commit per line, fixed field count) so the Graph surface appends older commits incrementally through a load-more control instead of materializing the whole history.

Commit message generation is opt-in at the host: it needs an LLM runtime and a resolvable model (the session default, or a custom provider/model). A staged diff (capped by commitMessage.maxDiffBytes) is sent to that route and the streamed suggestion is written into the editable commit message input. The system prompt defaults to a Conventional Commit instruction and can be overridden from Plugin configuration. Generation is suggestion-only — it never stages, commits, or pushes anything.

GitHub authentication, hosting-provider workflows, credential prompts, issues, pull requests, stash, cherry-pick, and merge-conflict editing remain outside this package. Push and sync invoke git push / git pull --rebase as separate argv values and surface Git's own errors when remotes or credentials are missing.

npm publication

The package is published to npm as @dsh-electron/dsh-plugin-git (MIT; latest 0.2.1). Releases are cut by pushing a vX.Y.Z tag: the workflow runs the tests and build, packs the tarball, publishes it to npm with build provenance, and attaches the same tarball to a GitHub Release. API and versioning remain pre-1.0. The UI host is the upstream built-in right sidebar; no separately installed third-party pairing package is required. Release steps and credentials are documented in docs/development/README.en.md.

Development

Use Node.js ^22.19 or >=24 with pnpm 11.

pnpm install --frozen-lockfile
pnpm test
pnpm build
pnpm pack

Model Experience

None, as this package registers no model tools, prompt sections, or request context.

KV Cache effect

None. Commit-message generation is an independent Host LLM request and does not add, replace, or retain session tokens.

Known Limitations and Deferred Work

  • No credential UI — push and sync call Git with no prompt for remotes or credentials; a missing origin or rejected auth fails as a Git command error.
  • Bounded command output — a diff larger than maxOutputBytes retains only the subprocess collector's tail, so deployments handling very large diffs must raise that validated setting.
  • Generation needs host + model — commit message generation requires a host LLM runtime and a resolvable model (session default or a custom route in Plugin configuration); without either, the Generate action stays disabled or reports git/generation-unavailable.

Dev Note

None.

Contributing

Setup, quality gates, and the documentation duty are in CONTRIBUTING.md. The user-visible changes of each released version are in CHANGELOG.md. The package is MIT-licensed; see LICENSE.