Commit Graph
1604 Commits
Author SHA1 Message Date
Brennan Benson ca84c49b35 Keep cancelled async questions hidden and show new ones (#35870)
* fix(chat): show each repeated async question

* fix(chat): keep async question identity stable across readbacks

* test(chat): preserve async question fixture types

* Keep async question cancellation scoped to individual occurrences

* Use checked types in async question test fixtures

* Share sender-aware async question retirement across chat views
2026-10-30 00:36:11 -07:00
Brennan Benson f26fb1cfda Keep async question controls available after agent notices (#35758)
* fix(chat): keep async questions open across agent notices

* test(chat): cover answering async questions after agent notices
2026-10-29 22:33:23 -07:00
Kelvin Amoaba 9b4c899dc8 feat(mobile): match every text input to the chat composer and rebuild the terminal dock (#36166)
* feat(mobile): give every text input the chat composer's look

Adds shared MessageBox, TextField and ComposerSendButton built from the
composer's own styles, and moves chat, form, search, Tasks, PR, review and
commit inputs onto them. The commit message becomes multi-line, every input
is 16pt (no page zoom on focus), and focus rings are gone. The terminal and
browser typing docks are unchanged.

* feat(mobile): rebuild the terminal dock around Keys and Message modes

Agent tabs open in Message mode, where you write in the chat composer and
Send types it into the terminal. Shell tabs open in Keys mode, where each
letter goes straight to the terminal through the live field. A pick made on
an agent tab lasts until the agent quits. The shell/agent rule is the one
keyboard dismissal already used, now shared.

The key row carries sticky ctrl, alt and shift (tap for the next key,
double tap to lock) and one arrow pad (tap a side, or hold and drag to
repeat through the existing held-key repeat). Paste, attachments, the
display width, the remaining keys and custom keys move to a ⋯ sheet. Return
in the composer adds a line; Send sends.

* fix(mobile): read arrow-pad taps from the pad and keep every key reachable from ⋯

A touch on a chevron made the icon the touch target, so the side was
measured against the icon's box and most taps read as left. The ⋯ sheet
now leaves out only the keys the current row shows, so agent tabs get Tab
and shell tabs get Shift+Tab and Enter back.

* fix(mobile): keep the last changed files clear of a growing commit box

The file list's bottom inset was a fixed 196 pt, so a commit message several lines long hid the last rows behind the commit bar. The inset now follows the bar's measured height.

* test(mobile): give the file list test its bottom inset
2026-10-30 04:51:47 +00:00
Brennan Benson a05cb89f1e Restore OMP thinking choices for non-running models (#36158)
* fix(acp): restore thinking choices for non-running OMP models

* test: cover OMP catalog persistence and menu scaling

* test: keep OMP scaling measurements in assertions

* test: load ACP fixtures before consumer tests

* test: preserve catalog source types in persistence cases
2026-10-29 21:25:58 -07:00
Brennan Benson bf3e7ed405 Show a card in the coordinator's chat when it starts a worker (#35263)
* 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

* Show newly started workers in native chats

* 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

* Use fixed timestamp in worker start context fixture

* Count fixture array reads without reflective access

* Use a typed store in runtime state fixture

* Fix worker card fixture types and CLI transport project includes
2026-10-29 20:28:54 -07:00
Kelvin Amoaba dc99281085 feat(source-control): resolve merge conflicts and complete merges from the phone (#36160)
* feat(source-control): resolve conflicts with one host operation shared by desktop and mobile

* feat(mobile): resolve merge conflicts and complete merges from Source Control

* test(mobile): pin Complete merge refusals and the older-desktop message

* fix(source-control): only resolve paths Git still reports as conflicted

* fix(source-control): refuse to keep a missing file and serialize conflict resolution per worktree

* fix(source-control): resolve only the exact conflicted path

* fix(source-control): match conflicted paths in Git's separator form on Windows and WSL

* fix(source-control): accept only the resolutions the live conflict offers

* fix(source-control): refuse to keep a both-modified file that is gone from disk

* feat(mobile): translate the merge conflict actions

* test(runtime): keep the mobile allowlist test under its line cap

* fix(mobile): let VoiceOver reach conflict action buttons
2026-10-30 03:18:48 +00:00
Kelvin Amoaba 1ed54cf4b5 fix(mobile): restore alerts without native push (#36125)
* fix(mobile): restore alerts without native push

* test(mobile): refresh notification reply matrix
2026-10-30 03:03:19 +00:00
OrcaWinandOrcaWin 6be126d65f test: remove low-value copy, layout, and equivalence checks (#36192)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 19:35:42 -07:00
OrcaWinandOrcaWin 2c4eb87240 fix(mobile): retain editor styling when switching color schemes (#35171)
* fix(mobile): retain editor styling when switching color schemes

* test(mobile): fit theme-switch harness hooks under the file line cap

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 19:28:48 -07:00
OrcaWinandOrcaWin 8a5c96349b fix(mobile): align task checkboxes with their first text line (#35157)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 19:19:51 -07:00
OrcaWinandOrcaWin 5d5073be6c fix(mobile): preserve blocks and images when formatting inline code (#35110)
* fix(mobile): preserve blocks and images when formatting inline code

* test(mobile): drop collapsed-selection inline code case

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 19:13:25 -07:00
OrcaWinandOrcaWin 3eda769de3 fix(mobile): preserve empty tasks through save and reload (#35085)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 19:02:59 -07:00
Brennan Benson b578e3012e fix(pi): the thinking menu before the first message matches the chat's (#34592)
* fix(pi): the thinking menu before the first message matches the chat's

Pi's pre-session catalog now asks Pi for its models over RPC and builds each
menu with the same projection a running chat uses, falling back to the text
listing only when Pi cannot answer over RPC.

* fix(pi): preserve remembered off effort on precise model lists

* test(pi): focus effort regression and stop fallback contracts

* test(pi): allow metadata reads between ordered option writes

* fix(pi): derive supported effort without replacing accepted intent

* test: cover host effort projection and refreshed frozen queues

* test: consolidate session option imports

* test: normalize absent catalog fixture records

* test: isolate host fixture types from client projects

* Preserve legacy effort capture for other agents
2026-10-29 18:59:25 -07:00
OrcaWinandOrcaWin 649cced481 fix(mobile): name task checkboxes from their current task text (#35081)
Task checkboxes take their own text (excluding the checkbox label, nested lists and code blocks) as an aria-label, refreshed on every change, with 'Task' as the fallback for an empty item.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 18:56:04 -07:00
OrcaWinandOrcaWin ec62243ded fix(mobile): keep table/list line breaks, item paragraphs and list code blocks through rich Markdown saves (#35259)
* fix(mobile): keep table-cell and list-item line breaks on their own source line

Table cells and list items save line breaks as <br /> (and sibling P/DIV
blocks inside an item as breaks), and reopen attribute-free <br> tokens
as breaks, so Shift+Enter or Enter no longer splits a row or ends a list.
Typed '<br>' text gets only its '<' entity-escaped, raw text newlines
become spaces, and browser caret placeholder breaks are dropped (a cell
that holds only a placeholder saves empty; a cleared item keeps a <br />
so its marker still parses).

* fix(mobile): keep fenced code blocks inside Markdown list items

Indented fences under a list item (README steps such as
'1. Install:' followed by an indented bash fence) now read as a code
block inside the item and save back under the item's continuation
indent. Only items whose continuation holds a fence change; headings,
quotes, rules and tables after the fence end the item and read as
before. Top-level and list code blocks share one PRE writer, blank
separator lines are not indented, and a fence needs no blank line
beside it so tight items stay tight.

* fix(mobile): keep caret code blocks out of the paragraph they follow

Code block with a collapsed caret after text in its block ran native
insertHTML, which merged the PRE into that paragraph as prose. Prepend
a <br> only when content precedes the caret, so block-start, empty-line
and empty-document insertions stay as they were.

* fix(mobile): keep authored runs of trailing table-cell breaks

* fix(mobile): use template literal for list code-fence probe

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 18:31:17 -07:00
OrcaWinandOrcaWin e988b5dd77 fix(mobile): preserve code, quotes and code blocks through rich Markdown edits (#35056)
* fix(mobile): preserve literal code through rich Markdown edits

* fix(mobile): preserve inline code containing backticks

* Preserve adjacent inline-code text when saving mobile Markdown

* Preserve quote paragraphs and blocks in mobile Markdown

* fix(mobile): preserve selected text when creating code blocks

* test(mobile): choose native history shortcut from browser host

* Preserve paragraph-owned mobile code blocks when saving

* Preserve code selected inside mobile headings after saving

* fix(mobile): keep code serialization space-normalized and trim review tests

- Inline code and code blocks keep turning browser-created NBSPs into spaces;
  only the reader-side entity fix is needed for literal code.
- Inline code line breaks save as spaces so table rows and headings stay intact.
- Code blocks keep trimming trailing newlines left by placeholder <br>s.
- Heading- and paragraph-owned code blocks join adjacent inline code runs.
- Empty nested quotes reopen as a plain empty paragraph.
- Trim synthetic and behavior-locking tests.

* fix(mobile): keep quoted text literal when block reading would rewrite it

Quoted list continuations and lazy lines were restructured on save because the list reader drops them; reopen quote blocks only when they save the source or the same bytes as the literal paragraph.

* test(mobile): use template literal for saved code-block markdown

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 17:38:16 -07:00
Neil 5121f25a5a perf(mobile): batch iOS push-dismissal ledger writes per page (STA-7366) (#36145)
Catch-up pages called the native ledger once per dismissal, each call
re-reading, encoding and writing the full 24h UserDefaults ledger. A new
rememberAll bridge merges a whole page in one locked read/encode/write with
identical semantics (max seq per identity, refreshed 24h expiry).
2026-10-29 17:36:12 -07:00
OrcaWinandOrcaWin 6236fdd4d7 test: remove low-value copy and CI fixture checks (#36159)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 17:20:50 -07:00
Brennan BensonandVyacheslav Scherbinin 00de405c5c fix: group Antigravity models and refresh effort choices (#34518)
* fix(acp): update Antigravity model and effort metadata

* fix: confirm ACP model families and idle option metadata

* Preserve provider-owned model and effort selection

* test: repair model option host and consumer fixtures

* Use the provider child type for optional delivery ownership

* test: match model option fixtures to their protocol contracts

* fix: isolate resting options from adapter type dependencies

* Preserve Antigravity option fixture types

* Match option fixture control response contract

---------

Co-authored-by: Vyacheslav Scherbinin <gentslava@mail.ru>
2026-10-29 16:21:22 -07:00
OrcaWinandOrcaWin 85522e89b8 test: remove low-value theme and copy suites (#36140)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 16:13:19 -07:00
Kelvin Amoaba 2e5711fcaa fix(mobile): use paired ports in firewall help (#36130)
* fix(mobile): use paired ports in firewall help

* fix(mobile): use a namespace type in diagnostics test
2026-10-29 22:55:38 +00:00
Kelvin Amoaba 7a805621b2 fix(mobile): forward iOS keys and Shift+Enter (#36120)
* fix(mobile): forward iOS keys and Shift+Enter

* fix(mobile): preserve Option text and newline mirrors
2026-10-29 22:46:04 +00:00
Kelvin Amoaba 41cd866fb1 fix(mobile): recover from native screen render errors (#36121)
* fix(mobile): recover from native screen render errors

* fix(mobile): avoid replaying launch links after recovery

* fix(mobile): discard launch intent before recovery Home

* test(mobile): correct recovery fixture types
2026-10-29 22:44:22 +00:00
Kelvin Amoaba a7c63de35e fix(mobile): return typed terminal input to the prompt (#36122)
* fix(mobile): return typed terminal input to the prompt

Phone input travels over RPC and bypasses xterm's user-input event.

Fixes #36092

* test(mobile): cover pointer queue failure retirement

* fix(mobile): preserve refused-send mutation anchor
2026-10-29 22:38:18 +00:00
Kelvin Amoaba a51164379e fix(mobile): explain scanned download QR codes (#36128) 2026-10-29 22:36:27 +00:00
Neil 6c6e6294c7 fix(sidebar): draw a cross-host project's header in each host section (#36012)
A project checked out on two hosts kept one header, placed in the host
section of its anchor repo, so the other host's rows sat under the
previous project. Project headers now carry, for each host that owns one
of their rows, that project's own registration on that host and its
counts, and host sectioning gives every such host its own copy, the way
Pinned and status lanes already split. A header never borrows another
host's or another project's registration, a hidden host that only
anchors the header no longer gets a section, and a view that ends up
showing one host still names that host's registration.

Every header inside a host section now names that section's host, and a
copy an earlier section already drew is marked repeated. When a repo id
is registered on several hosts, a copy's create button opens the
composer on its own host; header drag keys on the project's anchor and
skips repeated copies, so reordering still moves the project once; the
phone keys each copy per section while collapsing it as one. The desktop
list also resolves each row's repo by host, as the feed already does, so
same-id registrations on two hosts keep their own.

Host sectioning also stops carrying an ended project group into the next
ungrouped project, and host badge counts no longer add a project group's
project count when the group is expanded.

Fixes #35741
2026-10-29 15:32:59 -07:00
Neil c74168516b fix(mobile): update URI decoder for denial-of-service advisory (#36124) 2026-10-29 15:15:41 -07:00
Kelvin Amoaba 960332fc72 fix(mobile): keep shortcut swipes from sending keys (#36116)
* fix(mobile): keep shortcut swipes from sending keys

* test(mobile): follow array type style in shortcut tests
2026-10-29 22:12:43 +00:00
Kelvin Amoaba d5611cf274 fix(mobile): report task pages and review state accurately (#36115)
* fix(mobile): report task pages and review state accurately

* test(mobile): record task page error provenance

* test(mobile): record task page errors in reply matrices
2026-10-29 22:09:45 +00:00
Kelvin Amoaba 0a75796a03 fix(mobile): detect dead direct links in seconds (#36112)
Fixes #36093
2026-10-29 22:07:47 +00:00
Kelvin Amoaba f7bb5be8c2 fix(mobile): keep live input focus and recover failed sends (#36109) 2026-10-29 21:58:14 +00:00
Kelvin Amoaba 5ecfa8d5f5 fix(mobile): grow chat composer with its draft (#36083) 2026-10-29 21:42:39 +00:00
Brennan Benson 004907eb11 fix(sidebar): keep agent rows ordered by their session start once state history wraps (#14654)
* fix(sidebar): keep agent rows ordered by their session start once history wraps

Sidebar agent rows are ordered by the session's first reported state, read as
`stateHistory[0].startedAt`. `stateHistory` is a rolling window capped at
AGENT_STATE_HISTORY_MAX that trims oldest-first, so past ~20 transitions that
row is a recent turn: the row's identity clock silently becomes an activity
clock and busy agents re-sort themselves on every turn.

Latch the session origin in `firstStateStartedAt` when the entry is built and
read it through `agentEntrySessionStartedAt`, keeping the history lookup as a
fallback for entries that predate the field.

* test(sidebar): cover row order through activity and retention

* fix(sidebar): preserve session row order through activity and retention

* test: complete paired terminal status fixtures

* fix: carry accepted session origins across paired rows

* test: cover paired origin work and mobile action parity

* test(mobile): expect sessionLive in the phone chat identity after main's start-a-chat change
2026-10-29 14:27:16 -07:00
Brennan BensonandMerge Sim 6f99d480b3 fix(agents): stop a foreign agent name in task text from taking a pane (#19309)
* refactor(agents): extract the title name-anchoring vocabulary

Pure move, no behaviour change. The name tokens, display labels and the
bare-name/whole-title resolvers come out of agent-title-evidence.ts into
agent-title-name-anchoring.ts so more than one predicate can resolve a name to
an agent through the same implementation rather than by convention.

Nothing is added or reworded on the way out; the extracted functions are
unchanged and simply exported. Verified by the existing suites: the title,
identity and sidebar tests all pass untouched.

The identity ratchet moves with it — titleHasAgentName's two
parser-implementation callsites now live in the new module — so this commit is
green on its own rather than leaving the ratchet red until the next one.

* fix(agents): stop a foreign agent name in task text from taking a pane

A Claude pane's WORKING title is a bare braille spinner plus task text, so any
agent name inside that text resolved the title to a committed foreign identity.
The guard that fixed the mirror-image bug was written for the Claude label only,
so every other name short-circuited above it and took the pane from its owner —
the tab icon in use-tab-agent.ts, and the sidebar/dashboard row in
worktree-title-derived-agent-rows.ts, which never consulted the owner at all.

Make the rule agent-neutral in both directions: a title may only take a pane
from a known owner when it PRESENTS that agent, never when the name merely
occurs in free-form task text.

titlePresentsAgent sits beside collectAgentTitleEvidence and resolves names
through the vocabulary they now share. It differs from the parser in one
respect: the parser asks who a title names given no owner, so it must refuse
anything a task sentence could forge; this predicate is told which agent to
check, so it also accepts that one name in an identity POSITION — the whole
undecorated remainder, or the head of a `Name:` frame. The colon is what
separates `Codex: fix cursor offsets` from `Claude Code compare Opencode`.

resolveTabAgentFromSignals exists twice, already drifted in owner handling.
useTabAgent calls the copy in use-tab-agent.ts, which is what paints the tab
icon; every existing test imports the copy in tab-agent-from-signals.ts. Both
are fixed, and the new suite runs its whole contract through both so a future
divergence fails instead of hiding.

* fix(agents): let the title label map admit a missing label

Narrowing the map's value type to TuiAgent surfaced an inaccuracy that was
always there: noUncheckedIndexedAccess is off, so indexing Record<string, _>
types every lookup as a hit, and `label` is arbitrary text parsed off a terminal
title. The compiler concluded the `?? 'unknown'` fallback was unreachable and
the unknown-label comparison impossible.

The runtime disagrees — the map carries a fixed set of ~10 labels and misses
everything else. Deleting the branch would return undefined where the function
returns 'unknown' today, so the type is what is wrong. Partial<Record<...>>
makes absence expressible and leaves behaviour unchanged.

Pinned by a test, since nothing else forced the map to be honest about this.

* fix(agents): let an agent's own sigil still present it against an owner

titlePresentsAgent read only anchoredNames, so it missed the evidence class the
parser ranks highest: a vendor marker, the sigil an agent emits itself and task
text cannot forge. Gemini's four glyphs and Cursor's native literal are markers,
not anchored names, so every Gemini working, idle and permission title — and
Cursor's literal — failed the gate and the pane stayed on its previous owner.
Run Claude, let it finish, run gemini in the same pane: tab and sidebar both
stayed Claude. The bug this change exists to fix, mirrored.

Admitting the whole vendor class would have reintroduced #8940 the other way,
because Claude's '. ', '* ' and idle sigil are generic — OpenCode emits them
too — so they prove activity, not identity. hasGenericClaudeStatusPrefix already
modelled that distinction inside terminal-title-agent-type.ts; it moves to
agent-title-core.ts so both callers share the one definition.

Not isGenericClaudeStatusClaim, which is that model plus a clause for a
different question: it treats a 'claude' token as upgrading a generic prefix
into a real claim, which is right when asking whether a title may MINT Claude
identity and wrong when asking whether it PRESENTS Claude. Applied here it would
have let ". port the claude prompt" reclaim an OpenCode pane.

The predicate is now one memoized set per title rather than a memoized first
line and an uncached scan, so the common path — a title presenting nobody — no
longer re-runs the name matchers over every wrapper segment on each render.

* fix(agents): gate on one identity-frame grammar, ratcheted against the corpus

Two review rounds found the same class of defect: the gate was a second model of
"does this title present an agent", poorer than the model its callers use. Round
1 missed an evidence class, round 2 missed four whole ROUTES in a different
function. A third patch would have bought the fifth route.

getAgentLabel mints identity through routes the evidence parser cannot express,
because titleHasAgentName asks whether a name occurs ANYWHERE and never where.
One Codex branch therefore serves both 'codex working' and the mid-sentence
mention this change exists to reject. Route identity cannot separate them; the
gate genuinely needs position information the resolver discards.

So the models cannot be collapsed. What they can be is one GRAMMAR plus an
enforced agreement:

agentForIdentityFrame generalizes what isClaudeIdentityFrameSegment has always
described — a name, an optional status word, an optional '- action required' —
which was agent-neutral in shape and applied only to Claude. That was the same
one-way-guard mistake as the original bug, one level down. Generalized, it
covers every minting route: bare names, 'Codex: ...', em-dash frames, name plus
status, Windows launcher forms, '|'-headed titles and Pi's native format. The
positional and vendor-marker rules fold into it rather than stacking beside it.

terminal-title-pane-claim-corpus.test.ts is the enforcement. It sweeps the whole
classification corpus, and any title getAgentLabel still mints an identity from
must remain able to claim a pane. Shared code cannot enforce this because the
two models legitimately differ; the corpus can, and it names the offending title
when a future route is added.

Corpus: 14 lost claims before this commit, 0 after. One intended gain,
'claude.bat working', listed and explained in the ratchet: the old gate accepted
'aider.ps1 ready' for aider and refused the identical form for Claude purely
because the guard was Claude-only.

* fix(agents): stop reading a wrapper prefix as an identity frame

The head grammar treated '|' as a separator an agent puts after its own name.
Wrappers PREFIX the pane's title and the innermost title comes LAST
(terminal-title-wrapper-segments.ts), so a name before a '|' is a tmux window or
an ssh host, never the pane. `claude | zsh` on a Codex-owned pane therefore
handed it to Claude through all three consumers — this change's own bug,
inverted. Wrapper-joined titles already reach the real pane title through
getEvidenceTitleSegments' suffix splitting, which is what actually resolves
`ssh host | opencode ready`; the separator was not carrying that case.

'>' goes too. Pi's native `π > session` is matched before the head grammar runs,
so the only titles it affected were `name > text` breadcrumbs, which are closer
to task text than to an identity frame. That narrows `⠋ gemini > next steps` and
`⠋ codex > plan` relative to the previous gate; both are pinned as intended
rejections, since refusing leaves the pane with its known owner, which is the
safe direction on ambiguous evidence.

The corpus gain assertion is renamed to say it is corpus-scoped. Over every
string literal in the repo the change gains more than the one title this 67-title
corpus can see, mostly the same Claude symmetry, and the test should not read as
a global guarantee. Near-misses the grammar deliberately accepts are pinned too,
so the boundary is visible and moving it requires editing a list.

* fix(agents): admit identity frames before trusting terminal titles

* fix(agents): separate title identity from readiness policy

* Preserve title frame boundaries and normalization identity

* Preserve activity token whitespace at title wrapper boundaries

* test: expose typed mailbox idle evidence source

* test: scope title projection work contract to renderer

* test: distinguish task activity from agent identity

---------

Co-authored-by: Merge Sim <sim@local>
2026-10-29 14:26:46 -07:00
Brennan Benson 2e38249a7d Keep a chat's accepted model options in what it shows and sends (#31208)
* Keep a chat's accepted pick in what it shows and sends

A pick held while a new chat is created is committed into the chat's
active option record once accepted, through the same step a normal pick
takes, and older options reads are dropped. The host also publishes the
chat's saved effort, Fast and speed as optional status fields so another
device's pick moves the option stamp and re-reads options.

* Keep chat picks ordered and capture displayed send selection

* fix: keep chat choices in one controller with accepted input capture

* fix: pass captured Codex model input to the turn request

* Keep structured chat option pickers usable during turns

* Preserve logical selection ownership across runtime transitions

* Consolidate selection lifecycle contract coverage

* Consolidate mobile structured send imports

* Preserve legacy action outcomes and opening message identity

* Consolidate repeated selection test setup and assertions

* Fix option reset admission and preserve uncertain write notices

* fix(chat): complete option contract fixture types

* test(chat): place affinity integration in cross-layer suite
2026-10-29 14:18:23 -07:00
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