English | 中文
AI changed your files and you're not sure whether to keep them? Preview the diff first.
Gives OpenCode the same Accept / Reject workflow you know from Copilot, right inside VS Code. It connects to the OpenCode CLI via real-time SSE, automatically tracks every AI file edit, and lets you review, accept, or reject changes file by file.
⚠️ Only tracks AI tool calls (write/edit) — NOT a filesystem watcherUnlike tools like Hunkwise that watch the entire Git working tree, DiffGate listens exclusively to OpenCode's SSE tool events. It never scans your workspace or monitors file system changes.
Why this matters: In a monorepo with dozens of sub-packages, a filesystem watcher would scan every
node_modules, every build artifact, every ignored directory — and crash or freeze. DiffGate stays fast because it only sees what the AI actually touches, nothing more.
- Manually start or connect to an OpenCode server via VS Code commands — no auto-launch, no surprises
- After each AI edit: red deleted-line insets, green added-line highlights, and
✓ Accept/✗ RejectCodeLens buttons inline - Sidebar panel lists all pending files with Accept All / Reject All bulk actions
- Click a filename in the sidebar to open the VS Code native diff view (with the proposed API enabled, it shows the before/after comparison; without it, it degrades to CodeLens only)
- Dirty check before Reject: detects manual edits and warns before overwriting
- AI-only change tracking — listens to SSE tool events (
write/edit), not the filesystem. No performance hit in large folders likenode_modulesor monorepos - Instant disconnect detection + one-click reconnect — retains the terminal process, reconnects SSE automatically
- Multi-session support — connect to multiple OpenCode instances simultaneously, status bar shows all sessions
- Status bar shows live session states; click to open the management panel
Install via .vsix file:
code --install-extension opencode-diffgate-0.0.1.vsix --enable-proposed-api oc-diff.oc-vscode-diffNote:
--enable-proposed-apiis required because the red deleted-line insets (WebviewEditorInset) depend on a VS Code proposed API. Without it, the extension still works (green highlights + CodeLens), but red deletion insets won't render.
Engine requirement: VS Code ≥ 1.86.0
After installing, open any VS Code workspace. The extension activates automatically (onStartupFinished). Three entry points become available:
💡 Tip: If you notice high memory usage, check whether debug logging is enabled. Debug logs output detailed processing traces to the VS Code Output panel (
Output → OpenCode Diff), which adds memory overhead. It is off by default. Toggle it viaCtrl+Shift+P→diffgate: Toggle Debug Logging (切换调试日志), or look fordiffgate.debugLogin extension settings.
Type these commands to start or connect to OpenCode:
diffgate: Start OpenCode Server (启动服务端)— auto-creates a terminal and connectsdiffgate: Connect to OpenCode Server (连接服务器)— enter a URL manually to connect
The extension icon appears on the left side of the VS Code status bar:
- Idle: shows
OpenCode Diffgate - Connected: shows
✓ oc(port) - Click the status bar at any time → opens the session management panel where you can view all sessions, reconnect disconnected ones, or focus a terminal
Find the OpenCode DiffGate icon or panel name in the Activity Bar (left sidebar). If it's not visible there:
- Check the bottom panel area (same row as the terminal output) — if collapsed, expand it first
- Right-click the panel tab → Move to Side Bar to pin it to the sidebar
Once connected, the panel automatically populates with pending files whenever AI edits something.
DiffGate provides two connection modes, both triggered from the command palette (Ctrl+Shift+P):
| Command | Description |
|---|---|
diffgate: Start OpenCode Server (启动服务端) |
Creates a new VS Code terminal → runs opencode --port <random> → connects via SSE automatically |
diffgate: Connect to OpenCode Server (连接服务器) |
Prompts for an OpenCode URL → connects via SSE directly (no terminal) |
Multi-root workspaces: When you have multiple workspace folders open, Start OpenCode Server shows a QuickPick selector so you can choose which directory OpenCode runs in.
Operation flow:
┌──────────────────────────────────┐
│ Ctrl+Shift+P → │
│ "Start OpenCode Server" │
└────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Multi-root workspace? │
│ Yes → QuickPick folder picker │
│ No → use the only root │
└────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Create terminal "oc(port)" │
│ Run `opencode --port XXXX` │
└────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────┐
│ SSE connected │
│ Status bar: ✓ oc(port) │
│ Ready to receive AI events │
└──────────────────────────────────┘
When the OpenCode process exits or the network drops:
┌──────────────────────────────────┐
│ SSE connection drops │
│ onDisconnect fires immediately │
└────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Terminal still alive? │
│ ← Yes ──────────────────────── │
│ Keep session, mark ✗ │
│ ← No (Ctrl+W closed terminal) │
│ Remove session entirely │
└──────────────────────────────────┘
One-click reconnect:
Status bar shows ✗ oc(port)
│
▼
Click status bar → QuickPick panel
│
▼
Lists all sessions with terminals:
✓ oc(8080) Connected
✗ oc(8081) Disconnected · click to reconnect
│
Click ✗ item ────────────────►
│ ▼
Sends into terminal: Immediate SSE connect
"opencode --port 8081" SSE built-in retry
catches server startup
Status bar back to ✓ oc(8081)
Status bar format:
| Display | Meaning |
|---|---|
✓ oc(8080) |
Session on port 8080 is connected |
◎ oc(8080) |
Session is starting or connecting |
✗ oc(8080) |
Session disconnected, can reconnect |
✓ oc(8080) ✗ oc(8081) |
Up to 2 sessions shown at once |
✓ oc(8080) ✗ oc(8081) (3) |
Parenthesized number = more sessions exist |
Clicking the status bar in any state opens the session management panel.
When OpenCode is about to run a write or edit tool, DiffGate receives a tool.called SSE event and immediately snapshots the target file (in memory). After the tool succeeds (tool.success), it snapshots the modified content.
Diff calculation is cumulative: if AI modifies the same file multiple times, DiffGate always compares against the very first baseline. This shows the full accumulated change from "AI started editing" to "AI finished".
Unlike tools like Hunkwise that monitor the entire Git working tree, DiffGate does not watch the filesystem or scan the workspace. It relies solely on SSE tool events:
- You edit a file manually → nothing happens, no CodeLens, no sidebar entries
- AI edits a file → immediately captured and marked for review
- Large folders (node_modules, big monorepos) → zero performance impact
- Each change is cleaned up immediately after Accept / Reject — no stale state
If you manually edit a file after AI modified it, and then click Reject, DiffGate shows a warning:
"File xxx has been manually modified. Force restore?"
Choosing "Force restore" overwrites the file with the baseline content (including your manual edits). Choosing "Cancel" aborts the restore.
All snapshot data is stored in memory (SnapshotStore) and never touches disk. Closing VS Code or reloading the window loses all pending review state. This is intentional: snapshots are temporary diff-review helpers, not persistent state.
After AI modifies a file, the editor shows red deletion insets, green added-line highlights, and CodeLens buttons above each hunk:
- ✓ Accept — keep the AI change, remove the file from review tracking
- ✗ Reject — restore the file to its pre-AI baseline, remove from tracking
Clicking Reject triggers the dirty check. If the file was manually modified, a confirmation dialog appears.
Open the OpenCode DiffGate sidebar panel:
- List of all pending files, each showing filename, directory, added lines (green), and deleted lines (red)
- Accept / Discard buttons on each file
- Accept All / Discard All bulk action buttons at the top
- Click a filename to open the VS Code native diff view comparing baseline vs. current content
The following commands are available in the command palette (Ctrl+Shift+P):
| Type in Command Palette | Description |
|---|---|
diffgate: Start OpenCode Server (启动服务端) |
Create terminal and start an OpenCode server |
diffgate: Connect to OpenCode Server (连接服务器) |
Enter a URL and connect directly |
Diffgate: 管理会话 |
Open session management panel (view/reconnect/focus terminals) |
diffgate: Accept AI Change (接受AI修改) |
Accept AI changes in the active editor |
diffgate: Reject AI Change / Restore Original (拒绝AI修改) |
Revert AI changes in the active editor |
diffgate: Accept All AI Changes (接受所有AI修改) |
Accept all pending files at once |
diffgate: Reject All AI Changes (拒绝所有AI修改) |
Reject all pending files at once |
diffgate: Open Diff View (打开差异对比) |
Open VS Code native diff view |
diffgate: Show OpenCode Diff Logs (查看日志) |
Show extension log output |
diffgate: Toggle Debug Logging (切换调试日志) |
Toggle debug logging on/off |
Accept / Reject / Accept All / Reject All can also be triggered from the sidebar panel buttons.
src/
├── extension.ts # Entry: multi-session management, connect/reconnect, status bar
├── sseClient.ts # SSE event stream client (auto-reconnect, tool events)
├── snapshotStore.ts # In-memory snapshot storage (baseline + post-AI content)
├── decorationManager.ts # Editor decoration rendering (red/green highlights + insets)
├── diffCodeLens.ts # CodeLens provider (Accept / Reject buttons)
├── reviewPanel.ts # Sidebar panel
├── diffContentProvider.ts # Native diff view content provider
├── commands.ts # Command registration
└── storePool.ts # Multi-session snapshot pool
# Compile TypeScript
npm run compile
# Package .vsix
npm run packageInternally: esbuild bundles the source + diff dependency into a single out/extension.js, then @vscode/vsce generates the .vsix.
This is a personal project built by an individual developer — core features work, but expect rough edges. Always welcome to any contributions!
-
Sidebar → native diff view breaks proposal API insets: Clicking a filename in the sidebar panel opens a VS Code native diff view, which causes the proposed API insets (red deletion lines) to malfunction — the before/after diff comparison fails to render, degrading to CodeLens-only display. Reload the window to restore normal diff view.
-
Scrolling while many webview insets are visible causes high CPU: When AI modifies a large number of hunks, each deleted chunk gets its own webview inset. Scrolling through the file with the mouse wheel while many webviews are present causes continuous re-rendering that spikes CPU usage. Note: using the sidebar panel's file expand/collapse to navigate between modification positions does not trigger this issue.
-
First modification may get silently accepted after subsequent edits: In rare cases, the first hunk tracked by DiffGate is automatically accepted after AI makes additional modifications (2nd, 3rd, etc.). The root cause is unclear and cannot be stably reproduced.
-
First file's diff gets auto-accepted after second file is modified: When AI modifies multiple files sequentially, the pending diff in the first file may be silently accepted (removed from the sidebar) after the second file's modification completes. Root cause unknown, cannot be stably reproduced.
- In-memory snapshots are not persistent. Closing VS Code or reloading the window loses all pending review state.
- Only
write/edittools are tracked. AI changes made viashell,command, or other indirect methods are not captured. - OpenCode CLI must be available in the terminal for auto-start to work.
- Red deletion insets depend on proposed API. Without
--enable-proposed-api, only green highlights + CodeLens are shown.
This project is open source under the MIT License. See LICENSE.md for the full text.
Third-Party Notices — This project incorporates code and inspiration adapted from the following open-source projects:
- hunkwise — The inline decoration manager (red deletion insets), sidebar review panel UI, and splash screen were adapted from hunkwise. Licensed under MIT. Copyright (c) the hunkwise contributors.
- AI Diff Viewer by mtglitch — The snapshot-based inline diff review approach and per-hunk tracking logic were studied as reference.
- AI CLI diff view by konan1947 — The extension's SSE event handling design was referenced.
- Diffus by RostislavDugin — The workspace snapshot and filesystem detection patterns were reviewed.