Commit Graph
17601 Commits
Author SHA1 Message Date
OrcaWinandOrcaWin c10fbcb0d2 refactor(i18n): share one i18next setup between main and renderer (#35621)
* perf(i18n): load built-in catalogs once, without copies or a runtime plural fill

Each catalog load parsed the JSON, rebuilt it to fill CLDR plural forms
from _other, then deep-copied and deep-merged it into the store (about
26 ms after parsing per 1.3 MB catalog), and concurrent loads of one
locale fetched it twice.

- sync:localization-catalog now commits the plural forms a locale's
  CLDR rules need beside each _other (fr/es/pt many, tr one, a few
  de/ru), and verify:localization-catalog fails when one is missing.
  Plural forms may include {{count}} where English omits it.
- Renderer and main load built-in catalogs as-is; plugin packs keep the
  runtime fill.
- Renderer catalog requests are shared per locale; a timed-out request
  is dropped so a retry fetches again. Bundles are added with skipCopy.

* fix(i18n): require {{count}} in plural forms when English shows it

* refactor(i18n): share one i18next setup between main and renderer

- createOrcaI18n (src/shared/orca-i18n-instance.ts) owns the backend,
  init options, plugin-pack registration, resource-language resolution
  and the translate wrapper; main and renderer inject only how a
  built-in catalog loads (dynamic import vs. fetch) and extra modules.
- Remove setRendererUiLanguage (tests only); tests load then switch.
- resolveUiLocale maps built-ins by lookup instead of an if-chain, and
  catalog URLs/loaders are direct map lookups.
- Drop <I18nextProvider>: initReactI18next already binds the instance.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:21:12 -07:00
OrcaWinandOrcaWin 73c6b6d2ef fix(mobile): release skill scans from retired transport generations (#34949)
* fix(mobile): release skill scans from retired transport generations

* fix(mobile): read skill-scan transport generation when the request starts

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:07:56 -07:00
OrcaWinandOrcaWin 02db0146c6 perf(chat): order queued turns without repeated transcript scans (#34945)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:07:52 -07:00
OrcaWinandOrcaWin 34536771a7 perf(mobile): skip projection for abandoned diff replies (#34873)
* perf(mobile): skip projection for abandoned diff replies

* test(mobile): consolidate abandoned diff projection regressions

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:07:45 -07:00
OrcaWinandOrcaWin cde2472a83 fix(mobile): refuse PDF opens from hidden pages (#34869)
* fix(mobile): refuse PDF opens from hidden pages

* test(mobile): assert one refused hidden PDF open instead of scaled loops

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:07:42 -07:00
OrcaWinandOrcaWin d27c795b76 fix(mobile): bound file search cache after empty queries (#34841)
* fix(mobile): bound file search cache after empty queries

* test(mobile): fold empty-query cache bound regression into existing suite

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:07:32 -07:00
OrcaWinandOrcaWin 0909b148ad fix(mobile): skip retired file search ranking (#34837)
* fix(mobile): skip retired file search ranking

* test(mobile): fold stale-rank check into existing slow-inventory case

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:07:29 -07:00
Jinjing 79ba74dc38 Remove preview link from mobile setup (#35619)
* Revert incorrect mobile download destination

* Remove mobile preview install option
2026-10-28 20:02:24 -07:00
bfa0dc01ba fix(mobile): preserve long terminal and chat pastes (#31473)
* fix(mobile): preserve long terminal and chat pastes

Agents can keep only the last ~1 KiB read of unframed input (#13332).
Frame long single-line chat messages like multi-line ones, and frame Live
input appends over 1 KiB (an OS paste) with the terminal's paste rule,
including held text flushed before a terminal click.

Co-authored-by: Carlos Baraza Haro <carlos.baraza@ieee.org>

* fix(mobile): end the live input session after a framed paste

Agents such as Codex collapse a framed paste into one token, so later
per-character erases from the field mirror desynced the line. A long
append to a terminal in bracketed paste mode now commits the whole field
in one frame and clears the field, recording it like other session ends
so a late native echo cannot send the paste twice; without that mode the
paste stays unframed and editable. Chat sends measure the sanitized bytes
when deciding to frame.

---------

Co-authored-by: Carlos Baraza Haro <carlos.baraza@ieee.org>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-29 03:02:08 +00:00
OrcaWinandOrcaWin 8b3754d99a fix: retire native edit menus when their renderer document ends (#35383)
* fix: retire editable context menus with renderer documents

* fix: retire edit menus opened during a pending reload at commit

A right-click while a cross-document reload is pending opens a menu after
the navigation fence fired. Close it at main-frame commit and drop clicks
from retired menus, since macOS closePopup is posted asynchronously.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:59:15 -07:00
OrcaWinandOrcaWin 704d3cdd6f perf(i18n): load built-in catalogs once, without copies or a runtime plural fill (#35615)
* perf(i18n): load built-in catalogs once, without copies or a runtime plural fill

Each catalog load parsed the JSON, rebuilt it to fill CLDR plural forms
from _other, then deep-copied and deep-merged it into the store (about
26 ms after parsing per 1.3 MB catalog), and concurrent loads of one
locale fetched it twice.

- sync:localization-catalog now commits the plural forms a locale's
  CLDR rules need beside each _other (fr/es/pt many, tr one, a few
  de/ru), and verify:localization-catalog fails when one is missing.
  Plural forms may include {{count}} where English omits it.
- Renderer and main load built-in catalogs as-is; plugin packs keep the
  runtime fill.
- Renderer catalog requests are shared per locale; a timed-out request
  is dropped so a retry fetches again. Bundles are added with skipCopy.

* fix(i18n): require {{count}} in plural forms when English shows it

* chore(i18n): sync plural forms for catalogs merged from main

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:58:12 -07:00
b7aa695182 fix(mobile): make agent question cards the one answering surface and keep long ones reachable (#31663)
* fix(mobile): give agent questions one answering surface that fits the screen

A shown prompt card now replaces the chat composer, as on desktop. The
composer stays mounted underneath so its draft and attachments survive,
and comes back when the card collapses, clears, or dictation is running.

The card keeps the conversation visible above it (60% cap) and takes the
whole area while its reply is being typed. Question and Ask cards scroll
inside that bound and keep a focused reply in view as the card shrinks.

Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: Wooseong Kim <innocarpe@gmail.com>
Co-authored-by: fancivez <fancivez@gmail.com>

* fix(mobile): open each ask step at its question

The ask card's body now scrolls inside a bounded card, so a new step must not inherit the previous step's scroll offset.

* fix(mobile): keep the queued tray shrinkable and approval actions reachable

The composer wrapper passes the remaining height down again, the queued-message tray unmounts while a card owns input so a focused editor cannot keep typing out of sight, and an approval card scrolls as a whole when its choices exceed the card's bound.

* fix(mobile): keep the composer for an approval this build cannot answer

Its choices are disabled and only a new turn can cancel it, as desktop's pendingPromptsAllUnanswerableHere rule keeps the composer for.

* fix(mobile): keep the approval card's choices pinned and the composer for a terminal-only ask

A long plan shrinks inside the approval card again instead of pushing its choices below a scroll. An ask only the terminal can answer leaves the composer (and Stop) in place, like an approval this build cannot draw.

* fix(mobile): keep the queued tray mounted under a prompt card

Unmounting it dropped its in-flight guards, so Resume could run while Clear all was still deleting. A hidden focused editor loses focus with display none.

* fix(mobile): keep the composer while dictation lands, and each ask step at its question

Transcribed text arriving after the mic stops stays visible in the composer. A focused reply is revealed only when its card shrinks, so a step that grows the card keeps its reset to the question.

* fix(mobile): keep queued work in view under a question, and end an ask step's edit on navigation

Desktop leaves queued messages and background-task controls visible while a prompt card shows; only the composer steps aside. Moving between ask steps ends the reply edit so typing can't land in a field scrolled out of view.

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
Co-authored-by: Wooseong Kim <innocarpe@gmail.com>
Co-authored-by: fancivez <fancivez@gmail.com>
2026-10-29 02:57:12 +00:00
Neil ce44117d91 refactor(shared): colocate native chat cut-turn notices (#35617) 2026-10-28 19:54:34 -07:00
OrcaWinandOrcaWin 141f09b336 fix(browser): skip obsolete native snapshot conversion (#35377)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:51:18 -07:00
NeilandClaude 15c9dfc702 fix(wsl-host): a fresh host's first agent launch waits for the desktop's account (#29576)
* fix(wsl-host): a fresh host's first agent launch waits for the desktop's account

On a WSL host with no saved account env, an agent launched in the first
second could start on the distro's own login before the desktop's first
push landed. Agent terminals, structured chats and AI commit text now wait
up to 5 s, once, for that push.

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

* test(wsl-host): the startup restore arms the first-push wait only on a WSL host

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

* test(wsl-host): the desktop and non-WSL hosts never wait or start a timer before a launch

* fix(wsl-host): refresh the selected Claude folder before the host's own Claude launches (#29589)

* fix(wsl-host): refresh the selected Claude folder before the host's own Claude launches

A WSL host's orcad launched Claude on the account folder as the desktop set
it up when the account was added, so Claude replayed its first-run screens
and missed later settings. orcad now refreshes that folder from the distro
user's ~/.claude (state minus login keys, settings) before each Claude launch
it starts, with the desktop router's 5 s cap, reusing the guest helper's
provisioning.

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

* fix(wsl-host): refresh a newly selected account after a mid-refresh switch; skip non-Orca folders

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

* refactor(wsl-host): move the switch-aware Claude folder refresh out of the account controller

---------

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

* refactor(runtime): move the host account launch env into its own module

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 19:50:20 -07:00
OrcaWinandOrcaWin 3f356edcb7 test: remove 20 low-value cases and ten suites (#35574)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:49:33 -07:00
Neil 1603fd246a fix(linux): stop the serve orca dispatcher shadowing the screen reader, and remove it with the CLI (#35578)
* fix(linux): stop the serve `orca` dispatcher shadowing the screen reader, and remove it with the CLI

Headless `orca serve` writes ~/.local/bin/orca so Claude Team's bare `orca`
reaches Orca even when a login shell drops Orca's PATH entry. It exec'd the
launcher unconditionally, so it sat in front of GNOME's `orca` screen reader for
everyone, failed with "No such file or directory" once Orca was uninstalled, and
nothing ever removed it.

The dispatcher now answers for Orca's own children only (ORCA_CLI_BIN_DIR,
ORCA_PANE_KEY or ORCA_USER_DATA_PATH set). Anyone else gets the next `orca` on
PATH, skipping itself, with one hop so two dispatchers cannot loop; then this
app; then a clear message and exit 127 once the launcher is gone. Existing
dispatchers are rewritten on the next serve start. Removing the `orca` command
now also removes the dispatcher, and only if it carries Orca's marker.

* fix(linux): skip every Orca dispatcher on PATH instead of an env hop guard

The hop variable let a second dispatcher earlier on PATH send a screen-reader
user's `orca` to Orca, and leaked into the screen reader's environment so its
descendants' `orca` could land on Orca too. The PATH scan now skips any
candidate carrying the dispatcher marker (as well as itself), so dispatchers
cannot hand calls to each other, and the real target runs with nothing added to
its environment.

* test(linux): Orca's own children reach the screen reader once Orca is gone

* fix(linux): Orca's own children get "no longer installed", never the screen reader

With ORCA_CLI_BIN_DIR, ORCA_PANE_KEY or ORCA_USER_DATA_PATH set and the
launcher gone, the dispatcher now prints the message and exits 127 without
scanning PATH, so an agent's `orca …` can never start GNOME's talking screen
reader. The PATH scan also ignores relative entries, which depend on the
caller's folder. Tests cover each Orca variable, a PATH folder with spaces,
empty and relative entries, a symlink to the dispatcher, and an unreadable
candidate being run rather than skipped.
2026-10-28 19:44:52 -07:00
eb4f541cda fix(mobile): show live input caret and preserve selection edits (#31477)
* fix(mobile): show live input caret and preserve selection edits

Display the existing input directly so its native caret shows. Accessory
Backspace/Delete edit at the field's caret, read from the input when pressed,
so edits that keep the caret (IME composition) still delete, and the caret is
restored for subsequent typing.
Port and adapt community PR #28294 to the current command dock.

Co-authored-by: Kyino <kyino1025@gmail.com>

* fix(mobile): keep live input caret keys local and the dock height fixed

Hardware Left/Right/Home/End moved both the visible field caret and the
PTY cursor, so the mirror erased at the wrong place. With field text they
now move only the field caret, like Backspace and Delete; Right/End at the
field end still reach the PTY so shells can accept an autosuggestion. On
Android the key binding lets plain caret keys through to that decision
instead of sending them to the PTY. The dictation and upload status covers
the field instead of adding a row, so starting or stopping either no longer
resizes the terminal.

* test(mobile): annotate the DOM field cast in the accessory input test

* chore(mobile): allowlist the live input field strings for localization coverage

---------

Co-authored-by: Kyino <kyino1025@gmail.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-29 02:43:47 +00:00
NeilandKelvin Amoaba c9745246d4 fix(mobile): preserve new browser typing when an earlier send fails (#31710)
* fix(mobile): preserve browser typing across delayed keyboard sends

A failed send restores an old draft over newer typing, null success is treated as refusal, and rapid presses duplicate sends. Preserve newer typing, interpret acknowledgement explicitly, and fence page/client ownership.

* test(mobile): preserve browser drafts through same-computer connection cutover

* test(mobile): record browser keyboard acknowledgement semantics

* fix(mobile): warn only when a browser keyboard send's delivery is unknown

A refused send restores the text silently as before; only a lost reply or connection cutover shows the unconfirmed toast, using the app's existing unconfirmed-delivery wording.

* fix(mobile): keep a browser keyboard send's text through a reconnect

The pane remounts per page, so a reconnect that swaps the client keeps the same draft; only unmount should stop a late reply from restoring it.

* fix(mobile): warn only for written browser keyboard sends with lost replies

A cutover error already carries the delivery-unknown mark when its request was written, so the extra cutover check only warned about text that never left the phone. Classifying outside the resolved path also keeps an unconfirmed send from clearing the error banner.

* fix(mobile): let newer browser typing send while an earlier send is in flight

Claiming the draft from a ref stops a repeat tap before re-render without blocking a second send of newly typed text.

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-29 02:43:32 +00:00
fd8f1f9678 feat(wsl): convert UNC Windows-drive projects to drive paths across a restart (D1c-4c) (#33135)
* feat(wsl): convert UNC Windows-drive projects to drive paths across a restart (D1c-4c)

* fix(wsl): read the conversion's field table from its shared home

* test(wsl): the conversion runs Windows Git only on the drive path, since WSL denies UNC drive folders

WSL 2.7.11 answers EPERM for \\wsl.localhost\<distro>\mnt\c\... from Windows. Pin that the
preflight's Git runs and worktree-link reads use C:\... by making every UNC access throw EPERM.

* fix(wsl): name the cause when a conversion refuses over saved state

A refusal over saved state now says whether a project also holds an unconverted repo, or a drive
key already holds different data (and which key), instead of a bare collision code. The fields are
optional, so the window's copy still reads an older host's refusal. The seeded shape (a saved UNC
worktree with tabs beside the bare drive row startup discovery wrote) now converts.

* test(wsl): startup rolls back only when the drive key holds different user data

* fix(wsl): connect the conversion's pause to a WSL host as a user action, as #34059's mover now requires

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

* fix(wsl): never report a committed conversion as rolled back; record and check its profile; refuse paths off a Windows drive mount

- The journal's post-commit phase write sat inside the rollback catch, so a failure there
  dropped the journal and reported rolled-back for a profile already rewritten. The write now
  follows the commit outside the catch: a failure leaves the journal 'prepared', whose rewrite
  is idempotent, and reports resuming.
- The journal records the profile it rewrites, and startup runs only the active profile's.
- The run reads the distro's Windows-drive mounts and passes them to the scope.

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

* test(wsl): type the journal-failure switch without a cast

* fix(wsl): only this profile's waiting conversion blocks starting another

* test(wsl): compare the two profiles' journals without depending on directory order

* fix(wsl): a torn shell-history meta.json never stalls a conversion, it is written atomically, and only a prepared conversion blocks a new one

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 19:41:20 -07:00
NeilandClaude 8d319166bd fix(wsl): publish the resolved WSL hosts gate state to child processes (kill switch follow-up) (#35543)
* fix(wsl): publish the resolved WSL hosts gate state to child processes

Children inherit ORCA_INTERNAL_WSL_HOSTS=1 even when a remote policy block
closed the gate, and none inherit serve-only. Main now publishes its
resolved state as ORCA_WSL_HOSTS_GATE_STATE at startup, and the shared
serving check in a child trusts it over the internal gate env. A process
that resolves the gate itself ignores an inherited value, so a relaunch
never carries a stale state. ORCA_INTERNAL_WSL_HOSTS is left intact so a
relaunched or updated Orca keeps fetching the policy.

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

* fix(wsl): main ignores an inherited WSL hosts gate state from its first line

A relaunch or the updater's installer inherits the parent's published
ORCA_WSL_HOSTS_GATE_STATE. Main's entry now marks the gate as its own to
resolve before preflight, so even a read before configure falls back to
the internal gate env, and configure always overwrites the value. Tests
pin that a stale inherited closed or open is ignored and overwritten.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 19:38:20 -07:00
OrcaWinandOrcaWin 6037d91f4b fix(i18n): whole-sentence copy for review nouns, open-in labels, delete dialog, timeline and orca.yaml trust (#35608)
* fix(i18n): translate review nouns, open-in labels, and fragmented dialog/timeline sentences

* fix(i18n): address review findings (ru plural wording, typed test prop)

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:37:00 -07:00
OrcaWinandOrcaWin 34ad2218a9 fix(i18n): pick CLDR plural forms for background task and subagent counts (#35605)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:36:03 -07:00
Neil 3b158cfb7c test(wsl): wait for the chat provider's report to settle instead of reading it once (#35603)
* test(wsl): wait for the chat provider's report to settle instead of reading it once

* test(wsl): wait for the resumed turn's message, not just its launch
2026-10-28 19:35:06 -07:00
Neil eef196de06 perf(wsl): read a connect's pre-fence activation state in one command (#35591)
A WSL connect read the activation record, the transaction journal, the
activation fence and orcad's instance lock in separate guest commands,
some of them twice, before taking the fence. Read them once, alongside
the record the context already read, and hand that snapshot to recovery,
adoption and the deploy's pre-upload checks as a hint. A hint only skips
a read whose answer would let the step continue unchanged; anything else,
and every fenced decision, still reads the host. SSH passes nothing.
2026-10-28 19:33:48 -07:00
OrcaWinandOrcaWin 0144c429b4 perf(i18n): skip unchanged plugin language packs on plugin-list refreshes (#35602)
* perf(i18n): skip unchanged plugin language packs on plugin-list refreshes

Every plugin-list refresh produced a new entries array (even an empty
one), so I18nProvider removed and re-added every pack as a full copy and
ran changeLanguage, whose languageChanged re-rendered the whole tree.

- The plugin content list store reuses structurally unchanged entries
  (and the previous array when nothing changed).
- Pack registration re-adds only packs whose catalog changed, in main and
  renderer; main rebuilds menus only when something changed.
- I18nProvider re-applies the language only when the selected pack
  changes, which keeps forced re-application for real pack updates.

* fix(i18n): match reused plugin entries by id; keep the namespace after pack removal

removeResourceBundle drops the translation namespace that later backend
loads read, so removing one pack while others stay unchanged broke lazy
loading of built-in catalogs.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:32:54 -07:00
OrcaWinandOrcaWin 3bd8670091 perf(watchers): skip startup for canceled runtime requests (#35556)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:32:26 -07:00
Neil 005da54a15 fix(wsl): start a bridge fish older than 2.7 without -C instead of failing the pane (#35579)
* fix(wsl): start a bridge fish older than 2.7 without -C instead of failing the pane

fish before 2.7 rejects -C, so the claude function and cwd hook made a
WSL fish pane fail to start on distros such as Ubuntu 16.04. Read the
version first and start those plainly. The cwd-report test now decodes
reports through the daemon's parser and checks fish 4's own reports.

* fix(wsl): read a fish 2.x version from stderr

fish 2.x prints --version to stderr, so the probe read an empty string
and old fish started with -C and failed. Read both streams; the stub now
reports one old version on stderr so the test pins this.
2026-10-28 19:31:54 -07:00
Neil 9dd6f26a6e fix: allow dismissing workspace auto-name failures (#35545)
* fix: allow dismissing workspace auto-name failures

* fix: retain auto-name failures until dismissal is saved

* refactor: use workspace selectors for metadata state updates
2026-10-28 19:28:21 -07:00
Jinjing 2bb014e778 Add mobile app download translations 2026-10-28 19:27:28 -07:00
Jinjing 7980f2c23f Fix mobile download button destination 2026-10-28 19:27:28 -07:00
Neil 9d0a99ce56 test(runtime): give the tab-delta first-frame wait a real-socket budget and name the empty client (#35600) 2026-10-28 19:27:04 -07:00
Neil dc4a990c4a test(e2e): background work never starts a stopped WSL host distro (E9 guard) (#35580)
* test(e2e): background work never starts a stopped WSL host distro (E9 guard)

A desktop on the fake WSL transport keeps a WSL-host project and a local one. With the distro
stopped, a window of background activity elsewhere (window focus/blur/reveal, workspace switches,
linked issue/PR cards, a streaming chat in the local workspace, Settings panes and Tasks, account
switches) must start nothing; opening a terminal in the WSL workspace then starts it exactly once.
createGitProject returns the real path so the helper also works where tmpdir is a symlink.

* test(e2e): actually render each Settings pane in the E9 background window

openSettingsTarget alone only set the navigation target, so no pane mounted and none of its reads
ran. Open Settings, wait for each pane's section to mount, then close it. A repo pane that boots
the distro on mount now fails the guard.

* test(e2e): fail the host-mode E9 guard early on a missing repo or connect log; state its scope
2026-10-28 19:24:16 -07:00
Neil ae89e41cad fix(terminal): read nushell's folder reports, which send #, ? and % raw (#35596)
nushell (0.94+, shell_integration.osc7 on by default) percent-encodes
only non-ASCII bytes in its OSC 7 report. The daemon's URL parser cut the
path at a raw `#` or `?` (recording the wrong folder) and rejected a `%`
not followed by two hex digits (dropping the report). The parser now
encodes those three in the path first. A properly encoded URI never has
them there, so every existing sender parses byte-identically, pinned by a
104-case snapshot taken before the change.

One pinned result changes on purpose: a folder named `%ZZ` now parses as
that path instead of being rejected. Non-UTF-8 sequences such as %FF are
still rejected, and control-byte handling is unchanged.

Also pins that the WSL bridge starts nushell as a plain login shell with
its own config, so its own report survives.
2026-10-28 19:19:53 -07:00
Neil 9b1540c384 fix(runtime): a delegated child the save dropped is minted fresh in the same sync (#35533)
When upsertDelegatedMobileDevices returns fewer children than phones
(a child removed on disk meanwhile was dropped by the save), rerun it
once against the current parent so the phone gets a working child now
rather than at the next sync.
2026-10-28 19:17:11 -07:00
NeilandClaude 0976872b9e feat(wsl): let a cached remote policy close the WSL hosts gate (kill switch, remote half 2/2) (#35529)
* feat(wsl): let a cached remote policy close the WSL hosts gate (kill switch 2/2)

A cached remote policy of "block" now closes an internal gate the launch
environment opened, for the whole run. It reuses the closed-gate path that
already exists: with saved hosts or moves the gate becomes serve-only, so
moved projects keep working while nothing new is added or moved. With
nothing saved it is closed. A missing, unreadable or "allow" policy changes
nothing. Main stamps windows so preload agrees, the download runs only on
Windows with the internal gate open, and telemetry reports the block.

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

* feat(wsl): report the applied WSL hosts policy and keep the way back under a block

Telemetry reports the cached policy applied at launch as allow, block or
missing (omitted when the internal gate left it unread). Tests pin that a
block keeps Remove host, the way back and unfinished-move recovery, refuses
new hosts and moves, and that a mid-run download applies only next launch.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 19:16:42 -07:00
OrcaWinandOrcaWin f54b83eb5e fix(extensions): release consumed native-host backing buffers (#35368)
* fix(extensions): release consumed native-host backing buffers

* test(extensions): cover coalesced native-host messages with a carried partial frame

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:15:16 -07:00
Neil a0969d59e5 test(wsl): record the restart phase baseline for staged readiness (#35530)
Split first output into ensure, terminal create, and send-to-output, and
report orcad's internal startup medians (boot before the first timed phase,
each phase's end and duration, readiness) so moving the readiness publish
earlier can be judged per phase.
2026-10-28 19:13:21 -07:00
Neil 1e8d09aaf7 feat(orcad): per-feature readiness latches and requires: on RPC methods (#35571)
Adds OrcadFeatureReadiness (accounts, sessionSearch, orchestration,
unshownPlacement) and a requires: field on defineMethod. The dispatcher
waits a bounded 10 s for a method's features, then refuses with the
existing retryable runtime_unavailable. terminal.adoptOrphans waits for
unshown placement; reconcile-terminals stays on the critical path. Every
latch opens where its phase finishes today, before RPC starts, so
behaviour is unchanged.
2026-10-28 19:12:46 -07:00
Neil 008a7345a8 feat(terminal): tell the user when keys typed before a remote terminal bound were not sent (#35581)
A remote (WSL host or server) pane holds keys typed while it is still
binding its terminal. When that typing cannot safely reach the terminal
the pane binds (startup work or replayed history appeared, the create
bound no terminal, or the pane bound a different terminal than the one
on screen) the hold drops it so it never runs in the wrong shell. That
drop was silent.

The hold now reports a drop of a person's typed keys (not terminal
query replies) made before the bind, and the pane shows one non-blocking
notice per tab: "Some keys typed while the terminal was starting were
not sent." A closed pane reports nothing. Localized in all 11 locales.
2026-10-28 19:11:00 -07:00
OrcaWinandOrcaWin c0df84f6b7 fix(extensions): bound outstanding native-host writes (#35362)
* fix(extensions): bound outstanding native-host writes

* fix(extensions): evict the largest stalled native host and allow two queued frames per host

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:09:35 -07:00
Neil b1dfe54ca4 perf(orcad): drop the event-loop turns around the runtime imports (#35568)
The lane showed they never let the daemon fork land earlier in a way that
moved readiness (#35514 measured an earlier fork with no ready-time gain),
so they only add two loop turns to startup.
2026-10-28 19:08:52 -07:00
Neil 6d21afb09e refactor(wsl): one matcher for the stopped-distro refusal (E9) (#35567)
Two shared matchers recognized the same gate refusal by text:
isWslDistroNotRunningRefusal (beside the message builders) and
isWslDistroRefusalError. The detected-agents refresh now uses the
former and the duplicate module is deleted. Its IPC-prefix test moves
onto the surviving matcher.

The surviving pattern now matches any remedy wording after the sentence,
as the deleted one did, so a refusal phrased differently is still kept
quiet.
2026-10-28 19:07:58 -07:00
Neil 5be70ee00f fix(runtime): a device removed on disk stops authenticating at the next check (#35527)
* fix(runtime): a device removed on disk stops authenticating at the next check

Auth checks (token validate, device-key lookup, per-request principal
recheck) now stat orca-devices.json and, when it changed since this
process last read it, re-read and merge it the same way a save does.
An unchanged file costs one stat; an unreadable or corrupt one changes
nothing.

* fix(runtime): check the device file before handing out a pairing offer

A pending offer an admin removed on disk is never shown as a QR. The
auth-time re-read also skips while this process's own quarantine is the
reason the file is missing.
2026-10-28 19:07:54 -07:00
OrcaWinandOrcaWin cb49a37c5c fix(extensions): honor transient popup dismissal (#35360)
* fix(extensions): honor transient popup dismissal

* refactor(extensions): reuse allowPageUnload for the action popup

* test(extensions): cover action popup close despite a beforeunload veto

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:06:51 -07:00
Neil c8b6d38bd4 fix(ci): keep mobile localization out of desktop-only test installs (#35576)
Load the Hermes plural-rules polyfill from the phone app entry instead of
mobile-i18n, and transform mobile-i18n and its catalog loader without the
Expo tsconfig in root vitest.
2026-10-28 19:06:34 -07:00
OrcaWinandOrcaWin 7802d16fda test: remove 17 low-value cases and seven suites (#35394)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 19:04:19 -07:00
Jinjing 366eaffa99 Prioritize direct URL navigation over history suggestions 2026-10-28 18:56:15 -07:00
e1b7248f0a feat(wsl): re-key the profile of UNC Windows-drive projects converting to drive paths (D1c-4b) (#33128)
* feat(wsl): re-key the profile of UNC Windows-drive projects converting to drive paths (D1c-4b)

* fix(wsl): keep the conversion's field table out of the main layout-writer census

* fix(wsl): merge the drive-keyed rows startup wrote for a UNC drive project instead of refusing

WSL Git lists a UNC /mnt/c project's folders under their drive paths, so startup discovery writes a
bare C:\-keyed worktree row (and its identity alias) beside the saved UNC one. The re-key then
landed both on one key and every conversion was refused as wsl_drive_unc_key_collision.

Before the re-key, a drive-keyed row holding only discovery bookkeeping is dropped with its alias
and identity row, so the saved row (instance id, name, links) takes the key. Any other two keys
that meet merge when one is empty or both match; only differing user data refuses, and the error
names the key.

* fix(wsl): treat a chosen workspace status as user data, so the conversion never drops it as a discovery row

Discovery writes only the default status. A drive-keyed row with any other status now counts
as the user's, so the conversion refuses with the key instead of dropping it.

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

* fix(wsl): read /mnt/<letter> with the same case rule as the UNC path folding

Only a lowercase /mnt is drvfs, with the drive letter in either case, as
foldWslUncPathCaseInsensitiveParts already says; /MNT is an ordinary Linux folder.

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

* fix(wsl): a refused duplicate spelling no longer blocks the drive folder's one converted project as an overlap

* test(wsl): a project nested under a refused duplicate's folder still converts

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-28 18:51:54 -07:00
Kelvin Amoaba f5c84eae58 fix(mobile): the first Back while dictating stops it and keeps what was said (#35477) 2026-10-29 01:44:01 +00:00