feat(service,features,desktop): submit a review on an agent's pull request as the member who presses

Merged
DA
3d ago
+995-35

B1 of the "Review and comment" stack, stacked on #3272 (feat/pull-request-member-writes). The task: port stage-cli's review panel to the Pull request tab. You choose Approve, Request changes or Comment, with an optional Markdown body. GitHub's refusals show in GitHub's own words, the conversation is read again after submitting, and if the member already has a pending review, that review is the one submitted.

Wire

The action union in pull-request-write-wire.ts gets one new member, and there is no parallel path:

  • { action: "submit-review", event: "comment" | "approve" | "request-changes", body }
  • The body is capped at MAX_BODY_CHARS, 65,536 characters, which is GitHub's own limit for a comment.
  • The endpoint's body limit grows to match: up to 6 bytes per character as JSON, plus 4 KiB.

Service

submitPullRequestReview in github/pull-request-writes.ts runs on the member's token through githubWrite, behind memberPullRequestWrite, so the rule from #3272 still applies: it acts as the member and never falls back to the App.

  1. It reads the PR's pending reviews and picks the one where viewerDidAuthor is true.
  2. If there is one, it sends submitPullRequestReview on that review, so any comments the member started it with get published.
  3. If not, it sends addPullRequestReview with the event, which creates and submits the review in one step.
  4. An empty body is left unsent, so a pending review keeps whatever text it already has.

Nothing is refused on Luke's side that GitHub might allow. For example, approving your own pull request comes back as GitHub's refusal, in its words.

UI

While the pull request is open or a draft, the bar gets a Review button that opens pull-request-review.tsx, a popover like stage-cli's:

  • It has a Write / Preview Markdown field, the three choices with descriptions, Cancel, and Submit review. ⌘↩ submits and Escape closes.
  • The review gets its own usePullRequestWrites instance, separate from the pill's. That lets GitHub's answer show inside the panel instead of under the bar, and offer Sign in with GitHub when needed.
  • When GitHub accepts the review, the panel closes and clears its text, and the tab reads again.
  • If the panel is closed by a stray click, the text you wrote is still there when you reopen it.
  • Small shared changes: usePullRequestWrites.write takes an optional onDone, PullRequestWriteNote takes a className for where it is drawn, and AnchoredPopover takes a width.

Review panel, Request changes chosen
GitHub refusing to approve your own pull request, in its words
Review panel, dark

Tests

  • Service (coding-agents-app.test.ts, "changing an agent's pull request"):
    • with no pending review, the service sends addPullRequestReview with the event and body on the member's token, and GitHub's "Can not approve your own pull request" comes back as refused in its words;
    • the member's own pending review is the one submitted and nobody else's is touched, and a blank body is left unsent;
    • an unknown event, or a body over GitHub's limit, gets invalid-request and never reaches GitHub.
  • Renderer (agent-pull-request-tab.test.ts):
    • Review submits the choice and the body for the agent, the panel closes and clears, and the conversation is read again;
    • a refusal shows inside the panel, not under the bar, and the text stays;
    • a merged pull request has no Review button.
  • Goldens: two re-recorded with LUKE_UPDATE_FIXTURES=1, the request schema and the view's params, each gaining the submit-review member. Nothing else changed.

Evidence

pnpm check:affected ran out of memory in the sandbox (exit 137), so I ran the parts separately and all passed:

  • tsc for service and desktop
  • vitest: the service suite plus four affected files, 368 tests
  • ./scripts/oxlint.sh, biome, pnpm knip, ./scripts/repository-checks.sh and pnpm discarded-effect
  • the desktop build, within its bundle budget

The screenshots come from a throwaway esbuild harness with a fake window.luke, captured with Playwright. The harness has been deleted.

Made with Luke


Devin Review


Summary by cubic

Adds a Review button to the Pull request tab so a member can submit a review on an agent's pull request as themselves, choosing Comment, Approve, or Request changes with an optional Markdown body.

  • New submit-review action on the member-writes seam sends the review on the member's own GitHub sign-in token, never the Luke App's.
  • The member's own pending review is the one submitted; otherwise a review is created and submitted in one step, and a blank body is left unsent.
  • GitHub's refusals appear inside the panel in GitHub's words, and the conversation is read again after GitHub answers.
  • A press outside closes the panel, keeping its draft; it stays open while a review is in flight and scrolls within its fullest side in short windows. A merged pull request shows no Review button.