Skip to content

fix(terminal): a pane another client moves to a new tab leaves this window's source tab - #33032

Merged
nwparker merged 96 commits into
nwparker/fix-32939-move-pane-new-tabfrom
nwparker/snapshot-leaf-move-source-tab
Oct 26, 2026
Merged

nwparker merged 96 commits into
nwparker/fix-32939-move-pane-new-tabfrom
nwparker/snapshot-leaf-move-source-tab

Conversation

@nwparker

@nwparker nwparker commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 581 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​11453 $\color{#cf222e}{\Huge{\mathbf{−}}}$​11934 $\color{#cf222e}{\Huge{\mathbf{−}}}$​481
Prod 592 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​23103 $\color{#cf222e}{\Huge{\mathbf{−}}}$​15900 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​7203

ELI5

You have a terminal split in two on a paired Orca server. From your phone, another desktop, or the server itself, someone moves one half of the split into its own tab. Before this change, your desktop showed that terminal twice: once in the new tab, and again in the old tab next to its former neighbour. Now the old tab drops the moved pane, and the terminal keeps running in its new tab.

What Changed

  • Before: the new tab bound to the right terminal, but the source tab kept the moved pane too. Its saved layout still held both panes, and its pane manager still drew 2 panes, even after switching tabs. Typing in either copy reached the same terminal.
  • After: the source tab shows 1 pane, and the new tab shows the moved pane with its scrollback. The terminal is not restarted.

Two client-side paths each kept the stale pane, so both are fixed (1 and 2 below). Items 3 and 4 keep that fix from breaking this window's own optimistic move.

  1. Orphan recovery (web-session-terminal-orphan-recovery-surface.ts). When a host snapshot stops naming a pane this window has, recovery treats the pane as a possible orphan. It asks the host whether that terminal is still alive, and if so it puts the pane back into its old tab. A moved terminal is alive, so recovery put it back. The fix: if the same snapshot shows that terminal handle ready in a different tab, the old binding is stale, not an orphan. Recovery skips it, makes no terminal.list call, and the source tab's layout comes from the host alone.

  2. Pane reconcile (use-terminal-pane-reconciliation.ts, selectRetiredPaneIds). When the host drops a leaf, the mounted pane manager used to close only panes whose PTY had already ended, so a live moved pane stayed on screen. Now a retired pane whose PTY another tab of the same workspace binds is detached with detachPaneForExternalMove. That is the same no-kill path a local drag-out uses. The PTY keeps running for its new tab, and the last pane of a tab is still never removed.

  3. This window's own move (pending-host-pane-moves.ts). A pane this window is moving through fix(terminal): a pane moved to a new tab stays moved on paired servers #33027's host move is marked until the move settles. Until then, a host snapshot taken before the host had the move can't read the new tab's binding as stale. Without the mark, that snapshot would drop the new tab.

  4. Agent records. A pane detached this way also gives up its agent status records under the source tab, so the source tab doesn't keep the moved agent's badge. The one exception is a source key this window already aliased to the new tab, which is left alone so the live target keeps its records.

  5. This window's own move, after the reply. The host can reply before its snapshot of the move arrives. A move the host committed now stays marked until a host frame shows the pane in its new tab. Otherwise an older snapshot arriving after the reply could still drop the new tab. Only the raw host frame counts as confirmation, not rows that recovery keeps for this window. If that frame arrives before the reply, the reply does not mark the move again. If drawing the move throws, the mark is released.

Both checks rely only on what the host publishes, so they cover a move from a phone, from another desktop, or from the host's own window.

Why

The host already decides which tab holds each pane, and its snapshot after the move is correct (session.tabs.list shows each leaf alone in its own tab). The client was overriding it in two places. Fixing it at those two places makes every source of the move behave the same, without a new message or capability.

Alternatives considered:

  • Close the old pane. That kills the terminal the new tab shows.
  • Have each moving client notify the others. That needs a new opcode, and it would still miss moves made on the host itself.

Mixed versions: client-only and wire-neutral. Older hosts that can't move panes never publish one terminal in two tabs, so nothing changes for them. An older client keeps today's behaviour.

Mobile: checked. The phone rebuilds its terminal list from each snapshot's rows and has no orphan retention, so it never showed the duplicate. The web client uses the same renderer code as the desktop, so this fix covers it.

Folder workspaces / SSH: the change doesn't depend on git or the transport. It keys off the tab, leaf and PTY ids in the host snapshot.

Found while fixing #32939 (the window-side move in #33027). There's no separate issue. This PR is stacked on #33027 because its e2e calls session.tabs.movePaneToNewTab, which #33027 adds.

Known limit: a committed-move mark clears only when a host frame names the pane in its new tab. If the host never publishes that tab, for example because it closes before its first frame arrives, the mark stays for that pane key. The cost is that a later move of that same pane by another client is not detected as stale. Tab ids are unique per tab, so no other pane is affected.

Follow-up (not in this PR): when another client moves a pane, this window retires the source pane's agent records, and the host republishes the agent's status under the new tab. Local-only records (unread marks, launch config, sleeping state) do not follow the pane yet. An attempt to transfer them was dropped from this PR because it raced with snapshot freshness.

Linked Issue

No issue. Found while fixing #32939; it builds on #33027.

Visual Proof

N/A. This removes a duplicate pane that should never have been drawn. The paired e2e checks the outcome: the pane count, the layout leaves, and the bound PTY of both tabs.

Testing

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

  • E2e tests/e2e/paired-remote-terminal-pane-moved-by-another-client.spec.ts: a headless paired host and a paired Electron desktop, run with ORCA_BACKGROUND_LAUNCH=1 and hidden windows. The test splits a pane, echoes a marker into the second pane, and moves that pane from the host client with session.tabs.movePaneToNewTab. It then checks:

    • the new tab holds just the moved leaf, bound to the same PTY;
    • the source tab holds 1 leaf and 1 pane, and still does after switching tabs both ways;
    • the host's PTY id for the moved leaf is unchanged, and its scrollback still has the marker.

    It fails without this fix: the source tab kept 2 leaves and 2 panes. With only the reconcile change it still fails, keeping 2 panes. Both changes are needed.

  • fix(terminal): a pane moved to a new tab stays moved on paired servers #33027's own e2e (paired-remote-terminal-pane-move-to-new-tab.spec.ts, 2 tests) still passes on top of this change.

  • Unit tests:

    • web-session-split-pane-retirement-fences.test.ts: a real snapshot apply in which the second leaf moves to host-tab-2. It expects no orphan RPC, a source layout holding only the first leaf, and the reconcile planner detaching (not closing) the moved pane. It fails without the orphan-recovery fix.
    • terminal-live-layout-reconciliation.test.ts: the planner detaches a pane whose PTY another tab draws, and never removes the last pane.
    • web-session-split-pane-retirement-fences.test.ts, second case: this window's own optimistic move, followed by a snapshot from before the host move. The new tab's binding stays an orphan candidate and is not dropped. It fails without the pending-move mark.
    • terminal-pane-external-move-detach.test.ts: the source pane's agent records are retired, unless the source key is already aliased to the target.
  • E2e change: the spec now has the server create the source tab and splits once its shell is up. A desktop-seeded first tab in an empty paired workspace can leave a pane split right after it opens unbound, which is a separate bug.

  • Fence tests (web-session-split-pane-retirement-fences.test.ts, terminal-pane-tab-detach-runtime-host.test.ts): a committed move stays fenced past the reply until a host snapshot shows it; a retained row does not confirm it; a reply that arrives after its snapshot does not re-hold it. Each fails without its fix.

  • Local checks: every unit test related to the changed modules by import graph (1,918 files) passes. One timing-sensitive test failed under machine load and passed when re-run on its own. The full static-analysis job, Codex review (3 rounds; the round 2 alias finding is fixed) and an independent review (no P0-P2) are clean on the head.

Platforms: macOS, locally. The change has no platform-specific code.

…indow's source tab

When a phone, another desktop or the host moved a pane out of a split, this
window kept drawing the same live terminal in both tabs. Orphan recovery read
the source tab's binding as an orphan and kept it, and the pane reconciler
only closes panes whose PTY ended. A binding whose terminal the host publishes
in another tab is now stale rather than orphaned, and a live pane whose PTY
another tab now binds is detached with its PTY left running.
@blacksmith-sh

This comment has been minimized.

nwparker and others added 28 commits October 23, 2026 21:40
…snapshots; retire the moved pane's agent records

A host snapshot taken before the host processed this window's own move still
lists the terminal in the source tab, so the stale-binding rule would drop the
new tab's pane. A pending host move now exempts its target pane until it
settles. An externally moved pane's agent records are retired with the source
pane, and only leaves in a tab's tree count as binding a PTY.
…get this window already moved it to

If a pre-move snapshot redraws the source pane after this window's own move,
the source key already aliases the live target; retiring it would delete the
target's agent status and launch records.
# Conflicts:
#	src/renderer/src/components/terminal-pane/terminal-live-layout-reconciliation.test.ts
#	src/renderer/src/components/terminal-pane/terminal-live-layout-reconciliation.ts
#	src/renderer/src/components/terminal-pane/use-terminal-pane-reconciliation.ts
#33706)

A repo saved as \\wsl.localhost\<distro>\mnt\c\... runs Git in WSL, which
lists its worktrees as /mnt/c/.... The listing mapped those to C:\..., so the
primary worktree got the id <repo>::C:\... instead of the saved
<repo>::\\wsl.localhost\...\mnt\c\.... Its tabs, agents and terminal history
are keyed by the saved id: the renderer dropped them as belonging to no
worktree, and the C:\ row showed up as a hidden discovered worktree.

Map drvfs output to the distro's UNC view when the repo itself is saved
under it. Repos saved as drive paths (Git routed to WSL) and in-distro repos
keep today's drive mapping.
Moves the push gateway's database layer into a shared cloud/packages/cloud-database package (service name and schema passed in). Push's behaviour, log names, SQLite file and tests are unchanged.
* refactor(renderer): group agent-status records and reducers

* refactor(renderer): consolidate concrete type owner imports
…ot Orca's launch flag (#33460)

* fix(codex): resume a thread with the permissions it was last given, not Orca's launch flag

Codex restores a resumed thread's saved approval/sandbox settings unless the
launch passes a permission flag. Orca replayed its launch-time recipe
(--dangerously-bypass-approvals-and-sandbox, --approve-for-me, or the Ask
flags) on every resume, so a session switched to "Approve for me" came back
as Full Access after a restart, and that override was saved to the thread.

Fixes #10886

Co-authored-by: mys <4546173+wowpotato@users.noreply.github.com>

* test(mobile): Codex AI Vault resume no longer replays Orca's permission flag

The mobile AI Vault resume builds its command through the shared resume plan,
so it now omits --dangerously-bypass-approvals-and-sandbox like desktop does.

Co-authored-by: mys <4546173+wowpotato@users.noreply.github.com>

---------

Co-authored-by: mys <4546173+wowpotato@users.noreply.github.com>
…resumed (#33776)

* fix(agent-resume): record a background agent launch's recipe so resume keeps its flags

* test: narrow the reveal's notifier so the test needs no cast

* refactor(agent-resume): one recipe registration path; skip adopted panes

* test: add the launch-recipe listener to the remaining window mocks
)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…once its shell is up

A desktop-seeded first tab in an empty paired workspace is still settling its
first spawn when a split lands right after it opens, which can leave the split
pane unbound; the spec now has the server make the source tab, as #33027's does.
Its timeout bump says why.
releaseDrainWaiters runs on every stream-socket read, but waiters only exist
while a disconnect drains. Return early when the list is empty so each read
no longer allocates a throwaway filter array and callback closure.

Co-authored-by: OrcaWin <alpha-eng@stably.ai>
…#33794)

oxlint 1.89 adds eslint(no-setter-return), which flagged one test setter.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…33796)

* test: remove low-value inventories, passthroughs and redundant cases

* style: format test suites after pruning redundant cases

* test: remove obsolete workflow and flaky-test references

* test: prune deleted builder test from Windows shim allowlist

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
… failing (#24839)

* fix(agent-awake): back off and warn once when the Linux lid sleep assertion keeps failing

On a headless Linux host, systemd-inhibit starts and then exits with code 1.
start() reset the failure streak right after the spawn, so every 30 s retry
logged a fresh warning and the retry never backed off.

Keep the streak until an intentional stop or until an inhibitor has held for
a full retry interval, and double the retry delay on consecutive failures
(30 s up to 30 min).

Fixes #20739

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(agent-awake): keep the lid assertion failure streak across idle/active cycles

stop() reset the warn-once dedupe and backoff, so a host where logind denies
the inhibitor still warned once per agent turn. Reset only after an inhibitor
was actually held for a retry interval.

* fix(agent-awake): keep the 30s lid assertion retry instead of backing off

Backoff delayed re-acquiring the lid inhibitor on laptops after transient
failures; warning once per failure streak already fixes the log flood.

---------

Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…10586)

set_value looked up node.is_editable_text before attempt() ran. GI bindings
from at-spi2-core < 2.53 (e.g. Ubuntu 24.04) do not expose that function, so
the AttributeError escaped and every set-value failed. Probe with
get_editable_text_iface, which has been bound since 2.9.2 and checks the same
interface.

Closes #10569

Co-authored-by: bbingz <zzb@gxsmjx.com>
* fix(updater): probe latest-linux-arm64.yml on Linux arm64

Preflight HEAD of the Linux updater manifest used latest-linux.yml on
every arch, so arm64 could pin a tag whose arm64 yml was still missing
(or skip a tag that was arm64-ready). Match electron-updater and probe
latest-linux-arm64.yml when process.arch is not x64.

* test(updater): accept arch-suffixed Linux manifests in updater feed mocks

On a Linux arm64 runner the feed now requests latest-linux-arm64.yml, which the
[a-z]+ suffix in these mocks rejected (12 failures with process.arch=arm64).

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Each custom oxlint JS rule now checks the file text first and returns no
visitors when it cannot report, so oxlint skips the AST transfer to JS.
app-store-performance only resolves scopes for tracked hook names.
anti-slop rules are wrapped with per-rule text prefilters. react-doctor
rules are off for folders without React (the old cloud/** ignore never
matched: config/ globs need a leading **/).

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
#22494)

* fix(computer-use): send correct named keys and hotkey letters on Linux

press_key passed the keysym for named keys (Return, Tab, arrows, Escape)
to AT-SPI as PRESSRELEASE, which expects a hardware keycode, so a
different key was pressed. Synthesize with SYM instead.

hotkey forwarded upper-case letters such as CmdOrCtrl+A to xdotool,
which reads them as shifted keysyms and sends Ctrl+Shift+A. Lower-case
single letters in key combinations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(computer-use): drop the unreachable lone-key hotkey case

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* Unify terminal starts under one host operation

* Pin winning geometry across a late terminal join

* Use terminal creation options type in launch race test

* Check closed panes after acquiring the terminal spawn lease

* Preserve terminal start resource and join boundaries

* Keep terminal attach regression within project boundaries

* Capture terminal spawn authority and preserve image coverage

* Use checked fixtures for terminal image replay regression

* test: expose persisted pane to main layout in attach race

* test: contract terminal spawn scaling and retention

* test: correct spawn scaling fixture types and CI selection

* test(terminal): cover exited prompt claims and adopted team cleanup

* test(pty): consolidate mock registry imports

* fix(pty): retain untyped IPC resume inputs in common contract
…, not the first copy (#33818)

A worktree id or project host setup id repeats across hosts. Lookups that
named no host picked the first match, so a delete or setup mutation could
land on the other host's copy. They now go through one sole-copy rule and
refuse when the matches span more than one host; callers that know the
host (settings Remove, ephemeral VM rollback) now name it.

Co-authored-by: fettpl <38704082+fettpl@users.noreply.github.com>
nwparker and others added 27 commits October 26, 2026 03:09
… again

Back to the reviewed behaviour: the source tab's agent records are retired and
the host republishes the agent under its new tab. Keeps the independent fixes:
a committed move stays fenced until a host snapshot shows it (confirmed on the
raw frame, and not re-held by a reply that arrives after its snapshot), the
draw-before-reply release on a throw, and the reconcile effect's tab ids.
…-10 unit shards (#33887)

- Plan unit selection starts after setup (overlaps lint) instead of last.
- Localization extraction starts with the typecheck; test-file-runners is background.
- run-ratchets.mjs runs ratchets in a pool (19s serial -> 8s locally).
- pnpm lint uses CI's single-parse check-import-boundaries.mjs.
- ORCA_UNIT_FULL_SHARD_COUNT accepts 2-10 (default stays 5).

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Issue create (including the empty-body fallback and follow-up PATCH),
issue body edits, and issue comments passed the body as
`--raw-field body=...` on argv. Windows caps the command line at
32,767 chars, so bodies with pasted inline images failed with
`spawn ENAMETOOLONG` before reaching GitHub.

These calls now use `gh api -X <METHOD> <endpoint> --input -` with a
JSON payload on stdin. ghExecFileWithScopeAsync also now forwards
`options.stdin` to the child process; it was previously dropped.

Fixes #15832

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
… Linux (#31675)

Open in started editors with Orca's full environment, so an AppImage
launch leaked ARGV0/APPDIR/APPIMAGE/OWD/APPIMAGE_LIBRARY_PATH and the
mount-path PATH and LD_LIBRARY_PATH entries into the editor's integrated
shells (zsh then runs host commands like cargo under the AppImage name).

Add envWithoutAppImageRuntime() next to removeAppImageRuntimeEnv and pass
its result to every editor spawn path on Linux; macOS and Windows keep
inheriting the env unchanged. The clipboard publisher and both AppImage
daemon command builders reuse the same helper instead of their own
copy-and-scrub loops.

Fixes #31455

Co-authored-by: Neil <neil@stably.ai>
…don't skip dates (#19086)

The RRULE day scan stepped local midnight by a fixed 24h. Walking back
over a 23-hour spring-forward day landed at 23:00 two dates earlier, so
the latest-occurrence lookup used for catch-up runs skipped a date. It
returned a run a day too old for daily schedules, and a week too old for
weekly ones.

Step with setDate via a shared addLocalDays helper, in both the RRULE
scan and the cron feasibility scan. Add a regression test for
America/New_York and Australia/Lord_Howe. The test is skipped on Windows,
where unstubbing TZ doesn't restore the OS zone.

Co-authored-by: liutian <liutian.6000@bytedance.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
…ge fills (#32894)

Returning early from the for-await over the forward-page ReadStream
destroyed the stream, which closed the shared FileHandle before the
boundary checkpoint read, so any forward page that hit its limit failed
with transcript_parse_failed. Scan with positional handle.read calls
instead so the handle stays open and read errors reject inside the
caller's try/finally.

Fixes #32892

Co-authored-by: Kim Kaznowski <kim@doubledashstudios.com>
Co-authored-by: Neil <neil@stably.ai>
…6030)

`orca fill --value ""` and `orca select --value ""` were rejected client-side
with "Missing required --value" even though the browser.fill/browser.select RPC
schemas already accept an empty string. Read --value with the existing
getRequiredStringFlagAllowingEmpty helper so an empty value clears a field or
picks the blank option, while an absent --value is still rejected.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
…k_install_failed (#25287)

agent_hook_install_failed sent up to 200 chars of the raw installer error,
which embeds home-directory paths (and so the OS user name) and can echo
config contents. Send only the error's errno code or 'unknown', and enforce
that in the event schema. The anchored, capped errno pattern now lives in
src/shared/errno-code.ts and is shared with the renderer launch probe and the
file-write precondition instead of their own copies.

Fixes #21492

Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
…otification option (#26321)

On macOS the System sound option passed sound: "default" to Electron, which
the UNUserNotificationCenter backend resolves via soundNamed:"default" (a file
lookup) instead of UNNotificationSound.defaultSound, so banners were silent.
Leave sound unset so Electron plays the OS default, and drop the now-dead
sound field from the notification options type.

Fixes #26043

Co-authored-by: Neil <neil@stably.ai>
…` is not on PATH (#14010)

GUI-launched Orca often inherits a minimal PATH, so bare `code` fails with
spawn ENOENT for Open in VS Code, including Remote-SSH worktrees. When PATH
and install-dir lookup leave `code`/`code-insiders` unresolved, fall back to
the CLI bundled in the standard macOS app bundle (/Applications or
~/Applications) or the Windows user/system install. Linux packages already
link the CLI onto PATH, so no Linux candidates are added.

Fixes #14008

Co-authored-by: Neil <neil@stably.ai>
#33899)

The main bootstrap banner was prepended to index.js in generateBundle,
after Rolldown had already emitted index.js.map, so every main-process
crash trace decoded ~200 lines off. Emit it via Rolldown's output.postBanner
instead, which shifts the source map natively.

Co-authored-by: outof-place <contact@outofplace.space>
… in Jump Palette (#33902)

Panes are scoped to a single worktree and the Jump Palette has no
Shift-Enter handler, so replace those promises with the real flow:
watch sidebar status indicators and jump between worktrees with
Cmd-J (macOS) / Ctrl-Shift-J (Windows / Linux).

Fixes #10477
…ens fail (#33831)

* fix(drops): keep files dropped onto a remote workspace out of git status

Uploads into `.orca/drops` now write `.orca/drops/.gitignore` (`*`) the first
time it is missing, so dropped files no longer block a plain workspace delete
or get committed by `git add -A`. Callers share one constant for the folder.

Fixes #23856

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Re-check the import session after the drop staging ignore step

The ignore step swallows its own errors, including a stale session. When
nothing was staged the loop never asserted again, so the caller got
skipped/failed results instead of the retry error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(drops): say why a remote drop or file open failed

Co-authored-by: Jae Heo <83424878+jae-heo@users.noreply.github.com>
Co-authored-by: Bing.Z <zzb@gxsmjx.com>

* fix(drops): keep paths out of failure toasts and reuse the too-large classifier

* fix(drops): shorten whole quoted paths in failure toasts

* fix(drops): describe upload failures by category instead of host text

* fix(drops): match failure categories on unquoted text and name manual disconnects

---------

Co-authored-by: Younghwan Chae <chyohw97@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Jae Heo <83424878+jae-heo@users.noreply.github.com>
Co-authored-by: Bing.Z <zzb@gxsmjx.com>
…test ratchet (#33903)

lint:ast-grep and check-flaky-test-pattern-ratchet each parsed the whole tree.
ast-grep-gates.mjs scans once; the lint gate re-runs ast-grep only on files with
warning-or-error findings (ast-grep's own report and exit code), and the flaky
ratchet counts test-* matches from the shared scan.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Collapsing the section the View all diff viewport was inside kept the
scroll anchor's within-section offset, which pointed into the removed
body, so the structural restore landed on later sections. Pin the anchor
to the section header before the collapse is published.

Fixes #20665
…rse under any locale (#33898)

macOS ps formats lstart with the user's locale (%c) and vis-encodes
non-ASCII argv when no UTF-8 locale is set. Under de_DE/en_NZ/ja_JP the
process-table parsers dropped tty/startTime and folded them into command,
breaking agent recognition, pane fingerprints, agent-session start times
and daemon identity. Run those ps readers with LC_ALL=en_US.UTF-8 on
macOS; other platforms keep the inherited env.

Fixes #27004

Co-authored-by: outof-place <contact@outofplace.space>
#14812)

On drive and `\\` UNC roots, an open tab whose filePath used a different
separator or drive-letter spelling than the watcher event (for example
`c:\Repo\File.ts` vs `C:/Repo/File.ts`) never matched, so external edits
did not reload the tab or raise the changed-on-disk banner.

Both direct-match sites (the indexed batch lookup and the non-indexed
fallback in getOpenFilesForExternalFileChange) now compare through
externalChangePathKeyFor(root), which reuses editorBufferPathKey to fold
separators, the drive letter, and the UNC server only. Path-tail case stays
exact, and WSL, POSIX, SSH, and `//` roots keep byte-exact keys.

Fixes #14801

Co-authored-by: VXNCXNX <VXNCXNX@users.noreply.github.com>

Co-authored-by: Neil <neil@stably.ai>
…on macOS (#33901)

The resource panel summed RSS. On macOS that counts the Electron framework's
shared pages once per helper process, so main and renderer read 2-8x too
high, while the GPU process read 3-5x too low because RSS excludes graphics
memory. The detached terminal daemon was also missing from the app total.

On macOS, sample per-process phys_footprint from top (the figure Activity
Monitor shows) at most every 10 s while the panel is open, and fall back to
RSS when top is unavailable. Count the local terminal daemon in the app's
'other' bucket; its PTY children stay attributed to their worktrees. Linux
and Windows keep RSS/working set.

Co-authored-by: m4air <m4air@Mac.localdomain>
…sn't re-paired (#33109)

A WSL host's bridge listened on a fresh port each launch, which changed the saved
pairing endpoint. The renderer treats a changed WSL pairing as a different machine
and purges the host's workspaces, tabs and selection, then rebuilds them once the
host relists its projects.
…cleanup (#33907)

Prove the relay reaches wsl.exe through --exec unchanged, carries every byte
value both ways, holds the desktop back under a stalled reader on either
side, falls back to Node for no bash, old bash, no /dev/tcp and refused
dials with unchanged sentinels, and leaves no bash or cat behind when
either side goes away.
…Cmd+Shift+G (#18844)

The Cmd+G / Cmd+Shift+G path called findNext/findPrevious with only
{ caseSensitive, regex }. @xterm/addon-search only draws the active-match
decoration, fires onDidChangeResults, and keeps refreshing highlights on new
output when the call carries decorations, so the shortcut froze the active
highlight and the match counter.

Share one buildTerminalSearchOptions() between the find bar and the
shortcut path so both send the same decorated options.

Co-authored-by: Anton Kuligin <anton.kuligin@notraffic.tech>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
… it (#33906)

Agent Session History now routes Delete for a session on a paired or
SSH-managed Orca server to that server through a new aiVault.deleteSession
RPC. The host revalidates the path against its own roots, removes the
transcript (into Trash on a desktop host; permanently on a plain-Node host,
which has none), and invalidates its caches. Hosts advertise
aiVault.delete-session.v1; an older host keeps Delete disabled with
"Update <host> to delete its sessions from here."

Co-authored-by: brynnclaw <261708852+brynnclaw@users.noreply.github.com>
…ogin, not OAuth (#26609)

Orca has no OAuth app; it reads tokens from the gh CLI on the machine running
Orca. Document that, the per-host login for Remote Orca Servers, and the
repo/read:org/project scopes auth-diagnose expects.

Refs #26604

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
# Conflicts:
#	src/renderer/src/components/terminal-pane/terminal-pane-tab-detach-runtime-host.test.ts
#	src/renderer/src/components/terminal-pane/terminal-pane-tab-detach.ts
#	src/renderer/src/runtime/web-runtime-leaf-move.ts
@nwparker
nwparker merged commit 3804670 into nwparker/fix-32939-move-pane-new-tab Oct 26, 2026
105 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.