chore(sync): absorb upstream main through 024d49520 - #164
Conversation
…isc ui exports (pingdotgg#13207) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
pingdotgg#13208) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ui components (pingdotgg#13209) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…gg#13210) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…13212) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…3220) Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
…case screenshots (pingdotgg#13316) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com> Co-authored-by: Exotic <118054752+extoci@users.noreply.github.com>
…otgg#11580) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Simone <185146821+Lucenx9@users.noreply.github.com>
…3355) Co-authored-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…2613) Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…otgg#13397) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…otgg#13363) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merge upstream/main (pingdotgg/t3code) up to the commit before the new orchestrator (pingdotgg#2829): 821 commits, v0.0.44–v0.0.45 cycles. Stops short of pingdotgg#2829 on purpose — that is a full server rewrite that landed hours ago and deletes the hosts of two server customizations; it gets its own sync. Resolved 43 conflicted files and ported the six override shadows that drifted silently. Notable decisions: - CI: upstream split `check` into lint/typecheck/build; the fork's runner, lint-owned and shellcheck fences re-seated on the new jobs. Release gates follow the split macOS preview workflows. - Lint: upstream's new `@shadcn/lint` rules (no-restyle, no-arbitrary- values, …) are off for fork-owned files — restyling ui primitives is the fork's purpose — and the React Compiler rule baselines in lint-owned were re-measured after the vite-plus 1.0 bump. - Composer: context records replace the per-kind context blocks; the design-mode extraction runs ahead of upstream's resolver. The prompt editor is Tiptap now; the Lexical focus-skip hunk is covered natively (ProseMirror only writes the DOM selection when it owns focus) and the guard pins that instead. The composer overlay height is a ref upstream, so the transcript-mask inset is written straight onto the chat column. - Sidebar: ported the Working section (pingdotgg#13926) and the multi-PR badge control into the fork's card rows; dropped the fork's own PR anchor. - Model menu: ported multi-model drafts, provider-cycling shortcuts and the fast/ultrafast speed icon into the fork's combined menu. - Draft assignment resolves env mode through upstream's shared resolveProjectSettings (environment setting now outranks t3.json). - Icon shim: 26 new lucide names upstream imports. - Mobile: Expo 58; pnpm-patched deps pinned exactly for Release Smoke. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
Thermo-nuclear review of the fork-authored port (not the 821-commit upstream dump).
Do not approve. apps/web/src/overrides/components/chat/ModelPickerContent.tsx crosses 1k (898 → 1053). That shadow was allowed to keep the paged menu specifically because it stayed under the line. This sync pastes upstream's multi-model draft and provider-cycling into it and blows the budget.
The paged render belongs here. The increment that crossed does not: adjacentModelPickerProvider (L122), the selected-key set, the two cycle-eligibility memos, and cycleProvider. Move that machinery into a sibling under the override (pure helper + a small hook). Re-export the helper from this module so the shadow API stays compatible. The header already says four helpers are upstream-verbatim; the guard still pins three, and it never added selectedModels / onToggleModel to the API-compat list. Pin both when you extract.
Do not whole-file decompose this shadow. Do not pull ChatComposer / ChatView / yaml apart — those were already last-resort or already over 1k.
The rest of the absorb is structurally sound: Tiptap covers the Lexical focus-skip and the guard pins the condition; draft assignment uses resolveProjectSettings; the shadcn lint offs stay on fork-owned globs.
(Inline comments omitted: GitHub rejected file-level comments because this PR's diff exceeds the 300-file API cap.)
Sent by Cursor Automation: Thermo nuke 4.6
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. |
NoahHendrickson
left a comment
There was a problem hiding this comment.
Reviewed commit 185d774b7d82bcbb392ca8543cf62b2d4d45c930. Changes needed. I focused on the fork integration: conflict resolutions, override ports, composer/context handling, sidebar integration, release gates, and the failing CI jobs. This is not an exhaustive audit of all 821 upstream commits.
-
[P2] Preserve design attachments when sending to multiple models — ChatView.tsx:7922–7927. In a project draft, attach a design change from the Browser panel, Shift-select a second model, and send. The single-model path includes
forkDesignSend.text, but each multi-model target is built frommessageTextForSend, which excludes the attached design request. Consequently every spawned agent misses those instructions; a design-only send instead receives the attachment bootstrap prompt. The multi-model branch also returns beforeforkDesignChanges.markSent, leaving the pill pending after successful sends. Include the captured design payload in each target and handle its completion bookkeeping for successful/failed targets. -
[P2] Handle design blocks after legacy context serialization — MessagesTimeline.tsx:2011–2017. When connected to a server without
inlineMessageContext, sending a design change together with a terminal excerpt or preview annotation now callsserializeLegacyContextMessageafter adding the design block. That serializer appends the legacy context after the design block, so it is no longer trailing. HereextractTrailingDesignChangesreturns no blocks; the following context resolution removes the terminal/annotation wrapper but leaves the full design request in the visible message, with no design chip or its verification summary. Support both the historical block order and this new serialization order. A focused reproduction using the real serializer, extractor, and context resolver fails withblocks: []; the inline-context control passes.
CI also needs these concrete repairs before merge:
- Test Web: TraitsPicker.test.ts:173 still expects
showFastModeIcon: false; the migrated API returnsspeedIcon: null. - Test: DesktopPreReadyPlatform.test.ts:98 and 130 still uses the upstream icon basename in both the copy mock and assertion. The implementation correctly writes
com.t3tools.T3Code.Fork.desktop.png. Both Linux entry tests fail, including locally on macOS; these are not the documented Windows cross-architecture failure. - Lint: SidebarThreadHeader.tsx has no consumers after the fork sidebar port. The CI
knip:checkstep exits on this unused file before reaching lint. Account for this upstream component in the fork’s Knip configuration or reuse it where appropriate.
Validation: ran the focused TraitsPicker, DesktopPreReadyPlatform, ModelPickerContent, and composerModelTraits tests: 41 passed, 3 failed, matching CI. Ran a temporary two-case legacy design/context reproduction: 1 passed, 1 failed; removed it afterward. No browser verification performed. Workspace left unchanged.
Review by GPT-6 via Codex.
CI: - TraitsPicker test: the fork's separator case expected the pre-sync `showFastModeIcon` shape; the API returns `speedIcon` now. - DesktopPreReadyPlatform test: upstream derives the Linux icon basename from the desktop entry name, which the fork renames; both Linux entry cases now expect `com.t3tools.T3Code.Fork.desktop.png`. - knip: upstream's SidebarThreadHeader has no caller behind the fork's chrome rows; fenced ignore so the file stays in the tree for merges. Review (design mode): - Multi-model drafts now send the pill's design request to every target and clear the pills via markSent once a target started; before, each target was built from the bare prompt and the pills stayed pending. - On servers without inline message context the legacy serializer appended its blocks after the design run, hiding it from the transcript extractor. withDesignChangesTrailing serializes the prompt without the run and puts it back last, on both send paths. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Pushed Codex review — all five items fixed:
Verified locally: Cursor review — not taking the |
…ted runners client-runtime's persistence.test.ts samples two 1,000-value arbitraries at size 30 and round-trips each; ~0.5 s locally, but past the package's 5 s default on GitHub-hosted runners with the parallel Test job alongside (it timed out twice in a row on the same commit). Fenced per-test raise under ci-runners, the same treatment as imageCompression.test.ts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
NoahHendrickson
left a comment
There was a problem hiding this comment.
Ultra code review of the upstream sync (head 2b79e79). Nine finder agents ran over the fork-touched resolutions. I checked every finding below against the PR head; duplicates are merged and the rest were dropped (see the end).
Most important: design-mode pills on the new send paths (queue, multi-model), the dead Mod+Shift+E shortcut, assignDraftProject reading the wrong settings, and the composer placeholder CSS that the Tiptap swap broke. Items marked plausible were traced in source but not run.
Also: custom/DraftProjectPill.tsx isn't in this diff, but it drifted. Upstream now hides the per-environment Scratch project from its pickers (isScratchProject in DraftHeroHeadline and CommandPalette). The fork's pill lists every buildSidebarProjectPickerEntries row, so once Scratch has been opened it shows up as an ordinary assignable project.
Checked and dropped:
- The 400ms hero clock, the lint baseline re-measure and the
SidebarThreadHeaderknip ignore are deliberate, documented decisions. - The unfenced TraitsPicker test predates this PR.
- The env-mode precedence flip matches upstream.
- The icon shim, model-picker ports, CI gating and app identity all came back clean.
GitHub only allows inline comments on the first 3,000 files of a PR, and this PR's vendored
.repos/push most fork files past that. So the findings are below with permalinks to the head commit, apart from the lint-baseline note, which is posted inline.
1. ChatView.tsx:7796
Queued follow-ups drop design-change pills. Upstream's new queue path (followUpBehavior: "queue" is the default) returns here, before forkDesignChanges.takeForSend at ~7870, and sendQueuedMessage never reads the pills.
- Prose plus pills during a running turn: the prose is queued without the
<design_change_request>blocks. The pills stay pending and get attached to the next unrelated send. - Pills only:
hasSendableContentcounts pills (~7607), so the send passes. It is queued withprompt: "", andsendQueuedMessage'sderiveComposerSendStatethen sees nothing sendable and quietly finishes it. The design request never goes out.
Before this sync the fork had no queue, so this case went through the normal path that appends the pills. Either bypass the queue while pills are pending, or carry takeForSend's text and sent entries into the queued message and markSent when it actually dispatches.
2. ChatView.tsx:8250
Multi-model send + design pills: two problems with this markSent.
- Partial failure loses the design request.
startedCount > 0clears the pills even when some targets failed.restoreFailedDraftputs back onlymessageTextForSend, which doesn't include the blocks. Example: A starts and B fails. Retrying B sends the bare prompt with no<design_change_request>. The comment above ("a failed target restores the draft text, not the pills, which the next send reads again") is wrong, because the pills are already gone. Fix: onlymarkSentwhenfailedSelections.length === 0, or re-add the sent entries on restore. - The resolution prompt can never show. The record is keyed on
forkDesignChangeRef, which is the draft's thread. Every target runs on a freshtargetThreadId, solatestTurnAtom(draftRef)stays null.shouldOfferPreviewResolutionis then always false,setVerifyingnever arms, and the chip keyed onforkFirstStartedMessageIdnever gets a verdict line. A later single send from the same draft would also wrongly "cover" this record. The record needs the started thread's ref, not the draft's.
Smaller, plausible: the composer is released (sendInFlightRef.current = false) before await starts, but the pills only clear after every start settles. A second send typed during worktree prep can pick up the same pills, and the design request goes out twice.
3. ChatView.tsx:6987
Mod+Shift+E (composer.effort) does nothing in the fork. openControl clicks button[data-composer-shortcut~="composer.effort"]. Upstream puts that attribute on TraitsPicker and on CompactComposerControlsMenu when it receives traitsMenuContent. The fork renders neither: effort lives in the combined model menu, and ChatComposer ~5295 no longer passes traitsMenuContent. The combined trigger in overrides/.../ProviderModelPicker.tsx never declares the attribute either. So the new default binding calls preventDefault and then finds no target, in both wide and compact layouts.
Fix: add data-composer-shortcut="composer.effort" to the combined model trigger when traits exist, or route composer.effort to toggleModelPicker.
4. useNewAgentDraft.ts:223
assignDraftProject only half-adopts upstream's project-scoped settings. useHandleNewThread ("New thread in X") does all of the following; the New agent pill does not:
- Settings source. Upstream resolves against
environmentServerConfigs.get(projectRef.environmentId). This passesprimaryServerSettings, so for a project on a non-primary environment,projectSettingsOverrides[project.id]is missing and the environment tier is the primary's. The doc comment onuseAssignDraftProject("the same reading upstream's handler makes") is no longer true. - startFromOrigin (~259) reads raw
settings.newWorktreesStartFromOrigin. It is now a project-scoped key, and upstream usesprojectSettings.settings.newWorktreesStartFromOrigin. - Default model (~265) still reads the aggregate
project.defaultModelSelection. After the override fold, a model set or reset in project settings is ignored or overridden by a stale value. Upstream usesresolveProjectSettings(...).settings.defaultModelSelection. - Permissions.
useStartNewAgentDraft(~102) carriesruntimeModeover from the viewed thread, and assignment never applies the newdefaultRuntimeMode. Starting from a full-access thread keeps full access even when the project or environment default is approval-required. Upstream's handler now starts in the configured default.
One resolveProjectSettings(envSettings, project.id, project, projectFile) result, read from the project's own environment, would cover all four.
5. ComposerPromptEditorTiptap.tsx:1416
Fork composer placeholder CSS is dead after the Lexical → Tiptap swap. theme.custom.css ~698–735 targets [data-testid="composer-editor"] ~ div. That matched Lexical, where the placeholder was the editor's sibling. Here data-testid is on the ProseMirror node inside <EditorContent>'s wrapper div, and this placeholder is a sibling of that wrapper. So the rule never matches. The same goes for theme.custom.westworld.css ~197–204. On desktop the placeholder is back to upstream's text-placeholder/75 at upstream's size and leading, so the caret sits off the placeholder text, and Westworld's placeholder ink no longer applies. The guards (forkComposerShell.test.ts ~331–360, forkCoolDarkTheme.test.ts ~246–258) only check the CSS text, so they stay green.
Related, plausible: the fork moves the scrollport to [data-fork-composer-prompt]. The editor here now carries -m-1 … p-1 (line ~784), which can push its box 4px past the wrapper and bring back the phantom scrollbar that rule exists to prevent. The "12.5rem matches upstream's max-h-50" comment is also stale (upstream is max-h-52).
6. Sidebar.tsx:1289
Settled rows no longer mute their PR badge. Before the sync, settled slim rows drew the badge in text-secondary-label with settledPrHoverColorClass on hover. Upstream moved that muting onto its row surface (variantAction === "unsettle" && "[&:not(:hover):not(:focus-within)_*]:text-secondary-label/70"), but the resolution swapped that class list for threadRowSurfaceClassName. Neither version mutes it now. Expanding Settled shows full green or purple PR states on every row at rest, so the history tail looks as loud as live cards. No guard covers it.
7. ChatView.tsx:6394
Stale memo deps cause re-renders on panel toggles. The fork's composerLivenessPill body was kept, but the merge took upstream's dependency list. activeRightPanelSurface?.kind, addAgentsSurface and rightPanelOpen are never read in the body. So every right-panel open, close or surface switch rebuilds the pill. That invalidates composerContextStrip and re-renders the memoised composer, often mid-stream. Restoring the fork's five deps fixes it.
The same resolution also dropped upstream's "View agents" action from this pill without porting it. Decide whether that's intended; the spawn card still has its own link.
8. package.json:118
A patched dependency on a range. react-native-nitro-markdown is ^0.5.0, but pnpm-workspace.yaml patches @0.5.8. The same applies to node-pty (apps/server/package.json: ^1.2.0-beta.15, patch for @1.2.0-beta.15). Release Smoke deletes the lockfile and re-resolves. It passes today only because these are the newest matching versions. Once 0.5.9 or a newer node-pty beta ships, the patch goes unused and the required check turns red on every PR. Pin both exactly.
9. ws.ts:1432
Plausible: the bootstrap-branch fill-in misses upstream's new worktree fallback. preparingWorktree: bootstrap.prepareWorktree !== undefined (a few lines down) still assumes "a worktree will name its own branch". Since this sync, when hasCommit is false and requireWorktree isn't set, the thread runs in the project checkout instead (~1409). A client that sent branch: null then gets thread.create with branch: null on a real checkout, which is the gap server-local-thread-branch exists to close. Suggest preparingWorktree: bootstrap.prepareWorktree !== undefined && shouldPrepareWorktree.
10. theme.custom.css:2952
Plausible: "Show full message" lost its fork hover. The rule now covers only hover:bg-accent/20. "Show full message" is now a ghost-muted Button, which hovers with an opaque bg-accent: a stronger version of the cool smudge this customization exists to remove. The guard assertion for it was deleted rather than ported. .fork/customizations.yaml (~3799–3801) and the guard's header still describe two utilities. Consider keying a rule on the button inside .fork-timeline-cutoff and pinning it.
11. ChatView.tsx:3681
Plausible: mobile web lost the dock morph. The hero slide is forced on here (!prefersReducedMotion, 400ms), but runMobileComposerTransition (~7999) now takes active: panelAnimationsActive, which is off by default. On a mobile viewport with default settings, the view-transition morph is skipped, data-mobileComposerRouteTransition is never set, and the 400ms WAAPI translate runs instead. Before the sync the morph always ran on mobile and the slide stood down. The forced flag also ignores PanelAnimationSuppressionProvider.
12. ProviderModelPicker.tsx:355
Two small things in the trait suffix:
- The sr-only text below is hard-coded to "Fast mode on". With
speedIcon === "ultrafast"the trigger showsUltrafastIcon, but a screen reader announces the wrong tier. Upstream'sTraitsPickernow uses its speed label. - Plausible: in a multi-model draft the trigger still appends the primary model's traits, and the tooltip names
activeEntry. If the primary is shift-clicked out of the selection, the label shows effort and speed for a model nobody is sending to, and the effort slider edits that model's options.
13. UsagePage.tsx:110
Plausible: Escape can navigate away from the Usage popover. Upstream's new useEscapeToGoBack() attaches a window-level Escape → history.back() handler. It also runs in the fork's chrome="panel" mode, where this page lives in the sidebar popover rather than on a route. Base UI's dismiss stops the first Escape. But during the exit transition, or when a nested control consumes Escape without preventDefault, the keypress reaches the window and navigates away from the current thread. Skip the hook when chrome === "panel".
14. vite.config.ts:382
Convention: the shadcn/* rules are off for three whole upstream files. All five rules are disabled for Sidebar.tsx, SidebarChrome.tsx and MessagesTimeline.tsx. That also removes upstream's gate from all the upstream-authored code in those files, which contradicts the comment above ("stays on everywhere else so upstream-authored code keeps its gate"). It also lists MessagesTimeline, which isn't in FORK_ADOPTED_FILES, and omits AppSidebarLayout.tsx, which is. A narrower option is oxlint-disable-next-line shadcn/<rule> on the fenced lines; reportUnusedDisableDirectives: "error" keeps those honest.
15. AppSidebarLayout.tsx:66
Plausible: the traffic-light inset doesn't follow desktop zoom. Upstream's --desktop-window-controls-inset is 90 native points divided by the zoom factor. This sync also adds syncMacosWindowButtons, which keeps the native buttons at a fixed size. At Cmd− (zoom ~0.8), 80 CSS px ≈ 64pt, so the 28px sidebar toggle sits under the zoom button. Zoomed in, it drifts away to the right. Something like calc(80px * var(--desktop-window-controls-inset, 90px) / 90px) would keep the fork's figure and still scale with zoom.
16. compileCache.ts:24
Low: upstream-named cache directory. Upstream's new compile cache writes to <tmpdir | XDG cache>/t3code/compile-cache, the same directory an installed upstream T3 Code uses. The fork's app-identity work didn't rename it. On macOS it's outside $HOME, so launch-isolation-check.sh doesn't catch it. Functionally harmless because Node keys entries by path, but it breaks the fork-owned-paths rule.
17. MessagesTimeline.tsx:4566
Cleanup: this comment is inaccurate. Nothing renders AgentSpawnMemberRow anymore, and it never read this context anyway. That component and AGENT_MEMBER_STATUS_LABEL (~4579–4700) lost their only caller in this resolution, which leaves about 115 dead lines plus the two voids here. Either delete them or say plainly that they're kept so syncs merge cleanly.
🤖 Generated with Claude Code
- Design-change pills: a send that carries them skips the follow-up queue (which has no slot for them), and a multi-model send clears them only once every target started, recording the started thread rather than the draft. - ChatView: the draft pill, context strip memo and stray-drop guard run above the no-thread early return (drops the react(hooks) baseline); the liveness pill memo is back on its own five deps; the mobile dock morph runs on the fork's 400ms clock instead of the off-by-default panel motion. - Mod+Shift+E opens the combined model menu; the speed sr-only label names Ultrafast. - The New agent pill resolves the target project's own environment settings (env mode, start-from-origin, default model, default permissions), and leaves upstream's Scratch folder out of its list. - Settled slim rows mute their PR badge at rest again. - Usage popover never attaches upstream's Escape-to-go-back. - shadcn lint: per-line disables on the fork's lines instead of switching the rules off for three upstream files. - Traffic-light inset follows desktop zoom (8/9 of upstream's inset). - Bootstrap branch fill-in also covers the project-checkout fallback. - Compile cache moves to a fork-owned directory; node-pty and react-native-nitro-markdown are pinned to their patched versions. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Pushed Fixed
Handled in the parallel commit from the session that owns the composer CSS: #5 (Tiptap placeholder selectors and the 4px overhang) and #10 ("Show full message" hover, with its guard and manifest). Not changed
Verified: web, server and desktop typecheck are clean. Fork guards pass 488/488, plus the touched unit tests (design store, new-agent draft, usage). The server branch fill-in tests pass 2/2. 🤖 Generated with Claude Code |
…ndition Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
NoahHendrickson
left a comment
There was a problem hiding this comment.
Code review (/code-review max) at f9adf51
All 15 findings below were confirmed by an independent verifier at this head, and they are ordered most severe first. They are all in this review body because the PR changes 6,535 files and GitHub only indexes the first 3,000 for inline comments, so none of these lines can take one.
Several confirmed issues are left out because 427c3e5 already fixed them: queued messages dropping design pills, hooks after ChatView's early return, the liveness-pill memo deps, Mod+Shift+E (composer.effort) having no target, the Ultrafast screen-reader label, draft settings resolving against the primary environment, settled-row PR badge muting, the shadcn lint scope, and the node-pty/nitro-markdown pins. Roughly 20 lower-priority confirmed items were also cut: stale guards and manifest intents, upstream docs that describe upstream's UI, unfenced edits, and duplicated code.
1. apps/desktop/src/main.ts:142: SSH launches fail on packaged fork builds. This hands environment.appVersion to the SSH runner as its archive version. A packaged fork build (0.1.x, set by fork-release.yml's --build-version) therefore asks pingdotgg/t3code for a release that doesn't exist.
In archive mode the launch script runs
"$RUNNER_FILE" --versionunderset -eubefore any reuse check. The runner fetcheshub.lumenfield.work/pingdotgg/t3code/releases/download/v0.1.39/SHA256SUMS, gets a 404 (reproduced: curl exit 56), and the launch aborts. Before the sync, remotes witht3on PATH or a server already running still worked; now they fail too. Dev builds report 0.0.45, which upstream does publish, so local testing never shows this. A fenced, pinned upstream base version would avoid it.
2. apps/web/src/theme.custom.css:736: every desktop composer gets phantom scrollbars. The fork's scroll box on [data-fork-composer-prompt] now overflows by 4px on both axes, because upstream's Tiptap editor uses -m-1 … p-1 inside a flow-root container (pingdotgg#13301). At ≥40rem with a one-line prompt, the editor's border box spans [-4, W+4] × [-4, 27] inside a W × 23 wrapper with overflow-y: auto (so overflow-x computes to auto). index.css styles ::-webkit-scrollbar, which makes scrollbars always-on in Chromium/Electron, so a 6px vertical thumb and a horizontal bar show under the prompt, and a trackpad can nudge the text 4px. The fork's own comments at :748-765 describe guarding against exactly this. Quick check: $('[data-fork-composer-prompt]').scrollHeight - clientHeight === 4.
3. apps/web/src/theme.custom.css:701 (also :727, :766, and theme.custom.westworld.css:198): the placeholder rules match nothing. They select [data-testid="composer-editor"] ~ div, a sibling layout only Lexical had. Under Tiptap the placeholder is a sibling of EditorContent's wrapper, so the colour, the 14/23 type, the overflow clip and Westworld's draft-placeholder ink are all gone (a jsdom render of the real editor matches 0 elements). The placeholder renders upstream's text-placeholder/75. On the Westworld draft hero it loses its white-70% ink over the portrait, which is the legibility bug the westworld rule exists to fix. At a non-14px prompt font size the placeholder and the caret disagree. The guards only regex the CSS text, so they stay green.
4. apps/web/src/components/chat/ChatComposer.tsx:1139: Empty chips in narrow strips. The merge tagged the fork's text-only Build/Plan label (and the runtime SelectValue at :1174) with data-composer-control-label. Upstream's new icon-only collapse step hides those labels.
Phone-width web client on a server thread, composer unfocused, crowded strip (PR chip, liveness pill, env chip).
resolveRestingComposerControlsLayoutreturnsiconOnlyCount: 1for host widths between the icon-only and natural widths.[&_[data-composer-control-label]]:invisible absolutethen leaves the Build/Plan toggle as an empty pill and the runtime chip as a bare chevron. Before the sync, the block moved into the ⋯ overflow menu with its labels intact. Dropping the attribute from both places restores that.
5. apps/web/src/components/ChatView.tsx:7784: Design-pill sends overtake queued messages. 427c3e5's gate skips the whole queue branch, including upstream's queueStillSending ordering guard, and ignores Mod+Enter's 'queue this one'.
A turn is running with
followUpBehavior: "queue"(the default). The user sends A, which is queued until the next tool completes. They then attach a design change and send B. Becausecount(...) === 0is false, B goes out immediately as a turn start on the running thread (a steer; on Grok this cancels the in-flight prompt) while A keeps waiting. The agent reads B before A, and B lands above A in the transcript. The same happens on an idle thread whose queue head is still preparing attachments. The real fix is probably a pills slot onQueuedComposerMessage; removing the gate brings back the dropped-request bug.
6. apps/web/src/custom/ComposerShell.css:26: the runtime-mode chip shows a chevron in every composer. The rule that hides its caret targets [data-slot="select-icon"], which upstream's rewritten ComposerSelectControl no longer emits; it renders a bare <SelectPrimitive.Icon>. That breaks the manifest intent "label only, no icon or caret".
7. apps/web/src/components/Sidebar.tsx:1353 (also DraftProjectPill.tsx:212 and :252): the fork's folder marks never render. Upstream pingdotgg#11572 made ProjectFavicon return a coloured monogram whenever the project has a title, before it looks at fallbackIcon. Any project without a favicon now shows a hashed-colour two-letter tile in Sidebar V2 cards, the draft project chip and its picker rows, and the tile also flashes while a real favicon loads. sidebarV2CardRows.test.ts only matches the source string, so it stays green.
8. AGENTS.md:97: Upstream's instruction leaks a credential in this fork. It says to keep the admin T3CODE_DEV_AUTH_TOKEN in "the main checkout's gitignored .env", but this fork force-tracks .env in a public repo.
A maintainer or agent follows this line (CLAUDE.md symlinks to it) or
docs/operations/development.md:73.setup-worktreesymlinks.envinto every worktree and git shows the tracked file as modified, so the nextgit add -Aorcommit -apushes an admin-scoped dev credential to NoahHendrickson/t3code. The t3ConnectOfficialConfig guard only fails after the push. This needs a fenced correction, e.g. point to a gitignored file that setup-worktree also links.
9. apps/web/src/components/ChatView.tsx:8260: Multi-model sends leave the design pills live after the composer is released. This lasts until every target has started, and indefinitely after a partial failure.
(1) The composer is released at 8242-8244 while
await startswaits for checkout and setup scripts, which can take minutes. A new prompt sent in that window goes throughtakeForSend(a pure read), so the same<design_change_request>is appended again. (2) One target fails while the user has typed B:canRestoreDraft()is false and the toast says to send or clear B first. Sending B takes the old pills andmarkSentclears them. 'Restore prompt' then brings back text and attachments but no pills, so the failed model never gets the design request.
10. apps/web/src/components/BranchToolbarBranchSelector.tsx:792: A single-PR chip loses the fork's chip styling. It now renders through upstream's ThreadPullRequestBadgeControl, which emits an <a> with no data-slot for a single PR. None of the fork's :is(button, [data-slot="button"], [data-fork-context-chip]) context-chip rules match it.
A thread whose branch has exactly one linked PR, which is the common case. The chip renders with bare ComposerControl xs styling (transparent, 7px padding,
--control-radius, upstreamhover:bg-accent) next to the 24px glass-filled, 6px-radius chips; onlyorder: 1still applies. Stacks and multi-PR badges render as<button>and keep the styling, so the chips are inconsistent. Addingdata-fork-context-chipto the render element would fix it.
11. apps/web/src/theme.custom.css:2958: long file names render in two tones. The changed-files rule targets span.truncate, which under upstream's new MiddleTruncate (pingdotgg#12805) is only the head of the name. For a 15+ character name such as MessagesTimeline.tsx, "MessagesTi" renders at full --foreground and "meline.tsx" at the wrapper's text-foreground/85, a visible seam in nearly every card until row hover.
12. apps/web/src/overrides/components/chat/ModelPickerContent.tsx:514: A Shift-toggle from search results still runs the single-pick tail. It clears the query and opens the provider page, so a multi-model selection can't be built from one search.
Multi-model draft, combined menu open. The user types '5.5' and Shift-clicks Opus 5.5. It is toggled in, then
setSearchQuery('')andopenPage(Claude models)run. A second Shift-click where GPT-5.5 was now hits whichever Claude row (or the back row) sits there. Upstream keeps the query on a toggle. Fix:if (!isSearching || additive) return;.
13. apps/web/src/components/ChatView.tsx:8710: Unsent design pills are orphaned when a draft is re-threaded. If the bootstrap thread is deleted (Cancel setup, or Work locally after thread creation), the draft gets a new id from newThreadId(), but its unsent pills stay keyed under the old id.
A new-worktree draft with a design pill is sent, and the user cancels setup after the thread is created.
startPromisefails with disposition 'deleted' andturnStartSucceededis false, so the pills aren't cleared. The draft is then re-threaded here; the background path does the same throughrestoreFailedBackgroundDraftThreadaround :8652.useDesignChangeTargetRefresolves the new id, so the composer shows no pills and the next or automatic send reads an empty key. The old entries stay orphaned in the store.
14. apps/web/src/components/ChatView.tsx:7190: Rewind restores raw design-request markup. Upstream's new rewind path uses recallableComposerPrompt(message.text), which only strips terminal, element and preview blocks, so rewinding a turn that carried a design request writes the raw <design_change_request> markdown into the composer.
The user rewinds 'Fix the header' plus a design pill. The composer gets
Fix the header\n\n<design_change_request>…</design_change_request>with the caret after it. If they type and resend, the run is no longer trailing,extractTrailingDesignChangesfinds nothing, and the transcript shows the raw request inline. On servers without inline message context, the legacy context blocks also survive (reproduced with the real module).
15. apps/web/src/components/ChatView.tsx:8266: 427c3e5's multi-model sent-preview fix doesn't take effect. The record is keyed on the first started thread but stored under the pill's runtimeTabId, which embeds the draft's thread id. No panel can ever match both.
Draft D has a preview tab and sends design pills to two models.
markSentwritesbyTabId[runtimeTabId(D)] = { threadKey: key(S1) }. D's panel finds the record but compares it againstkey(D), sodesignSentPreviews.ts:248returns false. S1's panel computes aruntimeTabIdcontaining S1 and finds nothing. No 'did it land?' prompt appears, verification never arms, and the record stays until Discard or the tab closes (reproduced with the real modules).
🤖 Generated with Claude Code
- Design-change pills ride queued messages in their own slot (appended at dispatch, recorded for the resolution prompt, handed back on Stop), so a send with pills keeps the queue's order and Mod+Enter again. - Multi-model sends detach the pills when the composer clears and restore them with a failed target's draft; no sent-preview record, since the draft's preview tab can't answer for the started threads. - A draft re-minted after its bootstrap thread is deleted keeps its pills; rewind strips the trailing design-change run before recalling the prompt. - The text-only Build/Plan and runtime chips drop data-composer-control-label, so upstream's icon-only collapse can't empty them; the mode chip hides upstream's bare Select.Icon caret again. - An explicit fallbackIcon beats upstream's title monogram, so the card and project chip folder marks render. - Shift-toggling a search result keeps the query. - SSH remotes fetch the upstream release the fork is synced to, not the fork's own 0.1.x version. - The reusable dev auth token goes in .env.local (this fork tracks .env); setup-worktree links it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Pushed Fixed
Already in the held commit Open: #11 (two-tone Verified: web and desktop typecheck pass, fork guards pass 491/491, plus the touched design-store, queue-sender, composer and favicon tests (693 in total). Lint on the touched files shows 0 errors, 🤖 Generated with Claude Code |
NoahHendrickson
left a comment
There was a problem hiding this comment.
Reviewed the prior review bodies, the inline thread, and the follow-up fixes through 2a0c5c5b0199d115c07f5636dc1f73b9ce09da03. There is still work to do before calling the feedback fully addressed. This is a review of the reported fork-integration issues and their fixes, not an exhaustive audit of the upstream commit range.
Remaining reported issues
-
[P2] Land and verify the held composer CSS fixes. The PR head does not contain
eb2bab85a. The desktop prompt still combines the fork's scroll container with Tiptap's-m-1 p-1overhang, and the placeholder selectors still target a sibling of the contenteditable rather than a sibling of itsEditorContentwrapper. The scrollbar and placeholder findings therefore remain in the code being merged, including the Westworld placeholder rule. The held changes need to reach this branch after their visual pass. -
[P3] The other held styling fixes are also absent. A single PR renders as an anchor bearing
data-fork-pr-chip, but the context-chip geometry selector still matches only buttons, button slots, anddata-fork-context-chip. “Show full message” usesghost-muted, while the transcript hover rule only targetshover:bg-accent/20. Both fixes are in the held CSS commit, not this PR head. -
[P3] Finish the filename-color fix. The changed-files selector still colors only
span.truncate.MiddleTruncaterenders the tail in a separatespan.shrink-0, inheriting the wrapper'stext-foreground/85. Long filenames remain two-tone at rest. Apply the same ink to both halves without changing the intentionally muted header hint.
Omission in the latest queue fix
- [P3] Show queued design attachments in the queued-message row. QueuedMessageTimelineRow counts images/files and terminal/preview/review contexts, but never reads
queuedMessage.forkDesignChanges. Queue a design-only message during a running turn: the composer pill disappears correctly, but the queued row has no content or attachment summary—only “Queued” and its controls. With prose, the attached design request is likewise invisible until dispatch. Include a design-change summary/count so users can identify what is waiting and choose the correct row to send or restore. The sender itself now carries the payload correctly.
Explicit limitation, rather than a restored capability
The latest multi-model fix deliberately detaches the pills without creating a sent-preview record. This removes the invalid record, but multi-model sends still cannot offer the “did it land?” verification flow. Please record this as an accepted limitation/follow-up, or implement the missing flow, rather than treating that behavior as restored.
The other substantive fixes checked out on inspection, including payload delivery, queue ordering, failed-send restoration, draft rekeying, rewind cleanup, settings resolution, shortcuts, hooks ordering, SSH archive selection, dependency pins, and the original CI repairs. Deferring Cursor's model-menu extraction is reasonable: its asserted 1,000-line budget is not a repository rule. The liveness pill's “View agents” action remains an acknowledged follow-up.
Validation: 559 focused web tests passed using the web project's configuration, including the fork guard suite, design draft store, queued sender, new-agent draft, TraitsPicker, and model-picker tests. Current CI is green. No browser/visual verification performed; the remaining UI findings were checked against source and markup. No source changes made.
Review by GPT-6 via Codex.
A design-only queued message rendered as an empty row, and a design request queued with prose was invisible until dispatch. The row's summary now counts design changes like attachments. Also records the multi-model sent-preview gap as an accepted limitation in the manifest. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…a markup Three fork rules were written against markup upstream replaced in this sync. The prompt wrapper is the fork's scroll container, and Tiptap's editor wears a 4px negative margin with matching padding, so the overhang spilled past the wrapper and painted a horizontal scrollbar thumb under the draft placeholder. The wrapper now absorbs the overhang with its own padding and negative margin; the draft-hero minimum and the scroll cap grow by the same amount so the drawn geometry is unchanged. Tiptap also wraps the editor in a div, so the placeholder is reached through that wrapper with :has() for its colour, type metrics and overflow clip, in the base theme and the Westworld overlay. Upstream's pull request badge renders a single linked PR as an anchor, not a button, so the context-row chip fill, hover, glyph and glass rules now name [data-fork-pr-chip] explicitly across the three theme files. The "Show full message" line is a ghost-muted Button since this sync and hovers with the opaque accent; it takes the fork's 4% lift through the user-message footer upstream stamps around it (ultra-review finding #10). Guards pin the new selectors; the manifest intents describe the new markup. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Upstream's MiddleTruncate splits a long name into a truncating head and a shrink-0 tail; the fork's dark path-label rule only reached the head, so the tail kept the wrapper's /85 ink and the name read in two tones. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Re the review at
🤖 Generated with Claude Code |
|
Pushed 🤖 Generated with Claude Code |


Problem
customwas 821 commits behind upstream (last sync point12391bd0d, 2026-09-08). Upstream's next commit after this range is pingdotgg#2829, the new orchestrator — a full server rewrite that landed today, deletes the hosts of two fork server customizations (CheckpointReactor.ts,server.test.ts) and adds ~40 migrations. That one is deliberately not in this PR; it gets its own sync.What this does
Merges
upstream/mainthrough024d49520(v0.0.44–v0.0.45 cycles) intocustom. 43 conflicted files resolved, 6 override shadows ported by hand (they never conflict, they drift).Notable decisions, all fenced and recorded in
.fork/customizations.yaml:checkinto lint/typecheck/build; the fork's runner, lint-owned and shellcheck fences re-seated on the new jobs. Release gates follow the split macOS preview workflows (desktop-macos-preview-publish.ymlis newly gated).@shadcn/lintplugin (no-restyle,no-arbitrary-values, …) is error-level and fires ~280 times on fork components by design (restylingcomponents/uiis the fork's purpose). A fencedvite.config.tsoverride turns those rules off for fork-owned files only; upstream code keeps the gate. React Compiler rule baselines inlint-owned.mjsre-measured after the vite-plus 1.0 bump.resolveProjectSettings(environment setting now outrankst3.json; the fork previously had the reverse).Verified
vp lint apps/web/src0 errors;.fork/lint-owned.mjsno blocking warningsNot run in a browser. Worth a look after merge: provider switch with the combined model menu open via keyboard (Tiptap focus), and the transcript mask inset.
Follow-ups (not in this PR)
--desktop-window-controls-insetemits 90px; the fork wants 80).Claude Fable 5.1 via Claude Code (T3 Code), with three subagents for the sidebar, composer and override-shadow clusters.
🤖 Generated with Claude Code