description: "Summarize each top-level turn's changed files from git working-tree snapshots and whole-file captures around file-tool edits, announce them with a workspace/changes Session event, and serve the summary and per-file comparisons while the Session lives; configuration, repository requirement, and coverage rules."
English | 中文
This plugin summarizes which files each top-level turn changed, with per-file line counts, and serves each listed file's turn-start and turn-end comparison. Git snapshots of the working tree at turn start and turn end are diffed; every file a file tool edits is copied whole before its first edit and again at turn end, covering the files git does not. Without a repository or git, only file-tool edits are listed. The Session log receives one workspace/changes event naming the turn; summaries and comparisons stay on the Host until the Session is disposed. The Web changed-files card renders them.
The shipped Web bundle mounts this plugin. Mount it in any composition with the subprocess capability and a git executable on the Host:
- name: '@deepseek-ai/dsh-workspace-changes'
config:
maxFiles: 500
| Field | Default | Meaning |
|---|---|---|
timeoutMs |
30000 |
Milliseconds one git command may run before the turn's record is abandoned |
outputMaxBytes |
8388608 |
Bytes of git output retained per command; a larger diff listing abandons the record |
maxFiles |
500 |
Maximum files carried by one summary; total still reports the complete count |
maxFileBytes |
2097152 |
Bytes a file may hold to be captured around a file-tool edit or read from a snapshot for its comparison; a larger file gets no comparison, and one captured around a file-tool edit is also listed without counts |
diffTimeoutMs |
100 |
Milliseconds a line comparison may run before it degrades to whole-file replacement |
Every Session with a working directory and no subagent origin is recorded; subagent Sessions are not. Snapshots are written through a private index into a temporary object directory owned by the Session, with the repository's own object store attached as a read-only alternate; the repository's index, objects, work tree, and refs stay untouched, and the user's earlier uncommitted changes never enter a summary. Session disposal removes the directory. Nested repositories and submodules inside the working directory are recorded as gitlinks, so their internal changes do not appear. A working directory outside any git repository takes no snapshots. Without git — or, on macOS, with only the developer-tools stub at /usr/bin/git — no repository is located either, and the plugin logs that once. Either way the summary lists the file-tool edits alone, as described next, with the working directory as the workspace; shell edits are absent.
Before a write, edit, or mutating str_replace_editor call runs, the recorder copies the file at its path into the Session's temporary directory, once per path per turn, and copies it again at turn end; the copies are named by the SHA-1 of their bytes, so identical content is stored once. This needs no git. Paths the snapshots cover keep their git counts; the copies serve the other paths — files matching an ignore pattern, files outside the repository, and every file-tool edit when there is no snapshot — with counts from a line comparison of the two copies, so repeated edits to one file count once and a shell edit after a file-tool edit is included. A path whose content is unchanged at turn end is not listed. A copy larger than maxFileBytes is not stored: the file is listed with oversized and no counts, and a path whose both sides are that large is listed too, since unread content is never known to be unchanged. A path whose only difference is a missing final newline compares as unchanged, while git still counts that line. Files under /tmp or the platform temporary directory are excluded unless they lie inside the repository. Changes made only through shell commands outside the snapshot coverage are not recorded.
Each file carries a durable path — relative to the working directory inside it, absolute elsewhere — and a display path used for ordering and labels: the relative path, a ../ path for repository files above the working directory, a ~ path under the home directory, otherwise the absolute path. Files sort by display in code-unit order, which lists parent and absolute paths before the working directory's own files. The workspace/changes event carries only the turn number; ctx.workspaceChanges.summary(sessionId, seq) returns the summary the event with that sequence announced, or undefined once the Session is disposed or when this Host process never recorded it. ctx.workspaceChanges.diff(sessionId, seq, index, signal) compares the listed file at that index: hunks with three context lines from the two snapshot trees or the two copies, binary for a side git reported as binary or that holds a NUL byte, oversized for a side larger than maxFileBytes. A line comparison that runs longer than diffTimeoutMs degrades to one hunk replacing every line, marked coarse. A conversation reopened after a Host restart therefore has no card, and no comparison, for its earlier turns.
None, as the recorder appends a log-only workspace/changes event that only clients read and registers nothing model-facing.
Nothing here enters a model request, so provider cache reuse is unaffected.
core.splitIndex writes sharedindex.* files, and git-lfs runs its clean filter on changed files and stores their objects under .git/lfs.rev-parse --absolute-git-dir; an unsupported repository format or another git failure abandons the turn with a warning rather than being treated as a plain directory..gitignore that carries large build outputs costs that much temporary space until the Session is disposed..gitignore reliably.maxFileBytes, even for paths the snapshots also cover; the copies go with the Session's temporary directory.maxFileBytes.path; display is always slash-separated.