Skip to content

fix(windows): preserve remote multiline paste - #3282

Merged
Pimpmuckl merged 1 commit into
herdrdev:masterfrom
akbash-bot:akbash/3209-remote-windows-paste
Sep 1, 2026
Merged

fix(windows): preserve remote multiline paste#3282
Pimpmuckl merged 1 commit into
herdrdev:masterfrom
akbash-bot:akbash/3209-remote-windows-paste

Conversation

@akbash-bot

Copy link
Copy Markdown
Collaborator

Issue

A Windows user pastes multiline text with Shift+Insert or Shift+right-click during herdr --remote. The remote pane receives one wrapped block without line breaks.

Problem

Windows Terminal encoded each pasted newline as an Enter press and release report. The Windows client kept those reports as literal paste text instead of restoring the newline.

How did we fix it?

Herdr now converts the exact adjacent unmodified Enter press and release reports to one carriage return after a complete paste arrives. Other report-shaped paste text remains unchanged.

Verification

The reporter's exact input stream failed before because both Enter reports remained in the Paste event. The same test now emits one Paste with the expected line breaks, and the incomplete-pair test keeps unmatched reports unchanged. All 62 Windows input tests passed. just check passed formatting, Clippy, and 3,534 of 3,535 tests; the unrelated live-handoff process-discovery test still fails alone on this VPS.

refs #3209

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: b1060737-1f13-4630-81f6-6823a36b0984

📥 Commits

Reviewing files that changed from the base of the PR and between 99c23cd and f6f0e44.

📒 Files selected for processing (1)
  • src/client/input/windows_vti.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/client/input/windows_vti.rs

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

process_raw_events now decodes exact adjacent unmodified Windows Terminal Enter report pairs in Paste events as \r. It resets paste_from_win32_key_records for each Paste event. Tests cover complete report-pair decoding and preservation of incomplete pairs.

Suggested reviewers: pimpmuckl

Merge Risk: ⚪ Minimal · up to f6f0e

The change restores line breaks for completed multiline pastes on Windows while preserving unmatched report text, with no actionable merge-blocking risk remaining after normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 1 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the Windows remote multiline paste fix, which matches the primary change.
Description check ✅ Passed The description explains the Windows Terminal paste issue, the report-pair decoding fix, and verification results. It directly relates to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kangal-bot kangal-bot added the ai-review Trigger automated AI reviews for pull requests admitted by the PR gate label Aug 27, 2026
@Pimpmuckl
Pimpmuckl self-requested a review August 31, 2026 11:26
@Pimpmuckl
Pimpmuckl force-pushed the akbash/3209-remote-windows-paste branch from ed59290 to f6f0e44 Compare September 1, 2026 19:54
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@Pimpmuckl

Copy link
Copy Markdown
Collaborator

@greptileai

@greptile-apps

greptile-apps Bot commented Sep 1, 2026

Copy link
Copy Markdown

Greptile Summary

This PR restores multiline Windows Terminal paste behavior for remote sessions by normalizing adjacent unmodified Enter press/release reports after a bracketed paste is fully parsed.

  • Decodes each exact Enter report pair into one carriage return.
  • Leaves incomplete and other report-shaped paste payloads unchanged.
  • Adds regression coverage for multiline and incomplete-pair cases.

Confidence Score: 5/5

The PR appears safe to merge; the narrowly scoped normalization and regression tests preserve the intended normalized paste contract.

The changed path only transforms the exact adjacent Windows Terminal Enter press/release sequence after parsing a complete Paste event, while unmatched and differently shaped report payloads remain untouched.

Important Files Changed

Filename Overview
src/client/input/windows_vti.rs Normalizes exact Windows Terminal Enter report pairs inside completed paste events and adds focused regression tests without exposing a concrete correctness issue.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Windows Terminal input] --> B[Windows VTI framing]
    B --> C[Complete bracketed Paste event]
    C --> D{Exact adjacent Enter press/release pair?}
    D -->|Yes| E[Replace pair with carriage return]
    D -->|No| F[Preserve payload]
    E --> G[Normalized client Paste event]
    F --> G
Loading

Reviews (1): Last reviewed commit: "fix(windows): preserve remote multiline ..." | Re-trigger Greptile

@Pimpmuckl

Copy link
Copy Markdown
Collaborator

Manual verification completed on final head f6f0e44c:

  • Rebased onto current master, including fix(windows): preserve native pane key identity #3503.
  • Tested the Windows client over SSH to a disposable WSL Herdr server.
  • Shift+Insert and Shift+right-click both preserved all three pasted lines.
  • The pane produced - line one|- line two|- line three in both runs.
  • Input traces contained \r separators between every line.

Focused tests, release build, CI, CodeRabbit, and Greptile are green.

@Pimpmuckl
Pimpmuckl merged commit 0032c3b into herdrdev:master Sep 1, 2026
7 checks passed
@Pimpmuckl

Copy link
Copy Markdown
Collaborator

@akbash-bot could you check if this also fixed #3264 ?

@akbash-bot

Copy link
Copy Markdown
Collaborator Author

Yes. #3264 captured the same adjacent unmodified Enter pair that this PR normalizes:

ESC[13;28;13;1;0;1_ + ESC[13;28;13;0;0;1_

The normalization runs on the completed Windows Paste event before remote transport, so Ctrl+V versus Shift+Insert/right-click and --remote-keybindings mode do not change this path. I also reran the focused regression on current master; it passes. This fix covers #3264's leaked sequences and lost line breaks, so no separate code change is needed.

aryrabelo added a commit to aryrabelo/bora-herdr-ada that referenced this pull request Sep 9, 2026
…ll (stage 2) (#29)

* refactor: render the shell in the client (herdrdev#3487)

* feat: add opt-in client-rendered shell

* feat: add client-owned shell mouse controls

* feat: complete client-owned shell chrome

* feat: add client-owned shell settings and notifications

* feat: run client shell custom commands

* feat: render popup terminals in client shell

* feat: add client-owned scrollback and copy mode

* fix: preserve client worktree trust defaults

* feat: render startup diagnostics in client shell

* feat: render onboarding in client shell

* feat: render product announcements in client shell

* feat: render release notes in client shell

* feat: render mobile switcher in client shell

* feat: render kitty graphics in client shell

* fix: preserve client shell lifecycle coherence

* refactor: route client shell commands through endpoint connections

* refactor: make the client-rendered shell the default

* refactor: remove monolithic launch mode

* refactor: complete client-rendered shell cutover

* perf: retain client pane surface updates

* perf: scale retained pane surface updates

* perf: remove remote pane input latency

* test: make client shell checks platform-independent

* fix: prevent client timer starvation

* test: fix client shell platform gates

* test: accept retained surfaces in cross-area checks

* test: make client mode assertions platform-neutral

* fix: badge only outdated integrations

* test: allow slow documentation snapshot fixtures

* fix(windows): parse openssh mouse reports with physical escape (herdrdev#3502)

* fix(windows): parse openssh mouse reports with physical escape

* fix(windows): require sgr mouse prefix

* fix(windows): preserve escape ordering and modifiers

* fix(nix): fetch crates from static CDN (herdrdev#3504)

refs herdrdev#3505

* fix(windows): reject malformed process environments (herdrdev#3500)

* fix(windows): reject malformed process environments

refs herdrdev#3430

* fix(windows): validate registry environment strings

refs herdrdev#3430

* fix(windows): preserve hidden environment variables

refs herdrdev#3430

* fix(windows): recognize durable wmi daemon jobs (herdrdev#3507)

* fix(build): guide users when zig is missing (herdrdev#2281)

build.rs now reports how to install Zig 0.15.2 (brew install zig@0.15
on macOS, ziglang.org elsewhere) and mentions the ZIG environment
variable instead of panicking with a bare NotFound error.

Co-authored-by: JJ Liebig <jonathan.liebig@gmail.com>

* fix(windows): preserve native pane key identity (herdrdev#3503)

* fix(windows): preserve remote multiline paste (herdrdev#3282)

refs herdrdev#3209

Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>

* fix(windows): keep openssh mouse input draining (herdrdev#3512)

refs herdrdev#3459

* feat: add stable client endpoint compatibility (herdrdev#3509)

* feat: add stable client endpoint compatibility

* fix: keep portable-pty patch checks composable

* ci: run maintenance checks in pull requests

* fix: reject endpoint errors from terminal clients

* feat: keep compatible servers running across updates

* feat: support independent multi-client tab views (herdrdev#3526)

* fix: reliably submit delayed agent prompts (herdrdev#3506)

* fix(client): detach when terminal geometry is unavailable (herdrdev#3531)

refs herdrdev#3519

* fix: preserve mouse selection during pane output (herdrdev#3538)

* fix: stop treating claude background shells as working (herdrdev#3468)

* fix(windows): remove worktrees with active agent panes (herdrdev#3532)

* fix(windows): remove worktrees with active agent panes

* fix(windows): defer pane restore until shutdown exits

* fix: keep direct graphics bound to its client (herdrdev#3549)

* fix: include short viewport output in recent reads (herdrdev#3448)

refs herdrdev#3444

Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>

* fix(windows): preserve dead-key composition in kitty panes (herdrdev#3548)

refs herdrdev#3546

Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: JJ Liebig <jonathan.liebig@gmail.com>

* fix: reveal newly focused spaces in the sidebar (herdrdev#3554)

* perf: compress idle terminal scrollback (herdrdev#3556)

* fix: read Windows clipboard images in WSL (herdrdev#3572)

refs herdrdev#3376

* fix(windows): preserve ctrl+slash key identity (herdrdev#3578)

refs herdrdev#2954

* fix(client): batch host palette updates (herdrdev#3580)

* fix(windows): preserve LF paste order (herdrdev#3582)

refs herdrdev#3172

* fix: reject Android in Unix installer (herdrdev#3577)

refs herdrdev#3571

Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>

* fix: statically link the Windows CRT (herdrdev#3594)

refs herdrdev#3089

* fix(integration): resolve Devin config on Windows (herdrdev#3595)

refs herdrdev#2724

* fix: persist Codex resume sessions at launch (herdrdev#3617)

refs herdrdev#3517

* feat: enable kitty graphics by default

* fix(windows): use active release directory on PATH (herdrdev#3618)

* fix(windows): use active release directory on PATH

refs herdrdev#3611

* fix(windows): expand variables in PATH comparisons

refs herdrdev#3611

* fix(windows): restrict installer channel detection

refs herdrdev#3611

---------

Co-authored-by: Can Celik <ogulcancelik@gmail.com>

* fix: detect codex startup update prompts (herdrdev#3636)

refs herdrdev#3632

* fix: make Windows Codex prompt delay size-aware (herdrdev#3552)

refs herdrdev#3187

* fix: preserve pixel mouse after sgr reassertion (herdrdev#3637)

refs herdrdev#3295

Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>

* fix: retain mouse selections across unrelated terminal output (herdrdev#3641)

* fix(ui): keep selections visible without host colors (herdrdev#2710)

* fix(ui): keep selections visible without host colors

refs herdrdev#2708

* test(ui): strengthen selection fallback coverage

refs herdrdev#2708

* fix(ui): preserve selection contrast and terminal palette colors

refs herdrdev#2708

---------

Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>

* fix: run the full applicable test suite on windows (herdrdev#3660)

* fix: run the full applicable test suite on windows

* test: remove redundant test shell assignment

* test: make endpoint and metadata fixtures deterministic

* test: tolerate exited servers during windows probe cleanup

* fix: resolve Windows plugin pane launch paths (herdrdev#3666)

* fix: resolve Windows plugin pane launch paths

refs herdrdev#3024

* test: compare resolved Windows plugin probe paths

refs herdrdev#3024

* test: compare resolved Windows plugin working directories

refs herdrdev#3024

* test: wait for Windows plugin fixture completion

refs herdrdev#3024

* fix: prevent OpenCode child prompts from leaving status blocked (herdrdev#3669)

Child permission and question reports omitted the session ID, clearing
Herdr’s root session identity and preventing later lifecycle reports
from clearing the blocked state.

Track child-to-parent relationships and report prompt transitions with
their root session ID, including for nested children. This preserves
identity and lets existing ownership checks reject unrelated sessions.

Add regression coverage for prompt routing and lifecycle transitions,
and bump the OpenCode integration version to 11.

* chore: approve markjaquith as contributor

* feat: manage multiple ssh machines from one client (herdrdev#3670)

* docs: publish preview documentation

* fix: consume failed selection copies without interrupting agents (herdrdev#3681)

* fix: keep manual selections active during terminal output (herdrdev#3684)

* fix: resolve queued submissions when pty actor exits

refs herdrdev#3685

* feat: add conditional styles for sidebar tokens (herdrdev#3693)

* fix: match claude bash permission prompts at every cursor position (herdrdev#3615)

Claude marks the selected option with "❯", but bash_permission_prompt did not allow that prefix on numbered branches and did not cover the three-option "don't ask again" layout. Match both two- and three-option Bash approval prompts regardless of the selected option.

refs herdrdev#2650

* feat: make ui.pane_borders a three-state auto/always/off mode (herdrdev#3234)

* feat: make ui.pane_borders a three-state auto/always/off mode

Legacy booleans keep parsing (true = auto, false = off); "always" frames
a lone pane while pane_outer_borders is enabled.

* fix: align pane border reload test and documentation

---------

Co-authored-by: Rudolf Schmidt <me@rudionrails.com>
Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>

* fix: preserve sessions after interrupted pane exits (herdrdev#3418)

* fix: preserve sessions when pane shells are signaled

refs herdrdev#3415

* fix: preserve shutdown checkpoints across platforms

refs herdrdev#3415

---------

Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>

* fix: require explicit consent for remote server replacement

* docs: prepare 0.9.0 release documentation

* release: v0.9.0

* docs: publish release distribution for v0.9.0

* fix: reduce idle ssh cpu without dropping final output (herdrdev#3728)

* fix: stop polling idle ssh uploads on unix

* fix: preserve ssh output during idle bridge cancellation

* test: exercise active ssh upload cancellation

* docs: publish preview documentation

* fix: show ssh errors during machine setup (herdrdev#3733)

refs herdrdev#3731

Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>

* chore: move marketplace worker to website repository

* fix: collapse worktree groups with saved machines (herdrdev#3781)

* fix: collapse worktree groups with saved machines

refs herdrdev#3778

* fix: scope worktree collapse by machine

refs herdrdev#3778

* fix: collapse machines without switching focus

refs herdrdev#3778

---------

Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>

* fix: rewire the fork's server features the 0.9.0 merge disconnected and make lint green

The merge compiled and passed every test with 32 dead-code warnings; three of them were fork server features whose only call site lived in files upstream rewrote: the when-idle prompt drain tick, the pane input backpressure queue (upstream's pane_input.rs had reintroduced the keystroke drop 6a15918 fixed), and the idle_since setter behind the idle_seconds API field. All three are rewired with behavioural tests. Fork UI helpers that ceo-bora#275/herdrdev#276 re-port over the client shell are kept under justified allows; sidebar helpers superseded by upstream's client shell are deleted (pre-merge tree at 6b6be67). Upstream code is brought under the fork's deny lints (redundant_clone, redundant_closure_for_method_calls, implicit_clone, items_after_test_module, unwrap_used in bins), cross-target checks are green for linux-gnu and windows-msvc, and bora pane list accepts --json for loop-status.

refs aryrabelo/ceo-bora#274

* ci: exempt merge-inherited generated docs from the rules gate and keep the fork's preview snapshot

The rules-review gate flagged 107 generated paths that arrived untouched through the upstream merge (docs/versions/0.9.0 and upstream's docs/preview). A generated path whose HEAD blob is byte-identical to a non-first parent of a merge in base..head is now inherited, not hand-edited; a local edit on top still fires (two-sided e2e test). docs/preview is restored to the fork's own Preview-CI snapshot for every file that existed before the merge, since Preview CI regenerates it from docs/next.

refs aryrabelo/ceo-bora#274

* docs: keep the fork's preview snapshot whole on the upstream merge

scripts/docs/preview.mjs check compares docs/preview/website against the docs/next tree of the commit distribution/preview.json names; three pages upstream's Preview CI had added made the file lists differ. The snapshot is Preview-CI-owned and regenerates from docs/next on the next run, so a sync keeps it exactly as main had it.

refs aryrabelo/ceo-bora#274

* fix: repair the two remaining CI failures on the merge (orphan-file false positive, upstream namespace literal)

The dep-info-based orphan-file test read a rustc-recorded #[path] module path (src/client/shell/../shell/overlays.rs) as a different file than the on-disk walk finds, false-flagging 5 legitimately wired client-shell files; it now canonicalizes both sides through the filesystem (regression test: dep_info_paths_with_parent_components_resolve_to_the_module_file). The same run surfaced two REAL orphans the merge left behind with no mod declaration reaching them: src/app/channel_membership.rs and src/ui/chat.rs, both dead since the client-shell rewrite disconnected their callers; deleted (pre-merge implementation stays at 6b6be67 for ceo-bora#276 to re-port, per AGENTS.md).

Separately, tests/api_ping.rs, live_handoff.rs, machine_setup.rs and two dev scripts arrived from upstream hardcoding the debug namespace as herdr-dev instead of the fork's bora-dev, so shutdown_preserves_session_after_shell_is_signaled (linux-only) read a session file that was never written at that path. Renamed the namespace throughout, and widened no_source_file_references_the_upstream_binary_name to catch this rename class going forward alongside the CARGO_BIN_EXE_ check it already had.

refs aryrabelo/ceo-bora#274

* chore: refresh the pr head to recompute the stale merge ref

GitHub built refs/pull/29/merge from the stale head 67d9af1 (the same
head the pulls API was stuck on), so the reopen checks validated a tree
before the docs/preview snapshot restore. An empty synchronize event
forces the merge ref to be recomputed from 58dd7a7.

refs aryrabelo/ceo-bora#274

* fix: port upstream's stalled-prompt message and point the conpty ci job at bora

The merge kept the fork-side agent_prompt_stalled message while taking
upstream's tests/cli/agents.rs, which asserts upstream's newer text from
8633a39; tests/cli is linux-only (one of the four cfg'd-out files on
macos), so only check (ubuntu-latest) caught it. Port the text and drop
the now-dead baseline field exactly like upstream.

Upstream's ci.yml also brought the windows-conpty-package job with
herdr.exe paths while this fork builds bora.exe; rename the binary and
archive paths and gate the step that drives the never-fork-adapted
windows_install_conpty_package_test.ps1 to herdrdev/herdr.

refs aryrabelo/ceo-bora#274

---------

Co-authored-by: Can Celik <ogulcancelik@gmail.com>
Co-authored-by: JJ Liebig <jonathan.liebig@gmail.com>
Co-authored-by: Hopkins <kknkkk@hotmail.com>
Co-authored-by: akbash <akbash@herdr.dev>
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: Mark Jaquith <mark@jaquith.me>
Co-authored-by: kangal-bot <285672167+kangal-bot@users.noreply.github.com>
Co-authored-by: caner-akca <94343893+caner-akca@users.noreply.github.com>
Co-authored-by: Rudolf S. <rud.schmidt@gmail.com>
Co-authored-by: Rudolf Schmidt <me@rudionrails.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Trigger automated AI reviews for pull requests admitted by the PR gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants