Skip to content

feat(mobile): back swipe from scroll edges, Android text selection, terminal paste - #427

Merged
rynfar merged 3 commits into
pylonfrom
upstream/2026-09-08-mobile-interaction
Sep 9, 2026
Merged

feat(mobile): back swipe from scroll edges, Android text selection, terminal paste#427
rynfar merged 3 commits into
pylonfrom
upstream/2026-09-08-mobile-interaction

Conversation

@rynfar

@rynfar rynfar commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Three mobile interaction gaps, adopted from T3 Code.

What changed

Back swipe from a horizontal scroll edge. Swiping right to go back did nothing when the
gesture started inside a horizontally scrollable row — the code viewer, the tab strip, the
diff surface. The gesture was swallowed by the inner scroll view even when it was already
pinned at its left edge. A patch to react-native-screens lets the screen's back gesture win
once the inner scroller has nothing left to scroll.

Selectable chat text on Android. Long-pressing an assistant message on Android selected
nothing; iOS already had native selection. This adds an Expo module
(T3MarkdownTextSelectionModule) backed by an Android TextView selection host, and routes
SelectableMarkdownText.android.tsx through it. The iOS primitives were refactored alongside
it so both platforms share one component contract.

Paste the phone clipboard into the terminal. The mobile terminal had no way to paste.
There is now a paste key on the terminal accessory toolbar, and ctrl/cmd + v through
the armed modifier does the same thing. Pasted text is bracketed-paste encoded and written in
chunks so a large paste cannot overrun the pty write path.

Terminal keyboard handling moved out of the route screen into terminalInput.ts
(modifier resolution, paste encoding, write chunking) and terminalPaste.ts (clipboard read
and write sequencing), both unit tested.

Adopted from T3 Code

  • 80b53730d1e821563e5c348fdf4f5fc7616a49f7 (#9493) back swipe from horizontal scroll edges
  • 09d13de4381925fa2a6dea74eff8185fa301e905 (#8779) selectable chat text on Android
  • d5b94100863057fb4629f9ad4a35753d16917924 (#9199) paste the phone clipboard into the terminal

Pylon adaptations

TerminalBufferState gains upstream's lifecycleVersion, which counts pty lifetimes so a
delayed clipboard read is dropped when the terminal restarts underneath it. Pylon's terminal
buffer diverges from upstream here: PR #308 replaced the plain buffer string with a
generation-tracked TerminalOutputState and made version monotonic so appends never replay
retained history. Upstream's version of this change resets version to 1 on every snapshot
and rebuilds the buffer from scratch.

The resolution keeps Pylon's incremental output and monotonic version, and layers
lifecycleVersion on top:

  • terminalBufferStateFromSnapshot still takes current and still returns
    resetOutput(current.output, …) and current.version + 1, and now carries
    current.lifecycleVersion through.
  • The snapshot and restarted cases pass current to it — a blind merge dropped that
    argument on the snapshot path, which would have reset the output cursor generation and
    the version on every re-attach.
  • lifecycleVersion advances on restarted, and on a snapshot that arrives at a buffer
    that already has content. The initial attach snapshot leaves it at 0, so the paste session
    is not reset the moment the screen opens.

The host platform used to resolve ctrl versus cmd now prefers the server's reported
environment.platform.os and only falls back to guessing from the environment label.

Verification

  • Tests: 49 passing across 4 files — terminalSession, terminalInput, terminalPaste,
    terminalMenu.
  • Types: @t3tools/client-runtime, @t3tools/mobile, @t3tools/web all clean.
  • Lint, format, unused exports: clean across the 20 changed files; knip:check clean.

The pnpm-lock.yaml change is patch-hash only — the react-native-screens patch content
changed and the markdown-text local module gained an Android target. No new dependency;
expo-clipboard was already present.

Android native selection and the react-native-screens patch need a device or emulator pass;
neither is exercised by the JS suites or by an iOS simulator build.

Model and harness: Claude Opus 5 via Claude Code.


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

juliusmarminge and others added 3 commits September 8, 2026 23:37
Co-authored-by: Claude Code <noreply@anthropic.com>
(cherry picked from commit 80b53730d1e821563e5c348fdf4f5fc7616a49f7)
Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
(cherry picked from commit 09d13de4381925fa2a6dea74eff8185fa301e905)
Co-authored-by: Jake Leventhal <jakeleventhal@me.com>
Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
(cherry picked from commit d5b94100863057fb4629f9ad4a35753d16917924)
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 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.7 KiB 13.8 KiB +135 B (+1.0%) 15.1 KiB
Codex Thread snapshot wire 7.1 KiB 7.1 KiB −2 B (−0.0%) 7.3 KiB
Codex Live turn WebSocket wire 6.6 KiB 6.7 KiB +137 B (+2.0%) 7.8 KiB
Codex Live turn WebSocket decoded 56.5 KiB 57.4 KiB +866 B (+1.5%) 66.4 KiB
Codex Live turn messages 9 10 +1 (+11.1%) 21
Claude Total thread wire 13.8 KiB 13.8 KiB +56 B (+0.4%) 15.1 KiB
Claude Thread snapshot wire 7.1 KiB 7.1 KiB −12 B (−0.2%) 7.3 KiB
Claude Live turn WebSocket wire 6.7 KiB 6.7 KiB +68 B (+1.0%) 7.8 KiB
Claude Live turn WebSocket decoded 58.1 KiB 58.2 KiB +88 B (+0.1%) 66.4 KiB
Claude Live turn messages 8 10 +2 (+25.0%) 21

Baseline: 275de5e · PR result: ac613b5 · 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: 111.2 KiB
  • Claude decoded thread snapshot: 111.9 KiB

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

@rynfar
rynfar merged commit 9928508 into pylon Sep 9, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 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