An SSH workspace's browser reaches sites from the SSH host: the host's sshd
dials each destination over a direct-tcpip channel. sshd ignores the
host's HTTPS_PROXY/HTTP_PROXY/ALL_PROXY, so on a host whose only way out is
an HTTP proxy (a Docker sandbox, for example), every external site failed
with ERR_SOCKS_CONNECTION_FAILED while localhost pages loaded.
The SSH route now reads the proxy variables an exec session on the host
gets (the environment orcad runs with) when it opens, and picks the
upstream for each destination the same way a paired server's own tunnel
does: environment proxy with its NO_PROXY list, never for loopback. An
HTTP(S) proxy is reached over the SSH channel and asked to CONNECT; a
no-auth SOCKS5 proxy gets a SOCKS handshake. This works for both the ssh2
and system OpenSSH transports. The CONNECT and SOCKS clients now run over
any transport, so the server tunnel and the SSH route share them.
Fixes#35217
The host's files.readDocPreview sends a preview file in one RPC reply, capped at 512 KiB for text, so Open in Orca Browser failed for larger HTML on managed runtimes. Add files.readDocPreviewChunk, which runs the same grant authorization and size caps per range, and page through it after a file_too_large reply. Hosts without the method keep today's 413.
* feat(agent-session-journal): save each chat's open root turn beside its epoch
A restart could only tell whether a chat was cut mid-turn by replaying its
whole journal. journal_sessions now keeps the open root turn
(open_turn_id, open_turn_since), set by the row that opens a turn and
cleared only by a finish the provider reported, in that row's own
transaction. A turn a quit, crash or Stop cut short stays open, which is
what the next launch reads as Interrupted.
Journal schema version 5 adds the two nullable columns with a forward
migration; a new epoch starts with no turn open.
* fix(native-chat): restore chat tabs at startup without replaying any history
Startup opened every chat in the saved tab index and replayed its whole
journal into the main process to learn its status. With hundreds of tabs
and gigabytes of history, Orca froze in GC on every launch.
Startup now lists each restored chat from its record and publishes its
row as Interrupted (a turn was open when its host stopped, or the last
quit's resume offer lists it) or Done, through the status stream and the
agent-status sink, reading only each chat's journal_sessions row and its
newest row's time. A chat's history is read when something opens it; that
open settles what the gone generation left running and publishes the
journal's own row over the restored one.
No other startup path replays chats: restart offers list from their
markers without opening chats, and orchestration mail opens the chats it
must read one at a time. Opened chats are capped at 24 resident folds;
opening one past the cap closes the least recently active folds that are
only a cache, with the idle sweep's own close test.
* Fix lazy chat restoration and cache ownership
* Restore saved chat work across runtime restarts
* Wait for committed structural progress in migration fixture
* Correct restored ownership and bounded journal recovery
* Preserve bounded work selection during legacy recovery
* Complete deferred restart status publication
* Fix restart recovery test fixtures
* Use legal legacy recovery fixtures
* Correct population delete observation
* Bound legacy journal replay in a readonly worker
* Repair legacy worker proof oracles
* Reduce legacy scratch key serialization cost
* Decode population meter namespaces with scratch UTF-16 encoding
* Consolidate structured session imports for CI
* Remove redundant casts and document checked type exceptions
* Correct compiler contracts and retain journal fixture invariants
* Fix checked test fixture contracts after compiler validation
* Name population fixture identity type in exported signature
* Preserve historical quit presentation after rewind
* Fix structured session retry and remote worker delivery
* Preserve settlement and restored status contracts
* Enable legacy chat readiness on standalone hosts
* Repair structured session static checks
* Verify retained submission identity across rewinds
* Show saved chat status without replaying history at startup
* Keep chats closed when startup status finishes loading
* Keep startup owner recovery independent of history loading
* Preserve intentional quit verdicts in saved chat status
* Use a checked host fixture in startup restoration tests
* Group saved startup roster publication and verify scoped status work
* Use checked array access in status cut counters
* Complete checked saved status fixture typing
* Declare portable roster counter contract
* Use current saved chat startup APIs in contracts
* Preserve complete chat tab authority across startup
* Repair checked startup restoration test consumers
* Keep authority fixture module mocks in test entries
* Consolidate authority test fixture imports
* Check restore fixture contracts and recorded queue recovery
---------
Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* perf(terminal): read the macOS process table in process instead of forking setuid ps (#31783)
/bin/ps is setuid root, so every exec costs an uncached syspolicyd
assessment and an EDR inspection. The terminal host forked ~7-10 ps/lsof
per second with 4 agent panes, and each stale daemon multiplied that.
node-pty's patched pty.node now exports processTable (sysctl
KERN_PROC_ALL/KERN_PROCARGS2 on a worker thread), processCwd
(PROC_PIDVNODEPATHINFO) and processPath (proc_pidpath). runPsInProcess
renders the same ps column text for the invocations Orca issues, so the
existing parsers and callers are unchanged; anything it cannot reproduce,
non-macOS hosts, and builds without the exports keep running ps/lsof.
Measured with 4 anchored panes polled every 750 ms for 60 s: ~440
ps/lsof children before, 0 after.
* fix(daemon): roll the in-process macOS process table into a fresh v54 daemon (#31783)
* fix(terminal): bound, escape and complete the in-process macOS process table like ps (#31783)
Review follow-ups for the libproc reader:
- Timeouts: every caller passes its ps timeout; a read stalled behind a
saturated libuv pool resolves timed out (code null, timedOut) at that
budget, exactly as the killed ps would. Identical native reads share one
worker, each caller racing its own deadline; past 8 distinct reads in
flight callers run ps. execFile-shaped callers reject like a failed child.
- tty naming shares one slot with captureDarwinProcessTable's guard, so a
draining naming pass sends both paths to ps instead of naming again.
- Commands: the addon renders argv with adv_cmds' getproclline and strnvis
(VIS_TAB|VIS_NL|VIS_NOSLASH) under the caller's LC_CTYPE via a
thread-scoped uselocale, so newlines print as \012 instead of splitting
tokens; zombies print <defunct>.
- Other users' processes: unreadable argv is marked commandIncomplete. Only
-p selections and processes on a terminal under the user's own readable
process there (sudo in a pane) get a targeted `ps -p ... -o pid=,command=`,
cached by (locale, pid, start time); root daemons and a pane's root login
never spawn ps.
- -t selects with KERN_PROC_TTY after ps's addelem_tty path resolution, so
per-terminal reads skip argv for every other process (~0.3 ms vs 4 ms ps).
- -p deduplicates; rows sort by terminal then pid as pscomp(); stat adds
ps's < N X V L modifiers. The export is renamed readProcessTable so an
older pty.node falls back to ps rather than misreading the new query.
* test(terminal): diff the real libproc addon against /bin/ps on macOS (#31783)
Spawns a pty holder whose argv carries a newline, tab, invalid UTF-8 and é,
then compares Orca's ps invocations column by column: pid/ppid/pgid/tpgid/
lstart/tdev/tty exactly, commands for the user's own processes, and stat
modulo running/idle (thread state needs setuid ps). Rows are compared only
when two in-process reads around the ps run agree, so churn cannot flake it.
* fix(terminal): never serve a native process table read begun before the request (#31783)
A timed-out read stayed shareable, so a later descendant capture could join
an earlier poll's abandoned worker and take its rows as fresh; a descendant
that exited meanwhile could have its reused pid SIGTERMed. The addon now
reports when its worker actually began reading (startedAtMs), and
runPsInProcess refuses a shared read that began before its own request and
reads again, so every consumer that signals from rows (descendant
teardown, foreground-group signalling, identity probes) only sees rows
scanned after its stamp. Regression: pty-descendant-termination-libproc.
Also from review:
- argv recovered with setuid ps is keyed by pid, start time to the
microsecond, comm and executable path (exec changes the latter two) with
a 10 min TTL and 512-entry bound.
- Recovery covers a sudo use_pty tree: the unreadable chain must start on
the terminal of the user's own readable process, so the root shell and
agent on sudo's own pty qualify while root daemons, GUI helpers and a
pane's root login (own pty, under a terminal-less or tty-inheriting host)
do not.
- Concurrent tty= readers wait out the single naming pass, and readers past
the 8-read cap queue behind one, within their deadlines, instead of
bursting /bin/ps at startup restore (24 panes polled at once: 0 ps).
- darwin-terminal-naming-slot.ts is now darwin-terminal-naming-single-flight.ts.
* test(terminal): require /bin/ps row order in the libproc parity test (#31783)
Parsers that take the first matching row depend on ps's terminal-then-pid
order, so compare the order of the rows both captures share, not just their
contents.
* test(terminal): pin libproc read start times instead of reading the wall clock (#31783)
* fix(terminal): match native process table reads to requests by sequence, not wall clock (#31783)
Freshness compared the worker's gettimeofday with Date.now(), so a clock
step back let an abandoned read's rows through (wrong-pid SIGTERM) and a
step forward could reject fresh reads until the deadline. Each read now
takes a JS-side sequence number when created and is submitted a microtask
later; a caller joins only a read not yet submitted or created after it
registered, so callers in one turn share a worker and nothing submitted
before a request serves it. The addon drops startedAtMs again. Deadlines,
timeouts and the argv cache use performance.now().
Callers past the 8-read cap wait on one slot notifier and each joined read
has one settle notifier; both unsubscribe on timeout, so a stalled pool
retains no per-caller reactions. If the pool is still at the cap when an
overflow caller's deadline passes, the reader is marked stalled for 30s
and callers run ps, as before this branch.
Recovered argv is trusted for 30s: exec can keep pid, start time, comm and
executable (node -> node with another script) and no cheap field shows it,
so a sudo pane costs one targeted ps per process per 30s.
* fix(terminal): keep ps fallbacks off a stuck terminal naming pass (#31783)
- captureDarwinProcessTable's canonical fallback, taken while the naming
slot is busy, now runs /bin/ps directly instead of re-entering the
in-process reader and waiting on that same slot (a held lstat timed out
every strict capture without one subprocess fallback).
- In-process tty= readers wait out a short pass (startup restore) but hand
a pass older than 500ms to ps, which names terminals out of process.
- The naming single flight keeps one settle notifier per pass; waiters sit
in a Set and drop off on timeout, so timed-out callers leave no reactions
on a stuck pass (was one per call). The notifier moves to
deadline-settle-notifier.ts, shared with the native read scheduler.
- Once the native read breaker has tripped, a caller finding the cap still
held after the cool-down returns to ps at once instead of waiting out its
timeout.
- Descendant teardown and foreground-group signalling give the native read
half their budget and fall back to a fresh ps on a native timeout, so a
partly stalled pool cannot cost a kill.
* fix(terminal): give signalling ps fallbacks their full baseline timeout (#31783)
Splitting the budget in half shrank ps's window behind a stalled native
read: a 750ms ps lost descendant SIGTERMs and an 80ms foreground ps lost
group SIGWINCH. Descendant teardown and foreground-group signalling now try
the native reader for min(150ms, timeout/4) (inProcessSliceMs), then give
ps the whole original timeout; readProcessTableBeforeDeadline extends the
production reader's outer deadline by that slice, so ps succeeds exactly
when it did on main. The stale-read regression test now also asserts the
fresh rows' real descendant is signalled.
* fix(terminal): carry the in-process deadline allowance through every descendant reader (#31783)
readProcessTableBeforeDeadline granted the native slice only when the
reader was readProcessTable by identity, so the daemon shutdown sweep's
sharing wrapper kept a bare 250ms deadline: a stalled native read plus a
200ms ps missed it on every retry and descendants survived shutdown.
ProcessTableReader now declares deadlineAllowanceMs; the fresh reader sets
it (0 without the addon or with a stalled pool, so Linux and ps-only hosts
keep their exact deadlines), createProcessTableSnapshotReader and the
shutdown wrapper inherit it, and injected readers default to none. The
fresh reader moves to pty-descendant-fresh-table.ts. The real-ps parity
test gets a 30s per-case timeout, since whole-table /bin/ps runs slow
under suite load.
* chore(terminal): move the descendant reader's child_process baseline entry with it (#31783)
* test(terminal): pin the libproc test locale so lstart doesn't follow the runner's LANG (#31783)
* fix(browser): keep the chosen default browser profile across restarts
The default profile pick lived only in the renderer browser slice, so every
launch rebuilt it as Default. Store it in GlobalSettings, next to the
profile scope setting, and read it through one resolver.
* test: seed default profile map without a new cast
* fix(browser): drop a saved default profile only once it is gone
Trust the saved pick when reading it and forget it on a delete or a full
listing without it, since partial catalogs and failed fetches prove
nothing. Load this desktop's profiles at startup even when Settings shows
a paired server, so local tabs resolve the saved pick's partition.
* test: drop the default-profile test that only guarded the removed mirror
* refactor(browser): share the profile delete step and simplify the startup local fetch
* fix(browser): load this desktop's profiles at startup without a focus read
* fix(browser): apply overlapping default profile writes in order
Cold restore, sleeping-agent wake and account restart on a paired Orca
server quoted the resume line for this client's own OS, so a Mac client
quoted POSIX for a Windows server and a Windows client quoted PowerShell
for a Linux one. Fresh desktop-built launches knew the server's OS but
assumed PowerShell on Windows.
One resolver, resolveHostAgentStartupShell, now decides the shell a
desktop-built command runs in: a tab's override, then the executing host's
own Windows shell (this client's setting locally, the server's reported
terminalWindowsShell remotely), then the platform default. Fresh launches
and all three resume paths use it, with the server's reported OS. A nested
SSH workspace on a server quotes for its SSH target. A host that has not
reported its OS gets POSIX quoting with OS-specific agent flags off.
* feat(native-chat): preview cards for web links in chat
Hovering an http(s) link that isn't the repo's own PR or issue shows the
page's image, favicon, site name, title and description. The chat's host
fetches the page with no cookies, refusing private, loopback and
link-local addresses after DNS and on every redirect, and returns images
as data URLs. A Chat > Behavior setting turns web previews off.
* perf(native-chat): cap link preview caches at 20 MB each
Preview images are held as data URLs, so a count limit alone let the
renderer and main caches grow to hundreds of MB in a long session.
* fix(link-preview): keep a > inside quoted attribute values
Page tags ended at the first >, so content="Home > Docs" was cut short
and an og tag whose content came before its property was dropped.
* fix(native-chat): keep link preview caches within budget and keyed by host
A preview that finished after newer ones stopped eviction at itself, so
both caches could stay over their byte limit. The GitHub card's load key
also left out the host its repo lives on.
* fix(link-preview): decode the named entities page titles use
Only five named entities were decoded, so titles like
Docs – Guide showed the raw codes in preview cards.
* feat(native-chat): hover cards for GitHub PR and issue links
Links to the chat's own repo (origin or upstream) open a card with the
state, title, author, update time, and +/- or comment count. Bare #123
references in agent replies now link too. Cards use a light one-call
lookup; older hosts ignore the flag and answer with the full lookup.
* test(github): expect the preview options argument in runtime owner/repo lookups
* fix(native-chat): route GitHub link cards by the chat's own host and retry failed repo lookups
The repo lookup took the first worktree with the chat's id, so a twin on
another host could answer, and the preview cache keyed by repo id alone.
A failed slug lookup also left cards off until the chat remounted.
Resuming a saved session in an SSH or paired workspace assumed Linux whenever
the session had no recorded host OS, and a dropped session never passed one.
On a paired Windows server that quoted the command for the wrong shell and
could add Codex's Unix-only paste-burst flag. The resume now reads the
host's own reported OS. When the host hasn't reported it, quoting stays
POSIX, as before, and OS-specific agent flags stay off.
* feat(automations): label workspaces a host creates with the desktop's own automation run
A desktop's own automation could create its workspace on a managed or paired
host, but the workspace lost its automation identity: no badge, and its run
pane closed instead of sleeping. The desktop now sends a capable host its run
as a label, naming itself (`local`) as the automation's owner. The host
records it with origin 'client', only for automations it does not hold, caps
its fields, and never lets a client-origin label grant run ownership, sleep
authority or automation create policy. Older hosts get nothing new; older
desktops still create plain workspaces. A client-origin label whose
automation can't be found reads as unavailable, not removed.
Refs #34433
* test(automations): keep the dropped-label warning test independent of test order
Refs #34433
The agent-browser bridge cast agent-browser's {messages} and {requests} output to Orca's {entries, truncated} contract and dropped --limit, so text mode crashed and --json returned the raw shape. Map the output once at the bridge, keep the newest --limit entries, and make the contract fields agent-browser never reports optional.
* fix(codex): launch Codex without its paste-burst guess outside Windows
Codex treats a fast run of keys followed by Enter as a paste and turns the
Enter into a newline. Keystrokes relayed from a remote client can reach the
host bunched together, so the prompt stayed in the composer as a draft.
Orca's terminals bracket every real paste, so the guess can only misfire
there. Orca now launches and resumes Codex with disable_paste_burst=true,
except on Windows, where Codex reads console input records and relies on
the burst for pastes.
Fixes#34496
* test: expect Codex launches to disable the paste burst off Windows
Refs #34496
* fix(codex): keep the paste-burst flag out of commands that end their options
Refs #34496
* fix(codex): decide the paste-burst flag from a paired server's own OS on resume
Resume quoting on a paired server keeps the client's platform, so a macOS
client resuming Codex on a Windows server would have disabled the burst that
Windows Codex needs. The resume target now carries the server's reported OS
and leaves the flag off when it is Windows or unreported.
Refs #34496
* fix(codex): add the paste-burst flag only when the command runs Codex itself
A wrapper override may not forward -c, which would break every launch.
Refs #34496
* fix(codex): leave the paste-burst flag off compound commands and unreported SSH hosts
Refs #34496
* test: leave pass-through resume input untouched in the banner spec
Refs #34496
* test(mobile): expect AI-vault Codex resumes to disable the paste burst
Refs #34496
* fix(mobile): resend dictation audio a dropped connection left unanswered
The host feeds chunks in seq order, each seq once, holding audio that
arrives ahead of a resend for up to the reconnect grace, and says so in
its start reply. To such a host the phone resends chunks rejected as
delivery-unknown after each reconnect, so speech sent on a dying
connection is no longer lost.
* fix(mobile): cap held dictation chunks by count as well as bytes
* fix(mobile): skip every gap needed to keep held dictation audio within the cap
Every native terminal spawn schedules a Codex hook reconcile, which resolved
the Codex path twice with a synchronous stat scan of PATH and install dirs
(~50ms main-process block per spawn on Windows with a long PATH and no Codex).
The reconcile now resolves the path once and passes it to both the live
lookup and the saved-answer read. On Windows, where each stat is slow, that
lookup runs every read (PATH candidates, nvm dirs and aliases, install dirs)
through fs/promises; macOS and Linux keep the sync scan, now run once. Sync
and async share one lookup that yields its reads, so they cannot diverge.
Hook rechecks stay immediate on every spawn and nothing is cached. A spawn
that lands before a run's hook-file pass (while it is still finding Codex or
waiting for its answer) gets one trailing rerun, so an install or upgrade
that moved Codex mid-run cannot leave hooks unchecked.
Fixes#35565
Co-authored-by: Chad Tolkien <chad@sodadigital.com.au>
* fix(wsl): keep a stopped distro's worktrees and re-list once it runs
After a relaunch with a WSL distro stopped, the E9 gate refused the
worktree scan and the sidebar showed "Worktree scan failed" with no rows
until the user pressed Retry. The listing now answers with the stored
rows (non-authoritative, so nothing is pruned), marks the distro stopped
or unverifiable in a new optional field, and re-lists once a wake or a
settled running read shows the distro running. The re-scan is held once
per repo and dropped when the repo is removed. The sidebar shows a
neutral state instead of a failure.
* fix(wsl): make the stopped-distro Retry a user act that may start the distro
The indicator's click now runs the scan inside runAsWslUserAct for the
repo's distro (new worktrees:scanStartingWslDistro IPC), then re-lists,
so clicking it can start the distro instead of re-running the gated
background scan that never could.
RPC errors for a terminal held on a stopped or unchecked WSL distro keep runtime_error but carry a readable message and the hold in data. A headless launch the runtime held records the coded wslDistroStopped skip. A worktree create someone asked for (UI, CLI, agent, paired client) starts its setup and default terminals as their act; an automation's create stays background.
The renderer maps main's terminal_held_wsl_distro_stopped start failure to #35813's shared stopped card; its Start calls layout.startWslHeldPanes, which starts each pane through ensureRestoredPaneStarted as the user's act.
* fix(automations): a scheduled run never starts a stopped WSL distro
Scheduled runs whose target is on a stopped (or unverifiable) WSL distro skip with a coded, retryable wslDistroStopped reason naming the distro, checked at the tick and again at dispatch; repeated ticks fold into one skip. Run now is the user's act and still starts it.
* fix(automations): gate host-path WSL projects by their distro; translate the skip
A host-path project whose Git runs in WSL passes its project distro to the stopped-distro check (as #35778 does). wslDistroStopped is translated into the 10 other locales.
* fix(wsl): Source Control's PR push-target and Create PR checks never start a stopped distro
Showing Source Control resolved the linked PR's push target
(worktrees:resolvePrBase) and its Create PR eligibility
(hostedReview:getCreationEligibility); both read the repo's git config over
\\wsl.localhost and ran git and gh in the distro, starting a stopped one
(E9). Both now refuse a stopped distro unless the user is creating or
launching from the PR, or pressed Create PR (optional wakeWslDistro), in
the IPC handlers and their runtime twins.
* fix(wsl): gate the GitLab MR push-target lookup the same way
Source Control's push-target ensure also resolves a linked GitLab MR
(worktrees:resolveMrBase / worktree.resolveMrBase), which read the repo and
ran glab and git in a stopped distro. It now refuses unless the user is
creating from the MR, which passes wakeWslDistro.
* test(runtime): let the mocked running gate cover guardWslUncPathAccess too
Runtime specs fake win32 with no wsl.exe and mock blockedWslDistroForPath
to running; the real guard calls its own module's check, so the PR-base,
MR-base and eligibility gates refused there. The guard mock now asks the
mocked check, keeping per-test overrides working.
When a structured worker's dispatch preamble is definitively rejected, the
dispatch_preamble_undelivered error now appends the provider's failure detail
("Details: ...") unless the rejection sentence already quotes it. The quoted
text is bounded and normalized by the same quotedProviderDetail helper the
rejection writer uses.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* fix(windows): start the WSL holder with only a NUL handle to inherit
libuv starts every Windows child with bInheritHandles=TRUE and no handle
list, so a detached holder that outlives Orca kept any inheritable handle
Orca had open, such as a launcher's pipe or a DevTools socket. Start it
through CreateProcessW with PROC_THREAD_ATTRIBUTE_HANDLE_LIST naming one NUL
handle for its stdio. The build probes now check the newest export without
calling it, and the lane receipt labels ConPTY's own startup output.
* fix(windows): report isolated holder exits and kills the way libuv does
* fix(wsl): Codex WSL hook installs and host hook checks never start a stopped distro (E9)
(a) installManagedHooksIntoWslRuntime checks the settled running gate inside
its trust queue right before the first UNC read, and again before the
post-hash fallback trust write; a later reconcile checks before revoking or
reinstalling. A stopped or unverifiable distro skips (null, as with no WSL
plan). The canonical-path probe runs through process-host behind
blockedWslDistroForExec; a refused probe settles as unavailable and keeps the
known identity. The guest shell preflight and a pane launch's home preparation
run as user acts on their distro.
(b) repo.hooksCheck takes an optional background flag (older hosts ignore it);
the renderer sends it, and the host refuses a stopped distro's background
check the same way the desktop's hooks:check does.
* fix(wsl): a pane launch is not a user act for the Codex hook install
A passive restore or remount reaches launch preparation too (#35813), so it no
longer runs as a user act; a stopped distro skips the install and the relay
installs once the distro runs. A skipped WSL home now returns not_installed
instead of falling through to the host writer, which would have written the
WSL home over UNC.
* fix(wsl): a fallback grant skipped mid-install reports trust pending
hooks.json is written before the hash wait, so a skip after it is not a clean
skip: return an error status saying the trust is pending instead of null.
* chore: drop the stale process-host direct-import baseline entry
* fix(wsl): Settings' issue-command and path checks never start a stopped distro
Opening the repository and MCP settings sections read .orca/issue-command,
orca.yaml and stat'ed the repo root over \\wsl.localhost, which starts a
stopped distro (E9). The issue-command read (IPC and runtime) now returns
the unreachable result for a stopped distro unless a launch passes
wakeWslDistro, and shell:pathExists is gated like shell:pathsExist, with the
two link-click callers passing wakeWslDistro.
* fix(wsl): never save over an issue command a stopped distro kept unread
A refused read showed an empty, editable field, and typing then saved over
the hidden local override and started the distro. The editor now stays
read-only with a stopped-distro note, skips both saves, and re-reads when
main signals the distro running. Writes are gated too unless the user is
saving their own edit (wakeWslDistro). The MCP section's stopped message no
longer offers a Retry that cannot start the distro.
* fix(wsl): translate the stopped-distro issue command note; listen before reading
Adds the note in every shipped locale, and attaches the editor's running
listener before its read so a distro that starts while the refused read is
in flight still triggers a re-read.
* fix(wsl): keep the issue-command editor and writer tests on their seams
The editor reads window.api optionally, as hosts without a preload do, and
the writer tests spy on the gated write that the handlers now call.
* fix(i18n): translate updater failure messages shown in the renderer
* fix(i18n): localize the dev-channel platform list and paired-server updater errors
* fix(i18n): sync runtime catalog and coded updater status expectations
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): localize remote server pairing, host sign-in and Bitbucket connect failures
* fix(i18n): map pairing guard codes without a partial switch
* fix(i18n): type the Bitbucket connect bridge with its coded result
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): localize Orca's agent output and Kimi failure messages in AI text generation
* fix(i18n): keep Kimi option connectives inside the translated sentence
* fix(i18n): narrow Kimi empty-input diagnosis without an undefined case
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(wsl): a passive restore never starts a stopped WSL distro; its bridge panes wait with Start
* fix(wsl): a restore may start the distro only on the user's own open, once; an unanswered read holds too
* 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
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.
* 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
* 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.
* 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 (#35431)
(cherry picked from commit 0774fc9373)
* 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
* fix(plugins): load installed plugins whose engines floor predates their fields
The engines.orca floor rule is an authoring check. At runtime (install,
discovery, update, rollback) a manifest now loads when this host parses
every field and meets engines.orca; dev folders, validate:plugin and
catalog CI stay strict. Installed copies that can't load show user-facing
copy and offer Reinstall when the catalog has a loadable release with
different bytes.
* fix(plugins): give installed copies user-facing copy for every load failure
* fix(keybindings): show the ⇧ glyph for Shift on Windows and Linux
Spelled-out Shift made non-mac shortcut labels long (Ctrl+Shift+Backspace).
* test(menu): expect the ⇧ glyph in non-mac app menu hints; align double-tap hint
* fix(windows): keep Orca's std handles out of every spawned child
libuv spawns with bInheritHandles=TRUE, so an inheritable std handle reached
long-lived children such as the WSL holder and the daemon and held a
launcher's pipe open after Orca exited. Clear HANDLE_FLAG_INHERIT on the std
handles at the top of main startup; stdio 'inherit' still works because
libuv hands the child its own inheritable duplicate.
* test(windows): model Orca's Electron main, which keeps std handles inheritable
Plain Node clears its std handles' inherit flag at startup, so a Node child
never reproduced the leak. Electron main opts out of that, which is why Orca
leaks and why the control arm now runs Electron; a plain-Node arm pins the
difference.
* test(windows): say why the std-handle tests need longer timeouts
The cached policy gains an optional movedProjects: keep | bring-back, read
only with a block. An unknown value reads as keep, so it never drops the
block, and older builds ignore the field. The gate records the choice for
the run (wslHostsBringBackMovedProjects) and telemetry reports it as
wsl_hosts_moved_projects. Nothing acts on it yet; bringing projects back
follows.
Co-authored-by: Claude <noreply@anthropic.com>