diffing 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +364 -115
- package/dist/cli-agent-DZBvZoXZ.mjs +179 -0
- package/dist/cli.mjs +27 -27
- package/dist/client/assets/{angular-html-BmBRnRY-.js → angular-html-BABKYppC.js} +1 -1
- package/dist/client/assets/{angular-ts-BTywfy8Q.js → angular-ts-CtXLuOQb.js} +1 -1
- package/dist/client/assets/{apl-C-Nh4njw.js → apl-DOi69evI.js} +1 -1
- package/dist/client/assets/{astro-DGFZsGD0.js → astro-J8Em2tfW.js} +1 -1
- package/dist/client/assets/{blade-CK2WgF42.js → blade-B_tOnqRD.js} +1 -1
- package/dist/client/assets/{c-MXSr0H4Y.js → c-C0tRZWSi.js} +1 -1
- package/dist/client/assets/{cobol-BHSU4T5M.js → cobol-Dj_rkgIY.js} +1 -1
- package/dist/client/assets/{coffee-DiFXs9rA.js → coffee-C6Vq4BFF.js} +1 -1
- package/dist/client/assets/{cpp-CJWLNzrI.js → cpp-Cno48fgF.js} +1 -1
- package/dist/client/assets/{crystal-u5M0TrPu.js → crystal-C7tmDnU1.js} +1 -1
- package/dist/client/assets/{css-BMVhDkjX.js → css-0v4o-iNQ.js} +1 -1
- package/dist/client/assets/{edge-Di-AS7wq.js → edge-CvULxRem.js} +1 -1
- package/dist/client/assets/{elixir-CSMS6Yja.js → elixir-vRTauEw-.js} +1 -1
- package/dist/client/assets/{elm-CgUch6k4.js → elm-fLFTu1xn.js} +1 -1
- package/dist/client/assets/{erb-BY53XvrH.js → erb-CtItcikB.js} +1 -1
- package/dist/client/assets/{git-rebase-Cu4zaEs3.js → git-rebase-5MeRBXZD.js} +1 -1
- package/dist/client/assets/{glimmer-js-DgxwVbEv.js → glimmer-js-B7yA-u8_.js} +1 -1
- package/dist/client/assets/{glimmer-ts-CQgpMe8l.js → glimmer-ts-B2g1OaHc.js} +1 -1
- package/dist/client/assets/{glsl-C6rPllEZ.js → glsl-CqNPWp5Y.js} +1 -1
- package/dist/client/assets/{graphql-D0IXKtPr.js → graphql-CF78KbfF.js} +1 -1
- package/dist/client/assets/{hack-Bbv4uGLh.js → hack-Dz8fQ8O9.js} +1 -1
- package/dist/client/assets/{haml-BEq4fVEe.js → haml-3Gbl257r.js} +1 -1
- package/dist/client/assets/{handlebars-CGriKhdR.js → handlebars-5UZnh5L7.js} +1 -1
- package/dist/client/assets/{html-DhsWBiF-.js → html-JOaQiIkL.js} +1 -1
- package/dist/client/assets/{html-derivative-CU7SM-vj.js → html-derivative-GyX6oYy3.js} +1 -1
- package/dist/client/assets/{http-DAZNqWUu.js → http-t6uVAxgS.js} +1 -1
- package/dist/client/assets/{hurl-DGP3-RE2.js → hurl-OLQZpg0E.js} +1 -1
- package/dist/client/assets/{index-Bsby5xp2.js → index-CghVgrAF.js} +5 -5
- package/dist/client/assets/{index-BqD_EVaR.css → index-CmfB2R-C.css} +1 -1
- package/dist/client/assets/{java-CoIvfF-o.js → java-BqL_yaya.js} +1 -1
- package/dist/client/assets/{javascript-D2G0Bybq.js → javascript-CxBNAxR5.js} +1 -1
- package/dist/client/assets/{jinja-BRdOYMmE.js → jinja-CuaK033Z.js} +1 -1
- package/dist/client/assets/{jison-CVQZsA0e.js → jison-aL_w2vvo.js} +1 -1
- package/dist/client/assets/{json-BTFmVGAb.js → json-Byruj-EC.js} +1 -1
- package/dist/client/assets/{jsx-DYLgPaVb.js → jsx-CosY06uG.js} +1 -1
- package/dist/client/assets/{julia-CJWtNtRM.js → julia-u1y7fV63.js} +1 -1
- package/dist/client/assets/{just-CZyINJ-2.js → just-DS4T9P_K.js} +1 -1
- package/dist/client/assets/{latex-mNMnTIv1.js → latex-C9c2IWW4.js} +1 -1
- package/dist/client/assets/{liquid-BgSPl0Kv.js → liquid-DcXQgkEV.js} +1 -1
- package/dist/client/assets/{lua-rmIsezWJ.js → lua-DWe0hUn1.js} +1 -1
- package/dist/client/assets/{marko-Dfkwq7Gv.js → marko-CIW7o2up.js} +1 -1
- package/dist/client/assets/{mdc-f53p1REg.js → mdc-DKjGzb4k.js} +1 -1
- package/dist/client/assets/{nginx-Cn5ljkEv.js → nginx-CBXzDlkk.js} +1 -1
- package/dist/client/assets/{nim-DrAyHk_n.js → nim-CBf_vdee.js} +1 -1
- package/dist/client/assets/{perl-BLNIVaG-.js → perl-xC9qc39I.js} +1 -1
- package/dist/client/assets/{php-CxDOF44K.js → php-n4vnn5oz.js} +1 -1
- package/dist/client/assets/{pug-DGZxLxM3.js → pug-Db536lA_.js} +1 -1
- package/dist/client/assets/{qml-Dmqfyov_.js → qml-CrATLnNN.js} +1 -1
- package/dist/client/assets/{r-F2CLYuZ7.js → r-DBQ-dydl.js} +1 -1
- package/dist/client/assets/{razor-DYbbBV0d.js → razor-C_wvK1iP.js} +1 -1
- package/dist/client/assets/{regexp-TyKA4-BB.js → regexp-DowFj0Xd.js} +1 -1
- package/dist/client/assets/{rst-CMLF7yP9.js → rst-rY4UPiwe.js} +1 -1
- package/dist/client/assets/{ruby-BE4S9bsQ.js → ruby-C4cISY4u.js} +1 -1
- package/dist/client/assets/{sas-DOhcrhSM.js → sas-ui1PNNkD.js} +1 -1
- package/dist/client/assets/{scss-DZgJ0K1I.js → scss-BZrs95TC.js} +1 -1
- package/dist/client/assets/{shellscript-CWMAvx8a.js → shellscript-D9YVFS67.js} +1 -1
- package/dist/client/assets/{shellsession-OJxRnKbO.js → shellsession-DK7LMzYg.js} +1 -1
- package/dist/client/assets/{soy-C_oQW_S0.js → soy-CNkc-Oji.js} +1 -1
- package/dist/client/assets/{sql-DEXpTiLI.js → sql-BvRdqBMa.js} +1 -1
- package/dist/client/assets/{stata-BcrmvsDF.js → stata-Bawjgtiz.js} +1 -1
- package/dist/client/assets/{surrealql-Dwy3iKjf.js → surrealql-7v7lT5jp.js} +1 -1
- package/dist/client/assets/{svelte-BbWN9l2M.js → svelte-p7w_kluv.js} +1 -1
- package/dist/client/assets/{templ-BGIeAdtg.js → templ-0Gi_yZZr.js} +1 -1
- package/dist/client/assets/{tex-9fSuF3Cs.js → tex-nZ_J3lks.js} +1 -1
- package/dist/client/assets/{ts-tags-BcxYxF8C.js → ts-tags-CuG-Aj5j.js} +1 -1
- package/dist/client/assets/{tsx-B_z3ONaQ.js → tsx-Cc7GNb_V.js} +1 -1
- package/dist/client/assets/{twig-DQ7osXl9.js → twig-BBlmihVM.js} +1 -1
- package/dist/client/assets/{typescript-oc7bycaY.js → typescript-aiXwsZhm.js} +1 -1
- package/dist/client/assets/{vue-B3o6Rfti.js → vue-Cs5tk2kn.js} +1 -1
- package/dist/client/assets/{vue-html-BB_D6k4v.js → vue-html-BEI_B8Ml.js} +1 -1
- package/dist/client/assets/{vue-vine-CROD_1yE.js → vue-vine-CpWdOkP4.js} +1 -1
- package/dist/client/assets/{xml-BeVKeTE5.js → xml-madLQSkS.js} +1 -1
- package/dist/client/assets/{xsl-DaxeysAZ.js → xsl-CqZR37V9.js} +1 -1
- package/dist/client/assets/{yaml-DJD0ioac.js → yaml-DHr9ndbK.js} +1 -1
- package/dist/client/index.html +3 -3
- package/dist/mcp-BQmH_By-.mjs +119 -0
- package/dist/mcp-D9E2HQZ9.mjs +119 -0
- package/dist/server-lock-DbxpfF3j.mjs +575 -0
- package/package.json +18 -16
package/README.md
CHANGED
|
@@ -1,163 +1,412 @@
|
|
|
1
|
-
#
|
|
1
|
+
# diffing
|
|
2
2
|
|
|
3
|
-
A local code review tool designed for the coding agent workflow. Review AI-generated changes in a GitHub
|
|
3
|
+
A local-first code review tool and double-sided bridge designed for the modern AI coding agent workflow. Review AI-generated changes in a high-fidelity, GitHub-like web UI, leave inline comments, and hand them back to your coding agent to fix in real time.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<img width="1840" height="1196" alt="image" src="https://github.com/user-attachments/assets/767d42ed-a497-4b21-aca7-35be8b9a7006" />
|
|
6
6
|
|
|
7
|
-
## Install
|
|
8
7
|
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Quick Start
|
|
11
|
+
|
|
12
|
+
### 1. Install
|
|
13
|
+
Install `diffing` globally via npm:
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g diffing
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 2. Run
|
|
19
|
+
Launch it within any active git repository:
|
|
9
20
|
```bash
|
|
10
|
-
|
|
21
|
+
diffing
|
|
11
22
|
```
|
|
23
|
+
This instantly spins up a local server, establishes an active repository watcher, and opens your default browser to an interactive code review dashboard.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Web UI Review Dashboard
|
|
28
|
+
|
|
29
|
+
A local Hono-powered review server delivers a full-featured GitHub-like code review interface directly in your browser.
|
|
30
|
+
|
|
31
|
+
- **Split / Unified View** — Toggle between side-by-side (`split`) and inline (`unified`) diff layouts via toolbar or keyboard shortcut `m`.
|
|
32
|
+
- **Syntax Highlighting** — Powered by Shiki via `@pierre/diffs`, with high-fidelity highlighting for 200+ languages.
|
|
33
|
+
- **Interactive File Tree** — Hierarchical file navigation sidebar with collapsible folders, viewed/unviewed tracking, and change-type indicators (added, modified, deleted).
|
|
34
|
+
- **Status Dashboard (Comment Tracker)** — Bottom panel tracking open, replied, and resolved comments with filter tabs and click-to-navigate references to the relevant file and line.
|
|
35
|
+
- **Git Diff Stats** — Toolbar displays repo name, branch, file count, and additions/deletions (`+X/-Y`) computed from the patch.
|
|
36
|
+
- **Resizable Panels** — Drag-to-resize sidebar (240px–640px) and comment tracker panel (100px–600px). Widths and heights persist in localStorage.
|
|
37
|
+
- **Skeleton Loading Screen** — Full shimmer placeholder UI for toolbar, sidebar, search, tree nodes, and file diffs during initial load.
|
|
38
|
+
- **Image Diff Previews** — Visual side-by-side comparison for added, changed, and deleted image files (PNG, JPEG, GIF, WebP, SVG, BMP, ICO, AVIF).
|
|
39
|
+
|
|
40
|
+
---
|
|
12
41
|
|
|
13
|
-
##
|
|
42
|
+
## Themes
|
|
43
|
+
|
|
44
|
+
42+ built-in themes powered by Shiki, with instant switching and live preview.
|
|
45
|
+
|
|
46
|
+
| Category | Themes |
|
|
47
|
+
|----------|--------|
|
|
48
|
+
| GitHub Family | GitHub Dark, GitHub Light, GitHub Dark Dimmed, GitHub Dark High Contrast |
|
|
49
|
+
| Popular Dark | Dracula, One Dark Pro, Monokai, Synthwave '84, Material Theme (Ocean/Palenight/Darker) |
|
|
50
|
+
| Tokyo Night | Tokyo Night, Tokyo Night Storm, Tokyo Night Light |
|
|
51
|
+
| Catppuccin | Mocha, Frappe, Macchiato, Latte |
|
|
52
|
+
| Nord Family | Nord |
|
|
53
|
+
| Nightfox Family | Nightfox, Nordfox, Duskfox, Terafox, Carbonfox, Dayfox, Dawnfox |
|
|
54
|
+
| Rose Pine | Rose Pine, Rose Pine Dawn, Rose Pine Moon |
|
|
55
|
+
| Solarized | Solarized Dark, Solarized Light |
|
|
56
|
+
| VS Code | Dark+, Light+, Dark Modern, Light Modern |
|
|
57
|
+
| Others | Andromeeda, Aurora X, Houston, Laserwave, Min Dark/Light, Night Owl, One Light, Plastic, Poimandres, Slack (Dark/Ochre), Vesper, Vitesse Dark/Light, Ayu Dark/Light |
|
|
58
|
+
|
|
59
|
+
- **Searchable Theme Modal** — Press `g` `t` or use the toolbar to open a categorized, searchable theme picker with color swatches and live preview.
|
|
60
|
+
- **Dark/Light Dual Mode** — Each theme maps to corresponding dark and light Shiki themes for accurate syntax highlighting in both modes.
|
|
61
|
+
- **Instant Switching** — CSS transitions suppressed during theme changes for a snappy, lag-free experience.
|
|
62
|
+
- **Persistent Setting** — Theme choice saved to `~/.config/diffing/settings.json` and restored on next launch.
|
|
63
|
+
|
|
64
|
+
<img width="1840" height="1196" alt="image" src="https://github.com/user-attachments/assets/d4905604-e156-4c9b-998e-9015a7c36019" />
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Rust-Powered Code Search (powered by fff)
|
|
70
|
+
|
|
71
|
+
Blazing-fast, native fuzzy code search integrated directly into the sidebar search palette via `@ff-labs/fff-node`:
|
|
72
|
+
|
|
73
|
+
- **Fuzzy File Search** (`Files` scope) — Error-tolerant fuzzy matching on workspace paths using a native Rust engine.
|
|
74
|
+
- **Codebase Grep** (`Text` scope) — Instant case-insensitive text search with full **Regular Expression** support.
|
|
75
|
+
- **Syntactic Symbol Search** (`Symbols` scope) — Finds function declarations, class headers, type definitions, and variable assignments across JavaScript, TypeScript, Go, Rust, and Python (17+ language patterns).
|
|
76
|
+
- **Unified "All" Search** — Concurrent search across files, text, and symbols with automatic deduplication.
|
|
77
|
+
- **Frecency Ranking** — SQLite-backed history database remembers which files you open for specific queries, floating high-value results to the top.
|
|
78
|
+
- **"Changed Only" Filter** — Restricts search scope exclusively to files changed in the active git diff.
|
|
79
|
+
- **Git Status Chips** — Search results display git status indicators (modified, untracked, added, deleted, renamed).
|
|
80
|
+
- **Graceful Degradation** — If the native Rust binary is unavailable, search reports as unavailable without crashing the server.
|
|
81
|
+
- **Auto-Indexing** — The Rust engine maintains its own file system watcher for real-time index updates as the working tree changes.
|
|
82
|
+
|
|
83
|
+
<img width="1840" height="1196" alt="image" src="https://github.com/user-attachments/assets/0830b770-3c7f-44a1-b8ff-a70b2b34144a" />
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Vim-Style Keyboard Navigation
|
|
89
|
+
|
|
90
|
+
Full keyboard-driven navigation with vim-like motions and a modal status bar:
|
|
91
|
+
|
|
92
|
+
### Scrolling & Diffs
|
|
93
|
+
| Key | Action |
|
|
94
|
+
|-----|--------|
|
|
95
|
+
| `j` / `k` | Scroll down/up by 100px |
|
|
96
|
+
| `Ctrl+d` / `Ctrl+u` | Scroll half-page down/up |
|
|
97
|
+
| `g` `g` | Jump to top of diff |
|
|
98
|
+
| `G` | Jump to bottom of diff |
|
|
99
|
+
| `m` | Toggle split/unified view |
|
|
100
|
+
| `t` | Cycle tab size (2 → 4 → 8) |
|
|
101
|
+
| `w` | Toggle line wrap |
|
|
102
|
+
| `n` | Toggle line numbers |
|
|
103
|
+
| `i` | Cycle diff indicators |
|
|
104
|
+
| `I` | Cycle inline diff type |
|
|
105
|
+
|
|
106
|
+
### File Navigation & UI
|
|
107
|
+
| Key | Action |
|
|
108
|
+
|-----|--------|
|
|
109
|
+
| `J` / `K` | Jump to next/previous file |
|
|
110
|
+
| `v` | Toggle file viewed/unviewed |
|
|
111
|
+
| `b` | Toggle sidebar visibility |
|
|
112
|
+
| `/` | Open text search |
|
|
113
|
+
| `s` | Open symbol search |
|
|
114
|
+
| `g` `v` | Open file browser |
|
|
115
|
+
| `g` `t` | Open theme picker |
|
|
116
|
+
| `Cmd/Ctrl+K` | Open global command palette |
|
|
117
|
+
| `Cmd/Ctrl+,` | Toggle settings panel |
|
|
118
|
+
| `?` | Show shortcuts help modal |
|
|
119
|
+
|
|
120
|
+
A vim-style status bar at the bottom displays the current mode (NORMAL/INSERT), file path, and a help button. Multi-key sequences use an 800ms key buffer.
|
|
121
|
+
|
|
122
|
+
<img width="1840" height="1196" alt="image" src="https://github.com/user-attachments/assets/d230d020-4fb2-475a-a8a0-0ae11bb271ff" />
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Performance & Speed
|
|
128
|
+
|
|
129
|
+
Built from the ground up for a fast, fluid experience—even in large repositories:
|
|
130
|
+
|
|
131
|
+
- **Rust-Powered Search** — Native engine handles indexing and querying outside the JS event loop.
|
|
132
|
+
- **Async Diff Execution** — Server fetches unstaged, staged, and untracked diffs concurrently via `Promise.all`.
|
|
133
|
+
- **Web Worker Rendering** — `@pierre/diffs` uses a worker pool for syntax highlighting and diff computation off the main thread.
|
|
134
|
+
- **React.memo + useMemo** — Extensive component memoization prevents unnecessary re-renders when files haven't changed.
|
|
135
|
+
- **useTransition** — Settings changes (theme, diff style, font size) wrapped in `startTransition` for non-blocking UI updates.
|
|
136
|
+
- **Compositor-Only Resize** — Sidebar and comment panel resize use GPU-composited transform guides; width/height committed only on mouseup for 60fps feel.
|
|
137
|
+
- **Shiki Pre-Warming** — Highlighter engines preloaded on theme change for instant first paint.
|
|
138
|
+
- **Large Buffer Support** — Git operations use 50–100MB max buffer to handle large diffs.
|
|
139
|
+
- **Object Reference Stability** — Diff metadata reuses previous object references when file contents haven't changed (JSON comparison of hunks).
|
|
140
|
+
- **Stale Project Cleanup** — Project storage directories older than 14 days or with missing repo paths are automatically purged.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Real-Time Communication
|
|
145
|
+
|
|
146
|
+
Bidirectional, event-driven sync between the browser UI and connected AI agents via Server-Sent Events (SSE):
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
┌──────────────┐ SSE (change/comments/agent-status) ┌──────────────┐
|
|
150
|
+
│ │◄───────────────────────────────────────────►│ │
|
|
151
|
+
│ Browser │ │ AI Agent │
|
|
152
|
+
│ UI │ ┌─────────────────────────────┐ │ (CLI/MCP) │
|
|
153
|
+
│ │ │ comments.json │ │ │
|
|
154
|
+
│ │ │ (FileCommentStore on disk) │ │ │
|
|
155
|
+
└──────┬───────┘ └──────────┬──────────────────┘ └──────┬───────┘
|
|
156
|
+
│ user writes comment │ │
|
|
157
|
+
│ ──────────────────────► │ fs.watch detects change │
|
|
158
|
+
│ │ ───────────────────────────────► │
|
|
159
|
+
│ │ agent posts reply │
|
|
160
|
+
│ SSE broadcasts toast │ ◄────────────────────────────── │
|
|
161
|
+
│ ◄───────────────────────│ │
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
- **Single SSE Endpoint** (`/api/live`) — Multiplexed event stream with named events: `change` (working tree), `comments` (store updated), `agent-status` (agent connect/disconnect/send), `heartbeat` (15s keep-alive).
|
|
165
|
+
- **File System Watcher** — `fs.watch` on repo root (recursive, 200ms debounce) triggers live diff refresh on working tree changes. Skips `.git`, `node_modules`, `dist`, and `.changeset`.
|
|
166
|
+
- **Comment Store Watcher** — `fs.watch` on `comments.json` (120ms debounce) broadcasts updates when agents or humans write comments externally.
|
|
167
|
+
- **Agent Activity Toasts** — Real-time toast notifications when an agent posts a reply, showing model name, file path, and body preview. Clickable to jump to the file; auto-dismisses after 8 seconds.
|
|
168
|
+
- **Agent Status Indicator** — Green dot on the "Send to agent" button when an agent process is connected and waiting (via SSE `agent-status` events).
|
|
169
|
+
- **Bidirectional Sync** — User adds comments in UI → saved to `comments.json` → watcher → SSE broadcast → agent picks up. Agent posts reply → written to `comments.json` → watcher → SSE → UI toast.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## AI Agent Collaboration (Handoff Protocol)
|
|
174
|
+
|
|
175
|
+
`diffing` solves the friction of copy-pasting code review notes into LLM chat boxes. It establishes an **"agent waits, human releases"** pipeline using a robust, port-agnostic lockfile mechanism.
|
|
176
|
+
|
|
177
|
+
```text
|
|
178
|
+
1. The agent runs a blocking command/tool and enters sleep mode.
|
|
179
|
+
2. You review code in your browser, leave inline comments, and click "Send to agent".
|
|
180
|
+
3. The agent wakes up instantly, receives comments as structured XML, applies edits, and posts replies.
|
|
181
|
+
```
|
|
14
182
|
|
|
15
|
-
|
|
183
|
+
### A. CLI Integration (For any terminal-based agent)
|
|
184
|
+
The `diffing` binary acts as a port-agnostic CLI client. It automatically discovers the running server by reading a local repository lockfile:
|
|
16
185
|
|
|
17
186
|
```bash
|
|
18
|
-
|
|
187
|
+
diffing await-review # Block process until you click "Send to agent"; outputs comments as XML
|
|
188
|
+
diffing comments [--open] [--json] # One-shot query of the comments database
|
|
189
|
+
diffing reply <id> --body "..." # Post an agent response or explanation
|
|
190
|
+
diffing resolve <id> # Mark a comment resolved, updating the UI live
|
|
191
|
+
diffing url # Retrieve the active server base URL
|
|
19
192
|
```
|
|
20
193
|
|
|
21
|
-
|
|
194
|
+
### B. Model Context Protocol (MCP) Server
|
|
195
|
+
If your agent supports MCP (such as Cursor, Claude Desktop, or Gemini), configure `diffing` as a stdio-based MCP server. No ports need to be configured:
|
|
22
196
|
|
|
23
|
-
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"mcpServers": {
|
|
200
|
+
"diffing": {
|
|
201
|
+
"command": "diffing",
|
|
202
|
+
"args": ["mcp"]
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
Exposes four powerful tools directly to your agent: `await_review`, `list_comments`, `reply_to_comment`, and `resolve_comment`.
|
|
24
208
|
|
|
209
|
+
### C. Agent Skills
|
|
210
|
+
You can install diffing skills directly into your AI coding assistant:
|
|
211
|
+
```bash
|
|
212
|
+
npx skills add ahmedragab20/diffing
|
|
25
213
|
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
214
|
+
Provides three primary commands to coordinate reviews:
|
|
215
|
+
1. **`/diffing-start-review`** — Launches the review server.
|
|
216
|
+
2. **`/diffing-finish-review`** — Blocks the agent using `await-review` until comments are sent, then applies requested edits.
|
|
217
|
+
3. **`/diffing-review`** — Combined launch-and-wait flow.
|
|
218
|
+
|
|
219
|
+
### Send Review Popover
|
|
220
|
+
A GitHub-style "finish your review" popover with inline editing of each comment, an optional general/overall comment, and a visual indicator when an agent is waiting. The **"Copy comments"** toolbar button serializes all comments to the XML spec and copies them to the clipboard.
|
|
221
|
+
|
|
222
|
+
### Port-Agnostic Discovery
|
|
223
|
+
A per-repo lockfile (`server.json`) in `~/.diffing/<repo-hash>/` enables all subcommands and MCP tools to discover the server's port with zero configuration. Stale or crashed server locks are automatically detected and treated as dead via `process.kill(pid, 0)`.
|
|
224
|
+
|
|
225
|
+
### Monotonic Round Sequencing
|
|
226
|
+
A `ReviewSession` class with a monotonic `round` counter and race-guard logic ensures that if a "Send to agent" lands between polling intervals, the cached payload is delivered immediately. Multiple agents can block on the same review session simultaneously—all are released together on send.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Inline Comment System
|
|
231
|
+
|
|
232
|
+
Rich, real-time comment threads directly on diff lines:
|
|
233
|
+
|
|
234
|
+
- **Inline Threads** — Hover and click the `+` button on any addition or deletion line to start a thread. Supports markdown (GFM + line breaks) with syntax-highlighted fenced code blocks.
|
|
235
|
+
- **Multi-Line Comments** — Select a line range to comment on an entire block of code.
|
|
236
|
+
- **File-Level Comments** — Add general comments scoped to the entire file without targeting a specific line.
|
|
237
|
+
- **Comment Drafts** — LocalStorage-based draft system (`diffing-draft-*` keys) with 7-day TTL, so drafts survive page refreshes.
|
|
238
|
+
- **Agent Attribution** — Replies carry `role` (`user`/`agent`) and the agent's `model` name for clear attribution.
|
|
239
|
+
- **Suggestion Application** — Parse `` ```suggestion `` code blocks from comment bodies and apply them to the file in one click via `POST /api/comments/:id/apply-suggestion`.
|
|
240
|
+
- **Full CRUD API** — REST endpoints for creating, reading, updating, and deleting comments and replies.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Inline Diff Viewer Settings
|
|
245
|
+
|
|
246
|
+
Fine-grained control over how diffs are rendered:
|
|
247
|
+
|
|
248
|
+
| Setting | Options | Description |
|
|
249
|
+
|---------|---------|-------------|
|
|
250
|
+
| **Inline Diff Type** | `word` (default), `word-alt`, `char`, `none` | Pinpoint exactly what changed inside a modified line |
|
|
251
|
+
| **Diff Indicators** | `classic` (+/−), `bars`, `none` | Gutter markers for added and deleted lines |
|
|
252
|
+
| **Line Numbers** | on / off | Toggle gutter line numbers |
|
|
253
|
+
| **Line Wrap** | on / off | Soft-wrap long lines instead of horizontal scrolling |
|
|
254
|
+
| **Hunk Separators** | `simple`, `metadata`, `line-info`, `line-info-basic` | Style of the separator bar between diff hunks |
|
|
255
|
+
| **Line Hover Highlight** | `both`, `line`, `number`, `disabled` | Which element highlights on hover |
|
|
256
|
+
| **Font Size** | 11px – 16px | Configure globally |
|
|
257
|
+
| **Tab Size** | 2 / 4 / 8 | Default tab width (overridden per-file by EditorConfig) |
|
|
258
|
+
| **Expandable Context** | `expandContextByDefault`, `collapsedContextThreshold` (default 10 lines), `expansionLineCount` (default 20) | Control how collapsed context regions behave |
|
|
259
|
+
| **Haptic & Sound Feedback** | on / off | Tactile feedback via `web-haptics` and synthesized audio cues (click, toggle, navigate, open, close, resolve, send, error) |
|
|
260
|
+
|
|
261
|
+
All settings persist to `~/.config/diffing/settings.json` and the UI updates are wrapped in `useTransition` for non-blocking responsiveness.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Merge Conflict Resolution
|
|
266
|
+
|
|
267
|
+
When your repository is in a merge state (`.git/MERGE_HEAD` detected):
|
|
268
|
+
|
|
269
|
+
- **Conflict Banner** — A prominent warning banner appears in the toolbar indicating the repo is in a merge conflict state.
|
|
270
|
+
- **`UnresolvedFile` Rendering** — Conflicted files are rendered using `@pierre/diffs`'s `UnresolvedFile` component with color-coded conflict markers.
|
|
271
|
+
- **Custom Action Buttons** — For each conflict region, choose **Accept Current**, **Accept Incoming**, or **Accept Both**.
|
|
272
|
+
- **Save & Stage** — After resolving all conflicts in a file, click **Save & Stage** to write the resolved content and `git add` it in one step.
|
|
273
|
+
- **Merge Status API** — `GET /api/merge-status` returns conflict state and lists conflicted files via `git diff --name-only --diff-filter=U`.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Hunk Revert & History
|
|
278
|
+
|
|
279
|
+
- **Revert Individual Hunks** — Undo a single hunk from the working tree via `POST /api/revert-hunk` using `git apply --reverse`.
|
|
280
|
+
- **Blame & History** — View `git blame` for deleted lines and recent commit history for any file via `GET /api/hunk-history`, showing who authored deleted code and when.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Advanced Git Operations
|
|
285
|
+
|
|
286
|
+
- **File Open in IDE** — Open any repo file in VS Code, Zed, Vim, Neovim, or the system default editor via `POST /api/open-file`. Configurable in settings.
|
|
287
|
+
- **File Save & Stage** — Write file contents to disk and optionally `git add` in one call via `POST /api/save-file`.
|
|
288
|
+
- **Repository File Lister** — `GET /api/repo-files` lists all known files (tracked + untracked, respecting `.gitignore`).
|
|
289
|
+
- **File Content Retrieval** — `GET /api/file-content` and `GET /api/file-text` return old (HEAD) or new (working tree) file versions as binary buffers or JSON text.
|
|
290
|
+
- **EditorConfig Integration** — Respects your local `.editorconfig` rules (`tab_width`, `indent_size`) for accurate, per-file tab sizing that overrides the default setting.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Git Diff Drop-in Compatibility
|
|
295
|
+
|
|
296
|
+
`diffing` is designed as a **seamless, full drop-in replacement for `git diff`**. It features a comprehensive option parser that understands standard git revisions, options, and pathspecs, forwarding them directly to your local git engine.
|
|
297
|
+
|
|
298
|
+
Whether you are comparing branches, reviewing staged changes, or filtering specific directories, simply swap `git diff` for `diffing` to instantly elevate your review into a premium, interactive browser interface:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
diffing # Review working tree changes in the browser UI
|
|
302
|
+
diffing --staged # Review staged changes (drop-in for git diff --staged)
|
|
303
|
+
diffing HEAD~3 # Review working tree changes against 3 commits ago
|
|
304
|
+
diffing main..feature # Compare two branches (drop-in for git diff main..feature)
|
|
305
|
+
diffing -- --cached -- src/ # Staged changes specifically in the src/ directory
|
|
38
306
|
```
|
|
39
307
|
|
|
40
|
-
|
|
308
|
+
### Intelligent Output Modes (TTY Auto-Detection)
|
|
309
|
+
To integrate flawlessly with your existing developer shell workflows, build pipelines, and command scripts, `diffing` automatically resolves the optimal output mode based on how stdout is directed:
|
|
310
|
+
- **Web Mode (Default for interactive TTY)**: When executed in an interactive terminal session, it boots the local Hono review server, registers the repository lockfile, and opens your default browser.
|
|
311
|
+
- **Terminal Mode (Default for pipes, redirects, or non-TTY)**: When output is piped (e.g. `diffing | grep "const"`) or redirected to a file, it falls back to behave **exactly like `git diff`**, streaming clean, standard unified diff patch text directly to standard output and exiting.
|
|
312
|
+
|
|
313
|
+
> [!TIP]
|
|
314
|
+
> Any standard output control or format-related flags (such as `--raw`, `--numstat`, `--stat`, `--exit-code`, `--quiet`, or `-o`) will automatically force Terminal Mode fallback.
|
|
315
|
+
|
|
316
|
+
> [!TIP]
|
|
317
|
+
> For a full list of all git option categories (algorithms, whitespace ignoring, context lines, word-level diffs, moved/copied detection, and path filtering) supported by `diffing`, see the [CLI Reference Manual](docs/cli.md).
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Integration & Configuration
|
|
322
|
+
|
|
323
|
+
- **Persistent User Settings** — Settings saved to `~/.config/diffing/settings.json`, loaded on startup, synced to server via `PUT /api/settings`.
|
|
324
|
+
- **Custom Host/Port** — `--host 0.0.0.0` exposes the review dashboard to the local network; `--port <port>` overrides random port selection.
|
|
325
|
+
- **`--no-open` Flag** — Prevents auto-browser opening on server start.
|
|
326
|
+
- **Git Config Alias** — Register `diffing` as `git review` via `~/.gitconfig`.
|
|
327
|
+
- **Shell Aliases** — `.zshrc`/`.bashrc` examples: `gd="diffing"`, `gds="diffing --staged"`, `gda="diffing & diffing await-review"`.
|
|
328
|
+
- **Configurable Browser & IDE** — Choose which browser to auto-open (Chrome, Firefox, Edge, Brave, or system default) and which IDE to use for file opening (VS Code, Zed, Vim, Neovim, or system default).
|
|
329
|
+
- **Graceful Shutdown** — `SIGINT`/`SIGTERM` handlers remove the server lockfile on exit.
|
|
41
330
|
|
|
42
|
-
|
|
43
|
-
- **Syntax highlighting** — Powered by Shiki with GitHub themes
|
|
44
|
-
- **File tree** — Hierarchical file browser with search filter and file change-type icons
|
|
45
|
-
- **Inline comments** — Click the `+` button on any line to add a review comment
|
|
46
|
-
- **Comment replies** — AI agents can reply to comments via API, displayed with bot avatar in the UI
|
|
47
|
-
- **Comment status tracker** — Sidebar widget showing open, replied, and resolved comment counts with click-to-navigate links
|
|
48
|
-
- **Send to agent** — One click hands your comments to a waiting agent automatically — no copy-paste, works with any agent/model via the `diffit` CLI or an MCP server
|
|
49
|
-
- **Copy comments** — One-click copy all comments as structured XML for AI coding agents (offline fallback)
|
|
50
|
-
- **Image preview** — Side-by-side comparison for added, modified, and deleted images
|
|
51
|
-
- **Viewed tracking** — Mark files as reviewed to track progress
|
|
52
|
-
- **Staged / Untracked toggles** — Choose which changes to include
|
|
53
|
-
- **Custom diff commands** — Pass any `git diff` arguments after `--`
|
|
54
|
-
- **EditorConfig support** — Respects `.editorconfig` for per-file tab size
|
|
55
|
-
- **Persistent settings** — Your preferences are saved across sessions
|
|
331
|
+
---
|
|
56
332
|
|
|
57
|
-
## Comment
|
|
333
|
+
## Comment XML Specification
|
|
58
334
|
|
|
59
|
-
When
|
|
335
|
+
When review comments are exported or streamed to a waiting agent, they are serialized into an optimized, self-documenting XML structure equipped with CDATA blocks:
|
|
60
336
|
|
|
61
337
|
```xml
|
|
62
338
|
<code-review-comments>
|
|
63
339
|
<instructions>
|
|
64
|
-
You are an AI coding assistant
|
|
340
|
+
You are an AI coding assistant receiving a structured list of code review comments to address.
|
|
65
341
|
For each file, review the inline comments and apply the changes requested.
|
|
66
|
-
- Target lines are specified by the "line" attribute (e.g. line="
|
|
67
|
-
- "side" indicates whether the comment is on "additions" (
|
|
68
|
-
- "status" indicates whether the comment is "open" or "resolved". Only address
|
|
69
|
-
- The <code> block contains the
|
|
342
|
+
- Target lines are specified by the "line" attribute (e.g. line="42" for single lines, line="42-45" for multi-line blocks, or line="file" for file-level notes).
|
|
343
|
+
- "side" indicates whether the comment is on "additions" (new code) or "deletions" (old code).
|
|
344
|
+
- "status" indicates whether the comment is "open" or "resolved". Only address "open" comments.
|
|
345
|
+
- The <code> block contains the code context at the reviewed lines.
|
|
70
346
|
- The <body> tag contains the review feedback or request.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Option A: Via the diffit CLI or MCP (Preferred — port-agnostic, no copy-paste)
|
|
78
|
-
diffit reply <comment-id> --body "Your response" --model "<your-model-name>"
|
|
79
|
-
diffit resolve <comment-id>
|
|
80
|
-
(Or the equivalent MCP tools: reply_to_comment, resolve_comment.)
|
|
81
|
-
|
|
82
|
-
Option B: Via the local HTTP API (if you know the running port)
|
|
83
|
-
POST http://localhost:<port>/api/comments/<comment-id>/replies
|
|
84
|
-
Payload: { "body": "Your response or clarification request here", "model": "<your-model-name>" }
|
|
85
|
-
PUT http://localhost:<port>/api/comments/<comment-id> Payload: { "status": "resolved" }
|
|
86
|
-
|
|
87
|
-
Option C: Via Text Response (Offline / Chat Copy-Paste)
|
|
88
|
-
If you do not have local API access, output your comments/replies inside a structured XML block at the end of your response:
|
|
89
|
-
<comment-replies>
|
|
90
|
-
<reply to="<comment-id>" model="<your-model-name>"><![CDATA[Your reply or clarification request here]]></reply>
|
|
91
|
-
</comment-replies>
|
|
347
|
+
|
|
348
|
+
HOW TO REPLY OR MARK AS RESOLVED:
|
|
349
|
+
- Prefer using the diffing CLI or MCP server tools (reply_to_comment / resolve_comment).
|
|
350
|
+
- CLI: `diffing reply <id> --body "..."`
|
|
351
|
+
- CLI: `diffing resolve <id>`
|
|
92
352
|
</instructions>
|
|
353
|
+
|
|
354
|
+
<!-- [Optional] High-Level General Review Comment -->
|
|
355
|
+
<general-comment>
|
|
356
|
+
<![CDATA[Please refactor the parsing module to improve reliability.]]>
|
|
357
|
+
</general-comment>
|
|
358
|
+
|
|
93
359
|
<file path="src/utils/parser.ts">
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<
|
|
360
|
+
<!-- [Example A] Multi-Line Selection Addition Comment -->
|
|
361
|
+
<comment id="c1" line="42-45" side="additions" status="open" created-at="2026-05-24T22:00:00.000Z">
|
|
362
|
+
<code><![CDATA[
|
|
363
|
+
+ const parsedToken = tokenize(input);
|
|
364
|
+
+ if (parsedToken.type === 'EOF') {
|
|
365
|
+
+ return null;
|
|
366
|
+
+ }
|
|
367
|
+
]]></code>
|
|
368
|
+
<body><![CDATA[Refactor this tokenization block to check for undefined inputs as well.]]></body>
|
|
97
369
|
<replies>
|
|
98
370
|
<reply id="r1" created-at="2026-05-24T22:05:00.000Z" role="agent" model="claude-3-5-sonnet">
|
|
99
|
-
<![CDATA[I agree,
|
|
371
|
+
<![CDATA[I agree, I will add a guard clause for undefined.]]>
|
|
100
372
|
</reply>
|
|
101
373
|
</replies>
|
|
102
374
|
</comment>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
375
|
+
|
|
376
|
+
<!-- [Example B] Whole-File General Comment -->
|
|
377
|
+
<comment id="c2" line="file" side="additions" status="open" created-at="2026-05-24T22:08:00.000Z">
|
|
378
|
+
<body><![CDATA[This parser module needs additional unit tests to cover negative bounds.]]></body>
|
|
106
379
|
</comment>
|
|
107
380
|
</file>
|
|
108
381
|
</code-review-comments>
|
|
109
382
|
```
|
|
110
383
|
|
|
111
|
-
|
|
112
|
-
- **Instructions**: A detailed system prompt instructing the agent on how to interpret and act on the comments.
|
|
113
|
-
- **Attributes**: Every `<comment>` includes its unique `id`, targeted line range (`line`), change `side` (`additions` or `deletions`), comment `status` (`open` or `resolved`), and ISO `created-at` timestamp.
|
|
114
|
-
- **CDATA Blocks**: Code snippets (`<code>`) and comment bodies (`<body>`) are wrapped in `<![CDATA[ ... ]]>` to prevent special characters from breaking XML parsers.
|
|
115
|
-
- **Replies**: Nested conversation history (if any) is preserved within `<replies>` and `<reply>` elements.
|
|
116
|
-
|
|
117
|
-
## Agent Handoff (no copy-paste)
|
|
118
|
-
|
|
119
|
-
Instead of copying comments into a chat, you can hand them to an agent automatically — and it works regardless of which agent/model is active. The model is **"the agent waits, you release it"**:
|
|
120
|
-
|
|
121
|
-
1. The agent runs a blocking command (or MCP tool) and sleeps.
|
|
122
|
-
2. You review in the browser and click **"Send to agent"** in the toolbar (a green dot on the button means an agent is connected and waiting).
|
|
123
|
-
3. The agent instantly receives your comments, applies changes, and replies — the UI updates live as it works. Add more comments and click Send again for another round.
|
|
124
|
-
|
|
125
|
-
### CLI (any agent with a shell)
|
|
126
|
-
|
|
127
|
-
The `diffit` binary doubles as a port-agnostic client. Each subcommand discovers the running server for the current repo via a lockfile — no port needed:
|
|
128
|
-
|
|
129
|
-
```bash
|
|
130
|
-
diffit await-review # block until you click "Send to agent"; prints comments as XML
|
|
131
|
-
diffit comments [--open] [--json] # one-shot dump of current comments
|
|
132
|
-
diffit reply <id> --body "…" --model "<name>" # post an agent reply
|
|
133
|
-
diffit resolve <id> # mark a comment resolved
|
|
134
|
-
diffit url # print the running server's base URL (for raw API calls)
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
`await-review` exits `0` when comments arrive (XML on stdout), `2` if it times out (just run it again to keep waiting), and `3` if no server is running.
|
|
384
|
+
---
|
|
138
385
|
|
|
139
|
-
|
|
386
|
+
## Security
|
|
140
387
|
|
|
141
|
-
|
|
388
|
+
- **Path Traversal Prevention** — All file operations validate paths against the repository root, rejecting `..`, null bytes, absolute paths, and URL-encoded bypass attempts.
|
|
389
|
+
- **403 Forbidden Responses** — File operations (`open-file`, `save-file`, `revert-hunk`, `hunk-history`) reject paths outside the repo root.
|
|
390
|
+
- **Attachment Isolation** — Uploaded attachments are restricted to `~/.diffing/<repo>/attachments/`.
|
|
391
|
+
- **Client Directory Isolation** — Static file serving resolves against the client directory and rejects paths outside it.
|
|
392
|
+
- **XSS Prevention** — HTML is escaped before markdown rendering; `marked` is used for safe HTML generation.
|
|
393
|
+
- **Repo Path Verification** — `repo_path.txt` is written to storage directories for cross-checking.
|
|
142
394
|
|
|
143
|
-
|
|
144
|
-
{ "mcpServers": { "diffit": { "command": "diffit", "args": ["mcp"] } } }
|
|
145
|
-
```
|
|
395
|
+
---
|
|
146
396
|
|
|
147
|
-
|
|
397
|
+
## Deep-Dive Documentation
|
|
148
398
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
Install the diffit skills to use diffit directly from your AI coding agent:
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
npx skills add ahmedragab20/diffit
|
|
155
|
-
```
|
|
399
|
+
For advanced features, internal API endpoints, sequence specifications, and configuration parameters, explore the complete guide:
|
|
156
400
|
|
|
157
|
-
|
|
401
|
+
> [!IMPORTANT]
|
|
402
|
+
> Read the [CLI & Protocol Reference Manual](docs/cli.md) for detailed descriptions of:
|
|
403
|
+
> - TTY Auto-Detection and Output Mode resolution.
|
|
404
|
+
> - The port-agnostic discovery lockfile mechanics.
|
|
405
|
+
> - Monotonic sequence `round` synchronization for race-free polling.
|
|
406
|
+
> - Full Web API endpoints schema (`GET /api/review/await`, `POST /api/comments`, etc.).
|
|
407
|
+
> - Custom git config shell aliases.
|
|
158
408
|
|
|
159
|
-
|
|
160
|
-
2. **`/diffit-finish-review`** — The agent runs `diffit await-review`, blocks until you click **"Send to agent"**, then applies the requested changes and marks each comment as resolved. The browser UI updates in real time as comments are resolved.
|
|
409
|
+
---
|
|
161
410
|
|
|
162
411
|
## License
|
|
163
412
|
|