Skip to content

sync: upstream 9f62a4fa2d into swaplabs/main - #72

Merged
kiwidream merged 512 commits into
swaplabs/mainfrom
sync/upstream-20261029
Oct 29, 2026
Merged

kiwidream merged 512 commits into
swaplabs/mainfrom
sync/upstream-20261029

Conversation

@kiwidream

@kiwidream kiwidream commented Oct 29, 2026 •

Copy link
Copy Markdown
Files Added Deleted Net
Test 982 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​67458 $\color{#cf222e}{\Huge{\mathbf{−}}}$​6416 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​61042
Prod 2018 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​101466 $\color{#cf222e}{\Huge{\mathbf{−}}}$​18582 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​82884

ELI5

Upstream Orca moved forward 511 commits since yesterday's sync (#64). This PR merges them into swaplabs/main. Ten files conflicted where fork features sit in code upstream changed. Each conflict keeps the fork's behaviour on top of upstream's new code. Four more breaks that no conflict showed are fixed here too.

What Changed

Merge of upstream 9f62a4fa2d (the fork's mirror main) into swaplabs/main a1597a19ae. Upstream range 36d295628e..9f62a4fa2d, 511 commits (compare). Merge commit 48889413ac is signed with the sync key. It replaces #71 (head main, CONFLICTING).

Conflicts, by fork PR (10 paths, 15 hunks)

#6 auto-resume after a host restart

#25 drain a stale-bundle daemon

#10 / #14 / #16 update sources and the mac self-updater, against upstream stablyai#35833 (coded, translatable updater failures):

  • src/shared/update-status-types.ts: upstream's messageCode/messageParams on a failed ReleaseBuildListResult, plus the fork's ReleaseSourceInstallMode and ReleaseSourceStatus.
  • src/main/updater-release-builds.ts: imports from both sides. resolveTargetBuild keeps the fork's source/knownVersion signature. A bad tag for the primary source now throws upstream's coded invalidReleaseTag, the same English text as before. Another source keeps the fork's message naming that source.
  • src/main/updater/updater-build-selection.ts: upstream dropped DEV_CHANNEL_PLATFORM_LABEL; the fork's imports stay and upstream's coded helpers are added. The pinned-build catch sends updaterErrorMessage(error) plus the fork's presentation and release source.
  • src/main/updater/updater-check-state.ts: sendErrorStatus takes upstream's string | UpdaterCodedMessage plus the fork's releaseSource and presentation. sendSettledCheckStatus passes upstream's code and params plus the fork's fields.
  • src/main/updater/updater-download-install.ts: imports. Upstream's coded linuxPackageExternallyManaged replaces LINUX_PACKAGE_EXTERNALLY_MANAGED_MESSAGE; the fork's mac self-update imports stay.
  • src/main/updater.build-channel-selection.test.ts: the fork's vi.waitFor, since the jump reads the tag's manifest before pinning, plus upstream's objectContaining negative assertion.
  • src/renderer/src/components/settings/GeneralUpdateSettingsSection.tsx: LOCAL: offer one download per release source in Settings → Updates #14 moved this status text into SingleSourceUpdateHint and ReleaseSourceUpdateHint, so the fork's layout is kept. Upstream's change to the text (updateStatus.message → updaterMessageText(updateStatus)) follows the moved lines into both hints, including ReleaseSourceUpdateControls.tsx. Without it, Settings would show untranslated updater errors.

Breaks the conflict list did not show

  • max-lines, src/main/updater/updater-check-state.ts (312: upstream 285 + 27 fork lines). The fork's error-status fields and its pinned-source rule move to a new fork-owned src/main/updater/updater-error-status-fields.ts; the file is now 298. getPinnedReleaseSourceForStatus() becomes pinnedReleaseSourceForStatus(active, running) at its one caller, updater-check-failure.ts. Behaviour is unchanged.
  • max-lines, src/main/runtime/construction/runtime-service-state.ts (305: upstream 298 + 7 fork lines, a clean auto-merge). fix(sidebar): nest a delegated remote worker under its coordinator #4's delegatedWorktreeEdgeProjection field moves into the fork's own OrcaRuntimeWithDelegatedWorktreeEdgeSync layer, its only reader. The file is now 299. LOCAL: hold orchestration mail pointers while the user types #69's readTypedInputSerial option is its only fork line.
  • i18n, de.json: upstream feat(i18n): add German UI language stablyai/orca#34917 adds German with "Orca" for the fork's titlebar key auto.App.5096cbbc86. It now has the fork's value, as ru/tr/zh-Hant got on sync: upstream 36d295628e into swaplabs/main #64.
  • i18n, resume chooser ages: upstream refactor(i18n): native i18next plurals at call sites, plural-aware extraction stablyai/orca#35637's plural-aware extraction flags the fork's base keys components.terminalPane.AgentResumeChooser.age.{minutes,hours,days} as referenced nowhere. b2e572f added them only to satisfy the old checks, so they are removed from en.json and en-runtime-required.json, as upstream removed its own 22 shadowed base keys. The _one/_other forms and the English output are unchanged. Upstream's new CLDR rule then required _many forms for the fork's es/fr translations. Upstream's pnpm sync:localization-catalog copied them from _other and changed nothing else.

Fork lines this sync replaces: the three base keys from b2e572f (upstream's plural extraction now covers what they were for).

Why

Daily upstream sync.

Linked Issue

Follow-ups are noted on #41 (resume), #43 (update sources) and #45 (fork lines near line limits).

Visual Proof

N/A: the Settings change only translates existing error text through upstream's updaterMessageText.

Testing

Run in the merge's working tree before committing:

  • pnpm install --frozen-lockfile.
  • pnpm tc: passes. A deliberate type error made it fail, so the check is live.
  • pnpm lint with ORCA_SYNC_PR_DIFF_BASE=9f62a4fa2d (all ORCA_* host variables unset): all 38 steps pass. Before the fixes above, 3 steps failed: oxlint max-lines, verify:localization-catalogs and verify:localization-extraction.
  • pnpm run check:code-quality:changed with ORCA_SYNC_PR_DIFF_BASE=9f62a4fa2d: 0 new findings across 361 changed files.
  • verify:rpc-params-catalog, verify:localization-runtime-catalog, verify:localization-catalog, verify:localization-extraction: pass.
  • pnpm test over the touched directories and every unit test file the fork carries: 838 files, 7,840 tests passed and 5 failed. Four are the host-only bash-wrapper tests (bash-prompt-command-composition, shell-ready-bash-wrapper), which fail the same way on a pristine upstream 9f62a4fa2d checkout. The fifth was the fork's not-ready check test in updater.check-failure.test.ts. It now expects upstream's messageCode, as upstream's sibling test does, and passes 11/11.
  • The pre-commit hook's checks over the 5,266 staged files, run by hand first: oxfmt --check (no file would change), the three oxlint configs and ast-grep all pass. The hook then ran on the commit. Its re-add step reported that docs/schemas is gitignored. No file changed: git write-tree before the commit equals HEAD^{tree} after it (cb79b5cf1a), and the tree is clean.

Not run: the fork's Electron e2e specs.

AI Disclosure

Prepared by the "Orca upstream sync" automation (Claude Code, Claude Opus 5.5).

Agent skill upstream boundary

  • Not applicable: this PR merges upstream's history; it adds no agent skill.

Notes

orca-fork-ops status for swaplabs/main (a1597a19ae) against upstream 9f62a4fa2d:

Upstream release tag v1.4.244 was copied to the fork.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

Pr1p and others added 30 commits October 28, 2026 17:51
…tablyai#35315)

* fix(github): preserve concurrent changes on thread rollback

* test(github): assert reaction publication before rollback

* fix: restore thread resolution on newly posted replies

* test(github): trim thread rollback tests to behavior guards

Drop duplicate false/throw variants, the cleared-cache and paired-source
cases, and the helper case already covered by the remaining lib tests.

---------

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

* perf: cache folder workspace connection inference

* fix: preserve folder resolver fallback for partial catalogs

* test(renderer): trim folder connection cache test to one direct warm-read check

Drop the zustand store wrapper and duplicate 1,000-repo case, and use a neutral fixture path.

* test(renderer): drop folder connection read-count test

The invalidation and tri-state test guards observable behavior; the getter
read counter only pinned the cache implementation.

---------

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

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

upsertDelegatedMobileDevices returned every planned entry, including a child whose row was
removed on disk and so dropped by the merged save; the parent would pass that dead token to the
phone. It now returns only entries still in the written registry.
…ts (D1c-4a) (stablyai#33108)

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

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

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

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

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

* feat(wsl): scope and path map for converting UNC Windows-drive projects (D1c-4a)

The mover refuses a project kept as a distro's UNC path into a Windows drive
(\\wsl.localhost\<d>\mnt\c\x). D1c converts it in place to C:\x. This adds the pure
part: which local repos and folder workspaces qualify (every stored path on the drive;
not remote; not already a C:\ project here), the UNC → drive path map, and the
worktree id each converted worktree gets (same repo id, drive path). Reuses the mover's
list of a repo's stored paths. Nothing calls it yet.

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

* fix(wsl): say Windows denied access when adding a WSL path it refuses, not that it isn't a repo

* fix(wsl): name a refused WSL path only with WSL hosts on

The new message replaced "Not a valid git repository", which the renderer
matches to offer adding the folder as a non-git project. With the WSL hosts
gate closed the add fails with the usual text again.

(cherry picked from commit a5a70dad7743f679fd764c3e17a3e27b71c9f28b)

* fix(wsl): convert one UNC spelling per drive folder, and only folders the distro mounts from that Windows drive

- Two UNC spellings of one drive path (\\wsl$ vs \\wsl.localhost, \mnt\C vs \mnt\c) would
  both convert into two projects. Each accepted conversion now claims its drive path, so the
  next spelling is refused as a duplicate. Folder workspaces get the same duplicate check.
- Any /mnt/<letter> read as a Windows drive. The scope now takes the distro's Windows-drive
  mounts (drvfs/9p from its mountinfo, parsed as the WSL-host drive guard does) and converts a
  path only when its mount is that same whole drive. A folder workspace has one path, so that
  check is its mixed-location check too.

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

* fix(wsl): match the distro's drive mount point case-sensitively, so a real /mnt/C directory never converts onto C:

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…ed WSL distro (E9) (stablyai#35411)

* fix(wsl): background preflight and agent detection never boot a stopped WSL distro (E9)

Integration checks (git/gh/glab --version and auth status) and agent detection ran inside the
focused workspace's WSL distro on every mount, poll and status-bar render, and wsl.exe starts a
stopped distro. They now take a settled running read first and refuse (WSL_DISTRO_STOPPED or
WSL_DISTRO_UNVERIFIABLE) when it is not running. Window focus/visibility, retry buttons, agent
refresh buttons, a runtime choice in Settings and first-run onboarding pass wakeWslDistro, which
runs the check as a user act on that distro only. Running distros behave exactly as before.

* fix(wsl): a focus wakes only a focused WSL workspace's distro; end-to-end preflight gate test

A focus with a native workspace active sends no wake. Ports the real running-list preflight case
from stablyai#35395 and adds user-act scoping cases.

* test(wsl): model the running gate in the preflight RPC suite and cover a stopped distro

Windows CI runs the real gate, so the WSL detection case must state that the distro runs.

* fix(wsl): an agent refresh click never joins a background refresh it would be refused with

Store the wake flag with each in-flight refresh, as preflight.ts does, so a status-bar or Agents
refresh click during a mount refresh reaches main as a user act. Note why the RPC project branch
stays ungated.

* fix(wsl): a refused background check waits for the distro, and an agent picker wakes it

A preflight or agent detection refused for a stopped WSL distro was final: once the distro came
up, nothing re-ran it, so the tab-bar + menu offered no WSL agents (real-WSL golden). Now a refusal
is deferred until the distro is next confirmed running (deferUntilWslDistroRunning), and main tells
renderers to re-ask. Opening an agent-launch picker (tab-bar +, composer, continuation dialog,
source-control action dialog) whose list was refused retries it as a wake, never joining a
background probe.

* fix(wsl): an open agent picker wakes a refused list once, and never retries real failures

The picker wake fired whenever the list read 'failed', so a woken probe that failed again
(pending -> failed) re-fired it: an endless wsl.exe loop while the picker stayed open, and repeated
probes for native failures too. It now fires at most once per open per target, and only when the
last probe was an E9 refusal (distro not running/unverifiable), matched by the gate's message.

* fix(wsl): forget agent-inventory refusals when the inventory or its project contexts are cleared
…ty load failure) (stablyai#35513)

* fix(orcad): harden the startup qualification marker (execPath, node-pty load failure)

- The key includes process.execPath, so a slot re-pointed at another Node build re-qualifies.
- A node-pty load failure in orcad (degraded local PTY routing) discards the slot's marker, so
  the next launch re-probes node-pty and reports the cause; reported through a small listener so
  the shared provider stays free of orcad imports.
- Tests: a schema-1 marker never matches; a Windows slot is never qualified by a matching marker.

* fix(orcad): discard the startup marker only after an in-flight record lands

A node-pty failure right after readiness could unlink the marker before the confirm's write
renamed it into place, recreating it. The discard now waits for the last marker write first.
…tablyai#35498)

Moves ~600 strings in the root screens, settings, pairing, onboarding, accounts,
agent history, diagnostics, connection status, home and host workspace lists to the
translation API, with all ten translations.

- Connection verdicts carry an explicit `dialing` flag instead of matching the
  "…" ending of an English label
- Update-failure copy and connection-path accessibility labels are built from data,
  not by editing translated text
- Workspace status names stay the host's labels, as on desktop; transport errors
  stay English
- The stale-key check keeps a plural family while any of its forms is referenced

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…he sync reads the clock (stablyai#35516)

The mock built completed_at when the projection called it, after the
projection captured now. With 1 ms or more between the two, the
"stale" row was within the freshness window and the test failed under
load.
…ty (stablyai#35522)

The rc was released right after Enter, so on Linux CI the keys' trip to the host
sometimes outlasted the rc's 50 ms poll and they landed after the prompt. Wait for
the tty's echo of the typed line first, which appears only if the bytes reached
the PTY while the rc still waited, and restore the check that they came before
the first prompt.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…nals (stablyai#35458)

Git refuses `git worktree remove` without --force for any checkout with
submodules, even when nothing is dirty. Orca's dirty check passed such a
clean checkout, so the delete was accepted, its terminals were stopped, and
Git's refusal arrived later in the background, where the CLI and
automation never saw it.

The dirty check now applies Git's own test (submodule repositories under
the worktree's admin directory, or a gitlink checked out with its .git),
which the native Windows path already used, and refuses a clean checkout
that fails it with a message that keeps Git's wording, so every app
version still offers Force Delete with the submodule warning. The same
test now decides when a dirty refusal names submodules. Force is not
applied automatically: it would also delete submodule commits, branches
and stashes that were never pushed.

Refs stablyai#35135
…ceptance (stablyai#35459)

The host answers a worktree delete as soon as it accepts it and lets Git
delete the checkout in the background. Clients that show a "removing"
marker ask it to wait for Git, but the CLI could not, so it printed
`removed: true` before anything was deleted, and a delete Git then refused
(for example a checkout with submodules) failed only in the host's log.
Scripts saw success, and every retry repeated the same silent failure.

`worktree.rm` takes an optional `waitForBackgroundRemoval` flag, and the CLI
sets it, so the command exits with Git's real result or error. It waits as
long as the desktop and web clients do and, if it stops waiting first, says
the delete may still be running and how to check. A reply sent on
acceptance now says `removed: false` alongside `removing: true`, so callers
that still get the early answer are not told the checkout is gone. Older
hosts ignore the flag, and the CLI then says the delete is still running.

Fixes stablyai#35135
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…mpt (stablyai#35517)

The bridge fish launch's -C now also defines a fish_prompt hook that
sends the same percent-encoded OSC 7 as bash and zsh, only inside WSL,
after the user's config.fish.
Each terminal read in the restart measurement opened a fresh connection,
which on WSL spawns a new wsl.exe bridge, so first-output time counted
bridge spawns the app never pays. Hold one shared control connection per
restart, as the app does.
…ed distro; explicit opens may (E9) (stablyai#35410)

* fix(wsl): keep background git and GitHub reads from booting a stopped distro

Git history, diff and status-follower reads, GitHub issue/work-item/check
polls, chat link existence checks, the composer's create-base prefetch,
the worktree-root fan-out and the Settings/Automations orca.yaml previews
now refuse or skip a stopped WSL distro instead of starting it (E9).

* fix(wsl): explicit opens may start a stopped distro; more polls gated (E9)

Folds the parallel G1-G6 work into this branch and splits background
reads from user acts:

- An explicit open runs as a user act for its distro and may boot it:
  showing a diff tab or its Retry, showing Commits or its Refresh,
  opening the checks panel or entering its tab, checks Refresh, a check
  action, and linking or creating a PR. Main takes a wakeWslDistro flag
  on git:diff, git:branchDiff, git:commitDiff, git:history and
  gh:prChecks and runs those reads under runAsWslUserAct.
- Polls, timers, refreshes after Git actions, prefetches and fan-outs
  stay background and are refused while the distro is stopped.
- Also gated: the hosted-review card poll for every provider, the GitLab
  checks-panel poll (background flag), and the composer's open-time
  orca.yaml check (Create re-checks in the foreground).
- Pollers keep the data they already show on a refusal: the issue on a
  card, the checks list, an open diff and loaded submodule children, and
  stop logging it.

* docs(wsl): note that a hosted-review poll's stopped-distro refusal is still logged (E9)

* fix(wsl): Settings re-asks orca.yaml once a stopped distro runs; drop link-check gating (E9)

- Link existence checks (shell:pathsExist / pathExists) are no longer
  gated here: answering "missing" cached chat and terminal links as
  absent and toasted "File not found" on markdown link clicks. The
  pathsExist refusal lives in its own PR, which throws instead.
- Settings no longer sits on "checking" forever: a repo whose distro
  refused the background check is re-asked on window focus, on
  visibility, and after 10 s, until it answers. An unverifiable distro is
  now marked (wsl-distro-unverifiable) and treated as unread too, instead
  of being stored as "no orca.yaml".
- The sidebar issue poll and the Tasks list and count refuse with "Open a
  terminal in it to start it", since their Retry is itself a background
  read; the checks panel keeps "Retry", whose Refresh is a user act.

* fix(wsl): Tasks Refresh, interactive review refresh and manual PR lookups may start a stopped distro (E9)

- Tasks: a Refresh, Retry or search, or Tasks opened on a single repo,
  passes wakeWslDistro through gh:listWorkItems and gh:countWorkItems
  (IPC only; the RPC twins and web routes drop it). A multi-repo open
  stays background. Their refusal says "Retry" again; only the sidebar
  issue poll says "Open a terminal".
- hostedReview:forBranch wakes for an interactive request (the checks
  panel's manual Refresh), so GitLab, Bitbucket, Azure DevOps and Gitea
  reviews with nothing cached can load.
- gh:prForBranch, the renderer's fallback when refreshPRNow is missing,
  is gated like the other card polls; a manual lookup wakes, matching
  refreshPRNow's manual-only rule. The fallback call moves into its own
  module, built from the refresh candidate.

* fix(wsl): only an explicit Refresh starts a stopped distro for review status (E9)

hostedReview:forBranch woke on admissionTier 'interactive', but the
visible-review scheduler sends 'interactive' for the selected card on a
timer, so that poll restarted a stopped distro every interval. The wake
is now an explicit wakeWslDistro flag (desktop IPC only). The card
refresh helper sets it, since every caller follows a user act (the
checks panel's manual Refresh, or a review created, linked or edited),
and the manual Refresh also wakes its pre-refresh git status.
admissionTier is back to priority only.

* fix(wsl): an explicit review Refresh never joins a refused poll (E9)

fetchHostedReviewForBranch let a forced card Refresh join an in-flight
forced scheduler poll, since the join only compared force. On a stopped
WSL distro that poll is refused, so the click got the refusal. The
in-flight entry now records the wake, and a waking request joins only a
waking flight; a poll may still join an explicit Refresh.
…ew (stablyai#35532)

Moves ~600 strings in the shared components (modals, drawers, host cards, dictation,
accounts), the pull request sidebar and diff review to the translation API, with all
ten translations.

- Invalid account snapshots are detected by error type, not by matching English text
- Credit expiry wording uses separate keys for one and several credits instead of
  plural rules, which would pick the wrong sentence in Japanese or Russian
- The PR chip memo recomputes on a language change

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
…mote half 1/2) (stablyai#35528)

* feat(wsl): fetch and cache a remote WSL hosts policy for the kill switch

Adds the client half of a remote switch that can turn WSL hosts off: a
small versioned policy file, downloaded from a fixed release-asset URL per
channel, validated, bounded, and cached in userData with a monotonic
revision. Nothing reads it yet; wiring into the gate follows.

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

* refactor(wsl): expose the cached WSL hosts policy as allow, block or missing

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
…Codex heal batch (E9) (stablyai#35448)

* fix(wsl): anchor the guest kill's stop read after the guest ran; re-check before each heal batch

A 'stopped' answer skips the guest kill as proof the group ended, so it must come from a probe
started after the guest reported its group. The Codex index heal re-checks the distro right before
each batch spawns its guest codex, closing the window during the inter-batch delay.

* fix(wsl): the Codex heal also stops on an explicit may-have-stopped note

A hook-relay or watcher exit notes the distro may have stopped before any running list sees it;
shouldStop now hears those notes too, not only the running-list diff.
…er starts its distro (E6) (stablyai#33911)

* feat(wsl-host): a paired phone reaches the desktop's WSL host and never starts its distro (E6)

Behind ORCA_INTERNAL_WSL_HOSTS and the Experimental switch. The desktop relay
lists its WSL hosts to phones. Every relayed call (resolve, call, watchChanges,
status.get) passes a never-start check, and a WSL host serves a phone only
while it already runs.

- WslHostPhoneGate holds the phone's view. The call check reuses E9's
  focusReachability, so with no bridge in this process it refuses without a
  running-list read. A host shows as "stopped" only on a confirmed stop
  (liveness's distro-stopped, or a running list read by the check); anything
  else gets a neutral "isn't available" message. Hosts are hidden from phones
  while the Experimental switch is off or a Remove is pending.
- The relay host list sends optional `stoppedOnDesktop` only for a confirmed
  stop. The phone badges those rows "Start on computer"; older peers ignore
  the field.
- The paired-server rows producer carries WSL hosts like any server, so the
  main-computed sidebar feed a phone reads has their rows.
- The paired-phone e2e drives a WSL host project end to end and asserts a
  stopped distro is never started.

* fix(wsl-host): keep the phone's no-start check off non-WSL servers, and a stale stop off a ready host

- status.get runs the no-start check only for a WSL host, through a
  check-only helper. SSH-managed and paired servers reach the status owner
  exactly as on main: no reconnect, no redeploy, and the manual-disconnect,
  coalescing and repair handling stay in place. The preparation option is
  stripped before the probe.
- WslHostPhoneGate drops a 'stopped' read when a ready status arrived while it
  ran (a per-host ready generation), and clears a recorded stop when a check
  finds the host answering.
- A phone asking about a host that is switched off or being removed gets copy
  that says so, not "open one of its projects".

* test(wsl-host): the real no-start helper leaves SSH-managed and paired servers untouched

* fix(wsl-host): tie a phone's confirmed WSL stop to that host's status, and label a host not connected

- A stop a phone's check confirmed is stored with that host's own status
  object and holds only while that status is current. Another host's change no
  longer clears it. Any status of its own (ready, a disable's closed, a failed
  Remove's closed) does. A read never records a stop over a ready status, so a
  read shared with one begun before ready can't. Removed hosts drop their
  entry. The generation map and status listener are gone.
- The relay sends optional `unavailableOnDesktop` for a WSL host this desktop
  isn't connected to and doesn't know is stopped. New phones badge it "Open on
  computer"; older ones still show Connecting.
- The relay list reads the WSL host records once per poll (reachAll).

* refactor(wsl-host): one records read per phone check; note the gate's status identity compare

* test(wsl-host): read the phone's host flags as booleans in the paired-phone e2e

toMatchObject({ stoppedOnDesktop: undefined }) requires the key to be
present, and the desktop omits an unset flag, so the ready poll could never
match. The poll now compares relay plus both flags read as booleans.

* test(wsl-host): expect the neutral refusal once main's fake drops a stopped distro's bridge as closed

Main's fake connector (stablyai#34573) now publishes 'closed' when a stopped distro's
bridge drops, not liveness's 'distro-stopped'. So the phone's check reads the
stop under a ready status and doesn't claim it. The phone gets the neutral
copy and unavailableOnDesktop; the confirmed-stop copy stays unit-tested.

* test(wsl-host): the paired-phone e2e expects the confirmed stop again, and checks nothing booted the distro

Main's fake now publishes 'distro-stopped' when it drops a stopped distro's
bridge (stablyai#34624), as liveness does, so the phone gets "isn't running" and
stoppedOnDesktop. The spec also checks distros.json still reads 'stopped' at
the end: the fake boots a distro by rewriting it.

* test(wsl-host): the startup reconcile suite stubs the phone gate built beside the service

The reconcile still runs before the connector exists; the suite only lacked the new
setWslHostPhoneGate export on its service-instance mock.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
…ecks never boot a stopped distro (E9) (stablyai#35412)

* fix(wsl): Settings CLI status, startup CLI repair, interop health and link checks never boot a stopped distro (E9)

- cli:getWslInstallStatus: opening Settings takes a settled running read and shows a refreshable
  "not running" status instead of starting the distro; the refresh button passes wakeWslDistro.
- Startup CLI repair re-reads each listed distro (settled) right before its repair spawns and
  defers it otherwise, so a distro stopping mid fan-out is not restarted.
- Interop health: stop-triggered checks no longer trust the stop event's list; every check takes a
  settled read, and again before the root repair.
- shell:pathsExist (chat link and terminal hover existence) refuses a stopped distro's UNC path
  instead of statting it; callers already retry an unverifiable answer.

* docs(wsl): note the missing-kernel availability probe as the known E9 exception

* fix(wsl): shell:pathsExist refuses only the stopped distro's path, not the whole batch

One UNC path in a stopped distro no longer fails the host paths checked with it; the renderer
treats that path alone as unverifiable and retries it.
nwparker and others added 22 commits October 29, 2026 01:50
…ablyai#35852)

* perf(stats): stop retaining and rewriting the raw stats event log (stablyai#35544)

The collector kept up to 10K raw events (~203 B each since stablyai#14657 switched
meta to pane keys and added worktree ids) and re-serialized the whole ~2 MB
file every 5 s. No consumer reads events; persist aggregates only, keep the
v1 file shape with an empty events array, and compact legacy files on load.

* test(stats): use a small event burst for the retained-size bound
…t says why not (D1c-6) (stablyai#33531)

* fix(wsl): every local Git call follows its project's runtime unless it says why not (D1c-6)

* fix(wsl): rebuild Git routes on the store's own writes, never on a timer, and route a new worktree by its link

* fix(wsl): route WSL-made worktree links, aliased checkouts and sync Git; host Git only where marked; no wsl.exe storms

* fix(wsl): map WSL-made worktree links through each project distro's automount root

* fix(wsl): arm the missing-distro cache only with the Git router on, and feed it spawn failures

* fix(wsl): keep synchronous Git host-only, read the setup runner's path from the link, and keep the sync launch under the ratchet

* chore(wsl): move the sync Git runner's process-host import allowance with it

* fix(wsl): read only per-worktree git paths from the link, and only from a git dir that still exists

* fix(wsl): name which Git ran on stream and spawn spans too, so status shows its route

* test(wsl): setup runner lookups declare host Git; cover the link read with the router on and off

The hooks tests expected the setup runner's `rev-parse --git-path` call to
carry `wslDistro: 'Ubuntu'` for a WSL-runtime project. On main that field
never reached Git: main's gitExecFileSync options have no wslDistro and it
calls resolveCommand('git', args, cwd) with no distro override, so the
lookup ran host Git (WSL only when the cwd itself is a WSL path). The tests
pinned call arguments, not what ran. The sync runner now states that with
`hostGit: true` and resolves exactly as main did, so the tests assert that.

New worktree-runner-script-link tests cover the router-gated link read:
router on reads the link; router on with no usable link falls back to host
Git and converts its Linux path; router off makes main's host Git call and
never reads the link.

* test(git): read src/main once in the host-Git routing guard, so it holds under load

* test(wsl): pin the setup runner's sync Git spawn to main's exact launch on POSIX

The setup runner's path lookup now passes hostGit: true where it passed a
wslDistro that gitExecFileSync never read, so the binary, args, cwd and env
it spawns are unchanged. Update the call-shape assertions and pin the POSIX
execFileSync call itself.

(cherry picked from commit 6aae6d4d090e13b75c1d9ad2734f2f717dde7570)

* fix(wsl): await WSL Git admission in spawns only when there is one

With the Git router off admitWslGit returns null; awaiting it anyway added a
microtask to every spawn's admission path that main doesn't have.

(cherry picked from commit 883aaeb90bc23e89cafb039708a565ab3d72620e)

* fix(wsl): keep main's Git scheduling when the D1c Git router is off

The remote-identity sweep moved every user's probes to the background
admission tier, which only the router reads; it now keeps its tier unless the
router is on. Admission wrapping and the spawn stderr tail also step aside
without the router, so those calls run exactly as on main.

(cherry picked from commit 151a3091307c03078d0c0b98487bbe3bf467ec27)

* test(wsl): point the distro allowlist test at the sync runner's new home, as host Git

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 255e85fc93deba83addc4370f889c1b721180188)

* test(wsl): installing the Git router with the gate closed or off Windows leaves none installed

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

* perf(wsl): skip the span-only Git resolution on every spawn while the Git router is off

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

* fix(wsl): read a distro's automount root only from a running list probed after its stop settled, so it never boots a terminated distro

---------

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

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

* plugins: make Try it do the thing instead of opening the plugin page

* plugins: address review on Try it (row's icon theme, language switch result, pending plugins)
…stablyai#35861)

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

* 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>
* Default native chat naming to its conversation agent

* Preserve naming account overrides and accurate default selection

* Fix chat naming types and Japanese catalog spelling

* Isolate WSL interactive chat fixture from automatic naming

* Fix chat naming types after main integration

* Prove chat naming catalog bounds and recorded output routes

* Handle optional native launch environment in naming proof
…ch or expand (stablyai#35867)

The explorer's workspace-open read and the first git status woke WSL on every
mount, so a remount, launch restore or host loss after the user stopped the
distro started it again. Both now wake only when takeWorkspaceSwitchWake
reports a new user switch to that workspace, once per switch per consumer;
an expanded folder wakes only when it is newly expanded in the same
workspace, not when a mount or switch re-runs with the same folders.
…ed distro (stablyai#35829)

* 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.
…tablyai#35792)

* fix(ssh): flag a config host whose route is already registered under another name

The ssh-config picker compared names only, so a machine added by IP showed up
again under its config alias. It now also compares the endpoint: hostname
(case-insensitive), validated port, case-sensitive user, jump host and proxy
command. Entries without HostName still match by alias only.

Squashed from stablyai#15750 (3c3a3c6, a5575ce, 8daf213, a29d91e).

* fix(ssh): skip importing a config alias whose ssh -G route is already in Orca

Each config import now builds one snapshot: the config it read, and which new
aliases resolve, through ssh -G, to a route an existing target already has.
The duplicate check and the inserts both read only that snapshot. Imports and
picker refreshes run one at a time through a single queue, so none can race
another, and the picker reads the latest snapshot for its In Orca flags and
Add all count without waiting (alias-only until one exists).

A route is keyed only when ssh2's rules and system ssh's (OpenSSH run with
system ssh's own destination args, including an unclaimed alias's stored
endpoint) agree on host, port, user and proxy, with each transport's token
rules. Anything uncertain, or a failed ssh -G, gives no key, so nothing is
matched by guess. At most four ssh -G run at once. Restore brings back the
hosts it lists, previouslyRemoved stays alias-only, and DNS isn't consulted.

Co-authored-by: vam <zengyan@88.com>

* fix(ssh): rebuild the route snapshot after an import changes targets

An import that inserts or updates a target outdates its own snapshot, which
left the picker alias-only until the next refresh. It now queues a rebuild
behind itself. The picker also ignores a snapshot past its reuse window, and
the system-route shortcut requires a config alias.

Co-authored-by: vam <zengyan@88.com>

---------

Co-authored-by: vam <zengyan@88.com>
…H and WSL (stablyai#35875)

The bullet asked users to install Node for a relay that no longer exists.
Orca now brings its own Node; point restricted networks at the download
mirror setting or the offline archive path the error names.
…s no answer (stablyai#35869)

A first WSL deploy fetches the pinned Node archive, from this computer
and then from inside the distro. Behind a firewall that drops packets it
retried four times and then waited 20 s per host source, about two
minutes before failing. WSL deploys now give the desktop one 15 s attempt
with no retry on a missing response, and the host 15 s per source, so a
dead network fails in about 45 s. The host fallback stays, since the
distro's own route often succeeds when this computer's proxy refuses.
SSH keeps its timing.
…dy set up (stablyai#35879)

Moving a desktop's SSH state onto the host's Orca server refused with
orcad_migration_dormant_focus_conflict whenever the host already had a
focused project from another desktop. Focus is each desktop's own
selection, not saved state, so two desktops always differ and the second
could never move, on every retry.

The host now keeps its own focus as a unit and takes a desktop's focus
only when it has none, which is what the merge already did for the
fields it borrowed. Older servers still refuse until they update.

Fixes stablyai#35585
…stablyai#35761)

Warm start (an app relaunch or reconnect with the distro and orcad
running) to first terminal output is the flag-on gate at 2.5 s p50; cold
start (distro restart) is tracked against 3.0 s p50. Five warm reconnects
follow the cold runs, and the receipt reports n, p50 and p90 of first
output, ensure, create and send-to-output for each, with the runs.
… cannot write into an outer repo (stablyai#35859)

* test: clear inherited GIT_* env once per test file so real-Git suites cannot write into an outer repo

* test: clear only repo-locating Git env so the compat lane keeps GIT_EXEC_PATH
…i#35882)

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

* fix(wsl): Commits history wakes a stopped distro only on the user's own act

Showing Commits woke the distro on every mount, remount and re-show. Now
only the user expanding Commits in the same worktree, or the user's own
switch to the workspace (once per switch), may start it; the Refresh
button keeps its explicit wake (E9).

* test: a mount and a base-ref move read Commits history in the background

stablyai#35778's base-move refetch test expected every shown-history read to
wake a stopped WSL distro; only the user's own act does now.
…stopped distro (E9) (stablyai#35827)

* 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 (stablyai#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
…tablyai#35799)

* 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
Upstream range 36d2956..9f62a4f, 511 commits. 10 conflicted
paths, 15 hunks, all both modified.

Conflicts:
- cached-session-list.ts (#6): upstream's WSL carryover (stablyai#35367,
  stablyai#35729, stablyai#35810) wraps the scan result; the fork's appliedSessionDepth
  rides in the object it carries over.
- session-scan-issues.ts (#6): upstream's coded-issue imports (stablyai#35750)
  plus the fork's AI_VAULT_SCAN_ISSUE_LIMIT.
- daemon-pty-runtime-state.ts (#25): upstream's wslBridgeBootIdentity
  option beside the fork's draining.
- Updater (#10 #14 #16) against upstream stablyai#35833's coded failures:
  update-status-types.ts, updater-release-builds.ts,
  updater-build-selection.ts, updater-check-state.ts,
  updater-download-install.ts and the build-channel selection test take
  upstream's codes plus the fork's release source and presentation. A
  bad primary-source tag throws the coded invalidReleaseTag; another
  source keeps the fork's message naming it.
- GeneralUpdateSettingsSection.tsx (#14): the fork's layout; upstream's
  updaterMessageText follows the moved status text into both hints.

Breaks the conflict list did not show:
- updater-check-state.ts reached 312 counted lines (upstream 285). The
  fork's error-status fields and pinned-source rule move to the
  fork-owned updater-error-status-fields.ts. Now 298.
- runtime-service-state.ts reached 305 (upstream 298) in a clean merge.
  #4's delegatedWorktreeEdgeProjection moves into the fork's own
  OrcaRuntimeWithDelegatedWorktreeEdgeSync layer, its only reader.
  Now 299.
- Upstream's new de.json (stablyai#34917) carried "Orca" for the fork's titlebar
  key; it takes the fork's value.
- Upstream's plural-aware extraction (stablyai#35637) flags the fork's resume
  chooser base keys age.minutes/hours/days, which existed only for the
  old check; they leave en.json and en-runtime-required.json. es and fr
  gain the _many forms upstream's CLDR rule now requires.
- The fork's not-ready check test expects upstream's messageCode.

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

chatgpt-codex-connector Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-29T10:29:28.291700Z 4888941 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants