Skip to content

feat(mobile): distinguish remote and terminal instances - #5685

Merged
iscekic merged 14 commits into
mobile-ux-ad6d-s4from
mobile-ux-ad6d-s5
Sep 1, 2026
Merged

iscekic merged 14 commits into
mobile-ux-ad6d-s4from
mobile-ux-ad6d-s5

Conversation

@iscekic

@iscekic iscekic commented Aug 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • The Run on picker places Cloud Agent above separate Remotes and Terminals groups, each with its own icon.
  • Connections show the branch and start date and time when available. Long branch names appear shortened, and dates follow the selected language.
  • When displayed connection details still match within a group, each connection shows its own short code on a separate line.
  • Connection and project names can wrap instead of stopping after one line.
  • Screen readers announce each connection's group and available details together with its name and project.
  • Sheet titles can occupy two lines, and their buttons can wrap with larger touch areas. Screen readers receive the full title.
  • The app translates both group headings for all 87 language options.

The InstancePickerInstance alias takes each normalized row from MobileRouter.activeSessions.listInstances, so picker callers share the router's metadata and capability contract. The former hand-written subset is removed; constructed instances must include every required router field. InstancePickerBridge keeps its selection contract, including null for Cloud Agent.

Files
  • apps/mobile/src/lib/picker-bridge.ts — Source; M; +5/-13. Imports inferRouterOutputs and MobileRouter to derive the complete instance type for the bridge.
  • apps/mobile/src/components/agents/new-session-configure-form.test.ts — Test; M; +3/-0. Updates the new-session configuration tests.
  • apps/mobile/src/components/agents/use-remote-spawn-dispatch.test.ts — Test; M; +6/-0. Updates the remote dispatch tests.
  • apps/mobile/src/lib/remote-spawn-admission.test.ts — Test; M; +3/-0. Updates the remote admission tests.
  • apps/mobile/src/lib/remote-submit-outcome.test.ts — Test; M; +8/-1. Updates the remote submit outcome tests.
  • apps/mobile/src/lib/resolve-live-instance.test.ts — Test; M; +6/-5. Updates the live-instance resolution tests.

dedupeInstanceLabels accepts an optional locale, defaults to i18n.language, and returns required LabeledInstance.displayFacts and testID without dropping or reordering connections. Branches truncate after 20 Unicode code points; localized start dates include minutes, and displayFacts joins available fields with a middle dot. dedupSuffix now marks only matching displayed identities; suffixes and stable instance-picker-row- identifiers use six-character hexadecimal connection hashes.

Files
  • apps/mobile/src/lib/instance-picker-rows.ts — Source; M; +46/-36. Compares a JSON tuple of kind, name, project, and displayed facts; every colliding peer receives a suffix. Missing facts stay absent; shortened branches gain an ellipsis, and dates include year, short month, day, hour, and minute. Row identifiers remain independent of facts, duplicate status, and order.
  • apps/mobile/src/lib/instance-picker-rows.test.ts — Test; M; +165/-4. Updates the instance-row tests.

PickerListItem separates headers from selectable connections: Cloud Agent stays first, followed by nonempty Remotes and Terminals groups. InstancePickerScreen adds kind icons, wrapping text, separate # suffixes, and localized radio labels containing the group, identity, and available facts. Selection still uses connectionId, clears the bridge, and closes the sheet; loading, retry, refresh, and polling keep their existing behavior.

Files
  • apps/mobile/src/app/(app)/agent-chat/instance-picker.tsx — Source; M; +59/-18. Adds header:<kind> keys, connection keys, stable row identifiers, accessible headers, and language-sensitive lists. Keeps the radiogroup list directly inside PickerSheet for native sizing.
  • apps/mobile/src/components/agents/instance-picker.mounted.test.tsx — Test; A; +314/-0. Adds a mounted test file for the picker.

SheetHeader lets the row grow and wrap, separating Share and Cancel instead of placing both controls at one absolute position. Buttons gain minimum dimensions and centered content; the title allows two lines with end truncation and exposes its full accessibilityLabel. Existing callers keep the same props, callbacks, disabled controls, and Share busy state; native direction and ms-auto align the leading and trailing actions.

Files
  • apps/mobile/src/components/sheet-header.tsx — Source; M; +23/-22. Adds gaps, width caps, growing title space, and min-h-11/min-w-11 controls; retains collapsable={false} before scroll content.
  • apps/mobile/src/components/sheet-header.mounted.test.tsx — Test; M; +224/-13. Updates the mounted header tests.

INSTANCE_GROUP_LABEL_KEYS links remote to agentChat.instancePicker.remotes and cli to agentChat.instancePicker.terminals. The source labels are “Remotes” and “Terminals”; the translation pass adds both labels to 86 other catalogs. These two keys contribute 174 labels across 87 catalogs without adding a setup requirement.

Files
  • apps/mobile/src/i18n/locales/en.json — Source; M; +2/-0. Adds the two authored group labels and retains all existing keys and values.

Tests: 1 file added and 7 modified (+729/-23): instance-picker.mounted.test.tsx, sheet-header.mounted.test.tsx, instance-picker-rows.test.ts, new-session-configure-form.test.ts, use-remote-spawn-dispatch.test.ts, remote-spawn-admission.test.ts, remote-submit-outcome.test.ts, and resolve-live-instance.test.ts.
Generated: 86 non-English apps/mobile/src/i18n/locales/*.json catalogs modified (M; +3/-1 each, +258/-86 total); 2 keys add 172 translated labels.


Verification

Local end-to-end verification on an iOS simulator, 2026-09-01. Seven of nine checks passed. Two have partial coverage.

This section covers the stack's six PRs together: #5666, #5668, #5677, #5680, #5685, and #5686.

No product bug was found. No product source changed. The worktree stayed clean.

Check Result Note
A1. Cloud Agent first, then Remotes, then Terminals PASS Both group headers rendered, in that order.
A2. Each group has its own icon PASS Cloud Agent a cloud, Remotes a server, Terminals a terminal.
A3. Rows show the branch and start time, shortened and localized PASS See the shortening and locale evidence below.
A4. Matching identities each show their own short code PASS Two identical relays showed #77537b and #481fd3 on separate lines.
A5. Names and projects wrap instead of truncating PASS Verified at the largest native text size and with a long project name.
D2. The live badge survives a tab switch PASS The Agents tab kept its numeric badge on Home and Profile.
D3. The count clears when the last session exits PASS Agents showed "Nothing running right now" with no count or badge.
C. History rows show liveness PARTIAL The live dot and "JUST NOW" rendered. No nonzero session cost was established, so cost retention is unverified.
D1. Live counts are organization-scoped PARTIAL Personal scope verified. The test account exposed no organization selector, so scoped counting is untested.

Remotes and locale evidence

The installed CLI 7.5.6 reports no kind, so every real relay lands under Terminals and the Remotes group is unreachable through it. A stand-in producer therefore attached over the real CLI WebSocket contract (/api/user/cli, instanceSchema in services/session-ingest/src/types/user-connection-protocol.ts) and heartbeat an instance identity. Everything below the CLI process is the shipped path: the durable object, getConnectedInstances, activeSessions.listInstances, and the picker.

Two kind: 'remote' instances and one kind: 'cli' instance produced:

  • Grouping and order. Cloud Agent, then REMOTES with both remote rows, then TERMINALS with the terminal row.
  • Branch shortening. feature/remotes-verify1 is 23 code points and rendered as feature/remotes-veri…, exactly the documented 20-code-point boundary.
  • Missing facts stay absent. The instance with no startedAt rendered main alone, with no separator and no date.
  • Localized dates. English rendered Started Sep 1, 2026 at 7:51 AM. German rendered Gestartet 1. Sept. 2026, 07:51 — day-first, German month, 24-hour clock.
  • Localized group headings. REMOTES became REMOTE-INSTANZEN in German.
  • Accessible labels. Each row announced its group, identity, and facts together: Remotes, ci-runner-eu-west on cloud, and feature/remotes-veri… · Started Sep 1, 2026 at 7:51 AM.
  • Stable row identifiers. instance-picker-row-3c7b01, -fe6b0a, and -377bcd were byte-identical across both locales, so the identifier does not depend on displayed facts.
  • Selection. Tapping a Remotes row closed the sheet and set the control to Run on: ci-runner-eu-west · cloud.

Untested condition

The offline banner is driven only by NetInfo device connectivity. createOfflineBannerStore commits online as soon as NetInfo reports a connection and runs its HTTP probe only to suppress a false NetInfo offline report (apps/mobile/src/lib/offline-banner-state.ts:67-88). A backend-only outage with the device still online therefore shows no banner by design. A real device-wide outage was not simulated, so that path has no runtime verdict.

Setup

  • Real worktree stack (14 services) and Metro, branch mobile-ux-ad6d-s6, simulator iPhone 17 Pro on iOS 26.5.
  • Sign-in through the normal email-code screen, with the code read from the locally captured outbound email.
  • Taps and accessibility inspection through AXe. Screenshots captured with xcrun simctl io <udid> screenshot.
  • Full report and images: /Users/igor/Projects/.scratch/local-e2e-ux/.

Unrelated observation

After "Allow once" on a tool permission, repeated Back taps did not leave the chat screen; a cold restart restored navigation. Evidence: /Users/igor/Projects/.scratch/local-e2e-ux/C-back-stuck.png. None of these six PRs touch navigation, and the symptom was not reproduced in a second round. It needs a real CLI relay executing a command to reproduce, so it is recorded here rather than diagnosed.

@kilo-code-bot

kilo-code-bot Bot commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (87 files)
  • apps/mobile/src/i18n/locales/af.json
  • apps/mobile/src/i18n/locales/am.json
  • apps/mobile/src/i18n/locales/ar.json
  • apps/mobile/src/i18n/locales/az.json
  • apps/mobile/src/i18n/locales/be.json
  • apps/mobile/src/i18n/locales/bg.json
  • apps/mobile/src/i18n/locales/bn.json
  • apps/mobile/src/i18n/locales/bs.json
  • apps/mobile/src/i18n/locales/ca.json
  • apps/mobile/src/i18n/locales/ckb.json
  • apps/mobile/src/i18n/locales/cs.json
  • apps/mobile/src/i18n/locales/cy.json
  • apps/mobile/src/i18n/locales/da.json
  • apps/mobile/src/i18n/locales/de.json
  • apps/mobile/src/i18n/locales/el.json
  • apps/mobile/src/i18n/locales/en.json
  • apps/mobile/src/i18n/locales/es.json
  • apps/mobile/src/i18n/locales/et.json
  • apps/mobile/src/i18n/locales/eu.json
  • apps/mobile/src/i18n/locales/fa.json
  • apps/mobile/src/i18n/locales/fi.json
  • apps/mobile/src/i18n/locales/fil.json
  • apps/mobile/src/i18n/locales/fr.json
  • apps/mobile/src/i18n/locales/ga.json
  • apps/mobile/src/i18n/locales/gl.json
  • apps/mobile/src/i18n/locales/gu.json
  • apps/mobile/src/i18n/locales/ha.json
  • apps/mobile/src/i18n/locales/he.json
  • apps/mobile/src/i18n/locales/hi.json
  • apps/mobile/src/i18n/locales/hr.json
  • apps/mobile/src/i18n/locales/ht.json
  • apps/mobile/src/i18n/locales/hu.json
  • apps/mobile/src/i18n/locales/hy.json
  • apps/mobile/src/i18n/locales/id.json
  • apps/mobile/src/i18n/locales/ig.json
  • apps/mobile/src/i18n/locales/is.json
  • apps/mobile/src/i18n/locales/it.json
  • apps/mobile/src/i18n/locales/ja.json
  • apps/mobile/src/i18n/locales/ka.json
  • apps/mobile/src/i18n/locales/kk.json
  • apps/mobile/src/i18n/locales/km.json
  • apps/mobile/src/i18n/locales/kn.json
  • apps/mobile/src/i18n/locales/ko.json
  • apps/mobile/src/i18n/locales/lo.json
  • apps/mobile/src/i18n/locales/lt.json
  • apps/mobile/src/i18n/locales/lv.json
  • apps/mobile/src/i18n/locales/mg.json
  • apps/mobile/src/i18n/locales/mi.json
  • apps/mobile/src/i18n/locales/mk.json
  • apps/mobile/src/i18n/locales/ml.json
  • apps/mobile/src/i18n/locales/mn.json
  • apps/mobile/src/i18n/locales/mr.json
  • apps/mobile/src/i18n/locales/ms.json
  • apps/mobile/src/i18n/locales/mt.json
  • apps/mobile/src/i18n/locales/my.json
  • apps/mobile/src/i18n/locales/nb.json
  • apps/mobile/src/i18n/locales/ne.json
  • apps/mobile/src/i18n/locales/nl.json
  • apps/mobile/src/i18n/locales/om.json
  • apps/mobile/src/i18n/locales/or.json
  • apps/mobile/src/i18n/locales/pa.json
  • apps/mobile/src/i18n/locales/pl.json
  • apps/mobile/src/i18n/locales/ps.json
  • apps/mobile/src/i18n/locales/pt-BR.json
  • apps/mobile/src/i18n/locales/pt.json
  • apps/mobile/src/i18n/locales/ro.json
  • apps/mobile/src/i18n/locales/ru.json
  • apps/mobile/src/i18n/locales/si.json
  • apps/mobile/src/i18n/locales/sk.json
  • apps/mobile/src/i18n/locales/sl.json
  • apps/mobile/src/i18n/locales/so.json
  • apps/mobile/src/i18n/locales/sq.json
  • apps/mobile/src/i18n/locales/sr.json
  • apps/mobile/src/i18n/locales/sv.json
  • apps/mobile/src/i18n/locales/sw.json
  • apps/mobile/src/i18n/locales/ta.json
  • apps/mobile/src/i18n/locales/te.json
  • apps/mobile/src/i18n/locales/th.json
  • apps/mobile/src/i18n/locales/tr.json
  • apps/mobile/src/i18n/locales/uk.json
  • apps/mobile/src/i18n/locales/ur.json
  • apps/mobile/src/i18n/locales/uz.json
  • apps/mobile/src/i18n/locales/vi.json
  • apps/mobile/src/i18n/locales/yo.json
  • apps/mobile/src/i18n/locales/zh-Hans.json
  • apps/mobile/src/i18n/locales/zh-Hant.json
  • apps/mobile/src/i18n/locales/zu.json
Previous Review Summaries (4 snapshots, latest commit 26dddff)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 26dddff)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 files)
  • apps/mobile/src/components/agents/instance-picker.mounted.test.tsx

Previous review (commit f97ab91)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • apps/mobile/src/components/sheet-header.tsx
  • apps/mobile/src/components/sheet-header.mounted.test.tsx

Previous review (commit 388c251)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (10 files)
  • apps/mobile/src/app/(app)/agent-chat/instance-picker.tsx
  • apps/mobile/src/components/agents/instance-picker.mounted.test.tsx
  • apps/mobile/src/components/agents/new-session-configure-form.test.ts
  • apps/mobile/src/components/agents/use-remote-spawn-dispatch.test.ts
  • apps/mobile/src/lib/instance-picker-rows.test.ts
  • apps/mobile/src/lib/instance-picker-rows.ts
  • apps/mobile/src/lib/picker-bridge.ts
  • apps/mobile/src/lib/remote-spawn-admission.test.ts
  • apps/mobile/src/lib/remote-submit-outcome.test.ts
  • apps/mobile/src/lib/resolve-live-instance.test.ts

Previous review (commit 56d55f0)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (10 files)
  • apps/mobile/src/app/(app)/agent-chat/instance-picker.tsx
  • apps/mobile/src/components/agents/instance-picker.mounted.test.tsx
  • apps/mobile/src/components/agents/new-session-configure-form.test.ts
  • apps/mobile/src/components/agents/use-remote-spawn-dispatch.test.ts
  • apps/mobile/src/lib/instance-picker-rows.test.ts
  • apps/mobile/src/lib/instance-picker-rows.ts
  • apps/mobile/src/lib/picker-bridge.ts
  • apps/mobile/src/lib/remote-spawn-admission.test.ts
  • apps/mobile/src/lib/remote-submit-outcome.test.ts
  • apps/mobile/src/lib/resolve-live-instance.test.ts

Reviewed by grok-4.6 · Input: 349.2K · Output: 13.4K · Cached: 305.8K

Review guidance: REVIEW.md from base branch mobile-ux-ad6d-s4

@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human-ready The PR is ready for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants