feat(desktop): show a pull request's review threads in its Overview

Merged
DA
2d ago
+1556-25

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 GraphQL reviewThreads(last: 100) read on the App's installation token, run alongside the existing REST reads. I checked that GraphQL works on the installation token: viewer answers luke-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 in more. 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 COMMENTED review 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.
  • Wire: the review entry gets optional threads (ReviewThread), plus DIFF_SIDE and OVERVIEW_BOUNDS.MAX_THREADS / MAX_THREAD_COMMENTS. github-people.ts names thread authors the same way as other people. Each thread keeps path, lines, original lines, sides and diffHunk, so a later PR can place threads inline in Files changed.
  • Renderer (agent-pull-request-tab.tsx): a ThreadCard inside the review's EntryCard.
    • 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's threadPreview). It is drawn with the same rows and colours as Files changed; those rows moved unchanged into diff-rows.tsx so both views share them.
    • Comments are drawn with PersonRef and GitHubWords.
    • 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, --raised on 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 AgentChangesTab and 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; more and the overflow count into earlier; 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.
  • 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 optional threads array, and its thread and comment shapes, on the overview's conversation entry, in both coding-agent-wire-codingAgentOverviewAnswerSchema.json and coding-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.sh green. (CI)
  • JSON Schema goldens unchanged (LUKE_UPDATE_FIXTURES not 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 as type assertion outside the allowlisted files. (CI via anti-slop)
  • No Effect.runPromise/runSync/runFork outside 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.md sentence naming a changed part is edited: none names these parts.
  • PRIVACY.md changed: 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/diffs once Files changed moves there.

Made with Luke


Devin Review


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.md now discloses the read in the Pull request tab paragraph.