How Watch Mode Auto-Updates the Code-Review-Graph on File Changes
The code-review-graph VS Code extension implements watch mode through a coordinated two-part system: an external CLI daemon that rebuilds the graph database when source files change, and VS Code-side file watchers that detect those database updates and refresh the UI.
Watch mode in the tirth8205/code-review-graph extension eliminates manual rebuilds by continuously synchronizing the code review graph with your evolving codebase. This article breaks down exactly how the auto-update mechanism works by examining the source code implementation.
The Watch Mode Architecture
Watch mode operates across process boundaries. The extension delegates file monitoring to a separate CLI process, then reacts to the results through VS Code's file system APIs.
This design separates concerns: the CLI handles expensive parsing and graph construction, while the extension focuses on lightweight UI updates.
Part 1: Starting the CLI Daemon
When a user triggers watch mode through the Watch Graph command, the extension spawns the external code-review-graph CLI in watch mode.
Command Registration in extension.ts
The command palette entry is wired in src/extension.ts:
// registers the "Watch Graph" command
vscode.commands.registerCommand("codeReviewGraph.watchGraph", async () => {
const workspaceRoot = getWorkspaceRoot();
if (!workspaceRoot) {
vscode.window.showErrorMessage("No workspace folder is open.");
return;
}
vscode.window.showInformationMessage("Code Graph: Watch mode started.");
const result = await cli.watchGraph(workspaceRoot);
if (!result.success) {
vscode.window.showErrorMessage(`Code Graph: Watch failed. ${result.stderr}`);
}
});
The cli.watchGraph() call delegates to CliWrapper.watchGraph() in src/backend/cli.ts (lines 83-86), which launches the CLI with the --watch flag.
What the CLI Daemon Does
Once started, the CLI process:
- Scans the workspace for source files
- Builds the initial code review graph
- Writes the result to
.code-review-graph/graph.db - Enters a persistent watch loop monitoring the filesystem
- Rebuilds affected graph portions on any add/change/delete event
- Atomically updates
graph.dbwith each rebuild
The extension does not poll or directly observe source files—it relies entirely on this external process to detect and process changes.
Part 2: Watching the Database File
The extension's role begins after the CLI writes its output. Two coordinated watchers detect changes to graph.db and trigger UI refreshes.
The watchGraphDb() Function
In src/extension.ts (lines 94-107), watchGraphDb() creates a workspace-scoped file watcher:
function watchGraphDb(context: vscode.ExtensionContext): void {
const watcher = vscode.workspace.createFileSystemWatcher(
"**/.code-review-graph/graph.db"
);
const dbPathRef = { current: "" };
const workspaceRoot = getWorkspaceRoot();
if (workspaceRoot) {
const dbPath = findGraphDb(workspaceRoot);
if (dbPath) {
dbPathRef.current = dbPath;
}
}
// Reload when the file is written
watcher.onDidChange(() => {
if (sqliteReader && dbPathRef.current) {
sqliteReader.close();
sqliteReader = new SqliteReader(dbPathRef.current);
vscode.commands.executeCommand("codeReviewGraph.codeGraph.refresh");
}
});
// Create a new reader on first creation
watcher.onDidCreate(async () => {
const wsRoot = getWorkspaceRoot();
if (wsRoot && !sqliteReader) {
const dbPath = findGraphDb(wsRoot);
if (dbPath) {
dbPathRef.current = dbPath;
sqliteReader = new SqliteReader(dbPathRef.current);
vscode.commands.executeCommand("codeReviewGraph.codeGraph.refresh");
}
}
});
// Dispose the reader when the file is deleted
watcher.onDidDelete(() => {
sqliteReader?.close();
sqliteReader = undefined;
dbPathRef.current = "";
});
context.subscriptions.push(watcher);
}
This handler manages three lifecycle events:
onDidChange– The most common case: database exists and gets updated. Closes the oldSqliteReader, instantiates a new one, and triggers view refresh.onDidCreate– Initial database creation, typically after first watch mode start or manual rebuild.onDidDelete– Cleanup when the database is removed, preventing errors from stale file handles.
The GraphWatcher Class with Debouncing
For more controlled observation, src/backend/watcher.ts (lines 25-52) provides a reusable GraphWatcher class:
export class GraphWatcher implements vscode.Disposable {
private readonly watcher: vscode.FileSystemWatcher;
private readonly disposables: vscode.Disposable[] = [];
constructor(dbPath: string, onChanged: () => void) {
const dir = path.dirname(dbPath);
const filename = path.basename(dbPath);
this.watcher = vscode.workspace.createFileSystemWatcher(
new vscode.RelativePattern(vscode.Uri.file(dir), filename),
);
const debouncedOnChanged = debounce(onChanged, 500);
this.disposables.push(
this.watcher.onDidChange(() => debouncedOnChanged()),
this.watcher.onDidCreate(() => debouncedOnChanged()),
this.watcher,
);
}
dispose(): void {
for (const d of this.disposables) {
d.dispose();
}
this.disposables.length = 0;
}
}
The 500ms debounce prevents rapid-fire refreshes during active editing sessions when the CLI may write multiple incremental updates.
How the UI Refreshes
After the database reloads, the extension triggers codeReviewGraph.codeGraph.refresh via VS Code's command system. This command (implemented in src/views/treeView.ts) rebuilds the tree view nodes from the new SqliteReader instance without requiring a full extension restart.
The complete data flow:
- Developer saves a source file
- CLI daemon detects change → rebuilds graph → writes
graph.db - VS Code
FileSystemWatcherfiresonDidChange - Extension closes old reader, opens new reader
- Tree view refreshes with updated graph structure
Key Implementation Files
| File | Purpose |
|---|---|
src/backend/cli.ts |
CliWrapper.watchGraph() starts external CLI in watch mode |
src/backend/watcher.ts |
GraphWatcher class provides debounced file observation |
src/extension.ts |
Registers watch command, implements watchGraphDb() lifecycle |
src/views/treeView.ts |
Handles codeReviewGraph.codeGraph.refresh command for UI updates |
Summary
- Watch mode uses a two-process design: CLI daemon monitors source files; VS Code extension watches the output database
CliWrapper.watchGraph()insrc/backend/cli.tsspawns the persistent CLI processwatchGraphDb()insrc/extension.tscreates aFileSystemWatcherfor**/.code-review-graph/graph.db- Database changes trigger reader recreation: Old
SqliteReadercloses, new instance opens, tree view refreshes GraphWatcherinsrc/backend/watcher.tsadds 500ms debouncing for stability during rapid updates
Frequently Asked Questions
How do I start watch mode in code-review-graph?
Run the "Watch Graph" command from the VS Code Command Palette (Ctrl+Shift+P / Cmd+Shift+P). This executes codeReviewGraph.watchGraph, which starts the CLI daemon. You'll see a confirmation message when watch mode begins.
Does watch mode work with multiple workspace folders?
The current implementation in src/extension.ts uses getWorkspaceRoot() to identify a single workspace root. Multi-root workspace support would require extending the watcher to handle multiple .code-review-graph/graph.db files simultaneously.
Why does the graph sometimes take a moment to update?
The 500ms debounce in GraphWatcher and the CLI's rebuild latency both contribute to a brief delay. This intentional throttling prevents UI flicker and reduces resource consumption during active development with frequent file saves.
What happens if I delete the graph.db file while watching?
The onDidDelete handler in watchGraphDb() closes the SqliteReader, clears the reference, and updates the internal path tracker. The extension gracefully handles deletion; watch mode continues, and the graph will recreate when you restart watch mode or rebuild manually.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →