Commit Graph
1569 Commits
Author SHA1 Message Date
Neilandzhangxaochen 8a4bc559e6 perf(mobile): skip line stats when loading Source Control status (#36061)
* perf(mobile): skip line stats when loading Source Control status

Mobile Changes rows never render per-file line counts, so the default
git.status line-stats pass (up to two `git diff --numstat` subprocesses
plus untracked file reads) was wasted host work on every load. Hosts
that predate the param strip the unknown key and behave as before.

Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>

* test(mobile): re-record Changes-load goldens for the no-line-stats status read

Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>

---------

Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>
2026-10-29 13:36:57 -07:00
Brennan Benson 920fa6cdbc Restore Session History resume for symlinked workspaces (#35052)
* Fix Session History resume for symlinked workspaces

* Bound history alias derivation and cover resume consumers

* Reuse equal alias values across history publications

* fix(history): verify adopted source directory before commit

* fix: preserve UTF-8 paths in directory admission probe

* fix: bypass transcript preparation for non-adopted starts
2026-10-29 13:17:40 -07:00
Brennan Benson e08cb10cc6 Prevent resting chats from delaying native command menus (#35069)
* Scope native chat command discovery to menu demand

* Fix command discovery CI imports and test timing

* fix: recover demanded command menus after context retirement

* test: load command host fixture before mocked consumers

* test: retain eager cache reads across command expiry

* test: cover command recovery after pending deadline

* test: count demanded command renders and query isolation

* test: load mobile command host fixture during collection

* test: type command batch fields from subscribe events

* test: check command event arrays without assertion

* Fix command discovery fixture project boundaries

* Name command fixture mocks with public Vitest types

* Assert opening metadata on resumed session snapshots

* test: assert passive command population boundaries

* test: cover mobile command capability handoff

* test: correct capability proof scope adapters
2026-10-29 13:16:35 -07:00
Brennan Benson 7321b066e8 Show messages between agents as cards with the other agent's status (#34824)
* Snapshot agent message relations and verify task display prefixes

* Show native chat agent messages in navigable cards

* Keep agent message cards derived from canonical input and sidebar state

* test: correct agent card contracts and cover raw queue editing

* test: repair agent card runtime and operation contracts

* fix: preserve queued image previews and typed test measurements

* fix: use checked worker fixture and owned sender button typography

* fix: complete agent card fixtures and native presentation

* test: preserve queued edit exports and current authorship

* test: use namespace type imports in queued edit fixture

* Preserve sender progress and consolidate card contracts

* Simplify sender and notice contract instrumentation

* Remove duplicate sender and notice measurement mirrors

* Use a template literal for the dispatch boundary fixture

* Correct sender and notice verification phase accounting

* Consolidate agent message tests around user contracts

* Restore folded agent message preview on focus exit

* Consolidate agent message regression coverage

* Consolidate agent message fixture data

* Fix display text test lint diagnostics

* Use conversation view type for mail test records

* Reuse active copy control in card workflow test
2026-10-29 13:09:50 -07:00
641e4792b9 Startup shows chats as Interrupted or Done without reading their history (#32146)
* 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>
2026-10-29 10:20:52 -07:00
Neil 4595be8263 fix(codex): launch Codex without its paste-burst guess outside Windows (#35975)
* 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
2026-10-29 07:45:06 -07:00
Kelvin Amoaba c5957e7d4d fix(mobile): notice a silent drop while dictating within seconds (#35834)
An overdue chunk reply now asks the connection for one decisive liveness
probe instead of waiting for the idle watchdog, so the resend lands inside
the host's grace. Native clients probe directly; the OTA page asks the
shell with a new notify that older shells refuse with a diagnostic only.
2026-10-29 14:32:59 +00:00
Kelvin Amoaba 558be9909c fix(mobile): resend dictation audio lost when the connection drops (#35777)
* 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
2026-10-29 14:25:38 +00:00
Kelvin Amoaba 25bd428976 feat(mobile): stop tap-mode phone dictation after a minute of silence (#35716)
* feat(mobile): stop tap-mode dictation after a minute of silence

A forgotten mic kept recording and held the screen awake until stopped. Hold mode is left alone: a finger on the button isn't a forgotten mic.

* fix(mobile): time dictation silence from the last speech window the meter measured

* refactor(mobile): simplify the dictation silence timer
2026-10-29 14:24:18 +00:00
OrcaWinandOrcaWin c40f32163e fix(mobile): translate coded generation failures and counted chat copy (#35923)
- Commit-message generation keeps the host's optional errorCode, errorParams and
  errorDetail and translates every known text-generation code, matching desktop's
  rules: unknown codes, older hosts or missing values show the host's English
- Background tasks, subagent groups, the model label and agent-session write
  notices use localized mobile adapters instead of the shared English sayers

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 04:39:23 -07:00
Brennan Benson 2926b6e713 fix(native-chat): preserve models missing from provider listings (#35266)
* fix: separate chat option input from inventory observations

* fix: preserve scoped chat choices and publication ownership

* fix: complete scoped catalog and applied control ownership

* test: make catalog fixture dependency boundaries explicit

* test: request catalog discovery explicitly in demand contracts

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

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

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

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

* Preserve Claude effort validation advice through chat rejection

* test: align refresh mocks and preserve fixture type evidence

* fix: share catalog claims only across equivalent owners

* test: use typed catalog corpus instrumentation

* fix: consolidate structured launch imports

* Validate SDK queue regression envelopes without assertions

* fix: complete catalog runtime and fixture type contracts

* Align native option fixtures with explicit discovery and applied facts

* Keep initial compatibility catalog reads on held memory

* Complete the installed catalog fixture envelope

* Observe learned defaults after asynchronous projection settles

* Consolidate host fixture journal type imports

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

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

* test: load rejection wording before timed queue regression

* Fix catalog fixtures and queued option snapshot typing

* Align permission publication fixture with passive option reads

* Separate startup config from held turn permission fixture

* Align input lifecycle fixtures with sparse applied choices

* Simplify scoped catalog refresh ownership and coalesce cache snapshots

* Load catalog persistence real-module fixture during collection

* Compose catalog availability fixtures from valid session records

* Align catalog and startup fixtures with current option contracts

* Fix permission read types and separate catalog fixture preparation

* Align option and restart fixtures with current lifecycle owners

* test(mobile): retain reported model alongside discovery

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

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

* Preserve failure causes and correlate model rejection notices

* Cover catalog omissions and explicit model defaults in client hooks

* Keep ACP model refusals on the generic rejection path

* Include model failure copy in the runtime English catalog

* Align model retention tests and bound result correlation work

* Use checked array access in result correlation contract
2026-10-29 00:44:31 -07:00
Neil 78f2b32420 refactor: group native-chat merger with pair-window spec (#35714) 2026-10-29 00:28:27 -07:00
Brennan Benson 85a1d7ba04 Keep action model and effort choices out of Arguments (#34275)
* 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
2026-10-29 00:23:23 -07:00
OrcaWinandOrcaWin 4a5e10223d fix(editor): highlight Justfile recipes and mobile HCL assignments (#35573)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 21:39:54 -07:00
Neil 55f53280d8 refactor: group native-chat href routing (#35654) 2026-10-28 21:39:43 -07:00
OrcaWinandOrcaWin 0699da6143 fix(mobile): stop file save follow-ups after Discard (#35537)
* fix(mobile): retire file save continuations when preview closes

* fix(mobile): retire file saves only on unmount, warn when Discard interrupts a save

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 21:31:33 -07:00
OrcaWinandOrcaWin 646eeef55a fix(mobile): release metadata for retired terminals (#35535)
* fix(mobile): prune metadata for retired terminal handles

* test(mobile): give the terminal-inventory recording adapter the pruned caches

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 21:31:29 -07:00
OrcaWinandOrcaWin c84cca5ce1 fix(mobile): retire closed-tab composer state (#35589)
* fix(mobile): retire closed-tab composer state

* Require confirmed tab retirement before composer cleanup

* fix(mobile): keep drafts of tabs the host has not listed yet

Optimistically created tabs can precede their host listing, so an accepted inventory without them must not retire their composer state.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 21:15:56 -07:00
OrcaWinandOrcaWin 1a03d59ea4 fix(mobile): release retired route storage mirrors (#35586)
* fix(mobile): release retired route storage mirrors

* fix(mobile): keep route hydration through unrelated writes and route changes

Stamp writes per owned key so an unrelated write no longer voids a cold
route's hydration into host-profile-unreadable, and retain the next
route's keys before releasing the previous route's so shared host-wide
keys stay mirrored.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 21:15:44 -07:00
OrcaWinandOrcaWin c8f22c9dcb perf(mobile): skip model projection after discovery owner retires (#35540)
* perf(mobile): skip model projection for retired discovery owners

* test(mobile): drop spy-only model discovery projection test

Existing hook suite already covers stale-result exclusion; the new file only asserted a namespace spy call.

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 21:15:38 -07:00
Kelvin Amoaba ad2cce3af3 feat(mobile): show a voice meter and timer while dictating, with start and stop haptics (#35500)
* feat(mobile): show a voice meter and timer while dictating, with start and stop haptics

The phone meters the PCM it already streams with desktop's analyzer,
now shared from src/shared, so both shells get a level without a native
event crossing the page bridge. Recording start and stop tap the phone,
iOS now allows haptics during input, and "Dictation inserted" only
shows for live terminal input, where the text can be hidden.

* refactor(mobile): keep the dictation hooks under the line cap after #35502

Moves the start tap and stop tick into useMobileDictationHaptics and shares one current-finish guard in finishDictation.
2026-10-29 04:13:09 +00:00
OrcaWinandOrcaWin a99bc36593 feat(mobile): localize tasks, new workspaces and source control (#35646)
* feat(mobile): localize tasks, new workspaces and source control

Moves the last ~670 strings (task lists and boards, issue and PR sources, the
new-workspace flow, and source control) to the translation API, with all ten
translations. What remains in the coverage baseline is reviewed non-copy: key
names, schema errors and log lines.

- Source control section titles recompute on a language change

* fix(mobile): align catalog terminology across screens

A whole-catalog pass per language reconciled terms that differed between batches
(host/desktop, dictation, transcripts, address form) with the glossaries and the
desktop catalogs. The page bundle verifier now reports catalog bytes separately.

* fix(mobile): keep fetched history and source error slugs language-independent

History rows are derived from the fetched page at render so relative times follow a
language switch; quality-gate follow-ups for the tasks and source control migration.

* fix(mobile): name Android notification channels in the UI language

* chore(mobile): drop catalog entries for removed source-control copy

* fix(mobile): re-localize the composer source hook on current main

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 21:11:04 -07:00
OrcaWinandOrcaWin d8eef80bf4 feat(mobile): localize sessions, terminal, agent chat, browser and files (#35553)
Moves ~970 strings in session screens, the terminal, agent chat (including the
copy mobile used to render straight from shared English records), the browser pane
and the file explorer to the translation API, with all ten translations.

- Chat tool-run sentences, task lists, receipts, notices and turn status take
  translated words; the shared sentence joiner accepts an optional continuation so
  German nouns and Turkish casing survive mid-sentence (desktop unchanged)
- "Used the browser" vs "… 21 times" and resolved PR comment headers use explicit
  keys instead of plural rules, which would drop the count for Russian 21, 31, …
- Action sheet rows carry stable ids instead of being keyed by translated labels
- Rename inputs keep the raw title rather than a translated placeholder

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 03:55:41 +00:00
Jinjing bc55fe3cb0 Support explicit remote branch reuse across workspaces (#34295)
* Support explicit remote branch reuse across workspaces

- Preserve selected branch identity, tracking, and busy-branch handling
- Add explicit branch-off intent with v2 runtime capability gating

* Style existing workspace action in branch reuse UI

* Preserve explicit branch reuse with versioned host support

- Gate strict reuse on a new request capability while retaining legacy behavior
- Warn when a reused remote branch cannot be configured as the push upstream

* Clarify selected branch checkout options

* Offer existing or new branch choices for worktrees

* Preserve new-branch intent when reusing a branch name

* Adapt branch composer tests and catalog after rebase

* Refresh mobile RPC recordings for branch intent capabilities

* Remove retired Russian localization entries

* Remove retired German and Turkish localization entries

* Add branch selection translations for existing workspaces

* Localize mobile worktree branch selection
2026-10-28 20:48:16 -07:00
OrcaWinandOrcaWin d5e2c0b169 fix(mobile): refresh custom shortcuts when returning to a session (#34951)
* fix(mobile): refresh custom shortcuts when returning to a session

* fix(mobile): adopt accepted custom-key writes while the session is mounted

A focus or foreground reread could land between queued Settings writes and
keep an intermediate list. Subscribe to accepted writes, and fold the refresh
regressions into the existing lifecycle test fixture.

* test(mobile): type session scope custom keys without an assertion

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:35:39 -07:00
OrcaWinandOrcaWin 29e6910efc fix(mobile): retire obsolete file preview reads and grant retries (#34872)
* fix(mobile): retire obsolete file preview reads and grant retries

* fix(mobile): keep the post-refresh preview read as the one applied read

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:35:35 -07:00
OrcaWinandOrcaWin 5d235b624d fix(mobile): preserve text size selected during hydration (#34846)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:35:30 -07:00
OrcaWinandOrcaWin 18490c8395 fix(mobile): index cached workspace rows for failed servers (#34843)
* fix(mobile): index cached workspace rows for failed servers

* test(mobile): fold server-workspace fallback regression into existing suite

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:35:26 -07:00
OrcaWinandOrcaWin 14edd54f3f fix(mobile): retire browser pointer queues with their pane (#34825)
* fix(mobile): retire browser pointer queues with their pane

* test(mobile): use T[] array types in pointer retirement test

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 20:35:22 -07:00
Kelvin Amoaba 26aa174b3b feat(mobile): show dictated words as you speak and insert them at the cursor (#35502)
* feat(mobile): show dictated words as you speak and insert them at the cursor

Newer desktops already send the text so far with each audio chunk reply;
the phone now shows it: grey in the chat composer or command field where
it will land, and on the live-input status row. The final transcript
replaces the selection the field had when recording started, and is
appended when the field was never focused or changed since.

* refactor(mobile): pass the dictation preview by context and split its hooks out

The preview reaches composers through a context instead of four layers of
props, and the composer's and session's dictation logic move into their
own hooks, which keeps each file under its line cap.

* fix(mobile): keep dictation selections and live words to their own terminal

* test(mobile): keep the composer dictation test typechecked and under the line cap

* fix(mobile): keep the chat field controlled while dictation previews over it

The native composer field swapped its value for rich-text children while
showing heard words, so Android could duplicate or drop typed characters and
selection offsets could drift from the draft. Draw the preview as a hidden-
from-accessibility overlay shared with the web field, and only hide the
field's own text.

* refactor(mobile): build the dictation route context beside its destination

Keeps the session dictation hook under the line cap after rebasing onto main.

* fix(mobile): land dictation where its preview showed after switching chat or terminal

The final words now go to the target captured at start: the chat it began
in (its own draft when another chat is showing) rather than whichever
surface is visible. The command field preview only uses the saved selection
in the terminal it was read from, so it shows the words appended in another
terminal, as they will land.

* fix(mobile): send terminal dictation to the chat that replaced its terminal

Routing only by the captured target dropped the words when a chat tab
replaced the terminal mid-dictation, since no terminal draft was left to
take them.
2026-10-29 03:26:21 +00: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
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
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
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
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
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
Kelvin AmoabaandNico Hu 18c4e6bc47 feat(mobile): give chat code, tables, quotes and diagrams a clearer layout (#34456)
Code blocks get a header with the language and copy button, syntax
colours from the file reader's highlighter, a line-number column and
horizontal scrolling. Short tables fill the message width, cells get more
room, quotes sit on a panel, bullets are dots, and Mermaid diagrams use
the app's borders and type.

Co-authored-by: Nico Hu <haoyu.hu@lexmount.com>
2026-10-29 01:36:56 +00:00
Kelvin Amoaba f640517132 feat(mobile): show chat images that live on the paired desktop (#34462)
* feat(mobile): show chat images that live on the paired desktop

* fix(mobile): read every image type desktop chat shows

* refactor(runtime): share the bounded preview read and chat-image type check

* test: keep the chat-image tests typed and off importActual
2026-10-29 01:27:57 +00:00
NeilandClaude c14c99bb49 feat(wsl-host): a paired phone reaches the desktop's WSL host and never starts its distro (E6) (#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 (#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 (#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>
2026-10-28 18:23:02 -07:00
OrcaWinandOrcaWin 5ed3c8c072 feat(mobile): localize shared components, pull requests and diff review (#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>
2026-10-28 18:17:58 -07:00
OrcaWinandOrcaWin ccd0829e6f feat(mobile): localize app screens, settings, pairing and host lists (#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>
2026-10-28 18:03:37 -07:00
NeilandKelvin Amoaba 5470ff907c fix(mobile): stop review notes from disappearing or coming back after deletion (#31699)
* fix(mobile): stop review notes disappearing or coming back after deletion

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-10-29 00:40:56 +00:00
Kelvin Amoaba 785cd30ee9 chore(mobile): bump to 0.0.60 and Android versionCode 24 (#35505) 2026-10-29 00:39:21 +00:00