Commit Graph
16851 Commits
Author SHA1 Message Date
OrcaWinandOrcaWin a8f7afe84b test: remove 128 low-value cases and 22 suites (#34206)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 22:21:44 -07:00
Kelvin Amoaba 577af08b12 fix(browser): scroll off-screen elements into view before agent clicks (#34262)
Bump agent-browser to 0.27.3. Its 0.27.2 release scrolls the target node into
view (nested scroll containers included) before computing the click point and
errors when another element covers that point, instead of reporting a click
that never reached the page.
2026-10-27 05:21:38 +00:00
Brennan Benson 2e181b1b78 Reuse chat history snapshots across readers (#34215)
* Reuse rendered chat history across readers

* test: cover current journal reads across source changes

* test: align journal assertions with current snapshot reuse
2026-10-26 22:19:15 -07:00
9dd44715ba fix(mobile): keep a renamed tab's name on mobile after the host restarts (#33743)
* fix(mobile): keep a renamed tab's name on mobile after the host restarts

After a restart, the reconnecting client restarts each saved tab's
terminal (restored-pane-materialize -> createRuntimeOwnedMobileSessionTerminal),
and the mobile row built from the new terminal carried no customTitle, so
the phone showed the terminal's own title although the saved session still
held the name. publishPtyBackedMobileSessionTerminal kept a name only from
an earlier mobile row, which a restart does not have.

Both builders now resolve the name through one helper: a value already on
the mobile row wins, including a cleared null; only a row with no value
falls back to the tab's saved name.

Fixes #33737

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

* refactor(mobile): resolve a restarted tab's saved name through getPtyManualTitle

getPtyManualTitle already owns a terminal's manual name (the saved tab's,
else the live rename), so the row builders use it instead of a second
saved-session lookup. A cleared name reads as cleared from the saved
session, so the test now covers that instead of a row-only clear.

* fix(mobile): keep a row's cleared name instead of falling back to the saved one

A null customTitle on a row is a clear: paired desktops need it to drop a
cached name, and a desktop clear lands on the row before the debounced
session write. Only a row with no value falls back to getPtyManualTitle.

* test(mobile): pin that a row's cleared name survives a terminal restart

---------

Co-authored-by: clayphi <193966884+clayphi@users.noreply.github.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-27 05:18:58 +00:00
NeilandLance Woodson 4514634faa fix(scripts): resolve pnpm when npx or npm run exports npm's own CLI (#34271)
`npx` and `npm run` set npm_execpath to npm's own npm-cli.js/npx-cli.js,
so resolvePnpmCliInvocation ran npm with pnpm's arguments. Skip npm's CLI
by file name and fall back to PNPM_HOME / pnpm on PATH. Route
build-workspace-packages and terminal layout parity through the shared
resolver instead of their own npm_execpath parsing.

Fixes #29438

Co-authored-by: Lance Woodson <65194841+woodsonl@users.noreply.github.com>
2026-10-26 22:18:56 -07:00
Neil bff2843fca refactor(shared): organize native chat ask input owners (#34251)
* refactor(shared): group native chat ask input owners

* refactor(shared): keep split ask type imports erased
2026-10-26 22:18:52 -07:00
Kelvin AmoabaandChris Stephens 619ee954c9 fix(browser): paste the local clipboard into streamed browser pages (#34269)
The streamed page's keydown handler forwarded Ctrl/Cmd+V to the host as a
keypress and cancelled the browser's paste event, so the host pasted its
own (usually empty) clipboard. Native paste chords now fall through, and
the frame's paste event inserts the clipboard text with
browser.keyboardInsertText on the pane's input queue, split into chunks
that fit the runtime socket frame.

Co-authored-by: Chris Stephens <nyldn@users.noreply.github.com>
2026-10-27 05:16:01 +00:00
Kelvin Amoaba e79388e3ab fix(agents): keep OMP session titles when a turn finishes (#34266)
Orca wrote a synthetic "OMP ready" / "OMP - action required" title over
the session title that OMP and Orca's titlebar extension already paint.
OMP's hooks are authoritative and its own rest title reads as idle, so
stop synthesizing terminal titles for OMP, as for OpenCode.

Linear: STA-11986
2026-10-27 05:15:58 +00:00
Kelvin AmoabaandFelipe 19c53e5248 fix(browser): let Grab page element pick and track elements inside open shadow roots (#34265)
* fix(browser): let Grab page element pick and track elements inside open shadow roots

Document hit-testing and marker lookups stop at a shadow host, so Grab only
ever picked the host. The overlay now descends through open shadow roots,
and both the overlay and the annotation viewport bridge find the marked
element and listen for scrolls inside them. Closed roots stay opaque.

Co-authored-by: Felipe <5784455+fbetancourtc@users.noreply.github.com>

* fix(browser): track slotted ancestors and stop re-walking shadow roots for a lost target

* fix(browser): walk shadow roots once per selection and count fixed shadow hosts

* fix(browser): restore grab pointer events if a page's shadowRoot throws; type the shadow fixtures

* fix(browser): keep composed-tree walks safe from page-named form controls

---------

Co-authored-by: Felipe <5784455+fbetancourtc@users.noreply.github.com>
2026-10-27 05:15:54 +00:00
Neil 51c393bc2e fix(wsl): close a WSL host's loopback listener once it idles out or its distro stops (#34046)
* fix(wsl): close a WSL host's loopback listener once its orcad idled out or its distro stopped

The supervisor already stops watching an idle or stopped host and never relaunches it for
background work, but the bridge's loopback listener stayed open, and any dial to it (a status
probe, a stale client) spawned wsl.exe and booted the distro again. Retire the listener in both
branches without publishing 'closed', so the host keeps reading as idle or stopped; the next
user connect binds a new one.

* fix(wsl): a retired listener never proves orcad live; never retire a connect in flight

Review of the listener retirement: with no connection, the port probe answered 'ready', so a
wake verify with no orcad pid to compare read the host as live, published ready and re-held
the distro. It now reads as refused. retireListener also leaves alone a key whose user connect
is in flight, so a trigger mid-connect cannot retire the entry that connect produces.

* fix(wsl): retire the listener on E9's single park path too

E9 A parks every confirmed stop, visible work or not; retire the loopback listener there,
before the deferred re-check, so a dial cannot boot the parked distro.

* fix(wsl): read the park generation before retiring the listener
2026-10-26 22:15:00 -07:00
Jinwoo Hong c23ab5546c Antigravity: show a login with no quota as unavailable, not "Refresh failed" (#34163) 2026-10-26 22:07:52 -07:00
Jinwoo Hong 3b1ecd6de4 Antigravity: show usage for a login Orca can't identify instead of "account changed" (#34159) 2026-10-26 22:07:34 -07:00
Jinwoo Hong ad4b9af825 Stop opening a Google sign-in page every hour when agy is signed out (#34165) 2026-10-26 22:05:27 -07:00
Brennan Benson 192f5783ab fix(runtime): keep terminal.send under the file-length limit with one refusal helper (#34256)
#33968 pushed terminal-send-method.ts to 301 counted lines against the 300-line rule, failing Lint on main and every PR that merges it. Eight refusal branches spelled out the same zero-byte result; one helper builds it.
2026-10-26 22:01:45 -07:00
Kelvin Amoabaandpullfrog[bot] 3c8e40a4c9 fix(browser): make orca set media --reduced-motion apply and reject unknown values (#34253)
* fix(browser): make orca set media --reduced-motion actually apply

agent-browser's set media only looks for the bare tokens dark, light and
reduced-motion and ignores anything else, so the documented reduce value
was dropped and the command still reported success. Map Orca's values
onto those tokens in one builder used by the desktop bridge and the
orcad external Chromium path, and reject unknown values.

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>

* fix(browser): reject bad set media values before queuing and list both flags in help

---------

Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
2026-10-27 04:40:53 +00:00
Jinjing 887b781d72 Move palette matching utilities into shared modules (#34252) 2026-10-26 21:29:57 -07:00
NeilandClaude e2b8332804 fix(terminal): closing a kept host-loss tab after a relaunch ends its history (#34205)
* fix(terminal): closing a kept host-loss tab after a relaunch ends its history

A WSL bridge pane lost with its distro keeps its tab and unended history. The
adapter only remembers the loss in memory, so after a relaunch closing that
tab before waking it hit SessionNotFound and left its history directory
behind. The router now ends that history when the id's history is unended and
every daemon, current and legacy, answers that it does not list the id. A
listing or an unanswered daemon keeps the history.

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

* fix(terminal): end a lost session's history only when every daemon can answer for it

Review of the close-after-relaunch path: the router-only check never ran
when the app has no legacy daemons (the provider is then the bare adapter),
and the router's adapters are not every daemon sharing the history dir. An
older daemon whose socket probe failed at startup gets no adapter, and a
daemon held for a newer protocol has none either; both may still run the id.

The check now lives in the adapter's close. It ends the history only when it
is unended, no daemon is held for a newer protocol, no older protocol's pid
file names a process that may be alive without an adapter to ask, and every
known daemon answers listSessions without the id. A router shares its
adapters as the daemons to ask.

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

* fix(terminal): decide a lost session's close in one lock, and never connect a daemon to list it

Review: the unlisted-session check already runs inside shutdownWithHistoryLock,
so a spawn queued for the same id waits until the close has decided; a test
now holds the listing open and proves the spawn cannot slip in. listsSession
no longer connects (or respawns) a daemon just to list it: an unconnected
daemon cannot answer, which keeps the history.

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

* fix(terminal): count an older daemon Orca may not signal as alive; cover slept-tab closes

process.kill(pid, 0) failing with EPERM means the process exists under another
user, so legacyDaemonProcessMayBeAlive now treats it as alive; only a missing
pid file or ESRCH counts as gone. Tests pin that, and pin the wider scope of
the unlisted close: closing a slept tab without waking it ends its unended
history, and keeps it while another daemon lists the session.

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

* refactor(terminal): move the lost-session listing and check out of session control

daemon-pty-session-control.ts went over max-lines. The daemon listing read and
the unended-history check now live in daemon-unlisted-session.ts beside
mayAnyDaemonRunSession; the adapter keeps only thin calls. No behaviour change.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 21:28:36 -07:00
Kelvin Amoaba 75bcd328cf fix(mobile): answer multi-question asks like desktop and clear Claude's wait on phone answers (#33968)
* fix(runtime): clear Claude's question wait when a phone keystroke answers it

Claude sends no hook after AskUserQuestion is answered; desktop infers it, phone answers left the pane waiting.

* fix(mobile): answer multi-question cards like desktop, with Skip and back-stepping

Mobile required every answer and locked grouped structured questions once tapped; the card rules and structured mapping now live in shared code.

* fix(mobile): announce ask card options as checkboxes or radios

* fix(mobile): answer a grouped question only on the prompt it was picked on

* test(runtime): drop the multi-question case the shared answer rule already covers

* refactor(native-chat): share the typed-answer rules and fold the host answer check into terminal.send
2026-10-27 04:27:06 +00:00
Kelvin Amoaba 4c5af5d640 fix(terminal): one tab agent icon rule for desktop and mobile (#33963)
* fix(mobile): send terminal paste, keys and query replies like desktop

* fix(mobile): encode Shift+Enter for the pane's negotiated keyboard modes

The phone's xterm now tracks Kitty flags and modifyOtherKeys with desktop's tracker, seeded from the host snapshot.

* fix(mobile): keep keyboard modes across terminal snapshots

* fix(mobile): adopt snapshot keyboard modes with desktop's rule

* refactor(terminal): share snapshot keyboard-mode adoption and mode mirroring

* fix(mobile): compare terminal modes field by field instead of a dynamic read

* refactor(mobile): share terminal display-mode adoption between snapshot and resize

* fix(mobile): accept only known terminal display modes from the host

* fix(mobile): follow desktop terminal display rules

- ZWJ emoji width: activate the shared Orca unicode provider instead of plain Unicode 11.
- Contrast floor: share desktop's resolver and background parser; translucent
  backgrounds composite over the published light/dark surface.
- Word selection: use xterm's default word separators via a shared rule.
- Takeover reports: share the 30 s gate and single retry between desktop and mobile.
- Use the shared viewport minimums and default scrollback rows.

* refactor(mobile): trim duplicate tests and reuse shared terminal types

* fix(mobile): resolve terminal tab agent icons with the desktop rule

Moves the tab-strip identity resolver to src/shared and deletes the drifted copy in use-tab-agent.ts, so the desktop tab strip, open-tab search and the phone all run one rule.

* fix(mobile): rank host cursor identity as the tab's process signal

* fix(mobile): rank cached host cursor identity only for unowned terminal tabs

* fix(terminal): keep sleeping tab identity through hibernation shell evidence

The kill that hibernates a pane can report the shell foreground while the wake record is kept on purpose; the tab strip never retired sleeping identity on exit evidence, so the shared resolver keeps that behavior.

* test(terminal): drop tab agent tests that replay the shared resolver

* refactor(terminal): share the observed agent signal rule between tab strip and snapshots
2026-10-27 04:26:50 +00:00
Kelvin Amoaba 9f789a4a6d fix(mobile): use desktop's terminal width, contrast and selection rules (#33959)
* fix(mobile): send terminal paste, keys and query replies like desktop

* fix(mobile): encode Shift+Enter for the pane's negotiated keyboard modes

The phone's xterm now tracks Kitty flags and modifyOtherKeys with desktop's tracker, seeded from the host snapshot.

* fix(mobile): keep keyboard modes across terminal snapshots

* fix(mobile): adopt snapshot keyboard modes with desktop's rule

* refactor(terminal): share snapshot keyboard-mode adoption and mode mirroring

* fix(mobile): compare terminal modes field by field instead of a dynamic read

* refactor(mobile): share terminal display-mode adoption between snapshot and resize

* fix(mobile): accept only known terminal display modes from the host

* fix(mobile): follow desktop terminal display rules

- ZWJ emoji width: activate the shared Orca unicode provider instead of plain Unicode 11.
- Contrast floor: share desktop's resolver and background parser; translucent
  backgrounds composite over the published light/dark surface.
- Word selection: use xterm's default word separators via a shared rule.
- Takeover reports: share the 30 s gate and single retry between desktop and mobile.
- Use the shared viewport minimums and default scrollback rows.

* refactor(mobile): trim duplicate tests and reuse shared terminal types
2026-10-27 04:26:35 +00:00
Kelvin Amoaba a9f90e7a71 fix(mobile): use desktop's terminal paste, key and query-reply rules (#33957)
* fix(mobile): send terminal paste, keys and query replies like desktop

* fix(mobile): encode Shift+Enter for the pane's negotiated keyboard modes

The phone's xterm now tracks Kitty flags and modifyOtherKeys with desktop's tracker, seeded from the host snapshot.

* fix(mobile): keep keyboard modes across terminal snapshots

* fix(mobile): adopt snapshot keyboard modes with desktop's rule

* refactor(terminal): share snapshot keyboard-mode adoption and mode mirroring

* fix(mobile): compare terminal modes field by field instead of a dynamic read

* refactor(mobile): share terminal display-mode adoption between snapshot and resize

* fix(mobile): accept only known terminal display modes from the host
2026-10-27 04:26:16 +00:00
Kelvin Amoaba 7e5f9a48df fix(mobile): use desktop's sort, colour, count, agent-row and delete rules in the workspace list (#33995)
* fix(mobile): use desktop's sort, colour, count and agent-row rules in the workspace list

Recent ignores terminal output, repo colours fall back to desktop's neutral,
Home counts skip archived rows, folder workspaces trail each lane, and a stale
agent row on a live terminal reads "No update in …" like desktop.

* fix(mobile): keep Delete disabled on a primary checkout, as desktop does

* fix(mobile): keep the task text on a silent agent row

* fix(mobile): show a silent agent row's time since its last update

* test(mobile): drop agent-row tests that replay the shared verdict

* refactor(mobile): check host PTY liveness once and keep the delete guard on the row flag

* test(mobile): re-record the home catalog goldens for the list's active count
2026-10-27 04:25:59 +00:00
OrcaWinandOrcaWin 425425e200 test: remove 262 low-value cases and 31 suites (#34161)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 21:23:20 -07:00
Neil fe82078909 fix(wsl): background file reads and watches never start a stopped WSL distro (E9) (#34222)
* fix(wsl): background file reads and watches never start a stopped WSL distro

Any Windows touch of a \\wsl.localhost path boots a stopped distro. After a
terminate, the dying explorer watcher's overflow refresh ran realpath on the
project root 0.23 s later and booted the distro again. Background reads, stats
and watch installs now ask a fresh running list first (shared, with a 5 s lease
and a stop signal from the watcher exit and the hook relay link) and refuse when
the distro is stopped. Opening the workspace and Retry still start it. A stopped
watch waits for the distro and resyncs the explorer when it runs again.

* fix(wsl): trust a confirmed running read for 60 s without a stop signal

* fix(wsl): user acts wake; unverifiable is not stopped; settle after a stop

- Opening a workspace, expanding a folder, opening a path (explorer, quick-open,
  links), the active editor tab's load and every Retry pass wakeWslDistro on
  readDir, readFile, stat and readFileChunk. Background reloads, restored-tab
  scans and watchers stay gated.
- A failed running-list read is 'unverifiable', not 'stopped': the gate re-reads
  once past the failure backoff (once per failure window) and otherwise refuses
  with 'WSL didn't answer', never touching the path.
- After any stop signal, a running read that started within EXIT_SETTLE_MS of it
  never counts, in isWslDistroRunning itself, so neither the watcher's own
  overflow refresh nor the hook relay's restart check can read a stale listing.
- A confirmed read that sees a distro stop records a stop signal, resetting the
  60 s lease.

* test: user-opened stats now carry the WSL wake flag
2026-10-26 21:17:07 -07:00
Kelvin Amoaba 6c2423d25d fix(mobile): list Source Control changes with desktop's sections, order and row rules (#34017)
* fix(mobile): list Source Control changes with desktop's sections, sort and row rules

Conflicts get their own section in the user's group order, submodule rows lose stage and
discard like desktop, paths sort with the shared collator, and review notes go out as desktop formats them.

* fix(mobile): read the group order the host now publishes and keep submodule rows read-only

The host's paired settings projection now carries sourceControlGroupOrder, the
normalized status projection keeps submodule metadata, and conflict rows reuse the
shared conflict-kind labels.

* refactor(mobile): share Source Control grouping and row rules with desktop

Desktop and mobile group rows through one shared helper, mobile's unstage button
follows desktop's rule, and the group order resets when the host changes.
2026-10-27 04:14:56 +00:00
Neil e882d8eda7 fix(window): pump hidden-window frames from the renderer on Windows background launches (#34197)
* fix(window): repaint a never-shown background window on Windows so CDP screenshots return

Windows composites nothing for an idle window that was never shown, so
Page.captureScreenshot under ORCA_BACKGROUND_LAUNCH=1 waited forever once the
status-bar usage chip stopped animating (#33799).

* fix(window): pump hidden-window frames from the renderer on Windows background launches

Main-process webContents.invalidate() did not make a never-shown Windows window
produce a frame CDP can capture (verified on Windows 11). A one-frame root
background flip from the preload does, so main stamps a preload flag for
ORCA_BACKGROUND_LAUNCH=1 on win32 and tells the preload to stop on first show.

* fix(window): stop the hidden-frame pump only on main's show signal, including after reloads

A never-shown Windows window can report visible after a desktop change, so the
preload no longer stops on visibilitychange; main re-sends the stop after any
reload once the window has been shown.

* fix(window): register the frame-pump stop with on('show') so every window double supports it

createMainWindow suites simulate win32 under the runner's ORCA_BACKGROUND_LAUNCH=1,
so they install the pump stop; their window doubles implement on() but not once().
2026-10-26 21:13:42 -07:00
NeilandClaude 8d62374000 chore(terminal): log the WSL bridge exit verdict and how long the probe took (#34220)
* chore(terminal): log the WSL bridge exit verdict and how long the probe took

A bridge pane's exit is host loss only if the running list, read after the
exit, lacks its distro. Orca's own background reads can reboot the distro
within seconds, and nothing recorded what the probe answered, so a run could
not tell host loss from a raced reboot or a slow wsl.exe. The check now
returns lost, running or unavailable, and the adapter logs it with the probe
latency. Behaviour is unchanged.

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

* chore(terminal): put the probe's doc comment on checkWslBridgeDistro

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 21:12:42 -07:00
Neil 6357bd7d03 refactor(shared): organize native chat task-list evidence (#34226) 2026-10-26 20:43:05 -07:00
Neil c5f48b5cd3 fix(terminal): scope account restart metadata to its execution host (#34214) 2026-10-26 20:39:47 -07:00
Kelvin Amoaba 3347d47a7d fix(mobile): use desktop's PR lanes and status-dot rollup in the workspace list (#33966)
* fix(mobile): ask before running orca.yaml default-tab commands from the phone

The host's repo.hooks reply now carries desktop's setup config, so the phone
gates the Run/Skip choice and the trust prompt on defaultTabs commands too.

* fix(setup): keep the local script in run-both setup config without orca.yaml commands

* test(setup): drop the shared duplicate-host trust test desktop already covers

* refactor(setup): derive host setup trust from the shared setup config

* fix(mobile): count every host's repo rows before honouring repo-wide setup trust

* fix(mobile): show desktop's PR lanes and failed/interrupted status dots on the phone

The host builds worktree.ps linkedPR with the desktop's PR-lane cache reader
and sends the desktop sidebar dot as an optional sidebarStatus field.

* fix(mobile): keep uncached PR badges and let finished turns show through working titles

* fix(mobile): suppress agent panes' permission and parent titles in the host status dot

* test(runtime): expect sidebarStatus on the compact ps summary

* test(runtime): keep only host-specific sidebar status cases

* refactor(mobile): keep host title suppression and the uncached PR lane in one place each

* test(wire): pass the terminal title evidence map to new host builds

* fix(runtime): read each workspace's PR through its own host's repo
2026-10-27 03:20:58 +00:00
Kelvin Amoaba 71b55ab8a9 fix(mobile): use desktop's setup config and trust rules when creating workspaces (#33942)
* fix(mobile): ask before running orca.yaml default-tab commands from the phone

The host's repo.hooks reply now carries desktop's setup config, so the phone
gates the Run/Skip choice and the trust prompt on defaultTabs commands too.

* fix(setup): keep the local script in run-both setup config without orca.yaml commands

* test(setup): drop the shared duplicate-host trust test desktop already covers

* refactor(setup): derive host setup trust from the shared setup config

* fix(mobile): count every host's repo rows before honouring repo-wide setup trust
2026-10-27 03:20:46 +00:00
Kelvin Amoaba 76349e812c fix(mobile): build chat approval and question cards with desktop's rules (#33967)
* fix(mobile): read chat prompt cards with desktop's shared parser

Mobile guessed permission and question cards from assistant prose; the
guess could outrank the real approval and send the wrong key.

* fix(mobile): keep an ask answer valid across the status-to-transcript handoff

* chore(i18n): ship approval card copy in the runtime English catalog

Its fallbacks now come from the shared copy table, which i18next cannot rebuild from the call site.

* test(native-chat): own approval parsing cases in the shared test

* refactor(native-chat): build each prompt dismiss key once
2026-10-27 03:20:26 +00:00
Neil 68cb2847fb fix(terminal): copy from pi on a remote host reaches the viewer's clipboard (#34102)
Remote viewers get PI_CLIPBOARD_OSC52=1 in every pane so pi's in-app
selection also sends OSC 52 instead of only the host's clipboard. The
Codex SSH_CONNECTION marker stays limited to Orca-launched Codex.

Refs #33937
2026-10-26 20:20:12 -07:00
Kelvin Amoaba 88ffc5c5d1 fix(mobile): use desktop's check rules and fix-checks prompt in the PR panel (#34014)
* fix(mobile): prepare Create PR and the commit action like desktop

Create PR now fast-forwards a behind-only branch before committing, picks its push step
from desktop's shared rule, and the commit-area button reads the branch's review state.

* fix(mobile): keep Create PR commit failures intact and skip fork push-target gating

Restaging after a failed commit is best effort and checks the branch first, and reviews
with their own push target are not gated until mobile reads targeted upstream status.

* fix(mobile): enter Create PR on desktop's intent rule and leave fork push targets ungated

* refactor(mobile): share the linked-review push decision and enter Create PR on desktop's intent rule

Desktop and mobile compose the review push target through one shared function, the
Create button admits branches Create PR can prepare, and older hosts without a lookup
outcome still fail closed on mobile.

* fix(mobile): use desktop's check order, labels and fix-checks prompt in the PR panel

Check, step, reviewer and comment rules move to src/shared; the phone's fix-checks agent
now gets failing log tails, the worktree path and the action's saved agent arguments.

* test(shared): pass only the fields comment mutability reads

* refactor(mobile): gate fix-checks on desktop's broken-check set and drop the prompt re-export

Fix and Rerun show for the same checks the prompt and the host use, desktop imports
the fix-checks prompt from src/shared directly, and job steps split through the shared summary.
2026-10-27 03:20:02 +00:00
Kelvin Amoaba 75743353de fix(mobile): prepare Create PR and the commit button with desktop's rules (#34011)
* fix(mobile): prepare Create PR and the commit action like desktop

Create PR now fast-forwards a behind-only branch before committing, picks its push step
from desktop's shared rule, and the commit-area button reads the branch's review state.

* fix(mobile): keep Create PR commit failures intact and skip fork push-target gating

Restaging after a failed commit is best effort and checks the branch first, and reviews
with their own push target are not gated until mobile reads targeted upstream status.

* fix(mobile): enter Create PR on desktop's intent rule and leave fork push targets ungated

* refactor(mobile): share the linked-review push decision and enter Create PR on desktop's intent rule

Desktop and mobile compose the review push target through one shared function, the
Create button admits branches Create PR can prepare, and older hosts without a lookup
outcome still fail closed on mobile.
2026-10-27 03:19:49 +00:00
NeilandClaude 284411d893 fix(wsl-host): uninstall and startup release WSL holders; a partial Remove keeps the host pending (#33843)
* fix(wsl-host): uninstall and startup release the WSL distro holders Orca left running

The detached wsl.exe holder outlives the app, so an uninstall left its distro,
orcad and shells running. The uninstaller now runs Orca with
--orca-uninstall-release-wsl-holders after killing the app and its daemon; it
ends only the holders this profile recorded, each verified by pid, start time
and command line, and keeps any it cannot verify.

At startup the WSL host service now releases holders whose distro is no longer
a host (a failed add or remove), and every holder while WSL hosts are off; a
closed gate releases them too.

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

* fix(wsl-host): a Remove that can't prove the server stopped keeps the host, pending

A partial Remove dropped the host anyway, leaving a server whose live
terminals block the next add's activation. Remove now drops the host only on a
proven stop; otherwise it records a pending stop on the WSL record, keeps the
host listed and says why (live or unverifiable). Remove again retries without
ever booting a stopped distro (it says to start it); Connect or Add on the same
distro keeps the host; a distro that is no longer registered finishes. Nothing
reconnects a pending host on its own.

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

* fix(wsl-host): E11 review — keep holders when records are unreadable; finish removals a stopped or renamed distro proves

- Startup keeps every holder when the WSL host records can't all be read
  (unverifiable), and no longer re-adopts a pending host's holder.
- Remove matches a renamed distro by GUID (isWslDistroRegistered), and a
  stopped distro finishes a pending Remove: the cold probe proves the stop.
- Only the user's Connect or Add withdraws a pending Remove; other connects
  are refused, and re-adding respects startIfStopped.
- Settings' Remove carries the kept result, so it warns instead of 'Removed'.
- A holder record without a start time is never killed on its command line
  alone, except the one this process just spawned.

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

* fix(wsl-host): E11 review 2 — a closed gate keeps live hosts' holders; stop a renamed distro by its current name

- With the gate closed, a launch releases only orphan holders (no host record,
  or a pending Remove), under the same keep rule as startup; a user with no
  holder records costs one folder check, nothing else.
- The keep rule re-reads host records per holder and keeps an Add in flight.
- Remove resolves the distro's current name from its GUID and stops it there.
- The uninstall command arms its exit timer first and exits 1 if setup throws;
  NSIS launches it only when a userData holder folder exists.

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

* fix(wsl-host): never boot a host whose Remove is pending at the next launch

Early wake built its host list from every record, so a host focused when its
Remove ended pending was booted at each launch, undoing the stop's proof. It
now skips pending records, and Remove forgets the host's early wake whatever
the outcome.

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

* fix(wsl-host): no wake for a pending host; the e2e fake stops an unbridged server like the real one

- mayWake skips a host whose Remove is pending, so a due automation can't
  boot it (focus already couldn't).
- The e2e fake connector read a host with no bridge as stopped. Since E9 a
  re-enable connects nothing, so Remove after off/on left the host's shells
  running. Like the real connector, it now reconnects the always-running fake
  distro to stop its server.
- Status bookkeeping moves to WslHostStatusBoard, and the pending-host connect
  rule to admitConnectToPendingHost, to keep the service under max-lines.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 20:17:53 -07:00
NeilandClaude ea1cb2f18f fix(terminal): a WSL bridge pane that lost its distro keeps its session across a relaunch (#34200)
#34095 turns a bridge pane's exit into host loss (code -1) when its distro is
gone, so the window keeps the tab and the history stays unended. But main's
exit handling still retired the pane's surface from the saved workspace
session, as for any provider-observed exit, so the next launch found no
session id for the tab and started a fresh shell instead of cold-restoring.

The adapter now labels that exit hostLost, the pty listener forwards it, and
the runtime keeps the surface, as it already does for a sleep or an SSH loss.

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 20:15:42 -07:00
Neil f4103b8d3e test(accounts): cover the workspace-folder fallback for account-restart resume cwd (#34203) 2026-10-26 20:14:37 -07:00
Brennan Benson e79235371f fix: restore main typecheck after concurrent merges (#34202) 2026-10-27 02:55:37 +00:00
Brennan Benson 01db1c6326 feat(orchestration): let users choose the worker heartbeat interval (#34071)
* feat(orchestration): add a Settings switch to turn worker heartbeats off

Dispatched workers are told to send a heartbeat every 5 minutes. A new
"Worker heartbeats" switch under Settings > Agent Orchestration (on by
default) lets users turn that off: newly dispatched workers are no longer
told to send heartbeats, and the stale-heartbeat check is skipped.

The interval the brief states and the stale check both derive from one
resolver over the live setting, read from the runtime's own store like
the other orchestration settings.

* feat(orchestration): let users choose the worker heartbeat interval

While worker heartbeats are on, Settings > Agent Orchestration now shows
a "Heartbeat interval" field (1-60 minutes, default 5). Newly dispatched
workers are told to check in at that interval, and the stale-heartbeat
check uses twice it. The description explains the tradeoff: shorter
gives more frequent check-ins and more messages, longer gives fewer
messages and longer gaps.

Out-of-range or malformed values fall back to 5, both when saved and
when read. Both heartbeat settings now live in a settings group owned by
the heartbeat module, composed into GlobalSettings like other feature
groups.

* Test heartbeat preferences across settings and worker dispatch

* Keep focused heartbeat preference contracts

* test(orchestration): cover saved heartbeat intervals and runtime consumers

* Explain partial runtime fixture assertion

* Correct CLI integration fixture contracts

* fix(settings): indent the heartbeat interval under Worker heartbeats
2026-10-26 19:36:48 -07:00
Brennan Benson 07b5c083bd AI fix actions use the + menu's agent picker and remember chat or terminal (#31310)
* Source control actions start chats and terminals on their saved model

A "start an agent" action's model lived only in free-text CLI arguments, which a native chat
never reads, so AI Fix opened a chat on the default model. Each action now saves a structured
model and effort that both routes apply: chat create options, or the agent's own flags in a
terminal (winning over the same flag in CLI arguments). Desktop, dialog, fix-checks and mobile
launches carry it; Settings rows get Model/Effort selects and the CLI arguments field says it is
terminal-only.

Tracked in STA-11102.

* Name the model in the repository override note

* Type the dialog's model hand-off; keep Agent in English in Japanese copy

* fix: preserve action chat model choices through launch

* Preserve action selection ownership across chat launches

* Keep terminal host contract fixtures aligned with preflight

* fix: wait for action Settings agent inventory

* fix: consolidate direct agent routing imports

* fix: use standard action option labels

* fix: align action launch contracts with shared types

* fix: sync action option localization metadata

* test: provide action Settings inventory in mounted fixtures

* Keep action options row height stable while loading

* Let each Source Control action choose its chat permission mode

An action's saved chat choice may now carry a permission mode, with or without a model;
"Same as new chats" saves nothing. A model is replaced only when the action names one,
so a permission-only choice keeps the chat's remembered model and options.

* fix(native-chat): leave older hosts their own permission mode and keep action options readable

- An action's saved permission mode is sent only to hosts that advertise
  agentSession.create.options-mode.v1. Older hosts get no mode, in create
  options or a later setOption, so the chat starts on that host's new-chat
  default, as a phone launch to such a host already does. Hosts from
  1.4.225 to 1.4.227 refused a mode their tables lacked (OpenCode, Grok,
  OMP), leaving the action unable to start.
- Settings action rows give Model and Permissions full rows in the options
  column so saved values are readable; the loading placeholder reserves the
  same rows.
- Remove two unused locale keys; fix two stale comments.
- Tests: the older-host create carries no permission mode; a permission
  mode picked alone keeps the remembered model on an acquired create.

* fix(settings): reserve one options row while loading an action with nothing saved

Terminal and permissions-only rows no longer shrink when loading ends; a chat
agent with a model list may grow by its Model row once known.

* fix(native-chat): keep the create options mode a checked literal type

* fix(settings): share verified action option fields

* fix(settings): keep action selectors on standard typography

* feat(agents): Create worktree and continuation pickers offer chat or CLI per agent, like the "+" menu

The Create worktree, Create folder and session-continuation agent pickers now
list the same rows as the tab bar "+" menu: chat agents first, each with a
terminal button that picks the agent's CLI instead, then the agents that only
run in a terminal, labelled "(CLI)". A terminal pick shows as "Claude (CLI)"
and starts the agent in a terminal even when chats are the default.
A continuation into a subfolder shows chat as unavailable there.

* fix(agents): picker rows keep the combobox item spacing instead of restyling CommandItem

* chore: drop accidental lockfile churn

* fix(agents): type the surface picker's props and the composer's agent rows

* fix(agents): submit the picker selection captured by each form

* test(agents): include repository identity in continuation fixture

* Keep the launch files under their length limits after the main merge

The structured route imports its result types where they are defined, and the two older-host
action-launch tests share one setup helper.

* feat(source-control): Source Control AI actions pick chat or CLI with the unified agent picker, and saved actions remember it

The shared Source Control AI action dialog (commit/push failure fix, checks
fix, resolve conflicts, resolve comments, PR-page fix checks) now lists the
same rows as the tab-bar "+" menu: chat rows with a hover terminal button,
and "(CLI)" rows. The pick carries chat-or-terminal into the launch.

- One inventory: the dialog's own detection is gone; agent list, default
  selection, status copy, Start gating and auto-start all read the same
  host observation the "+" menu reads (the worktree's host, or the repo's
  host for the PR page's not-yet-created workspace).
- The captured launch choice threads through runSourceControlAgentActionStart
  into launchAgentInNewTab, and on the PR page through the fix dialog into
  both launchWorkItemDirect planning sites.
- Saved recipes gain optional `surface: 'chat' | 'terminal'`, bound to the
  recipe agent like launchPreferences: normalized, inherited, copied on
  Customize, dropped on agent change, compared for receipts and matches.
  A pick saves a surface only where the agent had a chat row.
- Default paths (split-button primary, fix checks with and without a
  workspace, saved auto-start) request a terminal only for a saved
  terminal; a saved chat follows the settings route so it can still fall
  back to a terminal.
- Settings rows are unchanged here; the dialog layout keeps following the
  settings route.

* Import Source Control action ids and the agent setter once in the recipe test

* One action settings section for chat and terminal launches

A Source Control action's Model, model options and Permissions now apply whether it opens a
chat or a terminal; terminals receive them as the agent's own flags, and a repository's own
CLI arguments keep the flags it sets. Extra CLI arguments stay terminal-only.

* Make saved source control starts explicit and preserve recipe intent

* fix(source-control-ai): one terminal projection for saved action choices

Ask in a terminal now states its permission instead of leaving it to the
user's own config: Claude and Grok pass --permission-mode default, Codex
passes -a on-request -s read-only -c approvals_reviewer="user" (the
interactive CLI has no untrusted policy, so a read-only sandbox is what
asks before edits). Agents whose CLI has no flag for a mode show the
existing "Applies to chats only" hint.

The strict launch-preferences projection now requires the launch agent at
every caller, composes model ids through the resolver's own step, carries
a mode only where the agent's terminal has a flag for it, and the local
string wire keeps booleans as 'true'/'false', so Cursor Thinking/Fast reach
the terminal and an OpenCode permission-only choice is not refused.

The argument parser knows flag arity, so removing a boolean permission
flag keeps other options' values, following positionals and '--'.
Pre-admission and executor share one terminal admission check on the
options the terminal will receive. Customize with Save launches the recipe
as it will resolve once saved; legacy partial repository overrides are
edited as the complete recipe they resolve to. Empty Extra CLI arguments
start collapsed.

* fix(source-control-ai): an edited repository action saves complete

Every Settings edit of a repository action (agent, model, permission,
prompt or arguments) now starts from the complete recipe the action
resolves to, whether its stored override is owned or a legacy partial.
The resolved agent selection is kept (never an agent only detected to run
a default), an explicit null args clear stays null, and empty args stay
empty instead of being dropped. Clearing the last preference therefore
means the action agent's own defaults rather than re-inheriting Global.

The action text draft is lossless: unset or cleared prompt and args stay
so until the user types, and the inputs show them as empty, so saving a
prompt no longer writes empty args that suppress the agent's default
flags. Untouched sibling actions are not rewritten by the edit.

* Keep source control correction and completion independent of launch eligibility

* fix(settings): style the Extra CLI arguments toggle through Button's own variant and size

CI's changed-code quality check refuses restyle classes on Button and
CollapsibleContent. Use the ghost variant at size xs with a margin, and
put the content spacing on a plain inner wrapper.

* Verify saved action launches and lossless repository reloads

* Update review refresh consumer after React commit

* Preserve independent source control actions and phone option precedence

* Repair launch contract test fixtures

* Save source control action choices before starting the agent

* Report source control recipe write failures without holding agent launch

* fix: keep saved action and restart launch recipes consistent

* Report pull request action save failures and correct recipe boundary types

* fix: describe inherited arguments and chat-only permissions accurately

* test: check repository action settings fixture type

* test: map saved action options into terminal compiler inputs

* Strip Unicode format characters from check log excerpts

* test: remove redundant source control action runner cases

* fix: retain saved action controls during agent detection

* fix(i18n): retire obsolete Portuguese action labels

* test: align folder launch fallback mock with outcome export

* test: complete source control recovery controller fixture

* Keep action argument visibility aligned with selected launch route

* fix: carry resolved connector launch intent and mode together

* fix: share host agent preferences across source control actions

* fix: keep preference refresh tied to observation inputs

* Fix optional agent preference contracts and typed fixtures

* Require preference keys while preserving undefined values

* test: pin shared action launch branches to recorded agent output

* test: preserve saved source control choices through detection and migration

* test: align launch fixtures with integrated result contract

* test: retain recipe and restart contracts after main integration

* Unify Source Control action permission settings

* Keep native Ask copy with its owning change

* Preserve action drafts and old-host permission intent

* Consume rejected Source Control action saves

* Follow the moved Settings persistence fixture

* Keep permission integration contracts in the cross-version test project

* Include the action permission inheritance label in English catalogs

* Align launch contracts with shared permission recipes

* Preserve settings snapshot for Source Control recovery

* Align saved action persistence fixture with shared agent picker

* Keep Source Control action controls within their Settings columns

* Use primitive variants for compact action settings controls

* Avoid returning from the launch test store setter

* Show action arguments only for terminal defaults and widen recipe rows

* Apply terminal-only action arguments visibility to repository overrides

* Align action permission control with model controls

* Use shared settings label for action permissions

* Hide action model controls until argument migration ships

* Show action arguments for explicit CLI picks

* Preserve Unicode joiners in check log excerpts
2026-10-26 19:16:53 -07:00
Kelvin Amoaba 89e272abc5 fix(mobile): use desktop's merge gating and PR link rules in the PR panel (#33982)
* fix(mobile): gate PR merge and linking on desktop's shared rules

Merge state moves to src/shared so the phone stops offering Merge on drafts,
conflicts and blocked PRs, and stops letting branch PRs override explicit links.

* fix(mobile): keep stack merges and stale-link recovery in the PR panel

Mobile now applies desktop's stack override and drops a linked PR the branch has moved
past, and only offers Ready for review when a relaying desktop also forwards it.

* fix(mobile): persist stale PR link clears and add a merge recheck

The phone now writes desktop's link clear instead of rereading the stale link, and a
blocked Merge can be rechecked since nothing on mobile polls PR state.

* fix(mobile): guard stale PR link clears like desktop

Re-reads the worktree before clearing so a link chosen after the lookup survives, and
localizes the merge-state strings the lift exposed to the coverage gate.

* test(mobile): drop identity test for worktree link params

* refactor(mobile): share one stack-merge decision and trim PR panel wiring

* fix(mobile): default worktree bare/archived flags for the stale-link guard

* fix(mobile): label the PR merge button from its default merge method
2026-10-27 02:12:00 +00:00
Kelvin Amoaba 9c0d30df5e fix(native-chat): keep the model an agent actually runs, not its startup report (#32006)
* fix(native-chat): save only the model a chat's turn ran, never a startup report

OpenCode's session/new names a model before its catalog loads; that report
became the chat's saved model and later sends switched to it.

* refactor(acp): move option proof with the agent's own late report

* test(pi): expect ranOptions on model-only sends

* fix(acp): follow the agent's model after an effort-only pick

An effort pick stopped the native model from tracking the agent's later
report, so a send with no model wrote the stale startup model back.

* test(acp): assert the agent's late model report arrives

* fix(pi): read run evidence at the prompt write

* refactor(acp): move the option write lifecycle into its own module

Keeps acp-structured-options.ts under the 300-line cap after the agent's late report is adopted.
2026-10-27 02:11:18 +00:00
Brennan Benson 29a5f89b8a Keep same-machine folders with matching Git remotes in separate projects (#32272)
* WIP: same-host same-remote checkouts keep their own project id

* WIP: claim the shared project id per checkout surface; drop the display-only clone split

* WIP: index derived ids by repo in the hydration normalizer

* Resolve workspace project affiliation from current checkout owners

* fix: preserve concrete project ownership across catalogs and operations

* fix: combine recent project selector imports

* fix: enforce canonical catalog reads and preserve search continuity

* fix: scope catalog lint exceptions to renderer files

* Resolve project search ownership before native candidate limits

* Combine duplicate session scope imports

* fix: derive returned history row ownership on the host

* Reconcile full session history replies by content

* Require authoritative project catalogs for terminal snapshots

* Preserve registered project claims and partial history results

* test: check orphaned setup cleanup state without assertions

* fix: align catalog callers and native search fixture contracts

* test: check full repo shapes in runtime routing fixtures

* Fix checked catalog inputs in compiler regression fixtures

* Keep checked PTY fixture repos mutable

* test: align catalog fixtures with canonical readers

* test: check catalog and runtime fixture inputs

* test: check catalog fixtures without outer assertions

* test: follow persistence harness relocation

* Adapt catalog test inputs to integrated main checks

* Test History hashing across cached depth revalidation

* test(settings): expect host-qualified setup removal

* test: capture host split listings and scope relay recovery

* ci: regenerate merge ref

* test: type host-split listing diagnostics
2026-10-26 19:07:06 -07:00
Neil cf381255c4 perf(wsl): return orcad's startup compile memory with a malloc mmap threshold (#34187)
V8 frees ~70 MB after compiling orcad's bundle, but glibc keeps it stranded
in the main arena. WSL launches of this build's own slot now set
GLIBC_TUNABLES=glibc.malloc.mmap_threshold=16384; orcad and its daemon
remove it at startup and orcad hands it only to the daemon, so shells,
agents and git keep the user's malloc. Older slots never get it.
2026-10-26 19:01:52 -07:00
NeilandClaude 584b11288d fix(agent-hooks): the WSL hook relay stays down while its distro is stopped (E9) (#34195)
* fix(agent-hooks): the WSL hook relay stays down while its distro is stopped (E9)

verify-15b: after `wsl --terminate`, the relay link died ("mux disposed
(connection_lost); scheduling restart") and about 10 s later a `wsl.exe … launch.sh`
restart booted the stopped distro. The restart already asked whether the distro
runs, but any running-list answer would do, including one from a read that started
before the link died. Now:
- only a confirmed running-list read started after the link died can allow the
  restart (the shared startedAfter rule; a failed read counts as stopped);
- while the distro is stopped the relay stays down, and it comes back on its own once
  something else confirms the distro runs again (deferUntilWslDistroRunning), or when
  a WSL terminal re-ensures it as before. Nothing in recovery boots a distro.

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

* fix(agent-hooks): keep the Codex home and pi/omp setups across a deferred relay restart

A stopped verdict dropped the relay state before the deferred restart ran, so the
relay came back without the managed Codex home or the pi/omp launch setups.
Capture them first and pass them through. Also re-probe once after 30 s so a
failed running-list read while the distro is up does not leave the relay down.

* fix(agent-hooks): anchor the relay restart check at check time and keep all relay config

The running-list read must start when the restart check runs, not when the link
died: a read begun right after a terminate can still list the distro. A deferred
restart now seeds every relay config field (Codex home, Claude agent view and
config dirs, OpenCode overlays, pi/omp setups) so ensure brings them back.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 18:55:30 -07:00
Brennan Benson 7f846fd4f9 Codex restarts keep the configured command before a session is recorded (#33629)
* fix(codex): honor configured command on unrecorded restarts

* test: update account restart startup consumers
2026-10-26 18:45:52 -07:00
Brennan Benson 028f609b5a Keep chat thinking before its answer across history loads (#33628)
* fix(chat): preserve transcript source order across history windows

* test(chat): use template literal for mobile transcript fixture

* test(chat): place composed transcript contracts across project boundaries

* test(chat): move reader-to-phone contract across project boundaries

* test(chat): reuse transcript input setup and caller contracts

* test(chat): align mobile recordings with source-order capability

* test(chat): scope phone transforms and await history snapshot
2026-10-26 18:45:21 -07:00
NeilandClaude 5ad2d09ee4 fix(terminal): a slept pane wakes in its own folder, with its prompt on a fresh row (#34172)
* fix(terminal): a slept native pane wakes in its own folder, with its prompt on a fresh row

On a WSL host (orcad on Linux, bash, no OSC 7) Sleep then Wake reopened the
pane in the project root with the new prompt joined to the restored one:
- Sleep recorded the shell's folder only for WSL bridge panes. A native
  shell's checkpoint kept its spawn folder, so Wake started there. Sleep now
  reads the live shell's cwd (OSC 7, else its process cwd) for the final
  checkpoint.
- The runtime's copy of a cold-restored pane, which a paired host's desktop
  (and a phone) paints, was seeded without the fresh-shell viewport the window
  adds, so the new prompt landed on the last restored row.

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

* fix(terminal): skip the process cwd lookup at Sleep on Windows

The lookup falls back to lsof, which Windows lacks, so every native pane
Sleep would spawn a missing binary. Windows keeps the OSC 7 cwd only.

* fix(terminal): bound the Sleep folder read and drop deleted folders

The live cwd read now gets min(1.5s, 25% of the remaining Sleep deadline),
the same share as the WSL read, so a busy daemon can't eat the final
checkpoint's window. A /proc cwd ending in ' (deleted)' maps to null.

* test(terminal): pin the Sleep folder read budget without the wall clock

* test(restore): read cold-restored history from scrollback above the fresh viewport

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-26 18:44:59 -07:00
Brennan Benson 6e3c10c835 Honor browser preferences and modifiers for HTML preview links (#33622)
* fix(browser): honor preview link destinations and modifiers

* Clarify the source browser provider contract

* test(browser): check preview guest before reporting modifiers

* fix(browser): report system link failures and cover preview routes

* test(browser): combine HTTP link destination imports

* refactor(browser): require source ownership for preview links

* test(browser): type the forbidden Active Server getter

* fix(i18n): retain required preview error catalog entry
2026-10-26 18:43:50 -07:00