Repository navigation
Refresh the web client live when a webhook delivery changes a PR - #304
Merged
Merged
Conversation
With [Webhooks] configured the server already patches its caches from each delivery, but an open page only found out on a manual sync or a reload. Now the server pushes a Server.PRUpdated notification (over the channel #303 added) for every PR a delivery changed, and the web client re-reads the PR in place and says what happened. - workflows: each apply function reports what it rewrote for each PR (cache fields, "head" after a refetch, "pr" for a pull_request payload) and a few-word summary ("alice approved", "bob commented on x.go", "alice pushed new commits"). CI is announced only as it settles (passing, or failing where it wasn't); a check starting refreshes quietly. applyWebhookEvent hands each changed PR to a hook registered with SetPRChangedHook, and the membership re-check sends a "sections" change when it rewrote rows. Deliveries that changed nothing send nothing. - server: NotifyPRChanged sends Server.PRUpdated (owner, repo, number, event, changes, head_sha, actor, own, summary, time) to a subscribed client; main.go wires it in server mode. "own" marks the configured user's changes. - web client: onPRUpdates/usePRUpdates batch a burst (400 ms from the first update). The review re-calls GetPR without a loading state and takes in comments, reviews, metadata and a changed diff, keeping open threads, expanded hunks, drafts and the feedback being typed; a new diff waits while an inline comment is being written. The list re-reads its rows in place and highlights the changed ones. A toast says what happened; the user's own changes and quiet ones refresh silently. - e2e: E2E.UpdatePR / backend.updatePR play a delivery; live_updates.e2e.ts covers the review, the held diff, the user's own change, sections-only updates and the list. - docs: protocol.md (Server.PRUpdated), webhooks.md, web_client_features.md §3.18, building_clients.md, CLAUDE.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AMPYZg3x4vXfFzqgvJ1AbU
Conflicts in Review.tsx and CLAUDE.md. #306 keeps the PR's full diff in fullDiff/fullDiffRef/applyFullDiff, which did the job of this branch's serverDiff/applyServerDiff, so the live refresh now builds on those: it compares the new payload with fullDiffRef and takes the new diff in through applyFullDiff, which leaves a filtered diff on screen. A filtered diff is then asked for again (loadFilteredDiff's new quiet mode: no spinner, no error toast, and the diff left alone when the answer hasn't changed) after a push or the user's own review or comment, either of which can move it. Two e2e specs cover a push with a filtered diff showing and another user's comment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AMPYZg3x4vXfFzqgvJ1AbU
Conflicts were additive on both sides: server/notify.go keeps main's Server.PluginOutputChanged / Server.AIOutputChanged beside this branch's Server.PRUpdated (NotifyPRChanged now copies notifier the way main's helpers do); server_events.test.tsx imports both sets of helpers; protocol.md, building_clients.md, web_client_features.md and CLAUDE.md describe all three notifications. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AMPYZg3x4vXfFzqgvJ1AbU
- Read again, quietly, when the event stream comes back after dropping (onReconnect, used by usePRUpdates), since a Server.PRUpdated sent while it was down is lost, as #305 does for plugin and AI changes. Unlike useServerChanges it skips the first connect, which only repeats the read the page made on load. - Stop reloading the plugin output after a push: the plugins the push re-runs now announce themselves, and the reload put the panel through a loading state. - Use #305's isChangeFor in place of the identical isUpdateFor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AMPYZg3x4vXfFzqgvJ1AbU
C-Hipple
pushed a commit
that referenced
this pull request
Oct 26, 2026
Brings in the live refresh (#304) and the pushed plugin/AI changes (#305). Conflicts: - CLAUDE.md: kept main's notification and live-refresh text, with this branch's comment positions on filtered diffs in place of "a filtered diff doesn't share" them / "skips inline comments while one is displayed". - Review.tsx: kept main's unlessSame / sameFilteredDiff helpers and this branch's LINE_NOT_IN_FULL_DIFF; COMMENTS_NEED_FULL_DIFF and NO_COMMENTS are gone, as nothing uses them since comments show on filtered diffs. main's live_updates e2e specs counted one file in #42's filtered diff and pushed a change to a line it no longer shows. The fake's filtered diff now takes a PR's ReplaceInDiff pushes as the full diff does (both end at the head), and the specs count its two files and push a line both diffs show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSunxLHtpVEQmGaGyiP217
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
With
[Webhooks]configured, the server already patches its caches from each GitHub delivery, but an open page only found out on a manual Sync or a reload. This uses the server → client notifications from #303: for every PR a delivery changes, the server sends aServer.PRUpdatednotification, and the web client re-reads that PR in place and shows a short toast saying what happened ("alice approved", "bob commented on server/notify.go", "Checks failed: build").The aim is for this to be as seamless as possible:
/api/eventsstream drops and reconnects, the review and the list re-read quietly, since anything sent while it was down is lost (as Push plugin and AI result changes to clients instead of having them poll #305 does for plugin and AI changes).own: the actor is the configuredGithubUsername) refresh without a toast, since the UI already reported them.widgets#42: alice edited the title).Changes
workflows/webhook_changes.go(new):PRChange,SetPRChangedHook, and the summary helpers (pullRequestSummary,reviewSummary,reviewCommentSummary,reviewThreadSummary,issueCommentSummary,ciOutcome/ciSummaryChange).workflows/webhook_events.go: each apply function'sheldPRnow carrieschanges(the cache fields it wrote,headafter a refetch,prfor a pull_request payload) and asummary.applyWebhookEventhands each changed PR to the hook.patchCachedCIreturns what it wrote, plus a summary when the head's CI settles. A delivery that changed nothing (PR not held, cache missing) sends nothing.workflows/webhook_membership.go: when the re-check rewrites section rows, it sends asectionschange so the list can pick up adds and drops.server/notify.go:PRUpdatedMethod, thePRUpdatedpayload, andNotifyPRChanged, alongside Push plugin and AI result changes to clients instead of having them poll #305's plugin and AI notifications.main.gowires it up in server mode.bun_client/frontend/src/server_events.ts:parsePRUpdate,changesPR,prUpdateMessage(newest three per burst,…and N more),onPRUpdates(the batching), andonReconnect(a reconnect after a drop, skipping the first connect). Matching a PR uses Push plugin and AI result changes to clients instead of having them poll #305'sisChangeFor.hooks/usePRUpdates.tswraps them for React.Review.tsx:refreshLive, which holds a new diff while a comment is being written, keeps unchanged state identity, and drops a stale response if a newer refresh has started. Plugin output isn't reloaded after a push, since with Push plugin and AI result changes to clients instead of having them poll #305 the re-run plugins announce themselves. It builds on Serve the diff since my last review or interaction, precomputed and cached #306'sfullDiffRef/applyFullDiff, andloadFilteredDiffgains a quiet mode (no spinner, no error toast, and the diff left alone when the answer hasn't changed).PRList.tsx: refreshes its rows in place, skips updates about PRs it doesn't show (unless it's a section change), and highlights changed rows (.crs-row-updated, a steady tint underprefers-reduced-motion).App.tsxpasses the toast to the list.E2E.UpdatePRin the fake backend andbackend.updatePRin the harness simulate a delivery.live_updates.e2e.tscovers seven cases: in-place review refresh, the user's own change, a diff held for an open comment, a sections-only update, a push with a filtered diff showing, another user's comment with a filtered diff showing, and the list.protocol.md(Server.PRUpdated),webhooks.md("Clients Follow Deliveries"),web_client_features.md§3.18,building_clients.md,CLAUDE.md,e2e/README.md.Since #305 the Emacs client and the Chrome extension subscribe too, but they only act on the plugin and AI notifications and ignore other methods, so
Server.PRUpdateddoesn't affect them.Test Plan
go build ./...passesgo test ./...passes (new:workflows/webhook_changes_test.go,TestNotifyPRChangedSendsAPRUpdated; also under-racefor the new tests)bun run lint,bun run format:check,bun run type-check,tsc -p e2einbun_client/bun run testinbun_client/(newserver_events.test.tsxcases for parsing, messages, batching and reconnects)bun_cliente2e suite after merging main (97 passed, 2 opt-in real-LSP specs skipped), including the sevenlive_updates.e2e.tsspecs. I confirmed the sections-only spec fails when the review'schangesPRfilter is removed.[Webhooks]on, open a review and comment / approve / push from github.com, and watch the page update with a toast.🤖 Generated with Claude Code
https://claude.ai/code/session_01AMPYZg3x4vXfFzqgvJ1AbU