# dsh-diff-approval English | [中文](README.zh.md) [![npm version](https://img.shields.io/npm/v/dsh-diff-approval)](https://www.npmjs.com/package/dsh-diff-approval) [![CI](https://img.shields.io/github/actions/workflow/status/9087/dsh-diff-approval/ci.yml)](https://github.com/9087/dsh-diff-approval/actions) A DeepSeek Harness (DSH) plugin for pending-change review: it automatically tracks every successful `edit`, `write`, and editor (`str_replace_editor`) mutation, folds them into a single pending list in the sidebar where each file's diff can be reviewed and kept/reverted — and it can also import the workspace's version-control repository's local changes (Git / SVN / Perforce) in one click. ![Pending changes panel](docs/images/pending-panel.png) The panel also collapses its file list into a floating card and expands to fullscreen: | Collapsed file list | Fullscreen | | --- | --- | | ![Collapsed file list](docs/images/file-list-collapsed.png) | ![Fullscreen](docs/images/fullscreen.png) | For Markdown files, the source-line diff can also be shown as a rendered before/after preview: ![Markdown preview](docs/images/markdown.png) ## ✨ Features - **Diff view**: syntax-highlighted whole-file diff with +/− counts, an overview ruler on the scrollbar showing where changes sit, and an in-file search (`Ctrl+F`, step with `F3` / `Shift+F3`) that highlights matched words. Rows are virtualized, so huge files stay smooth. - **Block navigation & decisions**: jump between change blocks with `Ctrl+↑/↓` (or the previous/next buttons) — the focused block flashes, navigation is anchored to the scroll position and wraps at the top/bottom. Hover a block to **Keep** or **Revert** just that block from a small actions frame that also shows its position (e.g. "2/5"); after a single-block decision, focus advances to the next block. The lead rows left above the jumped-to block are configurable in settings. - **Selection frame**: drag to select a range of lines and a frame appears to **Keep** / **Revert** exactly that range. - **Per-file and bulk decisions**: the files in the file list can be kept / reverted one at a time, or **Keep all** / **Revert all** from its footer. - **Resolved files stay listed**: once every change in a file has been kept/reverted, the entry remains in the list and the panel asks whether to remove it or keep it for later. - **Undo / Redo**: every keep, revert, and import is undoable with `Ctrl+Z` / `Ctrl+Shift+Z` (rebindable in Shortcuts; `Ctrl+Y` remains an alias), active while the panel is open — text inputs keep their own editing. - **Quick summon & file cycling**: `Ctrl+D` (configurable in settings) toggles the review panel from anywhere and `Esc` closes it; `Ctrl+Tab` / `Ctrl+Shift+Tab` cycle through the pending files. - **Line references**: select text in the diff — the status bar shows its `(file:line)` / `(file:start-end)` reference; click it (or press `Ctrl+L`) to copy, and with the setting on it auto-pastes into the composer and focuses it. References in the composer and queued messages are **auto-aligned** when the referenced file changes: surviving lines re-map to their new range, and a fully-removed line becomes `(file:LINE_MISSING)`. - **Highlight language**: auto-detected from the file extension, or overridden from a dropdown. - **Auto-wrap**: a "Wrap lines" toggle beside the language selector wraps long lines for that language (CJK breaks between characters, Latin words stay whole), remembered per language. - **Side-by-side split view**: an opt-in two-column diff (left "before" | right "current"), line-aligned with per-side horizontal scrolling and a shared vertical scrollbar. Toggle it from the toolbar or in settings (default: single-column unified view). In split view, changed blocks are aligned by content similarity and changed lines show intra-line word diffs — whole words for Latin text, per-character for CJK. - **Markdown preview**: for Markdown files, toggle between the source-line diff and a rendered before/after preview (`Preview` / `Source`). The preview content max width is configurable. - **Customizable appearance**: from the "Diff view" settings group, adjust the diff's code font size (%), line height (px), and the added / removed line colors, with a live preview. - **External changes**: files already in the pending list are monitored — if one is later modified outside the reviewed edits (another tool, an editor), the panel adopts the new content and flags the divergence. - **Open / Reveal**: while reviewing a file's diff, open it in its default app or reveal it in the system file manager with one click. - **Import workspace changes**: when the list is empty, click the button to import the workspace's local changes from **Git / SVN / Perforce** — modified, deleted, and (opt-in) untracked files. The VCS root is found by walking up from the workspace, so a workspace inside a subdirectory works too. - **Settings**: a "Diff Approval" section in DeepSeek Harness settings, grouped into **Diff view** (code font size, line height, added / removed colors) and **Shortcuts** (rebind the panel's keyboard chords) plus preferences for auto-paste on copy, whether untracked files are included when importing, the diff's tab width (2 / 4 / 8 spaces), the side-by-side split view, the block-jump lead rows, the Markdown preview default and width, and the quick-summon chord. - **Persistence**: pending state is stored per workspace at `/diff-approval/workspaces/.json` and survives restarts — unhandled changes are still there when you come back, even in a fresh session. ## 📦 Install If `dsh` is on your `PATH`: ```sh dsh plugin --profile web add dsh-diff-approval ``` Or, if you run the harness through npx (e.g. `npx @deepseek-ai/dsh web`): ```sh npx @deepseek-ai/dsh plugin --profile web add dsh-diff-approval ``` or manually: add the package to your profile's `package.json` dependencies and insert this row into the profile's `cordis.patch.yml`: ```yaml - insert: - id: diff-approval name: dsh-diff-approval # Optional: relocate durable pending state (defaults to # /diff-approval/workspaces). # config: # storageDir: ~/dsh-pending ``` Then restart `dsh web`. ## 🚀 Usage 1. Work with the agent as usual — successful `edit` / `write` / editor (`str_replace_editor`) calls are recorded automatically. 2. Click the **Pending changes** action at the sidebar footer, review each file's diff, and **Keep** / **Revert**. 3. When the list is empty, **Import workspace changes** pulls in the workspace's local Git/SVN/Perforce changes. ## 📝 Notes - Only tracked mutations (`edit`, `write`, and `str_replace_editor` editor calls) are recorded automatically. Deletions made outside these tools (e.g. shell `rm`) are sensed only for tracked files: the entry turns "File is gone" and its Revert restores the file. - The VCS import runs read-only Git/SVN/Perforce commands through the deployment's shell executor, so the respective CLI must be on `PATH`. Importing untracked files (default off) scans the whole workspace, which can be slow on large trees. - For a newly-created file, the whole-file revert action reads **Delete** and removes the file. - Reverting a file writes it back with its current line endings (LF / CRLF) preserved. - Sessions with no workspace keep their entries memory-only; corrupt persistence files are rejected and can be deleted to reset. - The sidebar footer entry stacks vertically with other plugins' footer actions and defers to the dedicated `dsh-footer-order` plugin when it is present. ## 🛠 Development ```sh corepack pnpm install pnpm run typecheck # tsc over both faces pnpm run build # emits lib/index.js and lib/client.js pnpm test ```