Skip to content

chore: sync upstream v0.0.32 line (47 commits) - #44

Merged
NoahHendrickson merged 49 commits into
customfrom
claude/sync-2026-08-02
Aug 2, 2026
Merged

chore: sync upstream v0.0.32 line (47 commits)#44
NoahHendrickson merged 49 commits into
customfrom
claude/sync-2026-08-02

Conversation

@NoahHendrickson

@NoahHendrickson NoahHendrickson commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Problem

custom was 47 commits behind the upstream mirror (origin/main = pingdotgg/t3code@e60821f0e). Notable upstream changes: the libghostty-vt terminal renderer replacing xterm.js (pingdotgg#4860), sidebar thread search (pingdotgg#4769), the Clerk bridge now owning Electron's single-instance lock, thread snoozing on mobile with the snooze API moved into client-runtime, and the ⌘P project file picker (pingdotgg#4855).

How it was resolved

Four conflicted files:

  • .github/workflows/ci.yml — kept the fork's ci-runners fence (macos-latest, 30 min) over upstream's new Blacksmith label. No new Blacksmith labels leaked into ci.yml, and the other workflows' runner label set is byte-identical to the fork's pre-merge state — but their files did change (sparse-checkout blocks excluding /.repos/, narrowed run-install filters, release.yml dropping fetch-depth: 0 from two jobs). Those workflows are release/relay/EAS paths the fork gates separately. ci.yml's mobile_native_static_analysis and release_smoke jobs moved from run-install: true to a --filter=@t3tools/scripts... install scope; CI on this branch is the proof that release-smoke.ts still resolves under it.
  • apps/desktop/src/app/DesktopClerk.ts — took upstream's userData-before-lock setup unconditionally, kept the fork's keyless bridge skip. Upstream's configure now reads bridge.isPrimaryInstance; the keyless path (no bridge) takes the lock directly via Electron.app.requestSingleInstanceLock() (the ElectronApp service method was removed upstream). DesktopClerkForkSkip.test.ts updated for the layer's new providers.
  • apps/web/src/components/SidebarV2.tsx — fork side kept wholesale (the card-rows redraw and PR feat(web): restyle sidebar chrome and monochrome accents #43 chrome own this file), then upstream's two applicable changes ported in: the tooltip inset normalization (follow-up normalization after #4700. pingdotgg/t3code#4498) and the new snoozeWakeLabel({ now }) signature (feat(mobile): add thread snoozing pingdotgg/t3code#5053). Upstream's settle-overlap fix (fix(web): stop settle controls overlapping the status label pingdotgg/t3code#4574) targets markup the fork's card redraw already replaced.
  • apps/web/src/components/ThreadTerminalDrawer.tsx — took upstream's ghostty setup and re-ported geist-typography: the surface takes font: { family: resolveTerminalFontFamily(mount) } and handles the webfont re-measure itself, so the fork's xterm refit shim (refitTerminalWhenFontsReady) is deleted from custom/terminalFont.ts along with its guard suite. Manifest intent text updated to match.

Follow-ups in the same commit: two new phosphor shim mappings (FileSearchIcon → FileMagnifyingGlass, TextSearchIcon → ListMagnifyingGlass) for the new file-picker icons.

⚠️ Deliberately not adopted: sidebar thread search (pingdotgg#4769)

Upstream's inline search input + results listbox lives in the sidebar chrome the fork replaced in PR #43 (palette-trigger Search row, per Figma 149:6235). Adopting it would rewrite the day-old fork chrome, and the fork-sidebar-chrome manifest explicitly forbids restoring upstream's chrome imports during a sync. The pure helper (searchSidebarThreadsByTitle in Sidebar.logic.ts) and its tests are kept, so porting the feature into SidebarV2ChromeRows later is straightforward — but that's a design decision, not a sync resolution. Flagging for an explicit call on whether/how the fork wants inline thread search.

Verification

  • Fork guard suite: 27 files, 197 tests passing
  • DesktopClerk suites (upstream + both fork suites): 11 tests passing
  • Sidebar.logic / Sidebar.snooze / ThreadTerminalDrawer / SidebarStageBackdrop tests: all passing
  • Web + desktop typecheck clean; fork-lint: 60 fork-owned files, no warnings; drift detection exit 0; vp fmt --check clean on all hand-touched files

Merged and verified by Claude Fable 5 (claude-fable-5) via Claude Code.

🤖 Generated with Claude Code

t3dotgg and others added 30 commits July 30, 2026 07:30
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…hy (pingdotgg#4988)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…tgg#4855)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Julius Marminge <julius0216@outlook.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
actions/checkout implements sparse-checkout with --filter=blob:none, so
the runner repo is a partial clone missing the .repos/ blobs. eas-cli
archives the project via `git clone --depth 1 file://<workspace>`,
which upload-pack cannot serve from a partial clone and exits 128
(pingdotgg#4802 broke both EAS build workflows this way).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…/ scheme on Linux (pingdotgg#5015)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…elpers (pingdotgg#5027)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ingdotgg#5025)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… to new tasks (pingdotgg#5064)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ngdotgg#4955)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge and others added 18 commits July 31, 2026 13:11
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…oot (pingdotgg#5102)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: T3 Code Test <t3code-test@example.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ydration (pingdotgg#5147)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…o their thread (pingdotgg#5159)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
…debug (pingdotgg#5076)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…erver running (pingdotgg#5217)

Co-authored-by: Claude <noreply@anthropic.com>
Absorbs 47 upstream commits, including the libghostty-vt terminal
renderer, sidebar thread search (not adopted in fork chrome — see PR
body), Clerk bridge single-instance lock, and the ⌘P file picker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cursor

cursor Bot commented Aug 2, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Aug 2, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thermo-nuclear code quality — DO NOT APPROVE

This is largely an upstream sync into custom, and the fork conflict resolutions (DesktopClerk, SidebarV2, ThreadTerminalDrawer geist port, terminalFont cleanup) look correct. The structural bar still applies to what lands.

Blockers

  1. ghostty/surface.ts (1393, NEW)GhosttyTerminalSurface is a god-class (~50 private fields; key/IME/pointer/scrollbar/blink co-located). Split into fonts/input/pointer/scrollbar + a thin facade. Upstream origin does not waive the 1k rule for a new module.
  2. ghostty/core.ts (1189, NEW) — ABI types, lifecycle, encode*, selection, and readRow in one class; paste/selection re-copy the probe→alloc pattern that encodeOutput already owns. Decompose and dedupe.
  3. CommandPalette.tsx — proved the extraction pattern (ProjectFilePicker / ProjectContentSearchDialog) then left OpenCommandPaletteDialog as an ~1800-line god function. Finish the judo: extract add-project/clone (and ideally browse/actions) the same way.

High

  • FilePreviewPanel.tsx 973→1065 — move useFileLineReveal out; extracting the centered-scroll helper was not enough.
  • ThreadTerminalDrawer.tsx — ghostty swap kept a giant mount effect inside a 1525-line file; extract mount/selection setup.

Watch

  • CheckpointReactor.ts 866→946followWorktreeBranchDrift is coherent, but the file is near 1k; land further drift helpers elsewhere.

Acknowledge

serviceLauncher slim of selfUpdate, well-sized ProjectFilePicker/ProjectContentSearchDialog, clean renderer/runtime/serviceProtocol seams, and the fork terminalFont shim deletion. ClaudeProvider 995→1005 is threshold noise.

Restructure the blockers and re-request review.

Open in Web View Automation 

Sent by Cursor Automation: Thermo-nuclear PR review

readonly onLinkActivate: (text: string, event: MouseEvent) => void;
}

export class GhosttyTerminalSurface {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocker: this lands at 1393 lines with ~50 private fields (selection/IME/pointer/scrollbar/blink/paste). Natural split is surfaceFonts / surfaceInput / surfacePointer / surfaceScrollbar + a thin facade. Upstream sync does not waive the 1k rule for a new god-class — decompose before merge.

return left.r === right.r && left.g === right.g && left.b === right.b;
}

export class GhosttyTerminalCore {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocker: GhosttyTerminalCore is 1189 lines mixing ABI layouts, lifecycle, encode*, selection, and snapshot. readRow alone is ~124 lines; encodePaste / selectionText re-implement the probe-size→alloc dance that encodeOutput already centralizes. Extract coreTypes / encode / rows and route paste+selection through the shared helper.

props.setOpen(false);
}}
>
{props.mode === "files" ? (

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missed code-judo: this correctly extracts ProjectFilePicker + ProjectContentSearchDialog, then OpenCommandPaletteDialog (L524+) stays an ~1800-line god function still owning add-project/clone/browse/actions with repeated addProjectCloneFlow?.step branching. The PR proved the pattern — finish it. Extract at least the clone flow into its own dialog module so this file stops being the dumping ground.

};

pendingFramesByPath.set(relativePath, requestAnimationFrame(reveal));
const guardScrollTarget = (line: number) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this pushes FilePreviewPanel past 1k (973→1065). resolveCenteredFileLineScrollTop was extracted but useFileLineReveal (~165 lines of Map state + rAF + guard cancellation) is still in-panel. Move the hook into fileLineReveal.ts (or a dedicated module) so the panel stays under the threshold.

let setupCleanups: Array<() => void> = [];

const setup = async (): Promise<(() => void) | null> => {
const terminalOptions: GhosttyTerminalSurfaceOptions = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ghostty migration replaced xterm but left TerminalViewport's mount as one giant async effect (setup through ~L731) inside a 1525-line file. Extract useGhosttyTerminalMount / selection+clipboard setup so the viewport is render + small sync effects. Same structural debt, new backend.

// orphans the thread's PR. Follow the drift here: adopt the checked-out
// branch as the thread's branch, but only when the worktree belongs to
// exactly this thread — for shared cwds the strict matching is the point.
const followWorktreeBranchDrift = Effect.fn("followWorktreeBranchDrift")(function* (input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

followWorktreeBranchDrift is coherent, but this file is 866→946 and approaching 1k. Prefer landing further drift/worktree helpers in a dedicated module now so the next sync does not tip CheckpointReactor over the line.

Copy link
Copy Markdown
Owner Author

Review

Reviewed at 20910edd. A 47-commit merge isn't reviewable as a unit, so I worked the surface that actually got authored: the 26 files whose content differs from both parents (d095fd86 and e60821f0). That's the real hand-resolution set — four of them are the conflicts the description names, the rest are files where git auto-merged fork hunks against upstream hunks without asking anyone, which is where sync bugs usually live.

I could not run the suite (no node_modules, no vp in this environment), so the test counts in the description are unverified by me. Everything below is read from the tree.


1. The typography customization now depends on an upstream file it doesn't watch

This is the one I'd hold the merge for.

The PR deletes refitTerminalWhenFontsReady and its five behavioural tests, on the stated grounds that the ghostty surface handles the cold-load re-measure itself. That grounds check out — surface.ts:453-458 awaits document.fonts.load(...) before measureGhosttyCell, and surface.ts:412/540-553 re-measure on loadingdone. The deletion is correct.

The problem is what replaced the tripwire: nothing. geist-typography's watch: list (.fork/customizations.yaml:1166-1174) is still index.css, ThreadTerminalDrawer.tsx, annotationTheme.ts, package.json. .fork/detect-drift.mjs:65 only reports drift for paths in shadows: + watch:, so apps/web/src/terminal/ghostty/surface.ts — 1,393 lines old as of today, and guaranteed to churn — can lose its loadingdone listener in some future sync and the drift report will be empty.

Net trade in this PR: five tests the fork owned, exchanged for an unguarded dependency on upstream internals, with the detector for that dependency left switched off. The intent prose at customizations.yaml:1137-1141 states the dependency precisely and correctly; the machine-readable half doesn't know about it.

Fix is two lines plus a guard:

  watch:
    - apps/web/src/index.css
    - apps/web/src/components/ThreadTerminalDrawer.tsx
+   # The fork deleted its own refit shim because the surface does this. If
+   # upstream stops, the terminal silently measures against fallback metrics.
+   - apps/web/src/terminal/ghostty/surface.ts
it("keeps upstream's cold-load re-measure, which the fork's shim was deleted for", () => {
  const surface = readSibling("../terminal/ghostty/surface.ts");
  expect(surface).toContain("document.fonts.load(");
  expect(surface).toContain('"loadingdone"');
});

Failure mode without it is the exact one the deleted suite existed to catch, and it's silent: a Geist Mono grid measured at fallback advances, with the PTY wrapping to a column count nobody re-derived.

2. The replacement guard is pinned to prettier's output

geistTypography.test.ts:103:

expect(drawer).toContain("font: { family: resolveTerminalFontFamily(mount) }");

That asserts an object literal stayed on one line. Add a size field, or push ThreadTerminalDrawer.tsx:390 past the print width, and vp fmt wraps it — the guard goes red with a message pointing at a missing call site that is in fact right there. The two assertions it replaced ("fontFamily: resolveTerminalFontFamily(mount)", "refitTerminalWhenFontsReady({") were single-token substrings and immune to this.

expect(drawer).toMatch(/font:\s*\{\s*family:\s*resolveTerminalFontFamily\(mount\)/u);

3. The fork's mono stack puts a generic family mid-list, ahead of the Nerd Font fallbacks

terminalFontFamily() (surface.ts:62-67) appends TERMINAL_GLYPH_FALLBACKS after whatever the caller passes. The fork passes the whole cascade-resolved --font-mono, which per theme.custom.css:54-56 ends in monospace. So the composed stack the fork ships is:

"Geist Mono Variable", …, Menlo, monospace, "Symbols Nerd Font Mono", "Symbols Nerd Font", …, monospace

Upstream's own DEFAULT_TERMINAL_FONT_FAMILY never does this — it lists no generic before the glyph fallbacks, precisely because the fallbacks are the tail. Per-character font matching should walk past a generic whose resolved face lacks the glyph, so powerline separators and devicons probably still render. But "probably" is doing work here: this is a stack shape upstream never exercises, reached only through the one line the fork owns, and the symptom if I'm wrong is tofu in prompts for every fork user with a Nerd Font shell theme.

Either trim a trailing generic in terminalFontFamilyFrom before handing the stack over, or open a terminal in a fork build with a powerline prompt and confirm. Not expensive either way; worth not guessing.

4. searchSidebarThreadsByTitle is dead production code

Sidebar.logic.ts:498 — exported, tested at Sidebar.logic.test.ts:695-712, referenced by nothing that renders. The description explains why (porting pingdotgg#4769 into SidebarV2ChromeRows later is a design call, not a sync resolution) and I agree with the call — the fork's chrome is a day old and upstream's inline search input targets markup that no longer exists.

Two things follow from that, though. First, tested-but-unmounted code reads as coverage from inside the suite; the 197-test guard number gets a little less honest each time this happens. Second, the reason it's being kept lives in a PR body, which is not a place future syncs look. Put a line in the fork-sidebar-chrome manifest entry — that entry already documents the deliberately-shorter import header in exactly this spirit — or drop the helper and re-take it from upstream when the design decision actually lands. Right now the next person to sync finds an orphan and no explanation in the tree.

5. Web snooze labels don't tick; mobile's now do

This sync moves snoozeWakeLabel to { now } on both surfaces, and the two surfaces landed in different places:

  • mobile threads a minute-granularity tick — HomeScreen.tsx:668 and ThreadNavigationSidebar.tsx:570 both pass snoozeLabelNow: \${nowMinute}:00.000Z``, so the countdown updates on its own
  • web (SidebarV2.tsx:3042) calls new Date().toISOString() inline inside the row map, so 2h stays 2h until something unrelated repaints the sidebar

Not a regression — the pre-merge call (snoozeWakeLabel(thread.snoozedUntil, new Date())) was equally untimed. But this PR is the moment the surfaces diverged, and CLAUDE.md names "a stale label" in the same breath as a dropped frame and a lying spinner. Follow-up sized, not blocking, but it should be a follow-up that exists.

6. The description overstates what CI escaped

No new Blacksmith labels leaked into ci.yml; the other workflows are unchanged from the fork's pre-merge state.

First half verified — I diffed the blacksmith label set between d095fd86 and the merge and it's byte-identical, and all four ci-runners fences survived intact (ubuntu-latest ×3, macos-latest for mobile native static analysis, 30 min each).

Second half isn't right. release.yml, deploy-relay.yml, mobile-eas-preview.yml, mobile-eas-production.yml and mobile-showcase-screenshots.yml all changed: sparse-checkout blocks excluding /.repos/, narrowed run-install filters, and release.yml dropped fetch-depth: 0 from two jobs. Unchanged labels, changed files. Worth correcting because the sentence is the reason a reviewer would skip those diffs.

One thing in there to confirm rather than assume: ci.yml's mobile_native_static_analysis and release_smoke jobs went from run-install: true to --filter=@t3tools/scripts.... That's upstream tuning install scope for upstream's dependency graph, and scripts/release-smoke.ts is the thing that has to still resolve under it on this branch. CI is where that surfaces, so it should be green before merge rather than after.

7. #13 will conflict

PR #13 is still open and adds an assertion to geistTypography.test.ts pinning FORK_TERMINAL_FONT_FALLBACK to the CSS stack. This PR rewrites that file (removing the whole cold-load re-measure describe and five imports). #13's assertion still makes sense afterward — both FORK_TERMINAL_FONT_FALLBACK and terminalFontFamilyFrom survive — but it needs a rebase, or it eats a review round on a conflict nobody caused.


Checked and clean

Stating these so the review's silence isn't mistaken for not looking:

  • Phosphor shim coverage is complete. I extracted every named import from lucide-react across apps/web/src — 154 distinct names — and diffed against the shim's exports. Zero missing. Given the lucide-react → shim alias in vite.config.ts:189, a single upstream icon the shim doesn't re-export is a build break, and this is the highest-frequency silent-breakage class in this fork. FileSearchIcon / TextSearchIcon are correctly added and both are live at CommandPalette.tsx:1401,1414.
  • Manifest integrity. Every path across all files:/shadows:/watch:/verify: lists still exists post-merge. No stale entries from the native/libghostty-vt relocation.
  • xterm is genuinely gone. No residue outside prose comments and unrelated xterm-256color TERM strings in NodePtyAdapter. Both @xterm/* deps dropped from apps/web/package.json; the .thread-terminal-drawer .xterm scrollbar rules are removed from index.css and replaced by .t3-ghostty-scrollbar*.
  • The keyless Clerk path is coherent under upstream's new lock ownership. bridge.isPrimaryInstance when keyed, Electron.app?.requestSingleInstanceLock() ?? true when not; second-instance is registered in configure on both paths, so keyless builds keep deep-link forwarding. setPath("userData") precedes lock acquisition on both — required, since Electron scopes the lock to userData and creates the directory on acquire. The duplicate setPath at DesktopApp.ts:241 and DesktopClerk.ts:124 is upstream's own shape, present at e60821f0, not a merge artifact.
  • New assets don't hit the JS bundle. ghostty-vt.wasm (630 KB) and SymbolsNerdFontMono-Regular.woff2 (1.15 MB) are ?url imports fetched on first terminal open, and the symbols face is lazily registered once per page behind symbolsFontLoad. Nothing here contradicts the performance bar.
  • Fork hunks survived every auto-merged file I opened: ChatView's composerContextStrip memo and the useCallback that exists to keep it, SettingsPanels' cool-dark option and its useSettingsRestore wiring, SidebarChrome's full header rewrite, TraitsPicker's triggerLabelSeparator, ProjectScriptsControl's data-fork-pill on both branches, every index.css fence, and vite.config.ts's override plugin + icon alias.

The sidebar-thread-search call is the right one and the tooltip/snoozeWakeLabel ports into SidebarV2 are minimal and correct. My blocking ask is item 1 — the deleted shim was load-bearing and its replacement is upstream code the fork has no tripwire on. 2 and 3 are cheap enough to fold into the same commit.


Generated by Claude Code

@NoahHendrickson NoahHendrickson left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review result: one actionable fork-specific finding; no other blocking issues found.

[P2] Exercise the keyless single-instance path

DesktopClerkForkSkip.test.ts:83-86 says the single-instance lock “must keep working,” but it only checks that service.configure exists. This sync changes that branch from the injected ElectronApp.requestSingleInstanceLock service to the fork-only Electron.app?.requestSingleInstanceLock() ?? true path in DesktopClerk.ts:185-195. As written, the suite would still pass if the Electron namespace did not expose app and every keyless launch silently took the ?? true fallback, allowing a second instance to continue.

Please execute service.configure with a mocked Electron app and cover both outcomes: primary registers the second-instance handler; secondary calls quit, interrupts startup, and does not register the handler. That also makes the manifest claim that singleton locking is preserved on both keyed and keyless paths an actual behavioral guard, as required by .fork/AGENTS.md.

Everything else I checked in the merge integration looks sound: the PR targets custom; the CI runner fence is preserved; the Ghostty font adaptation matches the surface’s load/remeasure behavior; the sidebar keeps the fork chrome while adapting the snooze API; the new Phosphor icon mappings resolve; 34 focused test files / 334 tests pass locally; and all GitHub CI jobs are green. The intentionally omitted inline sidebar search is reasonable as an explicit follow-up because adopting it here would replace the fork-owned chrome rather than resolve a sync conflict.

…ck tests

- geist-typography now watches ghostty/surface.ts and a guard pins the
  cold-load re-measure the deleted refit shim relied on
- call-site guard is whitespace-tolerant (regex, not a one-line literal)
- terminalFontFamilyFrom strips the trailing monospace generic so the
  surface's Nerd Font glyph fallbacks stay ahead of any generic
- searchSidebarThreadsByTitle orphan documented in fork-sidebar-chrome
- DesktopClerkForkSkip now executes configure on both lock outcomes:
  primary registers second-instance, secondary quits and interrupts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@NoahHendrickson

Copy link
Copy Markdown
Owner Author

Review feedback addressed in 92636b3b6. Item by item:

1. Surface tripwire (blocking) — done, both halves. apps/web/src/terminal/ghostty/surface.ts is now in geist-typography's watch: (with the why as a comment), and the guard suite pins the upstream behavior the deleted shim was traded for: document.fonts.load( and "loadingdone" must stay present in surface.ts. Drift report and CI now both trip if upstream drops the cold-load re-measure.

2. Prettier-pinned guard — replaced with toMatch(/font:\s*\{\s*family:\s*resolveTerminalFontFamily\(mount\)/u), as suggested.

3. Generic mid-list — took the trim rather than the manual verification: terminalFontFamilyFrom now strips trailing monospace generics before the stack reaches the surface, and FORK_TERMINAL_FONT_FALLBACK drops its own trailing generic (the surface's glyph fallbacks restore it at the true tail). Guarded: the composed shape can no longer carry a generic ahead of the Nerd Font faces, plus an edge test for a generics-only stack falling back. The fork now hands the surface the same stack shape upstream's default has.

4. Orphaned search helper — documented in the fork-sidebar-chrome manifest entry, right under the deliberately-shorter-imports paragraph it mirrors: kept on purpose so a future pingdotgg#4769 port is a design decision rather than an archaeology dig, not to be cleaned up, and not to be counted as rendered-path coverage.

5. Snooze labels don't tick on web — agreed follow-up sized; it now exists as #45 with the mobile-parity fix shape sketched.

6. Description overstated — corrected in the PR body: labels unchanged, files changed (sparse-checkout, narrowed run-install filters, dropped fetch-depth: 0), and the release_smoke install-scope change is flagged as the thing CI proves. Checks are running on 92636b3b6 now; the previous commit was fully green including Release Smoke.

7. #13 conflict — correct, this PR rewrites geistTypography.test.ts around it. Both symbols #13 asserts against (FORK_TERMINAL_FONT_FALLBACK, terminalFontFamilyFrom) survive, so it's a mechanical rebase. One interaction to note when rebasing: #13 pins the fallback constant to the CSS stack, and this PR removed the constant's trailing , monospace (item 3), so the assertion may need the same trim on the CSS side of the comparison.

P2 (keyless single-instance path) — done. DesktopClerkForkSkip.test.ts now executes configure with a mocked Electron.app on both outcomes: primary asks for the lock exactly once, doesn't quit, and registers second-instance; secondary quits, exits interrupted, and never registers the handler. The ?? true fallback can no longer silently absorb a missing app — the lock-request call count is asserted. 13/13 passing locally alongside the keyed suites.

On the Cursor automation blockersghostty/surface.ts, ghostty/core.ts, and CommandPalette.tsx structure are upstream-authored code arriving via this sync, same situation as PR #38: restructuring upstream modules in a sync PR maximizes future conflict surface for zero fork benefit. If they're worth splitting, that's an upstream issue. Not acting on those here.

🤖 Generated with Claude Code

@NoahHendrickson
NoahHendrickson merged commit a3c19aa into custom Aug 2, 2026
10 checks passed
@NoahHendrickson
NoahHendrickson deleted the claude/sync-2026-08-02 branch August 2, 2026 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.