fix(web): keep the composer expanded until the thread can scroll - #9965
Conversation
The desktop composer rested into its single-line layout whenever an existing thread lost focus, including a fresh thread with one short exchange. Nothing above it could scroll, so the collapsed row gave no space back and hid how to reopen the composer. The timeline now reports whether its rows extend past the viewport above the composer, and the resting rule requires that overflow. Short threads stay expanded. Long threads rest on blur and scroll as before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2f3b8b5. Configure here.
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a focused UI bug fix that keeps the existing composer expanded only when the timeline fits, while preserving current mobile, new-thread, and explicit-collapse behavior. The change is localized, tested, and has no schema, infrastructure, security, billing, or static-analysis implications. You can add or adjust custom eligibility rules. Learn more. |
… as fitting Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
## What's Changed * fix(server): keep Homebrew mise shims manual-only by @juliusmarminge in pingdotgg/t3code#10085 * fix(ssh): report remote package installation failures accurately by @juliusmarminge in pingdotgg/t3code#10088 * fix(web): keep bulk thread deletion going after failures by @m-de-graaff in pingdotgg/t3code#4615 * fix(web): scale agent spawn rows with interface font by @juliusmarminge in pingdotgg/t3code#10092 * fix(web): prevent sidebar tooltip title clipping by @UtkarshUsername in pingdotgg/t3code#10086 * fix(web): keep the composer expanded until the thread can scroll by @t3dotgg in pingdotgg/t3code#9965 * fix(web): preserve original mention text in the composer by @juliusmarminge in pingdotgg/t3code#10100 ## New Contributors * @m-de-graaff made their first contribution in pingdotgg/t3code#4615 **Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260905.1286...v0.0.39-nightly.20260905.1287 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260905.1287
When the PR selected for `early` does not apply at the reconciled upstream boundary, the command stopped with a single line that gave nothing to act on: ```console $ node scripts/upstream-queue.ts early 11784 --through upstream/main Selected pingdotgg#11784 cannot be applied at the upstream boundary. ``` That happens when the PR builds on upstream work the fork has not taken in yet, and the planner only looks for dependencies in the changes it replays after a successful apply. The command now reports which of the PR's files conflict at the boundary and which earlier pending upstream PRs and direct commits change those files, in upstream order. Text output lists the first 20 and says how many remain; `--json` includes every source with its SHA, PR, and title. A plan that succeeds prints as before. The intake runbook's `early` paragraph describes the report. ## Validation - A new test in `scripts/upstream-early.test.ts` checks which sources the report lists: pending sources after the boundary and before the blocked PR whose files overlap the conflicting paths, including direct commits and directory prefixes, and not recorded or later sources. - `scripts/upstream-early.test.ts` and `scripts/upstream-queue.test.ts` pass (21 tests); lint, formatting, and the scripts typecheck are clean. - Against fetched fork `main` (`495b7cfd5`) and upstream `main` (`b2b43bef7`), the same command now prints: ```console $ node scripts/upstream-queue.ts early 11784 --through upstream/main Fork 495b7cf; reconciled through d28077e pingdotgg#11784 does not apply at the reconciled boundary. 16 of its files conflict there: apps/mobile/src/features/threads/ThreadFeed.tsx apps/mobile/src/features/threads/thread-work-log.tsx apps/mobile/src/lib/threadActivity.ts apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts apps/server/src/orchestration/decider.ts apps/server/src/provider/Layers/ClaudeAdapter.test.ts apps/server/src/provider/Layers/ClaudeAdapter.ts apps/server/src/textGeneration/ThreadTitleContext.test.ts apps/server/src/textGeneration/ThreadTitleContext.ts apps/server/src/ws.ts apps/web/src/components/chat/MessagesTimeline.logic.ts apps/web/src/components/chat/MessagesTimeline.tsx apps/web/src/components/settings/SettingsPanels.tsx packages/client-runtime/src/state/environmentHttpAuth.test.ts packages/client-runtime/src/state/threadSnapshotHttp.ts packages/contracts/src/orchestration.ts Earlier pending upstream changes to those files: 110 PRs. Take them in first, or add their PRs to this plan. pingdotgg#9594 fix(connect): refresh HTTP credentials without reconnecting (pingdotgg#9594) pingdotgg#9894 fix(chat): show hours for long runs (pingdotgg#9894) pingdotgg#9933 fix(settings): share restart continuation across environments (pingdotgg#9933) pingdotgg#10092 fix(web): scale agent spawn rows with interface font (pingdotgg#10092) pingdotgg#9965 fix(web): keep the composer expanded until the thread can scroll (pingdotgg#9965) pingdotgg#9935 fix(web): align tool disclosure chevrons with expanded state (pingdotgg#9935) pingdotgg#10199 fix(mobile): size a chat image's frame before its bytes arrive (pingdotgg#10199) pingdotgg#10200 fix(web): size the chat image slot from server-reported dimensions (pingdotgg#10200) pingdotgg#10167 refactor(client-runtime): remove unused runtime exports and helpers (pingdotgg#10167) pingdotgg#10173 fix(mobile): restore live tool shimmer and add a Thinking row (pingdotgg#10173) pingdotgg#10210 fix(mobile): only make work rows expandable when the body adds something (pingdotgg#10210) pingdotgg#10211 fix(mobile): fold subagent lifecycle rows into one batch per spawn (pingdotgg#10211) pingdotgg#10212 fix(mobile): stop clipping expanded tool groups (pingdotgg#10212) pingdotgg#9875 feat: show provider usage limits with /usage-limits (pingdotgg#9875) pingdotgg#9561 fix(ui): unify loading and refresh feedback across clients (pingdotgg#9561) pingdotgg#10226 refactor(web): keep feature component helpers private (pingdotgg#10226) pingdotgg#9754 feat(settings): add shared project defaults and scoped overrides (pingdotgg#9754) pingdotgg#9895 feat(connections): balance new threads across connected machines (pingdotgg#9895) pingdotgg#10273 fix(mobile): stop the work log flickering during subagent runs and failing calls (pingdotgg#10273) pingdotgg#10271 fix(mobile): save linked media from chat (pingdotgg#10271) ... 90 more; --json lists every source. ``` `--json` returns the same 16 paths and all 110 sources. `early 5521 --through upstream/main`, which plans successfully, prints the same summary as before. --- Written by an agent (Claude Code, claude-opus-5-5).
…gdotgg#9965) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit c1d27e5) Upstream-PR: 9965

Opening a new thread showed the composer already collapsed into its single-line resting row, even when the thread had one short exchange and nothing above it could scroll. The collapsed row gave no space back and it was not obvious how to reopen the composer without clicking into it.
The timeline now reports whether its rows extend past the viewport above the composer, and the resting rule requires that overflow. A thread that fits stays expanded. A thread that can scroll rests on blur and scroll exactly as before, and it still opens at rest on its first paint.
Verification
vp test runoncomposerFooterLayout.test.ts,timelineScrollAnchoring.test.tsx,useComposerFocusState.test.tsx, andMessagesTimeline.test.tsx(88 passing), including new cases for the overflow helper and the resting rule.Created with Claude Fable 5.1 in Claude Code.
🤖 Generated with Claude Code
Note
Low Risk
Desktop composer layout behavior changes for short threads; overflow state depends on LegendList measurements and may lag until the next layout or scroll event in edge cases.
Overview
Short threads no longer open with the desktop composer collapsed into its resting row when the message list still fits above it. Timeline overflow is now measured from the last real row (ignoring the composer inset spacer) via shared
timelineContentOverflowsViewport, andMessagesTimelinepublishes that flag throughonContentOverflowChangeafter layout, scroll, row resize, and viewport changes.shouldUseRestingComposerLayoutrequirestimelineOverflowsbefore blur- or scroll-driven collapse applies, so resting only reclaims space when there is scrollable history.ChatViewwires the signal intoChatComposer; callers and tests pass the new required field.Reviewed by Cursor Bugbot for commit 7d4fa73. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Keep desktop composer expanded until timeline overflows viewport
timelineContentOverflowsViewporthelper in timelineScrollAnchoring.ts that measures the real last row against usable viewport height (scroll length minus composer inset and anchor offset), returning false for empty/invalid state.MessagesTimelinereports overflow via a newonContentOverflowChangecallback after initial layout, scroll, resize, row-size, row-count, or inset changes;ChatViewtracks this state and passes it toChatComposer.shouldUseRestingComposerLayoutnow requires atimelineOverflowsboolean, so the desktop resting (collapsed) layout is only selected when the timeline actually overflows the area above the composer.shouldUseRestingComposerLayoutandChatComposermust supply the new requiredtimelineOverflowsprop.Macroscope summarized 7d4fa73.