feat(desktop): reply to PR review threads from the Changes pane

Merged
AV
2mo ago
+608-94

Summary

  • The workspace Changes pane can now reply to PR review threads and post them to GitHub, matching the PR view's Code tab. Each thread bubble gets a reply box (Cmd/Ctrl+Enter submits) and a Reply button beside Resolve.
  • New workspace-scoped git.replyToReviewThread mutation. The GitHub call it shares with pullRequests.replyToThread moves into one helper so the two surfaces can't drift.

Why / Context

Review threads already rendered inline in the Changes pane with resolve/unresolve, but answering one meant leaving for the PR view or GitHub. The PR view had the full reply flow, so this ports that implementation over rather than inventing a second one.

How It Works

  • git.getPullRequestThreads already returns each comment's REST databaseId; useDiffAnnotationsByPath now puts the first comment's id on the thread metadata as replyToCommentId.
  • DiffPane's CommentThread owns a git.replyToReviewThread mutation. On send it clears the draft; on success it invalidates the workspace threads query, and the annotation version hash already includes comment count, so the new comment renders on the next refetch. On failure it toasts and hands the draft back (unless a new one was started).
  • git.replyToReviewThread looks up workspace → linked PR row and posts via pulls.createReplyForReviewComment using the PR row's repo owner/name/number. A comment id from another PR 404s rather than landing somewhere unexpected.
  • replyToReviewComment (new, git/utils) wraps the octokit call plus actionRejectionError mapping; pullRequests.replyToThread is refactored onto it.

Manual QA Checklist

Not run against the live app: no dev app was running from this worktree, and posting a real reply to GitHub is outward-facing. Worth a pass before merge:

  • In a workspace linked to a PR with review comments, open the Changes pane: each thread shows the reply box under the comments
  • Type a reply and click Reply (or Cmd+Enter): it appears on GitHub and shows in the thread within the 30s poll or on window focus
  • Reply stays disabled while the draft is blank or a post is in flight
  • With network off or a revoked token: "Couldn't post reply" toast and the draft comes back
  • Resolve / Unresolve still work beside the new button
  • Resolved and outdated threads still start collapsed; expanding shows the reply box

Testing

  • bun run typecheck (host-service and desktop)
  • bun test src/trpc/router/git src/trpc/router/pull-requests in host-service (145 pass). New reply-to-review-thread.test.ts: happy path, blank body rejected before GitHub, no linked PR → NOT_FOUND, GitHub 404 → NOT_FOUND
  • bun test on the DiffPane tree in desktop (30 pass). New CommentThread.test.tsx: submit + clear + invalidate, Cmd+Enter, disabled states, in-flight guard, orphaned thread keeps its draft, failure restores the draft
  • bun run check:i18n clean. Every string the reply box uses already exists in all 17 locales from the PR view, so no catalog changes
  • bun test in packages/i18n (enforced-dirs, display-only) and biome check on the changed files

Design Decisions

  • PR row over resolveGithubRepo for the reply target: getCheckJobLogs already uses the PR row; it needs no remote parsing and names exactly the repo the comment ids came from.
  • Draft restore on failure: the PR view clears optimistically and can't restore because its reply is a prop callback. Here the component owns the mutation, so restoring is two lines. A small, deliberate divergence.

Follow-ups

  • The resolve/unresolve GraphQL mutation is still duplicated between git.setReviewThreadResolution and pullRequests.setThreadResolution. The same shared-helper treatment would fit; left out to keep this focused.

https://claude.ai/code/session_01DQF36hf8kmYHRggDxFwXuk


Summary by cubic

Adds reply support for PR review threads in the workspace Changes pane, matching the PR view's Code tab. You can now type a reply in each thread and submit it to GitHub; previously the pane only allowed resolving/unresolving threads.

New Features

  • Adds a reply box and Reply button to each thread bubble; Cmd/Ctrl+Enter also submits.
  • New workspace-scoped git.replyToReviewThread mutation posts the reply to the linked PR.
  • Failed replies toast an error and restore your draft.

Refactors

  • The reply box is now a shared ReviewThreadReplyComposer, used by the Changes pane and the PR view's Code tab.
  • The GitHub reply call and error mapping now live in a shared helper used by pullRequests.replyToThread and the new mutation.
  • Thread metadata now carries the first comment's database id so replies thread onto the correct comment.

Summary by CodeRabbit

  • New Features

    • Added the ability to reply directly to review comment threads in the diff view.
    • Replies support trimmed text, Reply button, and Ctrl/Cmd+Enter submission.
    • Drafts are preserved when posting fails, with controls disabled for blank drafts or while submitting.
    • Reply controls are now consistent across diff and pull request review threads.
  • Bug Fixes

    • Review replies are correctly associated with the selected comment thread.
  • Tests

    • Added coverage for reply submission, validation, pending states, draft handling, and error scenarios.