Desktop, CLI, web and runtime transports now take a PairedRuntimeConnection
(endpoint, pinned host key, credential) instead of a PairingOffer. Offers stay on
the pairing input path (codes, QR, links, environment add) and are converted with
pairedRuntimeConnectionFromOffer. The credential is token-only today; request
envelopes still carry the same deviceToken, so the wire is unchanged.
This lets device-key and ticket credentials replace the token later without
touching every connect call site again.
Co-authored-by: m4air <m4air@Mac.localdomain>
* refactor(remote): one paired E2EE handshake core for desktop, CLI, web and mobile clients
Every paired client now builds its hello, checks the host's ready, seals its
auth frame and opens host frames through src/shared/paired-e2ee-client-handshake.
Platforms inject their own NaCl/base64 primitives. The v2 client session and its
pure-JS key schedule (@noble/hashes 1.8.0, the version mobile pins) move to
src/shared, and the per-host v2 latch policy is shared with an injected store.
No wire change: frames match the captured legacy and v2 fixtures byte for byte,
and a cross-version test drives the core against the released host and the
released client against this host. The auth step is now async so a device-key
signer can slot in later.
* fix(remote): keep @noble/hashes out of the CLI's unbundled runtime
The packaged CLI loads src/shared output from disk, so a bare @noble/hashes
import failed the packaged-runtime check. The v2 key schedule is now a
primitive: Node clients use the node:crypto schedule (moved to src/shared so
the CLI can reach it), while the browser and phone keep the pure-JS one.
* fix(mobile): re-check the v2 latch before sending a legacy auth frame
The auth step is async, so another socket can latch the host to v2 while a
legacy auth frame is being sealed. Refuse it at send time, as before.
---------
Co-authored-by: m4air <m4air@Mac.localdomain>
* Bound relay git-grep records and clean up capacity failures
Credits @OrcaWin for the original bounded-record proposal.
* Bound filesystem listing and transfer metadata at the execution host
Apply mobile limits before transport, list Markdown through its semantic producer, and retain complete directory results only within explicit capacity budgets. Stream SFTP directory packets and reject oversized transfer plans before reporting success; preserve narrow older-peer fallbacks and validate streamed response retention.
* Release inactive Markdown candidates and support folder scopes
Keep one current document snapshot per consumer and attach completion candidates to the actual editor model lifetime. Resolve folder workspace roots through existing workspace identities so their previews and completions receive the same authorized listing as worktrees.
* Preserve full runtime inventories under aggregate byte budgets
Leave unqualified inventories complete beyond 20,000 files. Charge retained paths and serialized bytes at local and relay producers, reject oversized full inventories explicitly, and bound old-peer response reassembly; keep caller-specific mobile and explicit result limits.
* Bound SFTP directory handle cleanup waits
Send CLOSE even after cancellation, stop waiting after five seconds without an acknowledgement, and ignore late callbacks. Preserve the original capacity or cancellation error and close handles returned after an aborted OPENDIR.
* Preserve registered root spelling in Markdown document paths
* Reject incomplete SFTP directory cleanup and final cancellation
* Bound pending response bytes before stream ownership arrives
* Preserve bounded directory reads on legacy SSH hosts
* Allow bounded per-chunk padding at response byte boundaries
* Bound response payload retention after stream metadata
* Bound complete legacy Quick Open inventories and cache retention by bytes
* Localize Markdown document listing fallback
* Exercise relay search decoding with real byte streams
* Preserve concrete relay stream fixture types
* test: compare distinct bundled ripgrep platforms on Windows
* Preserve Markdown discovery across Windows and legacy SSH hosts
* Make WSL process termination available to the bounds layer
* Cancel abandoned file searches and preserve search keyboard navigation
* Invalidate searches when workspace roots or owners change
* Cover root replacement and legacy search cancellation together
* Exercise search cancellation through the current desktop access seam
* Keep search ownership and cancellation contracts current
* Share local text-search execution and close canceled subscriptions
* fix(remote): stop painting a disconnected host as connected
A remote host row read "Connected" with a green dot in two states where it
was not connected: a cleanly closed control channel (server restart, host
sleep, network blip leaves lastError null, and the mapping required an error
string before it would say disconnected), and a half-open handshake still in
awaiting_ready/awaiting_authenticated.
lastError/lastClose were also never cleared on a successful reconnect, so a
recovered host kept showing "Connected" beside a stale failure indefinitely.
The SSH lane already clears on success; the shared-control lane did not, which
is why only Remote Server rows showed stale text.
* test(remote): cover stale diagnostics after reconnect
* Revert "fix terminal attribution shim removal edge cases (#14187)"
This reverts 585dd6d3a9. Re-landed in the next commit without the host capability gate. Nothing shipped with it, so no migration constraint.
* rm git shim: neutralize stale wrappers without a host gate
Re-lands the cleanup half of #14187: pass-through tombstones for retained wrapper paths, env/PATH scrubbing at every spawn owner, and the retired setting drop.
Only writes tombstones when the legacy directory already exists, so a clean install no longer has it created. Leaves out the terminal.attribution-removed.v1 capability gate: the tombstone neutralizes each host locally, so refusing terminal create/split against older hosts denied service without adding cleanup.
* rm git shim: surface neutralization failures and fix rollback marker
Readiness review follow-ups: warn on each failed attempt and on give-up (was silent and undiagnosable); write a VERSION marker distinct from the retired shim's '7' so a rolled-back build rewrites its own wrappers; clear a captured ORCA_REAL_* path that no longer exists so the cmd wrapper's where.exe fallback can run; stop a locked temp file masking the real error. Adds retry-exhaustion coverage.
* rm git shim: pin the cmd fallback order and correct the give-up count
Round-2 review follow-ups: string-pin that a stale ORCA_REAL_* is cleared before the where.exe fallback, and count the initial attempt in the give-up warning so it agrees with the per-attempt line.
* rm git shim: keep the split-failure toast
The revert took a toast that #14187 added alongside the gate but which stands on its own: without it a failed remote split only reaches the console and the pane silently never appears. Also pins attempt ordinals in the retry-exhaustion test.
* fix(remote): accelerate shared-control and pane recovery on resume/online
Narrow #8255 onto current main after #9774: fire pending shared-control
reconnect timers and pane recovery backoffs on system resume and browser
online, without replacing the per-pane recovery state machine or reconnect
banner UX.
* test(remote): cover online and occluded-resume recovery triggers
* fix(remote): centralize recovery acceleration
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>