Skip to content

fix(web): fix folder links, sidebar search and diff symlink crashes - #671

Merged
rynfar merged 3 commits into
pylonfrom
upstream/2026-09-19-nav-diff-safety
Sep 19, 2026
Merged

rynfar merged 3 commits into
pylonfrom
upstream/2026-09-19-nav-diff-safety

Conversation

@rynfar

@rynfar rynfar commented Sep 19, 2026 •

Copy link
Copy Markdown
Collaborator

Ports four upstream web fixes from T3 Code. Part of upstream integration cycle #667, bounded at upstream b44c1ce5d25ee0d5a5be82e380618a886c19ea96.

Sources

Source Upstream Outcome
9ea9c3d5d2c444133e3ddff40eecf38737951589 #11075 keep a file-to-symlink type change from crashing the diff view Adopted
886c83450797c46ee84ae28fc16c2208cafa965e #10909 folder links from chat open the file tree instead of a broken preview Adopted
c557bb10aa7cbb78a50df230d1e8e24af79cb662 #11761 sidebar search matches message content Adopted
3fd5d6439d8fd49d173503ecda96500463a39bd2 #12315 keep numbered jumps from stealing browser tabs Partial — see below

What lands

A file whose type changes to a symlink no longer crashes the diff view. A folder link from chat now keeps its breadcrumbs, drops the preview pane and reveals the folder in the tree instead of rendering a broken file surface. Sidebar search matches message content, not just titles, with a distinct pending state. Numbered jumps are gated so they stop stealing the browser's own tab shortcuts.

Conflict resolutions worth reviewing

Pylon's files are diverged, so each conflict's "theirs" side carried code from upstream commits Pylon has never adopted. Each was resolved by diffing git show <sha> -- <file> against Pylon's version and applying only that commit's change:

  • projectFilesQueryState.ts — theirs added a directoryPath argument to getProjectEntriesQueryAtom. That is not part of #10909 and Pylon's listEntries({ cwd }) has no such input. Dropped; only ProjectFileQueryState/isNotFile was taken.
  • FilePreviewPanel.tsx — theirs carried useUpdateClientSettings() and a showsRawText word-wrap block. Neither symbol exists anywhere in Pylon. Dropped; the commit's only real change there is previewPath !== null && on canToggleRendered.
  • FileBrowserPanel.tsx — upstream had already reordered the entry-kind guard above the handled-reveal dedupe in a different unadopted commit. Pylon's older placement is kept; only the condition changed, to capture selectedKind and guard undefined.
  • Sidebar.logic.ts / Sidebar.tsx — import-block conflicts, resolved additively so Pylon's OrchestrationThreadShell and delegated-threads imports survive alongside the new ones.

#12315 partial

  • pnpm-lock.yaml deliberately excluded. The upstream hunk was only an alchemy peer-hash churn with no dependency change. The lockfile does not appear in this diff.
  • PullRequestDetailPanel.test.tsx conflicted modify/delete — that file does not exist in Pylon, so it was not created.
  • docs/user/keybindings.md content matches upstream, rewrapped to Pylon's 100-column prose width.
  • Keybinding identity preserved: no key renumbered, no command repurposed. Only when conditions added. ShortcutMatchOptions.context is Partial<ShortcutMatchContext>, so the two new context keys break no existing consumer; all three call sites that build a full context are patched.

Known limits

  • Existing installs keep browser mod+1..9. apps/server/src/keybindings.ts only seeds defaults for commands not already present in a user's keybindings.json, so anyone with persisted thread-jump rules keeps them ungated until they edit them. This matches upstream, but the fix only reaches fresh configs.
  • Media and PDF reads are no longer skipped. #10909 deliberately removes the isMedia short-circuit so a folder named assets.png is detectable. Every image/video/PDF surface now issues a read; the server stats first and returns no body. Upstream accepted this cost; it has not been re-measured on Pylon.

Verification

Re-run on the final head, not taken from a report:

  • vp test run across the diff tree, diff rendering, project files query state, right panel store, sidebar logic and keybindings suites — 7 files, 389 tests passed.
  • vp run -F @t3tools/web typecheck and vp run -F @t3tools/shared typecheck — both exit 0 (@t3tools/shared confirmed to exist, so the flag matched a real package).
  • vp check on the changed files — 0 errors. The 74 warnings are pre-existing React-compiler notes in ChatView.tsx, Sidebar.tsx, _chat.pull-requests.tsx and FilePreviewPanel.tsx; every reported line was checked against the changed ranges and none falls inside one.

Upstream co-author trailers are retained, matching the 24 prior commits on pylon that do the same. Behavior was verified by code reading and unit tests; the folder-link, sidebar-search and keybinding paths were not exercised in a running browser.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@vercel

vercel Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pylon-marketing Error Error Sep 19, 2026 6:17pm UTC

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

github-actions Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.9 KiB 13.9 KiB +1 B (+0.0%) 15.1 KiB ✅
Codex Thread snapshot wire 7.2 KiB 7.2 KiB −2 B (−0.0%) 7.3 KiB ✅
Codex Live turn WebSocket wire 6.7 KiB 6.7 KiB +3 B (+0.0%) 7.8 KiB ✅
Codex Live turn WebSocket decoded 58.0 KiB 58.0 KiB 0 B (0.0%) 66.4 KiB ✅
Codex Live turn messages 8 8 0 (0.0%) 21 ✅
Claude Total thread wire 14.0 KiB 14.0 KiB +7 B (+0.0%) 15.1 KiB ✅
Claude Thread snapshot wire 7.2 KiB 7.2 KiB −4 B (−0.1%) 7.3 KiB ✅
Claude Live turn WebSocket wire 6.7 KiB 6.7 KiB +11 B (+0.2%) 7.8 KiB ✅
Claude Live turn WebSocket decoded 58.9 KiB 58.9 KiB 0 B (0.0%) 66.4 KiB ✅
Claude Live turn messages 9 9 0 (0.0%) 21 ✅

Baseline: 2725b65 · PR result: 67ba1d4 · Source CI: success

Scenario and decoded snapshot size

10 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.

  • Codex decoded thread snapshot: 115.7 KiB
  • Claude decoded thread snapshot: 116.3 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Mnigos and others added 3 commits September 19, 2026 12:16
…iew (#11075)

Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
(cherry picked from commit 9ea9c3d5d2c444133e3ddff40eecf38737951589)
…en preview (#10909)

Co-authored-by: exe.dev user <exedev@ropeway-swimming.exe.xyz>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Yash Singh <saiansh2525@gmail.com>
(cherry picked from commit 886c83450797c46ee84ae28fc16c2208cafa965e)
(cherry picked from commit c557bb10aa7cbb78a50df230d1e8e24af79cb662)
@rynfar
rynfar force-pushed the upstream/2026-09-19-nav-diff-safety branch from 434e84b to 67ba1d4 Compare September 19, 2026 18:17
@rynfar rynfar changed the title fix(web): fix folder links, sidebar search, diff symlinks and numbered jumps fix(web): fix folder links, sidebar search and diff symlink crashes Sep 19, 2026
@rynfar

rynfar commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Adversarial review outcome — 3fd5d6439d (#12315) dropped from this PR

An independent review found that the numbered-jump fix is inert for every existing install and cosmetically harmful on upgrade, so it has been removed from this branch (head now 67ba1d430edc79c53c91e7faa32e1a44bd3cbcd5, three sources).

Why, verified against a real profile rather than reasoned about: apps/server/src/keybindings.ts seeds defaults only for commands not already present in keybindings.json — it never rewrites the when of a rule already on disk. An existing ~/.pylon-code/userdata/keybindings.json contains {"key": "mod+1", "command": "thread.jump.1"} with no when, so after adopting this commit ⌘1 still steals the browser tab for anyone who has run Pylon before. Only brand-new profiles benefit.

Worse, it introduces a regression those users would see: sourceForBinding compares the persisted when against the default's, so all nine thread.jump.* and all nine modelPicker.jump.* rows flip from Default to Custom in Settings → Keybindings, showing an isDesktop clause the user never typed. Eighteen phantom customizations appear on upgrade.

Adopting it as written would ship a fix that does not fix the stated bug and does visible harm. It needs either a backfill for unmodified jump rules or gating evaluated outside the persisted rule — both beyond a catch-up port. Deferring rather than shipping it broken.

Upstream-inherited issues recorded, not fixed here

These are faithful ports of upstream behavior, confirmed present upstream, and are recorded so they are actionable rather than lost:

  1. Sidebar search highlight resets when async content matches land. Sidebar.tsx:2843 resets activeSearchResultIndex on any result-order change. Content matches now arrive after a debounce plus an RPC, so typing auth, pressing ↓↓ and hitting Enter within ~200–600 ms opens the first thread instead of the highlighted one.
  2. The excerpt usually truncates before the match. ThreadSearchMatch.tsx:59 uses truncate; the server builds snippets with a 72-character lead tuned for the ~640 px command palette, but the sidebar row is ~210 px (≈35 characters), so the <mark> is routinely off-screen.
  3. SVGs now ship their full body over the wire. #10909 removes the media short-circuit so folders named assets.png are detectable. Binaries are still rejected by the NUL scan, but .svg is NUL-free text, so a 400 KB hero.svg is read and transferred on every open and then discarded. Noticeable over tunnel or remote environments.
  4. A gitignored folder link renders a blank surface. dist/ is absent from the workspace index, so selectedKind is undefined, no reveal happens and previewPath is null — the user gets an unhighlighted tree and no message at all, where previously they saw the path_not_file error.
  5. File → folder is not noticed for media names. Mutation refresh is off when isMedia and not isDirectory, so an open logo.png replaced by a directory keeps rendering a broken image until the tab is reopened.
  6. A deduped type-change row reveals only its deletion half. revealDiffFile takes the first path match, so clicking the single "config.yml — modified" row scrolls to the deleted block and leaves the added symlink block collapsed.

Deliberate Pylon divergence

FileBrowserPanel.tsx keeps Pylon's guard placement rather than upstream's reordering (upstream resets handledRevealRef and replays a reveal when an entry leaves and re-enters the index under the same revealId). Pylon's placement is still correct for the folder case and avoids closing an active tree search on index churn. Recorded as a choice, not an accident.

Verification on the final head

3 files, 278 focused tests passed; @t3tools/web typecheck exit 0. The exhaustive leak check the reviewer ran — every identifier on an added line compared against all source commits — found no unadopted upstream code.

@rynfar
rynfar merged commit eea1ff3 into pylon Sep 19, 2026
19 of 20 checks passed
@rynfar
rynfar deleted the upstream/2026-09-19-nav-diff-safety branch September 19, 2026 18:51

This branch had an error being deployed

1 failed deployment
Preview — 67ba1d43 Deployed Sep 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 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.

4 participants