feat(desktop): show a pull request's review threads in its Overview
Merged
DA
2d ago+1556+1556+0123456789012345678901234567890123456789-25-25-01234567890123456789
Summary
The prompt: show a pull request's review comment threads, each with a preview of the code it's on, in the Overview of an agent's Pull request tab. Base the design on ReviewStage/stage-cli, but draw it in Luke's own parts. Until now the Overview never read line comments, so a review that only left line comments showed nothing.
- Service (
pull-requests.ts): one GraphQLreviewThreads(last: 100)read on the App's installation token, run alongside the existing REST reads. I checked that GraphQL works on the installation token:vieweranswersluke-agent[bot]. For each thread it reads the path, current and original line or range, the diff side,diffHunk, resolved, outdated, and up to 50 comments with author,bodyHTML, time and URL.- A draft's comments are left out.
- A bot's GraphQL login gets back the
[bot]suffix its REST login has. - A deleted author is shown as GitHub's ghost account.
- Bounds: threads beyond 100 are added to
earlier, and each thread counts its replies beyond 50 inmore. There is no character budget. - If GitHub refuses the GraphQL read, or answers with errors only, the threads are left out with a warning and the rest of the overview still loads.
- Grouping: each thread goes under the review its first comment was made in, matched by review id, as stage-cli groups them.
- A
COMMENTEDreview with no words is now an entry when it started a thread. - A thread whose review isn't listed stands at its own time as a review by its first commenter.
- A
- Wire: the review entry gets optional
threads(ReviewThread), plusDIFF_SIDEandOVERVIEW_BOUNDS.MAX_THREADS/MAX_THREAD_COMMENTS.github-people.tsnames thread authors the same way as other people. Each thread keeps path, lines, original lines, sides anddiffHunk, so a later PR can place threads inline in Files changed. - Renderer (
agent-pull-request-tab.tsx): aThreadCardinside the review'sEntryCard.- The header shows the file path, cut at its start so the file name stays visible, and the line or range.
- The preview is the end of the frozen hunk: from 3 rows above the range down to the commented line (
changes-model.ts'sthreadPreview). It is drawn with the same rows and colours as Files changed; those rows moved unchanged intodiff-rows.tsxso both views share them. - Comments are drawn with
PersonRefandGitHubWords. - Resolved and outdated threads start folded under "Resolved" / "Outdated" labels and open on click, using the transcript's own
Fold. - Styling follows the page's own parts: each thread is boxed like the Checks list, its head is a row like a check's with the chevron at its end, the labels use the quiet badge a bot's name wears, and spacing uses the page's tokens (
--boxed-inset,--raisedon hover).
- PRIVACY.md: the Pull request tab paragraph now says it reads review threads. This is a disclosure of the new read, not a new policy.
Not done:
- Opening the path in Files changed. It would mean lifting the chosen file out of
AgentChangesTaband driving the view switch, which is being reworked elsewhere. - stage-cli's "hide resolved" toggle. The prompt didn't ask for it.
Evidence
pnpm exec vitest run packages/service/src/github/pull-request-overview.test.ts: 7 passed. 2 new tests:- Threads nest under a review that only left line comments; the draft comment is dropped;
moreand the overflow count intoearlier; the bot login gets its suffix; a thread whose review isn't listed stands on its own. - A 403 or errors-only GraphQL answer leaves the overview standing.
- Threads nest under a review that only left line comments; the draft comment is dropped;
pnpm exec vitest run apps/desktop/src/renderer/tasks/agent-pull-request-tab.test.ts: 7 passed. 1 new test covers the preview rows and numbers, the head, comments, "2 more replies", and a resolved/outdated thread folded until clicked.apps/desktop/src/renderer/tasks/changes-model.test.ts(new): 3 passed. It covers a left-side line, a range across both sides, a missing line, and an unreadable hunk.- JSON Schema goldens re-recorded with
LUKE_UPDATE_FIXTURES=1. The only diff is the new optionalthreadsarray, and its thread and comment shapes, on the overview's conversation entry, in bothcoding-agent-wire-codingAgentOverviewAnswerSchema.jsonandcoding-agent-view-codingAgentOverviewAnswerViewSchema.json. pnpm check:affected: typecheck passed, and lint, knip, oxlint and discarded-effect pass after fixes. Of 189 desktop test files, 188 pass. The one that fails,src/main/app-menu.test.ts, does so only because this sandbox has no Electron binary ("Electron failed to install correctly"), which has nothing to do with this change.- Throwaway harness screenshots of the tab (deleted before commit) are below.
Screenshots
Throwaway harness, side panel at 620px. Left: dark, with the resolved and outdated thread folded. Right: light, with that thread opened by a click.

Invariants
-
./scripts/check.shgreen. (CI) - JSON Schema goldens unchanged (
LUKE_UPDATE_FIXTURESnot run, or diff explained line by line). (CI): re-recorded, see Evidence. - Every behavior change has, in this PR, the test that fails without it; no change-detector test added.
- Gateway envelope goldens unchanged. (CI)
- No new
astype assertion outside the allowlisted files. (CI via anti-slop) - No
Effect.runPromise/runSync/runForkoutside the runtime edges. - No new
setTimeout/setInterval/new Promise/AbortController/fs.watch. - No Effect, Stream, or Layer written as a statement and dropped.
- Test count delta: +6 (2 service, 1 tab, 3 changes model).
- Each hand-rolled file the PR replaces is deleted: none replaced.
- Every
CLAUDE.md/AGENTS.mdsentence naming a changed part is edited: none names these parts. -
PRIVACY.mdchanged: the review-thread read is disclosed (see Summary). - Package deps unchanged.
- Barrel/door rule unaffected.
Notes
- Blockers or follow-up verification: the Mac look is unverified beyond the harness, since CI is Linux only. A follow-up may move the previews to
@pierre/diffsonce Files changed moves there.
Made with Luke
Summary by cubic
Shows a pull request's review threads in its Overview, so a review that only left line comments is no longer invisible.
- Reads up to 100 review threads over GraphQL on the App's installation token, each with up to 50 comments; if that read fails or GitHub answers only errors, the threads are left out with a warning and the rest of the overview still loads.
- Groups each thread under the review its first comment was made in; a thread whose review isn't listed stands at its own time as a review by its first commenter.
- Draws each thread with its file path, lines, an end-of-hunk preview in Files changed's own diff rows, and its comments; resolved and outdated threads start folded under their labels and open on click.
PRIVACY.mdnow discloses the read in the Pull request tab paragraph.