feat(service,features,desktop): comment on an agent's pull request from the foot of its Conversation

Merged
DA
1d ago
+462-57

B3a of the "Review and comment" stack, after #3308 (B2, merged). The task is a new top-level comment box at the bottom of the Conversation, sent through the member seam, with Write / Preview like the review panel has. Commenting on a line from Files changed (B3b) waits until Files changed becomes one CodeView list.

Wire and service

  • One new member on the action union in pull-request-write-wire.ts: comment { body }. The body can't be blank and is capped at GitHub's 65,536 characters.
  • commentOnPullRequest in github/pull-request-writes.ts sends addComment with the pull request's node id as its subject.
  • It runs through memberPullRequestWrite, so it acts as the member pressing the button, on their own token, never the App's.

UI

  • pull-request-comment-box.tsx adds Add a comment at the bottom of the Conversation, shown once the conversation has been read. It has a Markdown field with Write / Preview and a Comment button (⌘↩ also sends).
  • It has its own usePullRequestWrites:
    • When GitHub accepts the comment, the box clears its text and the conversation is read again, so the new comment appears.
    • If GitHub refuses, its words show under the box, with Sign in with GitHub offered when needed, and the text you wrote stays.
  • The review panel's Write / Preview moved into markdown-field.tsx, which both now use. Its Write field is @luke/ui's TextArea, as the review panel's was on main, and ⌘↩ sends through the TextArea's onSubmit. The Comment button is the shared Button from @luke/ui, like the review panel's. The preview's CSS became .markdown-field-preview. The review panel looks and behaves the same.

The comment box with GitHub's refusal under it, light
The same, dark

The box's CSS uses the --luke-* roles (--luke-space-8, --luke-color-text-muted, --luke-type-caption-size), not the aliases #3524 retired. The screenshots come from main's stylesheet, with the box mounted alone and its computed gap, note colour and field border checked in both themes.

Tests

  • Service: a teammate's comment is sent as addComment on the pull request's node id with their own token, and a blank comment gets invalid-request and never reaches GitHub.
  • Renderer:
    • the comment goes to the service for the agent (⌘↩), then the box clears and the comment shows in the conversation as it is read again;
    • a refusal shows under the box and the text stays.
    • the text being written survives a failed conversation read, since the tab holds it, not the box, and it is back once Retry reads the conversation.
  • Goldens: two re-recorded with LUKE_UPDATE_FIXTURES=1, the action request and the view's params, each gaining comment.

Evidence

pnpm check:affected runs out of memory in this sandbox, so I ran the parts separately and all passed:

  • tsc for service and desktop
  • the affected vitest files
  • ./scripts/oxlint.sh, biome, pnpm knip and ./scripts/repository-checks.sh
  • the desktop build, within its bundle budget

The screenshot comes 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 comment box at the foot of an agent's pull request Conversation that posts a new comment to GitHub as the signed-in member.

  • The comment action rides the member-writes seam; commentOnPullRequest sends addComment on the pull request's node id with the member's own token.
  • The tab holds the box's draft (usePullRequestComment), so a failed conversation read, which temporarily removes the box, loses nothing written.
  • The review panel's Write/Preview moved into a shared markdown-field.tsx, which the comment box uses too.
  • GitHub refusals show under the box in GitHub's own words; a pending send is neither re-sent nor discarded.
  • Styling uses the --luke-* roles, not the aliases #3524 retired.