Repository navigation
Description
Summary
Desktop Review can sit forever on both panes:
- Sidebar: Filter files (
筛选文件), then加载中... - Preview: Loading changes (
正在加载更改…)
This is one shared pending flag, not two independent loaders. Related but not the same as #49260 (non-git directory) and #42964 (eager full diffs making Desktop unresponsive).
Environment
- OS: Windows 10/11
- Client: OpenCode Desktop Review tab (session-ui v2 sidebar + preview)
- Workspace: git repository (not a non-git folder)
Reproduction
- Open a session in Desktop for a git project.
- Click Review.
- Leave the panel open.
Observed: left tree and right diff stay on loading copy with no empty state and no error.
A heavy working tree makes this easy to hit. git status --porcelain --untracked-files=all plus per-untracked git diff --no-index will run against every untracked file. A local Electron unpack directory with thousands of files is enough to keep the request outstanding.
Expected
- Bound the VCS request; if it fails or times out, show an error, not a spinner.
- If there is nothing to review, show the empty state.
- Do not treat
isPendingas still loading when the query is disabled or never started.
Actual
Both panes key off createSessionReview().ready():
const ready = () => {
if (mode() === "git" || mode() === "branch") return !vcsQuery.isPending
return true
}- Sidebar loading:
ReviewPanelSidebardiffsReadyfallback (common.loading). - Preview loading:
ReviewPanelEmptywhen mode isgit/branchand!ready()(session.review.loadingChanges).
vcsQuery has no timeout. ready() ignores isError / fetchStatus. TanStack Query v5 keeps isPending === true when there is no cached data even if enabled is false, so a disabled query (disconnected, missing project.vcs, review not yet wanted) also looks like an in-flight load.
Working-tree diffs then call git status --untracked-files=all and may statUntracked / patchUntracked (git diff --no-index) per ?? path in packages/core/src/plugin/vcs/git.ts. That can run for a long time on large untracked trees, so isPending never clears.
Suggested fix
- Treat loading as
isFetching && !isFetched(orfetchStatus === "fetching"), not rawisPending. - Add an error empty state when
isError. - Cap/timeout
GET /api/vcs/diff; skip or bound untracked blobs instead of onegit diff --no-indexper file. - Keep ignored build/unpack dirs out of status (
--untracked-files=normalor respect ignore rules strictly).
Activity
13579ADGJLzcbm commentedon Oct 27, 2026
Confirming on Desktop 2.1.4 (Windows 11, bundled CLI 2.1.4). The heavy-working-tree path here does more than leave the Review pane loading: it black-screens the entire session view.
Environment
git status --porcelain -uall), 57,666 files on disktabs.panes.<key>.review = true)Repro
Measurements (local service, Basic auth)
GET /api/vcs/diff?location[directory]=<repo>&mode=working-> no response within 60s (client aborts at 60s). Call it again and it hangs again.GET /api/session/<id>/diff-> 200, 4.9 MB, 2.96s for a session that had touched a single 945 KB one-line file.renderer.log:[server-request-queue] server thrashing detectedevery 10s, plus continuousResizeObserver loop completed with undelivered notifications.Root-cause pointers (HEAD)
packages/gui-plugins/src/review/model.ts:127—const chosen = stored()?.mode ?? "git"; every session defaults to the whole working tree.:164—enabled: ... && wantsReview() && ...; this fires on mount when the side pane is persisted open.:186— the details query also callsvcs.diff({ mode: "working" })unbounded.:239—rows()returns the full array; no file-count or patch-size cap before rendering.mode=workingenumerates every untracked path, so 42k untracked files is an effectively unbounded request.Workaround I applied locally (patched app.asar, not upstream)
"git"->"turn"(session diff only)tabs.panes.*.reviewso Review starts closedSuggested fix
Related: #42964 (closed, eager full-file diffs), #51216 (service kill/restart loop when snapshot blocks
/api/info), #57441.Dante-dan commentedon Oct 27, 2026
The remaining plain working-tree query noted in the #59526 analysis is the session-location menu's change summary. I wired that query through the
untracked=foldersAPI added by #57527, matching the Review list and avoiding per-file patches for files inside untracked directories. The existing project-menu keeper now checks the actual request parameter.Fixed compare. This covers the location-menu request; the persisted-open Review blackout still needs Desktop/Windows validation.
bun run check(35 tasks) andlint:changedpass on Bun 1.4.4 / Node 24.12. Local Playwright launch is denied by macOS MachPort permissions, so I could not execute the browser assertion. The existing VCS folder fixture hit its 30-second timeout;typecheck:e2ealso reports 11 diagnostics in untouched test/performance files.opencodejr commentedon Oct 28, 2026
Thanks for the detailed report. I tried this on Linux with
@opencode/[email protected]: a git repo with about 23,000 untracked files (40 folders of 500 files plus 3,000 loose files), callingGET /api/vcs/diff?mode=workingon the server directly. The request finished in about 4 seconds and returned around 5.6 MB, so I couldn't get it to hang. I can't run the Windows Desktop app here, and the slowness seems to depend on Windows, where eachgitprocess starts much more slowly. The >60s measurement in the comment above fits that.I couldn't check the UI side either: whether the Review panes stay on loading while that request is slow, or after it fails or the server disconnects. That needs someone with Windows and the Desktop app.
Closely related:
/api/vcs/diffslow), but there the whole session view goes blackgitprocess per fileIf you can, these would help a maintainer reproduce it:
git status --porcelain --untracked-files=alllists