fix(cli): fix hanging sessions on huge-file diffs#9119
Conversation
Large snapshot diffs (tens of thousands of lines) ran the Myers algorithm synchronously on the TUI worker thread, starving the abort endpoint and SSE heartbeats. Cap inputs, offload structuredPatch to a dedicated worker, and race the session summary against a timeout + cancel signal so ESC actually stops the work.
# Conflicts: # packages/sdk/openapi.json
marius-kilocode
left a comment
There was a problem hiding this comment.
Its quite a complicated change for a seemingly small fix. Are you sure the complexity is worth it?
Code Review SummaryStatus: 1 Issues Found | Recommendation: Address before merge Overview
Fix these issues in Kilo Cloud Issue Details (click to expand)WARNING
Other Observations (not in diff)Issues found in unchanged code that cannot receive inline comments:
Files Reviewed (2 files)
Reviewed by gpt-5.4-20260305 · 1,440,918 tokens |
Core fix (what actually addresses the freeze)
That's the trivial fix. Everything else — added in the name of doing it "properly":
|
Merge origin/main into fix/snapshot-diff-freeze. Conflicts resolved: - packages/opencode/script/build.ts: keep kilocode diff-worker entrypoint alongside upstream rgPath ripgrep worker. - packages/opencode/src/file/index.ts: port kilocode DiffEngine.shouldSkip guard onto upstream's effect-based gitText/git.show flow. - packages/opencode/src/project/vcs.ts: accept upstream rename ServiceMap -> Context; drop unused structuredPatch/formatPatch imports (kilocode routes through DiffEngine.patchAsync). - packages/opencode/src/session/summary.ts: keep kilocode SummaryDispatch for tracked summarize/cancel alongside upstream Layer.suspend defaultLayer. - packages/sdk/openapi.json: take origin/main (no kilocode server changes).
Revert the worker pool, dispatcher, flags, and related scaffolding added on top of the initial cap guard. Post-#9046, the only remaining CLI callers of Vcs.diff are one-shot review opens, so the worker offload is no longer needed. The freeze repro is eliminated by the input caps in DiffEngine.shouldSkip alone. Shrinks the fork diff from 28 files (+1063) to 6 files (+199) and reduces shared opencode files with kilocode_change markers to 2.
|
@marius-kilocode I have removed the migration of git diff to another thread - that should happen in upstream OpenCode. I kept only skipping files too big from the diff - targeted fix with minimal code. Please check again. |
# Conflicts: # packages/opencode/src/snapshot/index.ts
Files over a few thousand lines no longer hang the session for minutes during summary generation or file view. Diffs for files of any size now render with full content in the TUI, VS Code sidebar, and web UI — previously they either froze the event loop or were reported with empty patch text.
The git-based diff path has been reliable across all tests and in production since the TUI-freeze fix shipped. Removing the JS Myers fallback eliminates ~220 lines of belt-and-suspenders code (a size-cap guard, a git cat-file blob loader, and a per-file git show fallback). If git ever fails now, callers emit an empty patch string; additions/deletions from git --numstat still come through unchanged.
The previous commit deleted ~150 lines of upstream OpenCode diff code because the git-based path always runs first. Restoring those lines as dead code (behind an early-return kilocode_change block) keeps our diff from upstream minimal, so future OpenCode syncs to the hot diffFull code path don't conflict. No runtime behavior change — the git-based DiffFull path still short-circuits before the restored Myers loop executes.
Why
The CLI could appear to lock up after a turn — typing would stop responding, ESC would not interrupt, and live updates would freeze. This happened when a file you edited was very large (tens of thousands of lines). On top of that, the file diff preview for large files came back empty, so you could not see what actually changed.
What changed
Diffs are now produced by git itself instead of an in-process JavaScript diff algorithm. The session stays responsive on edits of any size, and the full diff of large files is visible in the TUI, VS Code sidebar, and web UI instead of showing an empty patch.
Windows safety
This remains Windows-safe because diff generation is still delegated to git, the active callers pass normalized slash-separated paths instead of platform-specific separators, and subprocess spawning already uses the existing Windows-safe handling that hides console windows; Linux behavior is unchanged for the same reason.
Non-git folders
In folders without a git repository, this change is a no-op: diff generation is skipped and the UI still returns plain file contents with no patch, so there is no new failure mode or behavior change outside git-backed projects.
How to test
bun devThis rewrites every line of freeze.txt between snapshots, which is the worst case for the old diff implementation.
On stable v7.2.10 the TUI locks for ~28s after the assistant says "Done" — during that window typing and ESC are dead, and the file preview for freeze.txt comes back empty.
On this branch the TUI stays live and the freeze.txt preview shows the full diff.
Screen.Recording.2026-04-17.at.17.16.48.mov