Commit Graph
1710 Commits
Author SHA1 Message Date
Kelvin Amoaba 2e6d66077f fix(mobile): keep Resolve and its feedback after the PR tab's conflicts box went away (#37234)
The diff-review dock has no next-step bar, so its bottom action now offers
Resolve with <agent> for a conflicting pull request, with the launch notice.
In the hub the bar shows its agent launch notice on the Pull request tab
too, since the removed box was the one that showed it there, and an Unlink
failure reaches the bar's notice now that the PR tab has no footer.
2026-11-01 23:55:20 +00:00
Brennan Benson 9b15222da6 Keep OpenCode's default effort visible after a reply (#37159)
* Show the native default effort for OpenCode models

* Show the effort OpenCode 1.x actually runs when none is picked

OpenCode 1.x ACP runs a listed default variant, else the first listed
one, so declare that same variant instead of a no-override Default. The
draft and launch default stay as on main; the resting fallback now shows
it too. Shared declared-effort consumers expect no effort for a readback
without that model's menu.

* Name the recorded OpenCode listing test for what it checks
2026-11-01 15:51:59 -08:00
Kelvin Amoaba 03abca65dc feat(mobile): outline every text field at 3:1 with a focus ring, and drop the composer shadow (#37221) 2026-11-01 23:39:33 +00:00
Kelvin Amoaba 56e83655b0 fix(mobile): one bottom action on the PR tab, and conflicts said once (#37231)
The Source Control hub's next-step bar is now the only bottom action on the
PR tab: the tab body takes its footer from the caller, and only the
diff-review dock passes the old bottom action. The legacy Conflicts box is
gone, since the gate row and the bar's Resolve already cover it, so a
conflicting PR no longer says so four times. The bar keeps its reason line
only where its button does not name the blocker.
2026-11-01 23:36:51 +00:00
Kelvin Amoaba f7047a8fc7 feat(mobile): redesigned Changes tab with file-first rows and swipe to discard (#37214)
Rows lead with the file name and put its folder under it, so names stop
truncating. The whole row opens the diff, one quiet button stages or
unstages, and discard moves to a left swipe that still asks first. A
status line, a Commits row and a conflict banner with Abort sit above
Uncommitted and Staged sections that carry Stage all and Unstage all.
The rarer git actions move into the header's grouped menu.
2026-11-01 23:17:10 +00:00
Kelvin Amoaba f41f72a4f3 fix(mobile): keep the image viewer's close button out of the iPhone Duo status column (#37203)
The close button sat at a fixed 16pt from the right edge and ignored the
window's right safe-area inset, which on the iPhone Duo is the status
column holding the clock and the camera. Offset it by that inset, and size
it to 44pt itself because page Pressables ignore hitSlop.
2026-11-01 22:49:46 +00:00
Kelvin Amoaba 7f9940e937 fix(mobile): show the folder icon when a project image fails to load (#37202) 2026-11-01 22:43:03 +00:00
Kelvin Amoaba ac99f1cb39 fix(emulator): list only the worktree's attached emulators, iOS and Android (#37127)
* fix(emulator): scope emulator list to the worktree's sessions

emulator list ignored --worktree and returned serve-sim's global iOS helper list. It now lists the session registry's attached sessions (iOS and Android) for the selected worktree, or every worktree's for --worktree all.

* fix(emulator): drop stopped devices before listing sessions

* fix(emulator): point the no-active hint at emulator devices

* test(emulator): assert list results, not serve-sim calls

* refactor(emulator): prune stopped devices inside the registry listing
2026-11-01 21:34:03 +00:00
Kelvin Amoaba dc5cfd945d feat(mobile): keep the PR tab live, show each thread's code and ask the agent to fix bot findings (#37023)
The PR tab and the Checks and Comments screens refresh by themselves while
they are open and the app is in the foreground, on desktop's checks-panel
cadence (policy moved to src/shared). A failed background read keeps the
PR on screen and backs off instead of replacing it with an error.

Review threads show the lines they are about: the host forwards the tail
of each thread root's diff hunk, and mobile numbers it back from the
thread's line. Bot findings get "Ask <agent> to fix", which launches
desktop's Resolve comments prompt (moved to src/shared) for that thread.
Fix and Ask buttons name the agent that would start.
2026-11-01 21:23:53 +00:00
Kelvin Amoaba ebe94bc32e feat(mobile): rebuild the PR tab around what is blocking the merge (#36999)
The PR tab now leads with the PR's identity, one row per merge gate
(checks, unresolved threads, approvals, conflicts) that opens the screen or
sheet that resolves it, a changes card and a collapsed description. Close,
Unlink, Auto-merge, Edit title and Copy link move into the ⋯ menu.

Checks and Comments become pushed screens: failures open with their
annotation and Fix / Rerun / Open / Log on the failure, running checks
next, passed folded; comments filter by Unresolved / All / Hide bots with
Resolve and Reply on each thread and a comment box at the bottom.

Merge opens a sheet that lists only the methods the repo allows, starting
on its default. Reviewers move into a sheet with search to add and remove.

Every Create PR entry point opens one sheet: title and description seeded
from the branch's commits (shared seed rule in src/shared, GitHub's own
default), Write with AI, base picker and draft. It pushes first when
needed, works for all five providers and lands on the PR tab for GitHub.
2026-11-01 21:08:49 +00:00
Brennan Benson 42bdeffbe4 Move chat readers to the newest saved step after a no-op save (#37118)
* fix(chat): move forward readers to the covered tip after a no-op save

A write whose fold changes nothing stores no outcome record, so its
sequence never appears in a forward read. Readers placed themselves at
the last returned row and stayed behind the live cursor, so open chats
re-read an empty page and recomputed the prompt projection on every
later delivery until the next real save.

Forward journal reads now report the highest sequence they covered.
History pages move there when the read was complete, prompt reuse and
native responses compare against it, and a read cut short by its limit,
byte budget or damage still stops at the last returned row.

* fix(chat): append unlimited outcome reads without spreading, and report coverage from the mobile journal fake

* fix(chat): skip the retention scan for batches that change no journal items
2026-11-01 12:48:36 -08:00
Kelvin Amoaba 78484aac31 feat(mobile): one next-step bar under both Source Control tabs (#37104)
* feat(mobile): one next-step bar under both Source Control tabs

Changes and Pull request are the only segments. A bar at the foot of both
shows the branch's one next action: the commit box, push or pull, create
the review, resolve or fix with the workspace's agent, merge when ready,
merge, or why it can't. Commits opens as a pushed screen.

* fix(mobile): keep Merge reachable and show bar failures on both tabs

* test(mobile): expect the two Source Control segments in the page render test
2026-11-01 20:17:11 +00:00
Brennan BensonandClaude Opus 5.5 ad864a6ec7 Show a card in the chat when its agent hands work to another agent (#36848)
* Show a card in the chat when its agent hands work to another agent

An agent that hands work off with 'orca agent launch' from a native chat
now leaves a 'Handed off to agent' card there, linking to the new chat or
terminal, the way a supervised worker-start leaves 'Started worker'.

The CLI names its chat on agent launches (same-host only); the host records
a display-only agent-handoff item after a successful launch with a submitted
prompt, once per launch operation. Nothing about the card can refuse or delay
the launch.

Tracked in STA-13209.

* Keep orca commands working in a native chat that has no terminal handle

The launch-caller evidence read the host stamp off an absent evidence object, so every orca command from an ordinary native chat threw before sending. Adds CLI tests for which requests name the launching chat, restores the lockfile to the base, and fixes the Korean heading.

* Read a card's heading from its creation flags together

A caller passing only the started flag drew a handoff as Started worker; the heading now takes the message's flags as one argument.

* Show the handoff card for every agent a chat launches

A launch without a delivered task now records the card too, with no task text, as the common pattern records every agent a chat creates. The handoff tests now run the real chat host and journal: one card per launch operation, none on replay, a removed card stays removed across a restart, and the clock is fixed.

* Head a launch card Started agent when no task reached the new agent

Handed off to agent now appears only when the card carries a task; a card for an agent started with no task (no prompt, a draft, or a prompt that wasn't delivered) reads Started agent. The heading is derived from the card's text, so nothing new is saved. Also drops a self-launch check the launch path already refuses first.

* Show the handoff headings on the phone's agent cards

The phone card passed only the started flag, so with the new heading rules it would draw every creation card as a plain message. It now passes the message and has a heading for every case, so a missing one fails the build. The heading function now requires the message's creation facts, so no caller can leave them out. Adds the phone strings in every language, and the Japanese "Started agent" now uses the catalog's term for agent.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-01 12:08:34 -08:00
Neil 5228bff55c refactor(mobile): group web bundle transfer owners (#37124) 2026-11-01 11:43:21 -08:00
Kelvin Amoaba bf48d6665f feat(mobile): a commit's files open in the diff screen (#37113)
Tapping a file on the commit page now opens the shared diff screen for
that file in that commit (openDiffForFile kind 'commit'), in today's
Commits tab and inside the hub's Commits page.
2026-11-01 19:41:06 +00:00
Kelvin Amoaba a3efdcb21b feat(mobile): GitHub review threads, viewed sync and line comments on the diff screen (#37073)
* feat(mobile): GitHub threads, viewed sync and line comments on the diff screen

Committed files of a GitHub pull request now show its review threads under
their lines with Reply and Resolve, take their viewed state from GitHub and
sync the checkbox and Viewed · next file back through setPRFileViewed. A tap
or a long-press drag picks lines and opens a sheet that sends the note to
the workspace's agent through the existing send path, or posts it as a
review comment. Threads and GitHub comments appear only while the local
branch is at the PR head, the same contents desktop shows them on;
otherwise the file says to push. openDiffForFile takes an optional line for
a thread's Open in diff.

* test(mobile): use a type import for the line-mutations recording adapter

* fix(mobile): name the staged or unstaged side in the jump sheet's file labels
2026-11-01 18:38:23 +00:00
Kelvin Amoaba 24e7a0ba69 feat(mobile): list only this branch's commits, with a page per commit (#37050)
The Commits list now stops where the branch left its base. It groups
commits into Not pushed (hollow dots, with Push) and On origin, ends at
"Branched from <base>" with Update branch, and loads more past 50. A
commit opens its own page: message, author, date, pushed state, files
with +/-, and Copy SHA / Open on GitHub in the menu.

Older hosts ignore the new params, so the list falls back to the full
history without groups or the base marker.
2026-11-01 18:38:17 +00:00
Kelvin Amoaba 3edc370cdf feat(mobile): diff screen with jump to file, folded context and viewed/stage next (#36998)
The review screen becomes the one diff screen from the approved design.
It walks the Changes section the file came from (uncommitted, staged or on
the branch) or one commit's files, so 'N of M' and next/previous stay in
that list. The title opens a jump-to-file sheet built on the shared
source-control tree, with search and viewed boxes. Unchanged runs fold the
way desktop's diff does. The bar's main button is Stage · next file for
uncommitted files and Viewed · next file otherwise; Discard and Unstage move
to the menu. Filter chips, hunk jumps and Stage Reviewed are gone.

openDiffForFile also takes { kind: 'commit', commitOid, filePath }, read
through git.commitCompare and git.commitDiff.
2026-11-01 18:07:43 +00:00
Kelvin Amoaba 2e1f439620 feat(mobile): open every changed file on the diff screen (#36937)
Source Control rows used to open a file three ways: the review screen, a
desktop editor tab the session then switched to, or a text-only branch
drawer. Every row now calls one openDiffForFile entry point that pushes the
review screen. The drawer, the session tab reveal and their handlers are
gone; Open in Session stays in the review screen's menu.
2026-11-01 17:53:52 +00:00
Neil a82538c3be refactor(runtime): organize session records and runtime modules (#37070) 2026-11-01 08:59:05 -08:00
Kelvin Amoaba d6f54f3561 fix(mobile): size the queued-message panel to its rows and fit translated Save/Cancel (#36928)
The queue card's invisible full-text line-count probe overflowed its two-line
row and stretched the queue's scroll range far past the real rows. Clip it to
the card text.

The queued-message editor drew Save and Cancel labels inside 38pt round icon
controls, so translated labels spilled over each other. They are now pills that
hug their label and truncate only when the row runs out of room.
2026-11-01 15:50:58 +00:00
Kelvin Amoaba ba0ebfa010 fix(native-chat): show images agents read, and markdown images on mobile (#36953)
A Claude Read of a PNG returns only base64; the path is on the call. A shared
rule turns each finished file-read of a raster image into an image-ref under
the tool run header on desktop and mobile. Mobile chat prose now draws
https, data and absolute-path markdown images inline, every image in a
paragraph, through the existing host image read.
2026-11-01 15:50:29 +00:00
Kelvin Amoaba 0d724378df feat(notifications): separate agent needs-input alerts from finished alerts (#36941) 2026-11-01 15:46:46 +00:00
Kelvin Amoaba 77db0c2000 fix(mobile): build iOS from checkout paths with spaces (#37058)
* fix(mobile): quote expo-constants iOS build paths so checkouts with spaces build

Backports the expo-constants 58 quoting of the app.config build phase
(podspec bash -l -c argument and basename $PROJECT_DIR) to 55.0.17.

* fix(mobile): quote react-native-xcode.sh call in the iOS bundle phase

Expo SDK 55's template leaves the command substitution unquoted, so the
Bundle React Native code and images phase splits a checkout path with a
space. Expo's SDK 58 template applies the same quoting.
2026-11-01 15:43:35 +00:00
Kelvin Amoaba 17a43f64c3 fix(mobile): scroll wide tables sideways in the rich Markdown editor (#36966)
* fix(mobile): scroll wide tables in the rich Markdown editor instead of squashing columns

* fix(mobile): keep CJK table columns from shrinking to one character
2026-11-01 15:40:38 +00:00
Kelvin Amoaba 397d4443bd fix(mobile): keep focus when Android hides the keyboard for a tapped autocorrected word (#36947) 2026-11-01 15:40:25 +00:00
Neil 1ad332d8a9 refactor(mobile): organize native chat view and transcript owners (#37054) 2026-11-01 07:38:29 -08:00
Kelvin Amoaba 7e935c5961 fix(mobile): keep the app's state and layout when entering split screen on Android (#36977)
* fix(mobile): keep Android split screen from restarting or squeezing the app

One UI gives a split-screen pane its own density. Android recreated
MainActivity on that change, and React Native seeds its display metrics
from the application context, which keeps the full-screen density, so
the pane was laid out at the wrong scale. A config plugin declares
density in configChanges and re-seeds the metrics from the activity.

* fix(mobile): catch React Native's rotation re-seed before the frame draws

A one-shot listener added on configuration change missed a cold start or
a 180-degree flip at a non-zero rotation, where React Native's root view
re-seeds from the application context without a configuration change.

* fix(mobile): publish re-seeded display metrics in one step

Text measurement reads the holder off the UI thread, so build the
pane-density screen metrics before publishing them.
2026-11-01 15:16:27 +00:00
Kelvin Amoaba 2eb80fb8a0 fix(mobile): show workspace images in session Markdown tabs (#36970)
* fix(mobile): show workspace images in session Markdown tabs

* fix(mobile): show workspace images restored by undo or paste

* fix(mobile): keep session image loader current and inside the workspace

* fix(mobile): classify entity-encoded image URLs by their decoded scheme

* refactor(mobile): classify editor images with the shared Markdown href router

* test(mobile): expect workspace image markup in the code-block selection check
2026-11-01 15:13:22 +00:00
OrcaWinandOrcaWin 0646d26ff0 test: remove 157 low-value tests and route-contract suite (#37038)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-01 14:07:39 +00:00
OrcaWinandOrcaWin 70256eab83 test: remove 181 low-value tests and 2 suites (#37024)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-01 13:09:05 +00:00
Neil 89f9ce08de refactor(shared): organize session contracts and projections (#36979)
* refactor(shared): organize session contracts and projections

* chore: tighten dropped-path flaky pattern allowance

* docs: preserve current agent instructions with valid formatting
2026-11-01 03:14:46 -08:00
Kelvin Amoaba 4e2fcfe99c fix(mobile): send iPhone library photos as JPEG named .jpg, not HEIC named .png (#36989)
* fix(mobile): save iPhone library photos as JPEG named by their bytes

The iOS photo picker handed back the asset's HEIC bytes as-is, and the host
named every pasted image .png, so agents read a HEIC file as a PNG and failed.
Ask the picker for the compatible representation (JPEG), and name pasted
images by their signature so the extension always matches the bytes.

* fix(mobile): keep unknown pasted bytes on the .png name

A .heic name falls outside the shared image MIME table, so chat previews
and agent prompts would drop the image. The picker now sends JPEG, so
leave HEIC detection out.

* refactor(mobile): keep the pasted image extension list module-private
2026-11-01 10:32:11 +00:00
Kelvin Amoaba ff54751393 fix(mobile): render inline HTML cards and previews on iOS (#36986)
The iOS web shell cancelled every subframe navigation, including the sealed about:srcdoc frames that HTML previews and chat visual cards render in, so they stayed blank. Allow exactly about:srcdoc subframes, let only a main-frame load spend the shell-load allowance, and never fail the shell document over a subframe response. Chromium never asks the Android shell about about: subframes, so Android already renders them.
2026-11-01 10:26:19 +00:00
OrcaWinandOrcaWin 321574af87 fix(native-chat): steer async question answers instead of queuing duplicates (#36917)
* fix(native-chat): stop async question Submit from queuing duplicate answers

When the agent is mid-turn, answering a Codex async question queues the
answer as an ordinary message. The card stayed up until a transcript row
retired it, which a queued message never posts until the turn ends, so
every Submit queued another copy. Hide the occurrence once its answer is
queued, on desktop and phone.

* fix(native-chat): steer async question answers into the running turn

An answer to the agent's own mid-turn question belongs to that turn.
Queuing it behind the follow-up setting held it until the turn ended,
after the agent had already proceeded without it. Send it with the
steer intent whenever the follow-up resolver would queue a plain send,
on desktop and phone. Stop and a waiting command still queue, and the
queued fallback still hides the card.

* fix(native-chat): hold async questions while a queued answer waits

Replace the mount-scoped hide on a queued answer with one derived from
the queue: a question stays hidden while a queued card quotes it, across
remounts, and returns if that card is deleted or edited away. Lock
Submit until the send settles, and keep a returned answer out of the
composer draft.

* fix(native-chat): keep structured session under the line cap

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-01 01:43:26 -08:00
Neil 57454e6d7e refactor(agent-session): group lifecycle records and direct owners (#36909) 2026-11-01 01:24:37 -08:00
Kelvin Amoaba ac21582b35 fix(mobile): stop the chat jumping up when history draws during an Android scroll (#36949) 2026-11-01 08:40:38 +00:00
Kelvin Amoaba 57e287b555 fix(mobile): stop the unfolded Duo crashing on split keyboard (#36948)
UIKit's split-keyboard update crashes breaking our constraints on
keyboardLayoutGuide, so the probe reads keyboardWillChangeFrame instead.
The hinge interaction goes too: UIKit already relays out a view that
read reserved regions in layoutSubviews when they change.

Fixes #36742
2026-11-01 08:37:12 +00:00
Neil 25ac6fd1cf feat(mobile): collapse sub-agent lists by default and group idle sub-agents (#36939)
* feat(mobile): collapse sub-agent lists by default and group idle sub-agents

Mobile follow-up to #36936: per-parent child disclosure with +N count and a
live-state dot when collapsed, and a quiet 'N idle' group for two or more
idle children once expanded.

* fix(mobile): keep sub-agent disclosures reachable and remembered

- Hit slop extends only downward so toggles no longer steal taps from the row above
- Disclosure state survives workspace list remounts via a bounded module cache
- Collapsed signal considers all descendants, not just direct children
2026-11-01 01:19:08 -07:00
Neil c433d58f5c test(mobile): count dictation refusals before the slot probe fills the bridge (#36938)
The free-slot probe fills every desktop slot, so end()'s final chunk forward
is refused by construction. Since #36922 reserved native slots, that final
read now succeeds and its forward is refused, failing Mobile verify under Bun.
2026-11-01 01:04:49 -07:00
Kelvin Amoaba 5eac01e224 fix(mobile): keep bridge slots for photo picks when desktop calls stall (#36922)
Desktop RPCs and on-device native verbs shared the bridge's 64 in-flight request slots on both page and shell. Unanswered desktop calls could hold all of them, refusing native.media.pick and native.media.release; refused releases stranded staged handles until expiry, so later picks hit native_media_handle_cap. Desktop calls now stop at 60 so native verbs always have the last 4.
2026-11-01 07:34:46 +00:00
Neil c1c04700bc refactor(agent-session): group failure modules and use direct owner imports (#36906)
* refactor(agent-session): organize failure owners and direct imports

* test: retain historical release paths in literal baseline
2026-10-31 23:16:07 -07:00
Kelvin Amoaba c883603c75 fix(mobile): run the repo's archive hook when deleting a workspace from the phone (#36481)
* fix(mobile): run the repo's archive hook when deleting a workspace from the phone

Mobile's delete sent worktree.rm without runHooks, so the host skipped the
orca.yaml archive hook that desktop runs. The phone now does what desktop's
ensureHooksConfirmed('archive') does: it asks to trust an unapproved shared
archive script, sends runHooks with desktop's reply timeout, and when the hook
fails it shows the host's error with Delete Anyway, which resends with
allowFailedArchiveHook.

repo.hooks now reports archiveTrust (hash and content of the shared orca.yaml
archive script, or null when none needs trust). Older hosts omit it, and the
phone then keeps skipping the hook rather than run a script it cannot check.

* fix(mobile): share one Modal for delete drawers and pin each prompt to its host

Delete's confirm, archive trust prompt and hook failure now share one
BottomDrawerModalHost so iOS never presents over a closing drawer. A pending
prompt or failure keeps the clients it started on, the row hides as soon as
Delete is tapped, repo-wide trust counts server-owned repos, and folder repos
report no archive trust since their removal runs no hook.

* fix(mobile): recheck archive trust before Delete Anyway and count server repos once

Delete Anyway goes back through the trust decision, so a script changed since
approval is asked about again. Repo-wide trust counts each server repo once
rather than once per workspace, and restoring a row never duplicates it.

* fix(mobile): honour repo-wide archive trust only with the desktop catalog loaded

Until the catalog loads, a same-id repo on another host cannot be ruled out,
so only an approval of that exact script counts. The trust drawer's actions
take the pending request synchronously so a double tap cannot both run and
skip the hook.

* fix(mobile): drop archive prompts and failures from another desktop

A trust prompt or hook failure belongs to the desktop it started on. After a
host switch it is no longer shown or acted on, so a retry can never pair one
desktop's trust with another desktop's repo catalog.

* refactor(mobile): one archive trust check and an optional drawer busy flag

* fix(mobile): file delete-failure strings under the host screen overlays

Also pins the host's archive hash as a literal digest so the node test no
longer imports renderer code.

* fix(mobile): carry delete haptics and automations onto the renamed hook trust drawer
2026-11-01 05:45:51 +00:00
Neil c0190ff9fa perf(mobile): lighter liveness probes, preview-free terminal lists, cheaper terminal gzip (#36903)
The phone's liveness probe read a full status.get (~12 KB, ~2.3 KB gzipped)
and threw it away on every idle and foreground probe. It now sends
`status.get {probe: true}` and the desktop answers `{runtimeId}` alone,
skipping the machine-name wait. status.get keeps accepting any params, as
when it declared none; older desktops ignore the flag and answer the full
status, which still proves liveness.

terminal.list takes `includePreview: false`. The phone's session inventory
and automation pane lookup never read the 300-char output tail, so they ask
the desktop to drop it; older desktops strip the unknown key and keep
sending it.

Compressed terminal binary frames now use gzip level 1. On recorded-style
terminal output it keeps 93-99% of the level-6 saving (57-95% of bytes
saved) at 1.2-4x less main-thread CPU; text replies keep the default level,
where level 1 costs ~45% more bytes on the wire.
2026-10-31 22:43:17 -07:00
Neil 64021b0f47 fix(mobile): guard catalog snapshots against late replies and trim the snapshot paths (#36902)
* fix(mobile): guard catalog snapshots against late replies and trim the snapshot paths

A slow unchanged or delta reply that predates a client switch (A→B→A)
could re-point the paired-server snapshot token at rows it no longer
matched; the next row delta then rebuilt onto the wrong base. Pending
reads now carry the token they asked with, and admit drops any non-full
reply whose token is no longer held.

Single-flight reads with one trailing join move into
WorktreeCatalogSnapshotClient.read(), so paired-server rows get the same
protection home had; home's own copy goes away. Server rows use one read
path for old and new desktops and drop snapshots for servers that leave.

The host screen asks for a first page only while nothing is shown and
the full read is not failing, and drops it on an invalid reply. The
shell no longer seeds the page with a status proven on a connection
that has since dropped.

Cleanup: drop exactActivity (unreleased; home only ranks by coarsened
activity and its exact rows defeated delta reuse), fold the legacy opt-in
check into the snapshot resolvers, remove unused worktree.ps result
types and a duplicate page subscription, and re-record the affected
RPC goldens.

* fix(mobile): keep server-row snapshots per client and skip first pages for loaded empty hosts

A shared per-host snapshot let a slow read on a replaced client reclaim
ownership from the new one, discarding the new client's reply. Snapshots
are now kept per client, and a delta rebuild retry runs only for the
current owner. An empty host that already loaded no longer asks for a
first page on every poll.
2026-10-31 22:43:13 -07:00
Neil 7d76028a5c refactor: group agent session journal and request modules (#36882) 2026-10-31 22:33:23 -07:00
Kelvin Amoaba 6aa71261b9 feat(mobile): press feedback everywhere, smoother motion, and Reduce Motion for sheets (#36885)
* fix(mobile): stop page bounce and input zoom; URL keyboard for new browser tabs

* feat(mobile): smoother motion, press feedback everywhere, reduced motion for sheets

Working rings and the tool-run pulse run as compositor animations on the
page. Sheets, the right panel, the page stack and the pager cross-fade under
Reduce Motion. The right panel shares the sheet's drag physics. The composer
cross-fades Send/Stop/Save and the mic, jump-to-latest and prompt cards ease
in, banners ease their height, and every Pressable shows a pressed state.
Pairing gets a success beat, and the clean state fades in after a commit.
2026-11-01 04:29:28 +00:00
Neil fbb3381dfe fix(mobile): give a direct handshake as long as the desktop allows it (#36864)
The phone gave a direct socket 5 s from open to authenticated, while
the desktop keeps an unauthenticated socket for 10 s. On a slow link
(a handshake is two round trips, so ~2.5 s RTT is enough) the phone
dropped the socket the desktop would have accepted, then redialed into
the same deadline forever: the 'Can't connect' loop a test documented.

Both ends now share PAIRED_E2EE_HANDSHAKE_DEADLINE_MS (10 s). A link
that needs 6 s to authenticate now connects on the first dial; one that
never authenticates still escalates the same way, 5 s later. Relay
dials are unaffected: they keep their own stage budgets and race the
direct dial after 2.5 s.
2026-10-31 21:22:55 -07:00
Neil 6df565a130 fix(mobile): keep a first open checking while its dial is still retrying (#36863)
The very first time a host is opened there is no cached page, so a
single failed dial (a 12 s connect deadline or a 5 s handshake on a
slow link) put up the offline screen, 'Connect to this host to download
the latest app', while the phone was still redialing and often seconds
from connecting.

The shell's gates now carry whether the dial is still within the
attempts the connection label calls connecting (the same three it
waits before warning). A first open keeps checking through them; when
they run out the gate verdict changes, the flow restarts and the
offline screen shows as before. A cached page still opens at once, as
today.

The download-failure decision moves to mobile-web-shell-download-failure.ts
unchanged, to keep the session reducer under the size cap.
2026-10-31 21:07:52 -07:00
Neil 782e867be5 perf(mobile): draw a host's first rows while its full catalog arrives (#36862)
Opening a host with nothing cached waited for the whole worktree
catalog before drawing a row. On a real desktop with 1,084 workspaces
that is ~153 KB compressed, about 1.2 s at 1 Mbps.

The first read now also asks for the host's first 60 rows by its own
ranking (pinned, unread, active, most recent output), ~17 KB on the same
desktop, and draws them while the list is still empty. The full catalog
replaces them as soon as it lands, as it replaces cached rows today. The
first page is never marked loaded or cached, and a failed full read
clears it so the screen still reports the failure instead of a partial
host. Hosts of every version accept the limit parameter.
2026-10-31 20:59:51 -07:00