JAI: Diff Editor (lite-diff)

Working with AI assistants like Claude, Cursor, or ChatGPT? Tired of manually applying code patches?
This extension bridges unified diff format and your IDE. Apply AI-generated patches with preview, selective hunk application, automatic backups, and drift detection.
Two ways to work:
- Manual — Paste a lite-diff patch into the editor panel, preview in VS Code diff viewer, apply with one click
- AI-assisted (MCP) — Your AI agent reads code, generates patches, previews, and applies — all through MCP tools, no copy-paste needed
Features
- lite-diff v1.1 engine — Port of the reference implementation, passes the specification's conformance corpus;
git diff output applies as is
- In-file edits — Replace, delete, insert with familiar unified diff syntax
- Insert at file start/end —
@@ BOF and @@ EOF hunks
- Scope headers —
@@ <text> starts the search at the first file line containing the text (e.g. @@ function render)
- Boundary blocks — Delete ranges between two marker lines using
...
- Global and block-level options — Ignore whitespace or blank lines, apply to all matches;
option <name> sets an option for one block only
- Ambiguous anchors are reported — An anchor that matches several places is error
E414 with every position listed, instead of silently taking the first one (--first-match restores the old behavior)
- Strict and check modes —
--strict turns warnings that mark a possibly misplaced hunk into errors (setting diffEditor.spec.strict, specStrict for MCP); --check and "Validate" run the full check against the workspace without writing
- Already-applied detection — Hunks already in the file get the status
already-applied (W414) and are never applied twice (setting diffEditor.spec.skipApplied, on by default); with the setting off, an already-applied hunk is error E410, and a re-sent pure insertion gets warning W417 and is inserted again (an error under --strict)
- Compatibility profile —
--lite-diff 1.0 in the patch (or diffEditor.spec.version = 1.0 for patches without a --lite-diff line) runs the v1.1 engine with --auto-rename and --first-match implied, # lines inside hunk bodies dropped as comments and --strict off; all other v1.1 rules and diagnostics stay in effect
- Preview mode — See exact changes in VS Code diff viewer before applying
- Selective apply — Include or exclude individual hunks
- Drift detection — Refuses to apply when a file changed after preview
- Manual resolution — Fix a mismatched hunk in VS Code Merge Editor
- Path validation — Gutter icons and quick fixes for mismatched file paths
- Drop file as diff — Generate a lite-diff from a dropped file
- Multi-file support — Multiple files and file operations in a single patch
- Automatic backups — Every preview saves originals in
.ldiff/, with one-click restore
- Git auto-commit — Stage or commit applied files, with the message taken from
# comments in the patch
- MCP Server — Integrate with Claude and Cursor IDE for AI-assisted patching
- CLI —
ldiff runs preview and apply outside VS Code; ldiff conform runs the lite-diff v1.1 engine directly with the result JSON of the specification
Folder Diff and Tree Generator are available in the companion JAI Toolkit extension (Visual Studio Marketplace, Open VSX). The toolbar buttons here open them and offer to install JAI Toolkit if it is missing.
Tutorial Videos
Overview Demo
|
Claude Desktop — Chat
|
Claude Desktop — Code
|
Claude Code (VS Code)
|
Cursor IDE
|
|
Quick Start
- Open Command Palette (
Ctrl/Cmd+Shift+P)
- Run
JAI Diff Editor: Open Editor Panel
- Paste your lite-diff patch
- Review changes in diff viewer, then apply
Syntax Guide
Basic Edit
--- file.txt
+++ file.txt
@@
context line (unchanged)
-old line
+new line
Insert at File Start
--- file.txt
+++ file.txt
@@ BOF
+first line
+second line
Insert at File End
--- file.txt
+++ file.txt
@@ EOF
+last line
Note: After @@ BOF and @@ EOF only + lines are allowed. Context ( ) or deletion (-) lines will cause error E411.
--- src/app.js
+++ src/app.js
@@ function render
return (
- <Old />
+ <New />
The search for the anchor starts at the first line containing function render (error E418 if the text is not in the file). Use it when a short anchor occurs in several places.
Delete Range (Boundary Block)
--- file.txt
+++ file.txt
@@
-start boundary
...
-end boundary
+replacement
Deletes everything from "start boundary" to "end boundary" inclusive, then inserts replacement.
Rules for boundary blocks:
... cannot appear at the start or end of the block
- Two
... in a row without - line between them are forbidden
- Each boundary must have
- lines on both sides
See the lite-diff specification for the full format.
Global Options
Add at the beginning of your patch, before any diff block:
--lite-diff 1.1
--ignore-blank-lines
--- file.txt
+++ file.txt
@@
context line
-old line
+new line
| Option |
Description |
--lite-diff 1.1 |
Version marker (should be the first option); --lite-diff 1.0 selects the compatibility profile |
--ignore-space-at-eol |
Accepted for compatibility: trailing whitespace is always ignored when matching |
--ignore-space-change |
Ignore changes in the amount of whitespace (but not its presence) |
--ignore-all-space |
Ignore all whitespace differences (overrides other whitespace options) |
--ignore-blank-lines |
Skip blank file lines when matching context |
--apply-all-matches |
Apply the hunk to all occurrences (blocks with a single hunk only, E304) |
--first-match |
Ambiguous anchor: take the first match instead of E414 |
--auto-rename |
Differing ---/+++ paths without rename from/to mean a rename instead of E608 |
--check |
Check every block and hunk, write nothing |
--strict |
Treat W401, W410 (except an exact hit of the @@ -a,b +c,d @@ line), W412, W413, W417, W418, W511 as errors |
--indent-shift |
Re-indent a hunk whose anchor differs only in indentation (W415) |
--lenient |
Match a hunk ignoring the amount of whitespace when nothing else matches (W416; not together with --strict, E307) |
--skip-applied |
Skip a hunk that is already applied (W414) |
--strip <N> |
Remove N leading path components instead of the a/ b/ prefixes |
--eol lf\|crlf |
Line ending where the file has no line to copy it from (new files) |
--default-root @<name> |
Workspace folder for paths without an @<name>/ prefix (multi-root workspaces) |
Block-level options: a header line option <name> (between +++ and the first @@) sets an option for one block only, option <name> off switches it off. Allowed: ignore-space-at-eol, ignore-space-change, ignore-blank-lines, ignore-all-space, apply-all-matches, first-match, indent-shift, lenient, skip-applied.
Any other option is error E301. The extension's own options --ignore-comments and --ignore-prefix-context were removed in 1.0.0; the hint of E301 tells what to use instead.
Important Rules
- All patch lines must begin at the first position (no indentation):
---, +++, @@, -, +, (context), ...
- Every hunk needs a
@@ line (a block without it is error E404); a blank line inside a hunk body is an empty context line
- Global options (
--…) go before the first diff block; # comments are allowed there, in a block header, and directly before the next block — a # line between the lines of a hunk is error E401
- Paths that differ between
--- and +++ need rename from/rename to lines (otherwise E608)
- With Git auto-commit on, the
#git block at the top of the patch becomes the commit message; without it, # comments before each diff block are used
- Preview creates directories
.ldiff/<TIMESTAMP>/original/ and .ldiff/<TIMESTAMP>/preview/
Patches written for lite-diff v1.0 that may need a change are listed in §12.1 of the specification.
Configuration
| Setting |
Default |
Description |
diffEditor.verboseLogging |
false |
Enable verbose logging for debugging |
diffEditor.backupLimit |
5 |
Max backup packages to keep in .ldiff/ (0 = keep only the active package) |
diffEditor.spec.version |
1.1 |
lite-diff profile for a patch without a --lite-diff line: 1.1 or 1.0 (compatibility profile) |
diffEditor.spec.strict |
false |
Run every patch as with --strict |
diffEditor.spec.skipApplied |
true |
Skip already-applied hunks (W414, status already-applied); off: such a hunk is error E410 |
diffEditor.spec.eol |
auto |
Line ending for created files when the patch has no --eol line: auto (from files.eol, LF when auto), lf, crlf |
diffEditor.git.commitOnApply |
off |
Git action after Apply: off, stage, or always (also in the "Git" toolbar menu) |
diffEditor.files.exclude |
["dist/**", "out/**", …] |
Extra glob patterns to exclude from path suggestions |
diffEditor.dropAsDiff.enabled |
true |
Enable "Drop file as diff" in the patch editor |
diffEditor.mcp.autoStart |
false |
Start MCP Server automatically when the extension activates |
diffEditor.mcp.client |
cursor |
MCP client to register with: cursor, claude, or none |
MCP port and host, IPC, and drop-to-diff limits are available in Settings under "Diff Editor (lite-diff)". For MCP setup, see the guides for Claude and Cursor IDE.
Telemetry
This extension collects minimal anonymous telemetry (feature usage counts, no personal data) to help prioritize development. Telemetry respects the VS Code telemetry.telemetryLevel setting — set it to "off" to disable. See PRIVACY.md for full details.
Contributing
Found a bug or have a feature request? Please open an issue on GitHub.
For other inquiries: JeenyJAI@gmail.com
License
This extension is proprietary software. See LICENSE for details.
The lite-diff specification is licensed under CC BY 4.0. This license applies to the specification only and does not grant any rights to this extension's source code or binaries — you're free to create your own implementations of the spec.
🚀 Created with Claude