feat(service,features,desktop): comment on an agent's pull request from the foot of its Conversation
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. commentOnPullRequestingithub/pull-request-writes.tssendsaddCommentwith 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.tsxadds 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'sTextArea, as the review panel's was onmain, and ⌘↩ sends through the TextArea'sonSubmit. The Comment button is the sharedButtonfrom@luke/ui, like the review panel's. The preview's CSS became.markdown-field-preview. The review panel looks and behaves the same.


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
addCommenton 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 gainingcomment.
Evidence
pnpm check:affected runs out of memory in this sandbox, so I ran the parts separately and all passed:
tscfor service and desktop- the affected vitest files
./scripts/oxlint.sh,biome,pnpm knipand./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
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
commentaction rides the member-writes seam;commentOnPullRequestsendsaddCommenton 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.