dsh-build-diff
Agent-loop change review for the DeepSeek Harness web GUI (DSH). After every agent loop (one running → idle driver cycle, matching dsh-agent-loop's kick semantics), the plugin snapshots the session workspace, detects file/code changes, and lets you:
- Review — open the right-sidebar panel showing every changed file with inline line-level diffs (line-number gutters, +/- coloring, collapsible context runs), grouped by loop round.
- Undo — revert the whole loop or a single file back to the exact pre-loop content, delete files the agent created, restore files the agent deleted.
- Review bubble — after each turn ends, a bubble ("N files edited · +X -Y · Undo / Review") renders directly above the assistant message's copy / feedback button row. Width matches the message column; the file preview shows at most 3 files, with "Show N more files" expanding the rest in the bubble. Clicking a file opens that file's diff in the right sidebar.
- Round selector — browse previous loops of the workspace.
- Copy Diff / Mark reviewed — copy unified diffs, mark loops reviewed.
Official dual-face dsh plugin (host half + browser half), zero runtime dependencies. No dsh source changes.
Prerequisite
dsh-better-sidebar (^0.12.1) is required — the review UI lives as a tab in its VS Code-like right sidebar. The client half declares it through cordis inject, so the UI simply does not load without it (the host half keeps detecting and recording loops regardless). Install it first:
dsh plugin --profile web add dsh-better-sidebarInstall
# from npm (once published), or a local checkout:
dsh plugin --profile web add @kelearns/dsh-build-diff
# local development:
dsh plugin --profile web add link:/path/to/dsh-build-diffManual install (same result as the profile mechanism used by bundled plugins):
1. Copy this directory into ~/.dsh/profiles/node_modules/@kelearns/dsh-build-diff/ (keep index.js, lib/, package.json, cordis.patch.yml). 2. Append to ~/.dsh/profiles/web/cordis.patch.yml:
``yaml - insert: - id: dsh-build-diff name: '@kelearns/dsh-build-diff' ``
3. Restart DSH (restart the desktop app / dsh web). The settings page (Settings → Changes Review) lets you toggle detection and the content-capture cap.
How it works
agent/status running → snapshot workspace (fingerprints + small-file contents)
… agent edits files …
agent/status idle → re-scan, compare, persist loop record (Myers line diffs)
GET /dsh-build-diff/loops?cwd=… loop metadata
GET /dsh-build-diff/loop/<id> full record (diffs; old contents stay server-side)
POST /dsh-build-diff/loop/<id>/revert undo all or selected files
POST /dsh-build-diff/loop/<id>/dismiss mark reviewed- Storage:
$DSH_HOME/build-diff/{config.json,index.json,loops/<id>.json}; loops expire afterretentionDays(default 7, keep last 200). - Snapshot cost: fingerprints for every file + contents of text files ≤
contentCapBytes(default 1 MB, total budget 256 MB per loop), with an in-memory (path, size, mtime) content cache so unchanged workspaces cost ~zero I/O on later loops. - Excluded by default:
.git,node_modules,dist,build,target,out,coverage,.next,.venv,__pycache__,.idea,.vscode, … (seelib/engine.js).
Limitations
- Tracks loops that start after the plugin loads; a loop already running at activation misses its beginning.
- Files larger than
contentCapBytes(or binary): change is still detected and counted, but no diff and no revert. Raise the cap in settings for big-text workspaces. - Revert restores the pre-loop content verbatim; if a later loop changed the same file, reverting the earlier loop overwrites the later changes.
- Revert is per record and idempotent; there is no redo.
- Subagent and background-job agents in the same workspace also produce records (they share the workspace root), which keeps their changes reviewable too.
- Snapshot walks run with a file-count cap (default 50,000 files).
Integration surface
The client half depends on dsh-better-sidebar (cordis inject: ['betterSidebar', ...] — a prerequisite that parks the UI until the service exists) and registers:
| Surface | Entry | Purpose |
|---|---|---|
conversation.chat.turnTail | chain entry | Review bubble above the assistant message's copy/feedback button row (fetch loop-by-turn; hidden when the turn changed nothing) |
betterSidebar.registerTab | tab build-diff | Changes Review tab in the right sidebar (single-instance, pending-count badge, round selector, per-file inline diffs, revert) |
conversation.session.header.actions | build-diff | Header button that opens the review tab |
settings.section | dsh-build-diff | Settings page (detection / cap / history) |
The sidebar tab opens (and auto-expands the right panel) from the bubble's Review button, the header button, or the + menu.
Tests
node test/diff.test.mjs # Myers diff + hunks + unified text
node test/snapshot.test.mjs # walk / capture / compare / revert (temp dirs)
node test/host-integration.test.mjs# mock-ctx apply + full agent-loop → routes → revert
node test/client-smoke.test.mjs # browser-half module contract + slot registrationLicense
MIT