Skip to content

[upstream #30546] feat(mobile): make terminal touch scrolling follow the finger like a native scroll view - #343

Open
innocarpe wants to merge 10000 commits into
mainfrom
ios-terminal-finger-scroll-20261019
Open

innocarpe wants to merge 10000 commits into
mainfrom
ios-terminal-finger-scroll-20261019

Conversation

@innocarpe

Copy link
Copy Markdown
Owner

Portfolio mirror of my contribution to upstream stablyai/orca.
Exhibition only — the real review/merge target is upstream.

Upstream

Summary

Stacked on stablyai#30534 (smooth scrollback between rows): the first commit here is that PR's, and this PR's own change is the second commit. Once stablyai#30534 merges, the branch reduces to that one commit. ## ELI5 Scrolling the phone terminal now feels like scrolling a normal iPhone list

Note

  • Do not merge this into innocarpe/orca main until the upstream PR is merged.
  • After upstream merges: sync fork from upstream, then close this mirror PR.
  • This open PR exists so visitors see in-flight work on this fork's Pull requests tab.

@innocarpe innocarpe added the enhancement New feature or request label Oct 19, 2026
OrcaWin and others added 29 commits October 28, 2026 17:36
…ablyai#35332)

* fix(clipboard): order text, image and file IPC copies

* fix(clipboard): time out stalled file path resolution in the shared copy queue

---------

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

* perf(orcad): spawn the terminal daemon before the runtime graph evaluates

The daemon spawn now starts right after the login env lands, before the runtime graph's imports
instead of midway through them. Bundled dynamic imports resolve as microtasks without yielding to
the event loop, so two loop turns between the first imports let a finished login env start the
daemon process, which then boots on another core while ~0.4 s of runtime modules evaluate.

* fix(orcad): register the daemon disconnect as soon as its spawn starts

An import or init step that throws between the daemon spawn and the old registration point left
no cleanup to disconnect the in-flight daemon. It is now registered right after daemonStartup,
first, so it still runs last.
…d on disk (stablyai#35483)

* fix(runtime): a device registry save never resurrects a device removed on disk

Every DeviceRegistry save wrote orcad's whole in-memory list. A lastSeen flush (250 ms after any
socket auth, and again at shutdown) could therefore write back a device an admin had just removed
from orca-devices.json on the host, silently undoing the revoke; it also dropped rows another
writer had added. Saves now re-read the file and write the in-memory change merged over it: rows
this process knew of that are gone from disk stay gone (in memory too), rows added on disk are
kept, and this save's own adds and removals apply. The write stays the secure-file atomic rename.
The pairing-repair e2e logs the registry's device ids after the kill and after the reconnect.

* fix(runtime): tombstone devices this process removed so a stale writer can't restore them

Review of stablyai#35483: after removeDevice(a), a stale writer (an old orcad's flush during an SSH
relaunch or upgrade overlap, an external tool) could write a back; the next save treated it as
new on disk, adopted it and let it authenticate. DeviceRegistryWriter now remembers every id
this process removed, recorded before the write so a failed load-time cleanup counts too, and
never adopts those from disk. replaceRow reports false when the merge dropped the row, and a
pending offer removed on disk is replaced instead of handed out.
…tablyai#34976)

Monaco normalizes line endings per edit, so splitting a CR from its LF
across chunked executeEdits calls inserted an extra blank line.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Snapshot the paste target (model, container, focus) before the context-menu
clipboard IPC read and before the yielding byte measurement of large pastes,
and re-check it afterwards so a model swapped during the await (e.g. a diff
refresh via setModel) does not receive the paste.

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

Notebook cell models were anonymous and disposed whenever a cell lost
focus or the notebook view unmounted on a tab switch, so Undo did
nothing after returning to a cell.

Give cells that have a stable nbformat id a vscode-userdata model URI,
scoped to the view, so Monaco's model service keeps and restores the
disposed model's undo stack. Monaco restores only when the text is
unchanged and bounds retained history to its closed-file budget.
Id-less cells keep anonymous models because their position-based key
can move to a different cell, and a duplicate id falls back to an
anonymous model instead of colliding.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Key the notebook scroll listener and restore effects on notebook
readiness instead of raw content, so the listener attaches once an
invalid notebook becomes valid and content republishes no longer snap
the view back to a stale cached position.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
handleOpenDiffTargetFile keyed editor/markdown view-mode preferences by
the raw file path, but openFile returns owner-scoped IDs for remote
runtime files and same-path tabs in other worktrees, so Rich mode was
lost or written onto another owner's tab.

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

The mount reconciliation already reads the full model text for its
stale-cache guard. Pass that snapshot into syncContentOnMount so a mount
reads the model once instead of twice.

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

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

* fix(mobile): stop review notes disappearing or coming back after deletion

The phone sent its whole notes list on every add or delete, and the host
stored it as is. A note added on desktop after the phone loaded was wiped
by the phone's next edit, two quick taps could overwrite each other, and a
failed save rolled back to an old snapshot.

worktree.set now takes an optional diffCommentsBase, like linkedItemsBase:
the host applies only the writer's own adds, edits and removals to the
stored notes. The phone sends the list it started from, shows the host's
merged list from the reply, and undoes only its own change on failure.
Older hosts drop the field and replace the list as before; older phones
send no base and get the same.

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

* fix(mobile): keep loaded review notes when an early save fails

The first load was discarded once any save started, so a save that failed
before it landed left the host's notes hidden. The load now applies the
phone's changes made during the read onto the host's list instead.

* fix(mobile): send review-note requests one at a time

Two in-flight saves could reach the host in either order, so adopting the
later reply hid a note the earlier save had stored. Session notes now send
one request at a time and reconcile every reply with the phone's changes
made since it was sent, replacing the sequence counters.

* fix(mobile): drop review-note saves queued behind a failed one

A save queued behind one that failed still sent the list built on the
failed change, and an older host stores that list whole. Those saves now
undo their own change instead of sending. Also renames the shared base
type so it no longer shares a name with the renderer's mutation record.

* fix(mobile): show review notes as the host's list plus pending saves

A queued reply was reconciled against the list captured at tap time, so a
note desktop deleted meanwhile came back on the phone. The phone now keeps
the host's last list and its unanswered saves per workspace and shows the
two combined; a reply for another workspace is ignored. The review screen
also shows the host's list after a save, so an edit to a note desktop
deleted no longer looks saved.

* fix(mobile): fail queued review-note requests while disconnected

A notes request queued behind a pending load waited for a reconnect with
no timeout, holding every later save. Notes requests now fail at once when
the connection is down, like terminal input.

* fix(mobile): drop every review-note save built on a failed or dropped one

A save made while a dropped save was still pending carried its change,
so an older host could store it. Each failed or dropped save now moves
the failure count.

* fix(mobile): send each review-note save as the host's list plus its change

Each queued save now builds its payload when it is sent, from the host's
last list plus only its own change. A note added before the first load
no longer replaces the loaded notes on an older host, and a failed save's
change never rides along, so later saves no longer need dropping.
Delivered-note cleanup waits for a reconnect again so those notes are not
sent twice.

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
…lyai#34816)

Same-path files with different owners (runtime hosts or worktrees) shared
Monaco, rich-markdown, notebook, and PDF/media reading positions when the
tab id equals the file id. Key them by file id, matching the diff and
markdown preview keys.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(editor): copy gutter URLs from the owning file

* fix(editor): scope gutter remote URL fallback to the editor owner

Look up the gutter menu's owning file by fileId, falling back to a
same-path match only within the editor's worktree so conflict-overview
editors with synthetic ids still copy a URL. Drop the e2e proof spec
and trim the unit test to the same-path/different-owner regression.

---------

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

Conflict Next/Previous published a path-only reveal, so every editable pane
showing that file jumped, and overview mirrors never moved. Target the reveal
at the requesting file id and pane view id, and let read-only overview
mirrors accept only reveals that name them.

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

Above the 1 MiB override cap a Markdown file can never render rich, so
skip the unsupported-syntax scan and keep those documents out of the
eligibility cache.

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

Output stays buffered per task, so a long unit-test step looked hung for
30+ minutes. Print each task's completion, a 60s heartbeat naming running
tasks, and kill any step after 30 min (--timeout=<minutes> overrides).

Co-authored-by: Claude <noreply@anthropic.com>
…blyai#35327)

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

Subscribe to onDidChangeModelContent directly instead of the
@monaco-editor/react onChange prop, which calls editor.getValue() before
Orca's ownership and programmatic-sync checks run. Programmatic echoes
(external reloads, shared-record commits, read-only live tail) no longer
materialize the full model text only to discard it.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…tings (D1c-3) (stablyai#33097)

* feat(wsl): offer Git for Windows in a Windows-drive WSL project's settings

Project settings show a Git row for a WSL-runtime project on a Windows drive (WSL
hosts on). "Use Git for Windows" checks the project, shows any blocker in plain words,
optionally sets core.autocrlf in the repo, and saves the returned runtime through the
normal project update. Once converted the row says where Git and terminals run.
Switching the distro keeps Git for Windows instead of silently dropping it.

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

* fix(wsl): offer the Git choice only for a Git repo, not a folder

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…tablyai#34747)

* perf(github): avoid redundant REST reads for PR conversations

* fix(github): retain valid inline comments beside missing numeric IDs

* fix(github): preserve comment quota errors during REST recovery

* fix(github): order review summaries by submission time

* fix(github): keep forced PR conversation refreshes out of in-flight sharing

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* perf(github): reuse repository merge metadata reads

* Preserve capability reuse across worktree directories

* Use required braces for capability writer cleanup

* Isolate capability configuration and cancellation lifetimes

* Keep capability fixtures independent of ambient configuration

* fix(github): isolate fallback configuration directories

* Keep successful merge metadata through competing read failures

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* perf(github): combine PR detail context reads

* perf(github): avoid redundant file retry after context failure

* Isolate viewed-state failures and preserve cached PR metadata

* Start participant recovery independently of cached metadata

* Give cached metadata and PR context independent semaphore permits

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* Read sidebar PR and stack metadata in one GraphQL query

* Preserve direct PR error recovery without duplicate GraphQL reads

* Keep combined sidebar queries out of merge preflight

---------

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

* fix(editor): preserve folds and horizontal scroll across tabs

* refactor(editor): keep reading state cache with its lifecycle

* test(editor): give stale-cache model its URI

* refactor(editor): keep editor view state cache beside diff view state

Move editorViewStateCache into scroll-cache.ts, clear it in the shared model
lifetime fixture, drop the e2e evidence spec and the duplicate LRU test.

---------

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

* Keep Markdown completion catalogs owned by surviving panes

* Assign completion test editor ref in a layout effect

---------

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

* fix(editor): restore diagram scroll after async rendering

* fix(editor): retain pending diagram scroll while hidden

* fix(editor): key Mermaid restore on rendered source and cancel it on user scroll

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
findCommandsOnLocalPath() replaces one isCommandOnPath() call per agent
command: it reads each absolute PATH directory once with readdir and matches
command names and PATHEXT permutations in memory, then verifies only the
hits through isExecutableFile. Symlink, directory, permission,
case-insensitivity and absolute-only PATH semantics match the per-candidate
lookup. On the machine in the issue this replaces about 24,000 stat() calls
per detection run with about 38 directory reads.

Fixes stablyai#34636
- Deduplicate candidates per command: 'tool' and 'tool.CMD' may resolve to
  the same on-disk file and both must still be found.
- Probe known candidate names directly when readdir is denied (EACCES/EPERM):
  an execute-only directory cannot be listed, but stat on known names works,
  which is what the per-candidate lookup did.
- Skip the install-dir fallback's PATH re-scan: the batch already proved the
  missed commands absent on the PATH it searched, and that PATH is a superset
  of the fallback's (merged persisted PATH on Windows, the same filtered PATH
  on a WSL host), so the fallback scans install directories only.
nwparker and others added 29 commits October 29, 2026 00:20
stablyai#35765)

stablyai#35667 pruned src/shared/wsl-host-internal-gate.test.ts as a lone suite,
dropping stablyai#35543's child-side cases. Two non-redundant ones return inside
wsl-host-gate.test.ts: a child of a blocked run trusts the published
closed over ORCA_INTERNAL_WSL_HOSTS=1 (and serve-only with no env), and
falls back to the env when nothing valid was published. The main-side
cases were already there.

Co-authored-by: Claude <noreply@anthropic.com>
…stablyai#35766)

* test(wsl): prove OpenCode chat inside the distro in the real-WSL chat lane

* test(wsl): one helper runs each scripted provider chat
…stablyai#35782)

The live updater wrote JSON.stringify(parsed.policy), and parsing strips
fields this build doesn't know. Since an equal revision never rewrites the
cache, an older build that fetched a revision first would hide a field
such as movedProjects from a newer build on the same profile until the
server bumped the revision. It now writes the validated downloaded text
verbatim; the monotonic revision rule is unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
…5729)

* fix(wsl): close the session scanner's post-stop boot gaps

An OpenCode/ZCode WSL reader that exits notes its distro may have
stopped, so a respawn needs a settled running read. The Devin
sessions.db opens only on a running list from the transcript lease.
Queued transcript reads re-admit right before they run, and reads on
open 9P handles re-admit too. WSL roots and extra Codex homes come
from a confirmed running list (E9).

* fix(wsl): a failed running-list probe keeps WSL sessions and delete roots

Background discovery keeps confirmed-only WSL roots, but an unconfirmed
probe now carries over the last confirmed WSL rows (marked partial)
instead of dropping them. Path checks for user acts (delete, subagents,
transcript lookup) use last-known-good roots, since checking a path
against a root reads nothing.
* Unify dedicated agent launch choices and argument badges

* Enable action model and effort menus with argument migration

* Bound argument choice edit range processing

* Preserve independent action effort through launch and migration

* Preserve literal config arguments and explicit launch permissions

* Respect repository action argument groups and share launch controls

* Remove duplicate action launch command coverage

* Unify Source Control action choices and repository overrides

* Use precise types in action choice contracts

* Consolidate action choice test imports

* Correct action choice types and integration test boundaries

* Complete prepared terminal test result contract

* Align action integration expectations with canonical choices

* test(mobile): type the file preview retry test helpers so the test typecheck passes (stablyai#35431)

(cherry picked from commit 0774fc9)

* Commit edited action arguments before planning and launch

Reconcile deliberate raw edits once into the submitted action recipe so replacement model and effort flags reach Save and Start together. Preserve captured sources and untouched load conflicts.

* Name portable Source Control dialog fixture results
…he node-server lane (stablyai#35772)

Boot the built orcad the way a WSL host launch does, open a repo and two
terminals, idle 90 s, and assert the whole process tree stays under
400 MB of RSS (about 251 MB today). It catches a new always-on worker or
a retained buffer between device runs of the 1 GB memory gate.
…ssing, not a failed start (stablyai#35770)

* fix(claude): report a CLI the supervisor could not spawn as missing, not a failed start

The connection already flags a supervised exit 127 with a spawn ENOENT as a
missing executable, but the session's unexpected-exit settlement turned every
observed exit into providerExited, which startup then worded as
providerStartFailed. Route spawn absences through the startup failure fact so
they surface as cliMissing or launchFolderMissing.

* fix(codex): report a CLI missing during acquisition as missing, not an exit

Codex's acquisition-time exit had the same drop as Claude's unexpected exit:
a spawn ENOENT already marked on the error became providerExited. Share one
providerSpawnAbsent predicate and route marked errors through the startup
failure fact in both.
…iner in the schema walker (stablyai#35797)

The walker that proves bundled rule files need no parsing missed value
rewriting checks (trim, toLowerCase, overwrite) and never entered
intersections, object catchalls, maps or records. It now reports each,
with a detection test per case.
…ref (stablyai#35778)

* fix(wsl): don't start a stopped distro to read a repo's default base ref

Opening a repo's Settings pane ran git for-each-ref and git remote through
the repo's WSL distro, which started it after the user had stopped it (E9).
Background reads now return the existing unknown result while the distro is
stopped; an explicit refresh can pass wakeWslDistro. The runtime RPC that
serves the same read to paired clients is gated the same way.

* fix(wsl): re-read a refused default base ref once its distro runs

A refused read now names the distro and defers a preflight:wslDistroRunning
broadcast; Settings and Source Control re-ask on it, so base comparison
returns without a repo switch. Drops the unused wakeWslDistro option.
… Git for Windows (D1c-5) (stablyai#33122)

* feat(wsl): default a new Windows-drive project under a WSL default to Git for Windows

* fix(wsl): judge a new project's worktree links with the prune guard's test, so a //wsl.localhost link counts as Windows Git's

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

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
* fix(native-chat): turn a big paste into a file in terminal-backed chats and goal mode

A paste of 32 KiB or more already became a "Pasted text" file in
structured chats, but terminal-backed chats and goal mode put the whole
text in the editor, where one long line can stall the window for seconds
(issue stablyai#32355). Every composer that can store the file now follows the
same rule.

- Terminal-backed chats on this machine save the file in the paste
  folder, where their pasted images already live; their sends claim
  nothing, so the attachment store's 30-day sweep must not reach it.
- Terminal-backed chats never get the structured 256 KB refusal.
- Setting a goal claims the uploads its objective names in the same
  journal write, so a goal's pasted file is not swept; a file already
  gone refuses the goal before the agent starts.

* Preserve paste sources until submitted and retire refused goal claims

* Recover staged paste reads and cancel preparation before option commands

* Stabilize paste ownership test setup and sweep clock

* Keep large-paste folding scoped to structured chats

* Restore journal prototype forwarding methods

* Prepare attachment receipts from actual journal output

* Align goal and deferred paste fixtures with current contracts
…tinue a URL (stablyai#35767)

* perf(terminal): stop HTTP link backward scans at rows that cannot continue a URL

Framed (hard-wrapped) detection walked back up to 2048 rows per hovered line,
building column maps for every URL row; edge-wrapped walked ~54 rows at 80 cols.
Stop once a later row cannot be a continuation (borders, prose, blank rows).
Table-heavy buffer: provideLinks 1.3-2.1ms -> 36-79us per call.

* test(terminal): pin the edge-wrapped HTTP link backward-scan bound
…and comes back with it (stablyai#35732)

* fix(wsl-host): a terminal that meets its stopped distro shows Start, and comes back with it

After an external `wsl --terminate`, the first keystroke's runtime call found the distro stopped and
parked the host, but only liveness ever published a stopped status, and here liveness saw a quick
reboot instead. So no Start card appeared: the pane kept its old prompt, typing did nothing, and a
red toast showed Electron's raw "Error invoking remote method 'runtimeEnvironments:call'" text that
stayed after the distro ran again.

- The runtime-call gate (moved to wsl-host-runtime-call.ts) publishes distro-stopped when it parks
  a host, as liveness does, so every pane on it shows the Start card and its error gives way.
- The park lifts once a running list confirms the distro runs again (never booting it), and a
  host with open work reconnects.
- Panes that gave up on the stop retry when their host is ready again, not only after Start.
- A host refusal's toast drops Electron's IPC wrapper.

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

* fix(wsl-host): a workspace on a stopped WSL host shows no live terminals

Its panes keep their bindings for Start, so the card dot stayed green over dead terminals.

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

* perf(wsl-host): no new store listener per card or surface for the stopped host

The activity status folds the stopped-host check into its existing pty selector, and the pane
recovery portals derive both the Start card and the return retry from one host-status
subscription. The live-capture listener budget (8,000) is back under, with no budget change.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
…blyai#35266)

* fix: separate chat option input from inventory observations

* fix: preserve scoped chat choices and publication ownership

* fix: complete scoped catalog and applied control ownership

* test: make catalog fixture dependency boundaries explicit

* test: request catalog discovery explicitly in demand contracts

* fix(chat): preserve option observations and operation boundaries

* fix(chat): finish pending option and catalog lifetimes

* fix(chat): project saved permissions without launch preparation

* fix(chat): correct option rejection and catalog retirement

* Preserve Claude effort validation advice through chat rejection

* test: align refresh mocks and preserve fixture type evidence

* fix: share catalog claims only across equivalent owners

* test: use typed catalog corpus instrumentation

* fix: consolidate structured launch imports

* Validate SDK queue regression envelopes without assertions

* fix: complete catalog runtime and fixture type contracts

* Align native option fixtures with explicit discovery and applied facts

* Keep initial compatibility catalog reads on held memory

* Complete the installed catalog fixture envelope

* Observe learned defaults after asynchronous projection settles

* Consolidate host fixture journal type imports

* test(native-chat): align goal and seed fixtures with applied inputs

* fix(codex): retain applied proof when goal settings skip a write

* test: load rejection wording before timed queue regression

* Fix catalog fixtures and queued option snapshot typing

* Align permission publication fixture with passive option reads

* Separate startup config from held turn permission fixture

* Align input lifecycle fixtures with sparse applied choices

* Simplify scoped catalog refresh ownership and coalesce cache snapshots

* Load catalog persistence real-module fixture during collection

* Compose catalog availability fixtures from valid session records

* Align catalog and startup fixtures with current option contracts

* Fix permission read types and separate catalog fixture preparation

* Align option and restart fixtures with current lifecycle owners

* test(mobile): retain reported model alongside discovery

* test(mobile): recalibrate the measured route script envelope

* fix(native-chat): preserve models missing from provider listings

* Preserve failure causes and correlate model rejection notices

* Cover catalog omissions and explicit model defaults in client hooks

* Keep ACP model refusals on the generic rejection path

* Include model failure copy in the runtime English catalog

* Align model retention tests and bound result correlation work

* Use checked array access in result correlation contract
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…e once it matches (stablyai#35783)

* perf(terminal): stop re-reading the fit grid on every foreground write once it matches (stablyai#35273)

After a grid-drift probe finds xterm matching the fit, foreground output waits
for a geometry signal (pane ResizeObserver, xterm resize, visibility resume,
window wake) or a 2s backstop before forcing another proposeDimensions() read.
The first probe after connect and after any signal still runs at the 250ms
cadence, so drift without a pane resize is still repaired on output.

* fix(terminal): trailing grid-drift probe, unknown fit never settles, 1s backstop (stablyai#35273)

- A foreground write skipped by the probe interval arms one trailing probe
  (per session, cleared on probe and dispose) so drift can't stick when output
  stops right after a throttled write.
- measureTerminalGridFitDrift() returns 'drifted' | 'matched' | 'unknown';
  only a valid matching proposal settles the probe.
- Settled backstop shortened from 2s to 1s.
- Probe moved to foreground-grid-drift-probe.ts (pty-input-forward max-lines).
- Specs use fake timers and cover backstop, trailing probe, and unknown fit.

* fix(terminal): pull an armed grid-drift trailing probe forward when the cadence speeds up
… the signal race (stablyai#35812)

A paired host's repo.baseRefDefault now names the stopped distro that refused
it. Clients that cannot hear that host's running signal re-ask on window
focus and every 30 s while visible, until it answers. Locally, the running
listener is attached before the first read, so a signal that lands while main
is answering triggers a re-read instead of being lost.
… delete as user act, localized carryover notice (stablyai#35810)

OpenCode/ZCode transcript database lookups read inside the WSL homes
they get, so they take only confirmed homes. A WSL session delete runs
as a user act on its distro, so background readers stop trusting an
older stopped read. The carryover notice gets a stable code and
catalog copy in every locale.
…le retry and dot, SSH pin (stablyai#35822)

* fix(wsl-host): a stop published after the host came back says ready again; retry the card's panes

- e9-reviewer: a runtime call's stop could land after liveness had already reconnected and said
  ready, leaving Start on a working host. Once the distro runs, the deferred un-park re-reads the
  host and says ready from the live connection, or reconnects open work as before.
- fix-reviewer-2: the return retry picks panes by the Start card's rule, so a pane whose create
  failed before it reached the host is retried too.
- Pins that the refusal stays a plain, final Error with the same words for the move and automation
  callers.

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

* fix(wsl-host): the stopped dot keeps panes on another, running server live

e9-reviewer: match the Start card's rule; only a pane with no server or on the stopped host ended.

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

* test(terminal): pin that the host-refusal unwrap leaves SSH words and other channels as they were

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
…yai#35815)

stablyai#32919 gave typed workspace names a creature placeholder branch so
first-work naming could rename it. When generation fails or never runs,
users are left on branches like geoduck instead of the name they typed.
Typed names are valid branches in any script, so use them directly;
auto-rename keeps applying to Orca-generated creature names only.
…lyai#35800)

* fix(wsl-host): say which WSL distro an agent isn't installed in

* i18n: translate the WSL-distro missing-agent sentence

* test(wsl-host): reach the missing-agent words through a chat whose agent left the host
…serving (stablyai#35808)

A wake whose launch reply was lost but whose server did start left its
fence held; the next wake saw the slot serving and returned, so deploys
saw the fence busy until it aged out. When the slot is proven LIVE, the
fence names this app's interrupted-wake token and no journal exists,
release it through the owner-guarded release command.
…r-write JSON signature (stablyai#35824)

* perf(editor): compare worktree owner rows by identity instead of JSON signature

Activity/unread/rank patches to worktreesByRepo still stringified every
worktree's owner fields on each write to decide the route token. Walk
buckets and rows identity-first against the last tokenized map instead;
same order-sensitive owner-field semantics, no per-write allocation.

300 worktrees, 200 open files: route check per activity write ~40-70us -> ~0.8us.

* perf(editor): hold the last owner-rows baseline weakly and pin token semantics
…exec-ing into it (stablyai#35823)

After a watch or holder exit, a distro the running list still names is
usually stopping. Liveness now re-reads only the running list (never
boots) once a second for up to 5 s before any identity exec, and
publishes distro-stopped as soon as the list drops it. An exit that
arrives during a recovery backoff ends that recovery so the exit
re-checks at once (E9).
@innocarpe
innocarpe force-pushed the ios-terminal-finger-scroll-20261019 branch from 7e8c59b to fa6584e Compare October 29, 2026 08:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants