以结构化数据返回有界、相对仓库根的 Git 状态,不暂存、不提交,也不切换分支。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:txy-ucas/dsh-workspace-snapshot
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
该插件的 README 只有英文版本。
A bounded, read-only Git workspace status tool for DeepSeek Harness. It adds one model-facing workspace_snapshot tool that reports branch tracking and repository-relative path states as validated structured data.
The plugin never stages files, changes branches, writes Git configuration, creates commits, or pushes.
Scope
This plugin is intentionally a status probe, not a complete Git workflow. It answers which paths are staged, unstaged, conflicted, or untracked without exposing repository mutation operations or file-content diffs. Use a dedicated review or Git workflow plugin when the agent must inspect changed lines, create commits, or manage branches. The narrower scope keeps this plugin useful in read-only deployments and complementary to broader Git tooling.
Requirements
- Node.js
^22.19.0 || >=24.0.0 - DeepSeek Harness
0.1.0-rc.6 - Git available in the Harness subprocess provider's execution world
The package pins the exact Cordis and DSH peer API versions it was tested against. An incompatible Harness upgrade fails package resolution instead of silently loading an unverified API combination.
Install
Install the prebuilt v0.1.0 release into the profile you use:
dsh plugin --profile web add https://github.com/txy-ucas/dsh-workspace-snapshot/releases/download/v0.1.0/dsh-workspace-snapshot-0.1.0.tgz
The release tarball needs no package build allowance. A pinned source install is also supported:
dsh plugin --profile web add github:txy-ucas/dsh-workspace-snapshot#v0.1.0
Git installations run the package's prepare build. pnpm 10 or newer may require this entry in the profile's pnpm-workspace.yaml before repeating the install:
allowBuilds:
dsh-workspace-snapshot: true
For local development, run this from the checkout's parent directory:
dsh plugin --profile web add ./dsh-workspace-snapshot
Verify composition without starting the UI:
dsh --profile web --dump-config
The output must include the workspace-snapshot row.
Use
Ask the agent:
Inspect the Git workspace before making changes.
The model can call workspace_snapshot and receives a canonical object such as:
{
"status": "ok",
"repositoryRoot": ".",
"branch": "feature/status-tool",
"detached": false,
"upstream": "origin/feature/status-tool",
"ahead": 2,
"behind": 0,
"clean": false,
"entries": [
{ "kind": "changed", "path": "src/index.ts", "indexStatus": "M", "worktreeStatus": "." },
{ "kind": "changed", "path": "README.md", "indexStatus": ".", "worktreeStatus": "M" },
{ "kind": "untracked", "path": "notes.txt" }
],
"totalPaths": 3,
"conflictCount": 0,
"stagedCount": 1,
"unstagedCount": 1,
"untrackedCount": 1,
"omittedPaths": 0,
"truncated": false
}
Every path appears once in entries. A changed entry separates Git's index and worktree status characters; rename and copy entries also carry originalPath. A conflict entry carries one validated unmerged status, and an untracked entry carries only its path.
| Field | Meaning |
|---|---|
repositoryRoot |
Stable "." path base. Every entry path and optional originalPath is relative to the repository root, without exposing its host absolute path. |
branch |
Current branch name, or null for detached or unknown HEAD state. |
detached |
Whether Git reports a detached HEAD. |
upstream |
Tracking branch, or null when none is configured. |
ahead / behind |
Commit distance from the configured upstream. Both are zero when Git reports no branch comparison. |
clean |
Whether Git reported no tracked changes, conflicts, or untracked paths. The tool always requests untracked paths. |
entries |
Bounded path records discriminated by kind: changed, conflict, or untracked. Each path appears once. |
totalPaths |
Complete number of Git path records parsed from bounded stdout. |
conflictCount |
Complete number of conflict paths, including omitted entries. |
stagedCount / unstagedCount |
Complete changed-path counts derived from non-dot index/worktree statuses. One changed path may increment both. |
untrackedCount |
Complete number of untracked paths. |
omittedPaths |
Path records excluded from entries by maxPathRecords or maxResultBytes. |
truncated |
Whether entries is incomplete. The count fields remain complete when this is true. |
Native and Code Mode consumers receive the same canonical object. Native rendering is exactly its JSON serialization; paths containing control characters are JSON-escaped.
Errors
Expected external failures are returned as structured values rather than raw exceptions:
{
"status": "error",
"code": "NOT_A_REPOSITORY",
"message": "The session working directory is not inside a Git repository.",
"retryable": false
}
Stable codes are NOT_A_REPOSITORY, GIT_UNAVAILABLE, TIMEOUT, CANCELLED, OUTPUT_LIMIT, INVALID_GIT_OUTPUT, and GIT_FAILED. Raw stderr, thrown values, and stack traces are never returned to the model.
Configuration
The installable bundle inserts the plugin with defaults. Override the complete row configuration in the profile's later cordis.patch.yml layer when needed:
- id: workspace-snapshot
config:
timeoutMs: 5000
maxGitStdoutBytes: 262144
maxPathRecords: 500
maxResultBytes: 131072
| Field | Default | Contract |
|---|---|---|
timeoutMs |
5000 |
Shared deadline for executable lookup and status, from 100 to 120000 ms. |
maxGitStdoutBytes |
262144 |
Retained Git stdout limit, from 1024 to 4000000. Exceeding it returns OUTPUT_LIMIT; partial output is never parsed. |
maxPathRecords |
500 |
Maximum path records initially retained in entries, from 1 to 10000. All records in bounded stdout still contribute to complete counts. |
maxResultBytes |
131072 |
UTF-8 byte limit for the complete canonical JSON result, from 1024 to 4000000. Entries are removed whole until it fits; JSON is never cut. |
Configuration is intentionally flat. Invalid limits fail plugin loading.
Safety and lifecycle
- The plugin declares
inject = ['tools', 'subprocess']; Cordis activates it only while both services are available. - Tool registration is owned by
ctx.effect()and disappears on HMR, unload, or uninstall. - Every call runs one fixed read-only argv:
git --no-pager --no-optional-locks -c core.fsmonitor=false -c core.untrackedCache=false -c status.relativePaths=false status --porcelain=v2 --branch -z --untracked-files=all. - Git runs through
ctx.subprocess, nevernode:child_process, so the selected execution-world provider and its process-tree cleanup remain authoritative. - The child environment removes every inherited
GIT_*value, then sets onlyGIT_CONFIG_COUNT=0,GIT_OPTIONAL_LOCKS=0, andLC_ALL=C. Ambient repository, index, object-store, and config injection cannot redirect the query. - Optional locks, repository FSMonitor hooks, the untracked cache, and relative-to-cwd status paths are disabled explicitly. No model- or user-controlled string enters argv.
- The NUL-delimited parser handles spaces, newlines, Unicode paths, and rename/copy source paths without shell quoting.
- The parser requires complete branch headers and validates record tags, submodule state, file modes, object IDs, rename/copy scores, and status enums before accepting output.
- The caller's abort signal and the configured timeout bound executable lookup, the Git process, and complete process-tree exit. Captured stdout is not accepted while descendants remain live. Timer and signal-listener ownership ends before the tool settles.
- Git stdout, retained path records, and canonical result bytes are independently bounded. The plugin keeps no cache, watcher, socket, interval, or cross-session mutable state.
- UI presentation is a pure generic read card. The model-facing result is derived only from the validated canonical value.
Scope and limitations
- Ignored paths are not returned.
- Submodule state appears through Git's porcelain status fields but is not expanded recursively.
- Git may read repository metadata and working-tree paths. The plugin disables known status-time hooks and write optimizations; it does not claim that Git itself performs no operating-system reads.
- The snapshot is point-in-time information. Another process may modify the repository immediately after Git exits.
- This tool does not replace
git diff, review tools, permission policy, or commit tooling. - DeepSeek Harness is in developer preview. Exact peer versions deliberately reject unverified Harness APIs; the scheduled compatibility workflow reports when
@deepseek-ai/dsh@latestrequires a plugin update.
Uninstall
dsh plugin --profile web remove dsh-workspace-snapshot
Development
corepack enable
pnpm install
pnpm run check
node tests/install.e2e.mjs
DSH_VERSION=latest node tests/install.e2e.mjs
The suite covers strict porcelain headers and record metadata, path classification and complete counts, result-byte truncation, fixed argv, inherited Git-environment isolation, a real FSMonitor hook sentinel, lingering process-tree timeout and cancellation, structured external failures, canonical rendering, Cordis fiber disposal, package construction, and installation into an isolated Harness profile.
License
链接
同类插件
zhu1090093659/dsh-web#packages/dsh-git-graph★ 8178
输入框上方提供 Git 分支选择器,并把分支泳道与提交历史画成图谱,沿着时间线找到任意变更。
Akimiya-z/codex-guard#dsh★ 139
在 DeepSeek Harness 内做提交前的 Pull Request 卫生检查:扫描当前改动中的 TODO 残留、硬编码密钥与非规范提交信息。
Cerbur/clutch-dsh#clutch-dsh-worktree★ 30
为 DSH Web UI 增加按 Git Worktree 组织 Session 的视角,同时继续由 DSH 管理原始 Project 和 Session 数据。
lehhair/dsh-diff-viewer★ 26
PiUI 风格 diff 查看器,替换 write/edit 工具调用的默认 DiffBlock。
DietCokewithSugar/dsh-user-experience★ 20
帮你发现项目中可能存在的用户体验问题:自动走查 React/TypeScript 源码,定位问题并给出具体优化建议。
DamonKoy/dsh-web-ui#dsh-git-graph★ 19
dsh web GUI 会话头部栏的 Git 分支选择器与提交图。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。