feat(desktop): populate file panel Diff/History from session snapshots#158
Merged
Conversation
The desktop file panel's Diff/History tabs were always empty: the renderer runs core's runAgent without a SessionManager (the webview has no node:fs), so core's snapshot capture (agent.ts) never fired for desktop sessions. Capture snapshots on the Rust side instead, mirroring core's on-disk format (~/.deepcode/sessions/<id>/snapshots/ — manifest.jsonl + blobs) so /rewind interops: - snapshots.rs: capture_file_snapshot + session_snapshots(sessionId, filePath) command. sha2 for the hash; ISO/blob timestamps hand-rolled (no chrono). - tool_write/tool_edit take an optional session_id and capture a pre+post pair per mutation, best-effort (a snapshot hiccup never fails the edit). The post is stamped +1ms so history timestamps never collide. - mac-session.ts publishes the active session id (mac-agent -> mac-tools + panel) so tools snapshot under it and the panel reads them back. Render it: - diff.ts: pure LCS line differ -> DiffLine[]. - file-history.ts: snapshots -> History timeline (consecutive identical states collapsed) + Diff baseline (oldest snapshot). - useFilePanel.open fetches a file's snapshots -> Diff (current vs session baseline) + History; selectHistory(ts) recomputes the diff against that revision and jumps to the Diff view. Diff defaults to the NET session change (oldest snapshot -> current) — the "what did this conversation do to this file" view. Tests: +5 Rust (capture<->list roundtrip, capture-pair seq/ms, time fmt), +15 TS (differ, history mapping), +2 reducer. Verified the full hook flow (Diff, History, selectHistory) in the mock-Tauri preview. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
… titlebar The right activity rail was icon-only (tooltips on hover only), so the Inspector / Files / Settings toggles were not self-explanatory. Add a text label under each icon (rail 48->64px) and surface the active right-panel's name centered in the otherwise-empty macOS titlebar strip (pointer-events:none keeps it OS-draggable, matching the shell's no-webkit-drag approach). No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The desktop file panel (FilePanel.tsx) has Source / Diff / History tabs, but Diff + History were always empty — the follow-up noted in use-file-panel.ts ("Diff/History data is left empty here — those are backed by session snapshots, wired in a follow-up").
This wires both tabs to session snapshots.
Why it needed Rust-side capture
Core captures snapshots in agent.ts (pre/post each Edit/Write) — but only when a
SessionManageris passed. The desktop runs core'srunAgentin the renderer (mac-agent.ts) and deliberately passes no manager (the webview has nonode:fs). So desktop sessions captured zero snapshots. The fix captures them on the Rust side instead.How
Rust (
apps/desktop/src-tauri/src/)snapshots.rs(new):capture_file_snapshotwrites a blob + appendsmanifest.jsonlunder~/.deepcode/sessions/<id>/snapshots/— the same on-disk layout/shape as core (filePath, capturedAt, reason, hash, size, seq, blobPath, kind) so/rewindinterops. Addssession_snapshots(sessionId, filePath)command. Usessha2for the hash; ISO + blob timestamps are hand-rolled (nochrono).tools.rs:tool_write/tool_edittake an optionalsession_idand capture a pre + post pair per mutation. Best-effort — a snapshot hiccup never fails the user's edit. The post snapshot is stamped +1ms so two history rows never collide on a millisecond timeline.mac-session.ts(new): publishes the active session id (mac-agent→mac-tools+ panel) so tools snapshot under it and the panel reads them back, with nomac-agent ↔ mac-toolsimport cycle.Renderer
diff.ts(new): pure LCS line differ →DiffLine[](testable, no deps).file-history.ts(new): snapshots → History timeline (collapses consecutive identical states) + Diff baseline (oldest snapshot).useFilePanel.openfetches a file's snapshots → Diff (current vs session baseline) + History;selectHistory(ts)recomputes the diff against the chosen revision and jumps to the Diff view.Diff semantics
The Diff tab defaults to the net session change — oldest snapshot → current file — i.e. "what did this conversation do to this file". (The task suggested most-recent-pre-edit vs current; for a multiply-edited file the net view is the more useful default, and the History tab drills into individual revisions. One-line change if you'd prefer last-edit-only.)
Tests / verification
cargo build --releasecompiles clean under LTO. (CI does not build Rust — ran locally.)setDiff.typecheck/lint(0 new warnings) /format:check/ desktopvite buildall green.preview-app.html): opened the file, confirmed the Diff renders the real computed baseline diff, History shows the deduped timeline, and selecting a History row recomputes the diff vs that revision + switches to Diff.Diff + History tabs (mock-Tauri preview)
Diff =
<meta charset>added,<canvas>changed (del+add),<script>block added (oldest snapshot → current); History = 3 deduped rows with tool badge + time.Remaining manual step
A live packaged-app check (build the
.app, run a real agent Edit/Write, open the file → confirm Diff/History populate) needs DeepSeek credentials + GUI interaction, so it's not automated here. The Rust↔JS IPC mapping (camelCase→snake_case) follows the existingtool_read/tool_editconvention already shipping in prod.🤖 Generated with Claude Code