Uh oh!
There was an error while loading. Please reload this page.
fix(web): unlock the composer when preview capture fails - #9127
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This change modifies the existing preview-capture flow across desktop main, Electron preload, web UI, and IPC, including concurrent session lifecycle and timeout behavior. It also broadens a file-level static-analysis suppression to disable timer diagnostics, warranting focused human review. You can add or adjust custom eligibility rules. Learn more. |
3a80b7a to
f99b885CompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
cdfd618 to
0e6f672CompareUh oh!
There was an error while loading. Please reload this page.
0e6f672 to
4851952CompareUh oh!
There was an error while loading. Please reload this page.
4851952 to
7c92f8fCompareUh oh!
There was an error while loading. Please reload this page.
7c92f8f to
6847d7aCompareThere was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6847d7a. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
Picking an element in the browser preview and pressing send could leave the overlay stuck on "Capturing..." forever. Two unbounded waits caused it: `capturePage` in the main process never settles when the guest's compositor is wedged, and `getElementContext` in the picker preload can stay pending on some pages. Either one strands the pick session, so the renderer keeps awaiting a result that never arrives and focus never returns to the composer. Both capture steps now have a bounded timeout, every exit from a pick session resolves the renderer's promise exactly once, and a failed crop raises an error toast instead of holding the send. The message still goes out without the attachment. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Three review findings on the pick session fix. A capture that outlived its session still sent the captured signal, which tore down whatever pick had replaced it. The register step emptied the slot before cancelling the old holder, so a third pick could claim it in between. The screenshot timeout manufactured an Error just to fill a defect. The session swaps into the slot atomically, cleanup only drops a slot it still owns, a capture that lost the race does nothing, and a timed out capture logs a warning and yields no screenshot. The failure toast now says what happened instead of asking for a resend that would duplicate the message. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The stored and forwarded annotation kept its screenshot metadata after the capture failed, so the prompt told the agent a crop was attached when no image was sent. A failed capture now strips the screenshot before the annotation is stored or sent. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The send path returns early when the thread is busy or disconnected and shows its own toast, so the capture toast now only says the crop was dropped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The submit chain kept sending the picked annotation after the session had been cancelled or replaced, which could hand a discarded annotation to the next pick's listener. It now returns once the session finished. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Cancelling the previous session yields, and a newer pick can cancel this one in that window. Registration now stops after the swap if the session already settled, so it cannot attach listeners that cleanup has no chance to remove. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The element context lookup can take up to its timeout while the user keeps editing the overlay. The completion read regions, strokes, style changes, and the comment at completion time, so one annotation could mix what was submitted with what came after. Everything the annotation carries is now captured at submit time. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A timed out or failed element context lookup dropped the element from the annotation. On the heavy pages the timeout targets, a send with only element picks could go out with no elements and a full-viewport crop. The element now falls back to a DOM-only payload with its tag, a short HTML preview, and a null selector, so the pick and its crop rect survive. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A failed or timed out capturePage came back as a null screenshot, which the renderer could not tell apart from a comment-only pick, so the main hang this PR bounds produced no notice at all. The pick result now carries an optional screenshotFailed flag and the renderer shows its toast on either failure path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
6847d7a to
b925f2eCompareUh oh!
There was an error while loading. Please reload this page.
## What's Changed * fix(mobile): show an error instead of an endless preview spinner by @t3dotgg in pingdotgg/t3code#9123 * fix(usage): price new models without waiting a day for the rate table by @t3dotgg in pingdotgg/t3code#9202 * fix(web): unlock the composer when preview capture fails by @t3dotgg in pingdotgg/t3code#9127 * fix(antigravity): refresh the model manifest so older Gemini models fold as legacy by @t3dotgg in pingdotgg/t3code#9397 * perf(ci): reuse dependency checks in release builds by @t3dotgg in pingdotgg/t3code#9399 **Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1268...v0.0.39-nightly.20260903.1270 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1270

Picking an element in the browser preview and pressing send could leave the overlay stuck on "Capturing..." forever. No attachment landed, no message went out, and the composer stayed locked until the thread reloaded.
Two unbounded waits caused it. In the main process,
capturePagenever settles when the guest's compositor is wedged. In the picker preload,getElementContextcan stay pending on some pages. Either one strands the pick session, so the renderer keeps awaiting a result that never arrives and focus never returns to the composer.The fix bounds both capture steps with a timeout. Every exit from a pick session now resolves the renderer's promise exactly once, so a cancelled or replaced session can no longer return without settling. When the crop fails, the picker raises an error toast and sends the message without the attachment instead of holding the composer.
Closes#9026
Built by Claude Opus 5 in the Claude Code harness.
Note
Medium Risk
Changes concurrent pick-session lifecycle and timed capture paths across main, preload, and renderer; legitimate crops slower than 5s may now arrive without a screenshot instead of blocking indefinitely.
Overview
Fixes preview element picks that could hang on "Capturing…" and never return focus to the composer when screenshot or context capture never completes.
Desktop (
PreviewManager) adds a 5-second bound on guestcapturePagefor annotation crops (interruptible via abort signal) and returnsscreenshotFailed: truewhen the crop times out or errors.pickElementis reworked so each session settles exactly once (cancel/replace always resolves the renderer), overlapping picks swap sessions atomically, and a late crop from a replaced pick cannot sendpreview:annotation-capturedor tear down a newer overlay.Guest preload (
PickPreload) capsgetElementContextat 5s and falls back to a DOM-only element payload instead of dropping the target; submit snapshots comment/regions/strokes/style changes, skips IPC if the overlay already finished, and tears down on capture rejection so main is not left waiting.Web replaces direct screenshot file conversion with
capturePreviewAnnotationScreenshot(timed fetch →captured/none/failed).PreviewViewshows an error toast when the crop was dropped, stores/forwards annotations without a screenshot on failure, and still sends the message without an image attachment.Contracts add optional
screenshotFailedonPreviewAnnotationSubmissionResult.Reviewed by Cursor Bugbot for commit b925f2e. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Unlock composer when preview screenshot capture fails or times out
PreviewManager.pickElementpick-session ownership so cancellation, replacement, and navigation each settle the pick at most once; stale captures from a replaced session no longer sendannotation-capturedIPC into the active sessionscreenshotFailedtoPreviewAnnotationSubmissionResultin ipc.ts and updates PreviewView.tsx to keep the annotation with a null screenshot and show an error toast when capture or conversion failsscreenshot: nullandscreenshotFailed: trueinstead of being dropped or hanging the composer; out-of-tree consumers expecting rejection on capture failure will receive a settled result with a null screenshotMacroscope summarized b925f2e.