Skip to content

refactor(mobile): unify the sheet, dialog, list, image and video surfaces - #7110

Merged
iscekic merged 80 commits into
mainfrom
kwf/mobile-ui-element-unification
Oct 8, 2026
Merged

iscekic merged 80 commits into
mainfrom
kwf/mobile-ui-element-unification

Conversation

@iscekic

@iscekic iscekic commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Implements the element map and the guardrails from mobile-ui-element-unification-plan.md.

Landed: phases 1–7, the native device pass, and the visual repair pass. The earlier native pass records revision 25be7315a1. Current boundaries appear below. CI owns the full test suite.

What landed

  • Lint guardrails. no-restricted-imports bans every element the work replaces (one entry per module), including a direct @expo/ui/community/bottom-sheet import. The ratchet override is deleted — no file in apps/mobile/src imports a banned element outside the ten sanctioned paths. A new oxlint plugin, tools/oxlint/no-destructive-alert.mjs, forbids a destructive-style Alert.alert button. apps/mobile/AGENTS.md gains ## Library First and ## Unified Elements.
  • Sheets. @/components/ui/sheet wraps @expo/ui/community/bottom-sheet. The account picker, the reaction picker, the session filter sheet and the markdown table reader use it, and so do the full-window surfaces: SessionPageSheet (the session page's 14 detail sheets) and ImageViewer. They present a native window, so they stack above a formSheet route.
  • Dialogs. @/components/ui/dialog holds two surfaces: useConfirmDialog (a native sheet) and DialogCard (a portal card on @rn-primitives/dialog, for a form). All 40 destructive Alert.alert sites moved to the confirm; RenameModal and FeedbackPromptDialog moved to the card. The 33 remaining Alert.alert calls are the non-destructive confirms, which stay by design.
  • Lists. The last 9 FlatList sites are FlashList. @shopify/flash-list moves 2.3.2 to 2.3.3.
  • Images. react-native-zoom-toolkit replaces the hand-rolled gesture stack; image-viewer-modal becomes ui/image-viewer.
  • Video. expo-video renders a video file part inline.
  • Keyboard. react-native-keyboard-controller 1.22.6 and one KeyboardProvider at the app root. app-aware-keyboard-padding.tsx, app-aware-keyboard-padding-state.ts, use-composer-reveal-scroll.ts and their tests are deleted; every lift is a native KeyboardAvoidingView, the session-list bands and the toast offset read useKeyboardState, the login screen reads the provider, and the Kilo Chat list follows the newest message when the conversation screen's KeyboardAvoidingView shrinks its viewport. Nothing subscribes to React Native's keyboard events any more.

Execution boundaries

  • Session composer attachments use real signed uploads to a local authenticated S3-compatible store for native verification.
  • Kilo Chat uses real incoming attachment messages, signed downloads, native viewers, and share-sheet handoffs.
  • Actual Restart confirmations create durable commands and new local cloud/CLI sessions on both platforms.
  • Local deterministic inference proves Restart control-plane behavior, not model correctness or vulnerability analysis completion.

Temporary VM-only endpoint changes do not enter this PR. No production changes or real purchases ran.

Initial implementation verification

  • pnpm format, repo-wide oxfmt --list-different ., git diff --check, pnpm lint (0 errors, 497 rules), pnpm typecheck, pnpm check:unused — all clean.
  • Target suites pass: 396 files / 6054 tests across the migrated surfaces and everything the migration re-pointed.
  • expo export bundles iOS and Android Hermes bytecode (38 MB each), so every new import resolves under Metro.
  • expo prebuild succeeds for both platforms; expo-video and @expo/ui autolink on both.
  • expo-doctor is 19/21, the same two failures as main.

Decisions worth a reviewer's attention

  1. The confirm is a native sheet, and there is no second presentation. A portal dialog renders inside the app's React tree, so it is invisible behind a presented sheet, and a confirm is reached from inside formSheet routes (pr-merge-sheet, pr-review-submit, comment-composer, comment-edit, conversation-comment) and from message-details-sheet, which is content inside SessionPageSheet. A sheet presents its own window and stacks, so one confirm element serves every path. The cost is the shape: a destructive confirm is now a bottom sheet, the platform's own idiom on iOS, not a centred alert.
  2. keyboardInsetOffset (@/lib/keyboard-inset-offset). react-native-keyboard-controller lifts by the keyboard's overlap with the view's own bottom edge, and on Android edge-to-edge its height is the full IME inset — KeyboardAnimationCallback.getCurrentKeyboardHeight subtracts the navigation bar only when hasTranslucentNavigationBar is false, and animated.tsx forces that flag on for an edge-to-edge app. A surface whose content pads the platform inset itself therefore passes -bottom so the lift excludes it. The plain surfaces pass nothing, because their previous Android value already equalled the full IME. This is the per-site derivation the four old flags encoded.
  3. SessionPageSheet and ImageViewer moved onto Sheet at the 100% detent with no drag indicator, so ui/sheet.tsx holds both the picker sheets and the full-window surfaces. ImageViewer drops supportedOrientations: a native sheet rotates with the activity. No file imports Modal from react-native any more, so the ban carries no exception: the allowlist is ui/sheet.tsx, ui/dialog.tsx and the test globs.
  4. DialogCard is a portal card and stays behind a presented sheet. That is fine for RenameModal and FeedbackPromptDialog: every call site is a plain screen, a tab, or a portal overlay. It is recorded in AGENTS.md as a rule, with the alternative named (a formSheet route, or a Sheet) for a future surface that must stack.
  5. @expo/ui stays at 57.0.17. Its build/community and native sheet sources are byte-identical to 57.0.21 (compared the published tarballs), so the bump would buy a minimumReleaseAge exemption and nothing else.
  6. platform-filter-modal and markdown-table changed surface shape. Both use full-height native sheets. The filter uses one 100% detent to keep Cancel and Apply visible without dragging. Both add the Android top inset to clear the status bar.
  7. use-composer-reveal-scroll is deleted. The new-session composer uses the library keyboard lift. The native device pass fixes keyboard clearance and verifies Start remains reachable with a filled prompt.
  8. @rn-primitives/alert-dialog@1.5.2 ships untranspiled JSX in dist. Metro parses it for the app; no Node-side test transformer does. vitest.setup.ts stubs the primitive with the same contract so the app's dialog stays under test. The same file stubs react-native-keyboard-controller and expo-video for the same reason.
  9. Two packages sit above their Expo SDK pin, each with a minimumReleaseAgeExclude entry and an exact package@version in minimum-release-age-policy.test.ts: @shopify/flash-list@2.3.3 (one day old at adoption; carries the EngagedIndicesTracker scroll-window fix) and react-native-keyboard-controller@1.22.6 (the SDK pins 1.21.9, which predates the KeyboardChatScrollView fixes).
  10. The iOS floating-keyboard clamp is gone on the migrated surfaces. The deleted layer clamps the lift with min(screenHeight − keyboardTop, frameHeight) (keyboardPaddingFromEvent); react-native-keyboard-controller reports the raw frame height and lifts by the keyboard's overlap with the view's own frame. The two agree for a docked keyboard and for a floating one that is fully on screen; they differ only when the keyboard frame extends past the screen bottom. Worth a device check on iPad.
  11. Guards updated with the migration: minimum-release-age-policy.test.ts, single-line-input-guard.test.ts (a pinned raw input moved three lines), and alert-dialog-platform-parity.test.ts (the Profile screen's destructive confirms are the in-app dialog now).

Native device pass

Fix commits: 3ed1ff9a67, fd87eaeff0, 888d46fc3d, ad708c743f, 978d619ce5, 25be7315a1. Main merge: 4906071b08. Android runs on the development VM. iOS runs locally against the same backend.

  • Fixed blank full-screen images with measured zoom dimensions.
  • Fixed sheet dismissal/reopen ordering on both platforms.
  • Fixed title focus after native attachment and layout.
  • Fixed undersized reaction controls and profile Delete overlap with the tab bar.
  • Fixed new-session keyboard clearance and Android fullscreen text editing.
  • Removed the conversation list’s second keyboard inset.
  • Migrated remaining single-line fields to Input. Enforced zero vertical padding, Android center alignment, and iOS single-line clipping. Multiline defaults now use physical padding that Android applies.
  • Fixed disabled settings: Keep editing retains the draft and controls. Undoing the edit retries navigation.
  • Fixed the collapsed slash-menu viewport and Android command-name clipping. Native names, filtering, and selection pass on both platforms.
  • Fixed the session filter footer. A full native detent keeps Cancel and Apply visible without dragging. The Android top inset clears the status bar.

Observed final checks: 292 tests in 22 related files pass. Mobile typecheck, lint, unused-code check, and formatting pass. The final source join resolves every native proof identifier. Android has 63 semantic groups; iOS has 134 checks. All 1,176 screenshot/accessibility references exist and contain data.

Mobile CI on 25be7315a1 passes 17,183 tests in 1,111 files. The main CI workflow passes after one failed-job retry. Kilobot recommends merge; all nine valid review findings are fixed, replied to, and resolved.

The initial cloud-agent-next job hit a workerd segmentation fault. The retry passed on the same head. PR #7110 changes no files in that service. The iOS build, package, and artifact upload pass. All active checks pass on 25be7315a1.

Input proof: 22 actual class variants pass on each platform. Matching placeholder/value glyphs stay centered. Native focus/blur does not move their baseline.

Evidence: /Users/igor/Projects/.worktrees/cloud-pr7110-device-pass/.device-pass/. The 99-row source checklist covers 83 visual source files and 16 sheet consumers. It links individual platform evidence. Artifacts are not product code. The throwaway input route is removed.

The three former execution blockers are resolved. Six additional native records are in .device-pass/continuation-native-checks.json. Their related subset passes 101 tests in seven files. The iOS native Files picker remains stuck; document preview uses the existing share-staging path.

Account deletion proof covers local PENDING request enrollment and signout, not physical purge. Remediation proof covers a persisted cancellation request, not terminal job completion.

The two new analysis sessions were intentionally stopped after Restart/navigation proof, not reported as completed assessments. All temporary endpoint source/configuration and environment keys are restored. The local store and owned runtimes are stopped. The four model keys and synthetic token cache are restored.

The cached-search preview Delete path exposed a late defect. 978d619ce5 refreshes search queries through the existing session invalidation helper. Actual Android and iOS searches now remove a deleted row without manual reload. A behavioral regression fails before the fix and passes after it.

No defect reached five failed attempts. The Android slash label repair passed on attempt four. Earlier dated checks retain their tested revisions; the rebuilt iOS binary and final changed-path native smokes pass.

Complete report: .device-pass/final-report.md. Per-surface results: .device-pass/surface-results.md. Machine evidence: .device-pass/final-source-row-mapping.json and .device-pass/verification-manifest.json.

Visual repair pass — 97a253baf1

  • Reviewed 24/24 shards: 1,940 screenshots, 1,527 unique, and 413 exact duplicates.
  • Assigned all 68 observations to 21 groups. No shard gaps remain.
  • Fixed physical input padding, the Kilo Chat keyboard gap, and the empty typing-indicator row.
  • Removed duplicate notices, switch captions, profile selection, language names, PR badges, totals, and empty subtitles.
  • Fixed review summary clipping and native share destination alignment.
  • Android searchable route sheets use the existing capped full detent above the keyboard.
  • A local native safe-area provider clears direct PR entry without double-insetting presented sheets.
  • Exact auto-merge entry, ordinary merge presentation, and Cancel pass on native iOS and Android. No merge action runs.
  • A real native PUT and Retry against a loopback HTTP 503 endpoint show one error toast per attempt.
  • Failed attachment Retry and Remove remain usable. No session starts and no message is sent.

Observed related verification: 368 tests in 22 files pass. Mobile typecheck, lint, unused-code, i18n, 87 catalog comparisons, formatting, and git diff --check pass. New-head mobile and repository CI pass on 0c39bdea7b. Kilobot reports no issues and recommends merge.

Current boundaries

  • Android proves intentional account-delete signout without the duplicate expiry toast.
  • The disposable iOS account requires interactive provider consent. No consent was accepted.
  • Explicit profile selection and manual overrides pass. Android automatic bound-profile application remains unobserved.
  • The header repair passed on attempt four. Failed padding/navigation changes are removed. No defect reached five failed attempts.
  • The temporary R2 source and four owned environment keys are restored. The local store and fault server stop.
  • Both owned cache files and drafts are removed. Both apps finish on primary Personal Home.
  • No production changes, real purchases, merge actions, or branch deletion ran.

Evidence: .device-pass/visual-reaudit/finding-dispositions.json, platform *-fix-proof.json, and evidence-integrity.json. All 319 native evidence references exist and contain data. Artifacts remain outside the product commit.

CI contract cleanup — 0c39bdea7b

The first visual-repair CI run passed 17,093 tests and failed five mock-only foreground assertions. Its React Native mock lacked Platform. The wiring-only suite is removed rather than re-pinned. The retained logout and push reconciliation suites pass 45 behavior tests. Mobile typecheck, lint, unused-code, formatting, and diff checks pass. No product behavior changes in this cleanup.

The first repository CI run also hit a workerd SIGSEGV in sandbox-control-v2-runtime-proxy.test.ts. The preceding native pass observed the same crash. This PR changes no service source. New-head CI passes, including the cloud-agent-next job. No service code changes were needed.

Final current-head result — 0c39bdea7b

  • Mobile CI passes 17,093 tests in 1,110 files, plus typecheck, lint, formatting, unused-code, and i18n checks.
  • Repository CI passes all 61 jobs, including cloud-agent-next.
  • The native build gate passes; iOS and Android build jobs are skipped. Native smoke uses the current Metro source on both devices.
  • Kilobot reports No Issues Found and recommends Merge for both repair commits.
  • The iOS consent boundary and unobserved Android automatic profile binding remain explicit above.

CI evidence: mobile run, repository run, and review.

Library follow-up (2026-10-06)

Igor's library review chose these items. Each one was tried on device; a trial stays only if the device run proved it.

  • Markdown → react-native-enriched-markdown 1.1.0. Native md4c rendering replaces the react-native-marked chain (renderer, table card and reader, render cache: ~6,900 lines deleted). Tables render inline. Fences get native highlighting and a header copy button. Long-press on a fence still opens Message details (enableBlockContextMenu={false}).
    • Android, same 1,500-line fixture, 3 runs each: enriched 83/77/85 skipped frames, old chain 51/741/613. No ANR in either.
    • Untrusted images stay gated: the markdown is rewritten before the native view sees it, so an untrusted host is never fetched. The image shows as a "Load " link that runs the existing trust flow; a trusted image opens ImageViewer.
    • 1.1.0 is 4 days old; it has an exact minimumReleaseAgeExclude entry and a policy-test entry, like flash-list and keyboard-controller.
  • Mermaid → react-native-webview. A closed ```mermaid fence renders as a diagram; a load or parse failure falls back to the code block. An unclosed (streaming) fence stays code. The Mermaid 11.12.0 script ships with the app (assets/vendor/, MIT, byte-identical to the published file, marked linguist-generated). Once per launch it is copied next to a static host page in the cache directory; each diagram WebView loads that page by file URL and receives only its own source, so the 2.7 MB never enters the JS heap. No network request: checked with internet blocked on Android and with a packet capture on iOS.
  • iOS code selection → @bsky.app/react-native-uitextview. A selectable fence in a tool detail sheet now gives native range selection and the iOS callout. Android is unchanged.
  • Background glanceable refresh → expo-background-task. A periodic task (WorkManager on Android, BGTaskScheduler on iOS, 15-minute floor) reads the tray once and republishes the widgets, the ongoing notification and the Live Activity when the OS drops a data-only push. Signed out, it does nothing. A failed read keeps the last snapshot. The publisher is built before the read, so a sign-out during the read wins the surface. Android device run: the surfaces updated with no push, kept their state with the backend down, and stayed empty after sign-out. patches/expo-background-task@57.0.21.patch stops a cold-start run from cancelling itself; the package builds from source on Android so the patch applies. iOS simulators cannot run BGTaskScheduler; the Info.plist keys are in place.
  • Rozenite removed. It was added, then removed: agent-device already covers logs, network, perf, React profiling and traces, and the performance plugin linked a native module into release builds. apps/mobile/AGENTS.md now tells agents to use agent-device.
  • Liquid Glass ban. expo-glass-effect and @callstack/liquid-glass are in no-restricted-imports; the element map names expo-blur.
  • Checked, no change: expo-quick-actions. The app ships launcher shortcuts and an Android Quick Settings tile in modules/kilo-launcher-surfaces. The only maintained library has no npm release for SDK 57 (6.1.0 is only on main), has an open cold-start bug (quick actions doesn't work when app is in killed state EvanBacon/expo-quick-actions#54), and does not cover the tile.

Device verification

  • iOS simulator and Android emulator against the VM backend, light and dark: agent transcript (assistant parts and user bubbles), read tool .md body, .md file preview, Kilo Chat messages, Security Agent analysis panel, image gate, link confirm, fence copy, Mermaid, the 1,500-line fence, iOS UITextView selection.
  • Found and fixed on device: dark-mode table rows and quotes (library light defaults), Mermaid clipped on first mount (re-measured with ResizeObserver), and the library block menu opening over Message details.
  • One Android run showed the block menu after Message details closed; it was taken right after a hot reload and did not reproduce on 3 cold-launch tries.
  • Pre-existing, not changed: a raw <details> HTML block renders nothing in both the old and the new chain.

Related checks: mobile typecheck, i18n catalogs, format, and lint on every changed file pass. 165 tests in the markdown and code-block suites pass. Local full pnpm lint reports tRPC error-typed values at this PR's previous head too; CI is the judge.

Dependency upgrades (2026-10-06)

Mobile-only upgrades that pass the pnpm release-age gate, each checked on an iOS simulator and an Android emulator against a local backend.

  • @formatjs/intl-durationformat 0.10.18 → 0.11.1: feature release; the polyfill formats durations in the app runtime on both platforms.
  • @sentry/react-native 8.28.0 → 8.29.0: SDK 8.29.0 starts on both platforms with no native error.
  • expo-speech-recognition 56.0.4 → 57.1.0 (SDK 57 line): Android reaches "Listening..." and stops cleanly. The iOS simulator cannot capture audio, so iOS needs a physical-device check.
  • typescript (mobile only) 6.0.3 → 7.0.2: mobile typechecks with tsgo; Expo's config loader detects TS 7 and uses its own transpiler. Lint, knip, the Expo config contract and bundle export pass.
  • react-native-reanimated 4.5.5 → 4.7.1 and react-native-worklets 0.10.4 → 0.13.0: one exact minimumReleaseAgeExclude entry for reanimated 4.7.1 (4 days old), with a policy-test entry. No crash, RedBox or [Reanimated] error. Covered: sheets, dialogs, navigation, tabs, the skeleton, and the keyboard lift.
  • react-native-appsflyer 6.18.0 → 7.0.2-v2: src/lib/appsflyer.ts moved to the v7 API (init + session-ready + start, object params, setConsentData({...})). Consent, stop/resume and the late-callback invalidation are kept, and consent, stop and start now run one at a time. On both platforms: no SDK traffic before consent, and init → start → launch after consent; revoke stops it, and re-grant starts it again.
    • The patch is ported to patches/react-native-appsflyer@7.0.2-v2.patch. create() still drops its promise. The patch also adds a Kotlin stdlib fallback for RN 0.86's Kotlin 2.1.20, and a @ts-ignore on the package's typeof jest.
    • Behavior change to review: v7 requires a boolean GDPR flag, so the app now sends isUserSubjectToGDPR: true together with the user's consent choices. v6 sent "undetermined".

Not upgraded:

  • jotai 3: the app hands its store to @kilocode/cloud-agent-sdk, which builds atoms with jotai 2.18.1 (156 type errors). Fixing it means moving the SDK, which web and the extension also use.
  • nativewind 5.0.0-rc.0: on device, leading-N became N × 14 × fontSize, which hid the tab labels and made code lines ~150pt tall. rc.0 drops preview.4's unitless leading-* override, and react-native-css 3.1.0-rc.0 multiplies the length by the font size. Reverted to the preview.4 pair, and re-checked on device.

pnpm patch review: all 11 other patches are still needed on the newest release of the same version line. The react-native view-assert guard is fixed upstream only on main.

HTML in markdown and fixtures (2026-10-06)

  • Converter (markdown-html-convert.ts + scan/tree/inline/block/script helpers). HTML that markdown can express becomes markdown before the native renderer, so it gets one style, native selection, and the image gate.
    • Converts: b/strong, i/em, s/del/strike, code, kbd (inline code), a, img (https only, through the image gate), br, p, h1–h6, lists, blockquote, pre, hr, plain tables.
    • sub/sup with digits, signs, parentheses or simple letters become Unicode script characters (H₂O, x²).
    • Never converts inside code spans, fences, indented code or comments. While streaming, an open tag converts as if closed.
  • The rest renders with @native-html/render 1.0.3, which replaces the deprecated react-native-render-html (now in no-restricted-imports). <details>/<summary> is a collapsible row, collapsed by default; before, it rendered nothing. Unknown tags keep their text. A sub/sup/kbd that markdown cannot express draws as smaller or code-colored text on the baseline, because iOS clips offset inline views.
  • Inline tables stay (product decision): wide tables scroll sideways in their own box.
  • Fixture committed: pnpm dev:seed app:mobile-markdown-fixture <email> seeds the transcript used for these checks: markdown, tables (wide, long-cell), fences, Mermaid (four diagrams), HTML cases. It returns the deep link.
  • apps/mobile/AGENTS.md: new "Fixtures for End-to-End Testing" rules. Fixtures are dev-only (__DEV__, entered through +native-intent.tsx), faithful to actual usage, fall back to real backend state when they cannot be faithful, and are committed for reuse.
  • Device checks: Android emulator and iOS 26.5 simulator, light and dark. Checked every converter case, the untrusted image (not fetched), details expand and collapse, keys, scripts and the footnote fallback with no clipping, and all four diagrams.

… map

Add the no-restricted-imports rule set that bans every element the UI
unification replaces, with a ratchet override listing the files not yet
migrated. Add 'Library First' and 'Unified Elements' to apps/mobile/AGENTS.md.

Bump @shopify/flash-list 2.3.2 -> 2.3.3 (EngagedIndicesTracker scroll-window
fix) and exempt it from minimumReleaseAge. Delete the stale 'FlashList v2 does
not support inverted' comment.
…aces

Migrate every surface the plan named, and land the guardrails with it.

- Sheets: add `@/components/ui/sheet` (`Sheet` over `@expo/ui`'s native
  BottomSheet). Migrate the account picker, the reaction picker, the session
  filter sheet and the markdown table reader. They are no longer RN `Modal`, so
  they stack above a `formSheet` route.
- Dialogs: add `@/components/ui/dialog` (`ConfirmDialog` over
  `@rn-primitives/alert-dialog`, plus `useConfirmDialog`). Migrate all 40
  destructive `Alert.alert` sites. The default presentation is the RN `Modal`
  confirm, which is visible above a native sheet; `presentation: 'screen'`
  selects the portal dialog for a path nothing can be presented over.
- Lists: migrate the last 9 `FlatList` sites to FlashList.
- Images: replace the hand-rolled gesture stack with
  `react-native-zoom-toolkit`; `image-viewer-modal` becomes `ui/image-viewer`.
- Video: add `expo-video` and render a video file part inline.
- Lint: enable `no-destructive-alert`, which forbids a destructive-style
  `Alert.alert` button.
@iscekic iscekic self-assigned this Oct 2, 2026
@socket-security

socket-security Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Priority Alert  (click "▶" to expand/collapse) Action
Low priority
Potential typosquat (AI signal): npm react-native-enriched-markdown as a typo of react-native-markdown-renderer

Did you mean: react-native-~~enriched-~~markdown**-renderer**

From: apps/mobile/package.json → npm/react-native-enriched-markdown@1.1.0

ℹ Read more on: This package | This alert | What is AI-detected potential typosquatting?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Given the AI system's identification of this package as a potential typosquat, please verify that you did not intend to install a different package. Be cautious, as malicious packages often use names similar to popular ones.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/react-native-enriched-markdown@1.1.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
Low priority
Potential typosquat (AI signal): npm react-native-zoom-toolkit as a typo of react-native-zoom-reanimated

Did you mean: react-native-zoom-toolkreanimated

From: apps/mobile/package.json → npm/react-native-zoom-toolkit@5.1.1

ℹ Read more on: This package | This alert | What is AI-detected potential typosquatting?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Given the AI system's identification of this package as a potential typosquat, please verify that you did not intend to install a different package. Be cautious, as malicious packages often use names similar to popular ones.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/react-native-zoom-toolkit@5.1.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn

View full report

Add `react-native-keyboard-controller` 1.22.6 and wrap the app in its
`KeyboardProvider`. The session list, session history, quick chat and session
detail screens each rendered a platform fork: an app-aware JS padding container
on Android (React Native's `KeyboardAvoidingView` is inert there under
edge-to-edge) and RN's `KeyboardAvoidingView` on iOS. All four now render one
native `KeyboardAvoidingView`, so the IME is measured once in native code.

- Delete `session-keyboard-container-state.ts` and its test: the fork is gone.
- Delete the `.oxlintrc.json` ratchet. No file imports a banned element now.
- Rewrite the two suites that asserted the removed JS padding.

The three surfaces that correct their own bottom-inset double-count keep
`AppAwareKeyboardPaddingView`, and the chat-scroll schedulers stay. Each
correction came from a device finding and moves only with a device pass.
Every keyboard lift now comes from `react-native-keyboard-controller`'s
`KeyboardProvider`, so the app keeps one keyboard engine:

- The new-session footer, the kilo-chat conversation screen and the PR-review
  comment bar replace `AppAwareKeyboardPaddingView` with the native
  `KeyboardAvoidingView`. Each passes
  `keyboardVerticalOffset={keyboardInsetOffset(bottom)}`: the provider's Android
  height spans the translucent navigation bar, so a surface whose content pads
  the inset itself must reduce the lift by it.
- The session-list bands, the manual-review footer and the toast offset read
  `useKeyboardState` instead of React Native's keyboard events.
- The login screen reads the provider; `resolveKeyboardBottomPadding` loses its
  platform argument, because the provider's metric reaches the screen bottom on
  both platforms.
- The kilo-chat message list's scroll container is `KeyboardChatScrollView`, so
  the IME scroll is native. `message-list-keyboard-scroll.ts` keeps only the
  newest-message follow and is renamed `message-list-newest-scroll.ts`.

Delete `app-aware-keyboard-padding.tsx`, `app-aware-keyboard-padding-state.ts`
and their three test files.

`use-composer-reveal-scroll` stays: it reveals a NON-focused element (the
new-session composer card's pill row), which the native chat scroll view has no
equivalent for.
The global `react-native-keyboard-controller` stub returned the whole state
object whatever the argument, so a reader asking for `state.height` got an
object and every numeric lift derived from it was NaN. Match the real hook's
signature: apply the selector when one is passed.
…-import gap

`use-composer-reveal-scroll` scrolled the new-session composer card's bottom row
above the IME. Delete it, its test, and the two form tests that pinned it. The
card's own `onLayout` still feeds the prompt's input floor, so the frame height
and card top survive; only the reveal's scroll wiring goes.

Ban a direct `@expo/ui/community/bottom-sheet` import. `ui/sheet.tsx` is the
app's one bottom sheet, and its allowlist entry was dead because nothing banned
the module it imports — the entry now carries the rule that makes it the only
home, and a probe confirms the ban fires.

Bounded verification: the 46 suites that render a keyboard reader or carry a
keyboard-controller mock, 661 tests.
@iscekic iscekic added the merge-by-human the merge bot routed this PR to a human label Oct 2, 2026
Both were RN `Modal` surfaces a native sheet can already take: `Sheet` renders
`@expo/ui`'s native bottom sheet, which presents its own window, so it stacks
above a `formSheet` route and above another native sheet just as `Modal` did.

- `Sheet` takes an optional `background`, so a surface that owns its whole
  window paints its own colour instead of the card surface.
- `SessionPageSheet` is a `Sheet` at the `100%` detent with no drag indicator.
  Its `topInset="ios-page-sheet"` contract is unchanged: iOS presents the sheet
  below the status bar, Android expands it over the status bar and the surface
  pads the top inset itself.
- `ImageViewer` is a `Sheet` at the `100%` detent with no drag indicator. It
  drops `supportedOrientations`: a native sheet rotates with the activity
  instead of being locked portrait like an RN full-screen `Modal`, which is what
  e11 viewer-landscape was about.

`session-page-sheet.tsx` and `ui/image-viewer.tsx` leave the RN-`Modal`
allowlist. Rewrite the ten suites that asserted the old `Modal` host against the
shell's `BottomSheet` host.
Delete the last three RN `Modal` surfaces. No file imports `Modal` from
`react-native` any more, so the ban carries no exception.

- `DestructiveConfirmDialog` is a native sheet: content-sized, no drag
  indicator. A confirm is reached from inside `formSheet` routes and from
  content already presented in `SessionPageSheet`, and a portal dialog renders
  behind a presented sheet, so the confirm must present natively.
- `ui/dialog.tsx` loses the portal `ConfirmDialog` and the
  `presentation: 'screen' | 'sheet'` split: one confirm element, no opt-in.
- `DialogCard` (new, on `@rn-primitives/dialog`) hosts a form in a portal card
  with its own backdrop pressable — the primitive owns Android Back and the
  accessibility escape but not the backdrop. `RenameModal` and
  `FeedbackPromptDialog` move onto it, so both keep their shape and their
  backdrop-dismiss.
- `profile-screen` sends its sign-out confirm through `useConfirmDialog`;
  `use-sign-out-confirmation.ts` and the `@rn-primitives/alert-dialog`
  dependency are deleted.

The dialog allowlist is now `ui/sheet.tsx`, `ui/dialog.tsx` and the test globs.
Comment thread apps/mobile/src/components/ui/sheet.tsx Resolved
Comment thread apps/mobile/.oxlintrc.json Resolved
@kilo-code-bot

kilo-code-bot Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental delta since 8834d3b5 is the main merge 56e4c78bb (mobile conflict resolution) plus the test-isolation commit edf039719; the resolution keeps the PR's keyboard/sheet behavior while adopting main's unrelated screen-inset, config, and i18n cleanup, and no new issues were found.

Files Reviewed (14 files)
  • apps/mobile/app.config.ts
  • apps/mobile/src/components/agents/new-session-configure-form.tsx
  • apps/mobile/src/components/agents/new-session-prompt.tsx
  • apps/mobile/src/components/consent/consent-card.tsx
  • apps/mobile/src/components/login-screen.tsx
  • apps/mobile/src/components/pr-review/pr-review-entry-screen.tsx
  • apps/mobile/src/components/profile-screen.tsx
  • apps/mobile/src/components/tab-screen.tsx
  • apps/mobile/src/components/profile-screen.test-helpers.tsx
  • apps/mobile/src/components/login-screen.test.ts
  • apps/mobile/src/components/home/agent-sessions-section.test.ts
  • apps/mobile/src/components/pr-review/pr-review-entry-screen.test.ts
  • apps/mobile/src/lib/case-guard.test.ts
  • apps/mobile/src/i18n/permission-prompt-locales.ts

Scope Note

The two-dot diff 8834d3b5..HEAD also contains ~400 files merged from main (schema/migrations, services, web, i18n catalogs, lockfiles). Those are main's already-reviewed changes pulled in by the merge, not this PR's authored work, and are outside the PR diff against main; they were not re-reviewed here.

Previous Review Summaries (18 snapshots, latest commit 8834d3b)

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

Previous review (commit 8834d3b)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental changes resolve all three prior findings - the mixed setext-underline matcher, sub/sup edge whitespace, and adjacent kbd/code code spans - and the new guards in markdown-html-scan.ts and markdown-html-inline.ts are correct, with no new issues found.

Files Reviewed (3 files)
  • apps/mobile/src/components/agents/markdown-html-inline.ts
  • apps/mobile/src/components/agents/markdown-html-scan.ts
  • apps/mobile/src/components/agents/markdown-html-convert.test.ts

Previous review (commit 886f09d)

Status: 3 Issues Found | Recommendation: Address before merge

Executive Summary

The previous setext-underline finding is fixed, but the new [=-]+ matcher over-matches mixed =/- runs and lone - list markers, and the new sub/sup and kbd conversions change rendered text in edge cases.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/agents/markdown-html-scan.ts 44 [=-]+ matches mixed =/- runs and a lone -, masking genuine indented content as code
apps/mobile/src/components/agents/markdown-html-inline.ts 224 scriptText trims edge whitespace (including &nbsp;), changing rendered text

SUGGESTION

File Line Issue
apps/mobile/src/components/agents/markdown-html-inline.ts 246 Adjacent <kbd> convert to abutting code spans that merge into one
Files Reviewed (10 files)
  • apps/mobile/src/components/agents/markdown-html-inline.ts - 2 issues
  • apps/mobile/src/components/agents/markdown-html-script.ts
  • apps/mobile/src/components/agents/markdown-html-scan.ts - 1 issue
  • apps/mobile/src/components/agents/markdown-html.tsx
  • apps/mobile/src/components/agents/markdown-html-details.tsx
  • apps/mobile/src/components/agents/markdown-html-convert.test.ts
  • apps/mobile/src/components/agents/markdown-html.mounted.test.tsx
  • apps/mobile/src/components/agents/markdown-text.test.tsx
  • dev/seed/app/mobile-markdown-fixture.ts
  • tools/nativewind/check-classes.mjs

Fix these issues in Kilo Cloud

Previous review (commit ebe0973)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

The code-region scanner fix resolves both prior findings, but its new paragraph-end detection still misses -/-- setext underlines, so HTML inside indented code after such a heading is still converted.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/agents/markdown-html-scan.ts 43 PARAGRAPH_END_LINE misses -/-- setext underlines, so indented code after such a heading is not masked and its HTML converts.
Files Reviewed (2 files)
  • apps/mobile/src/components/agents/markdown-html-scan.ts - 1 issue
  • apps/mobile/src/components/agents/markdown-html-convert.test.ts

Fix these issues in Kilo Cloud

Previous review (commit 46d9c9b)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The new HTML-to-markdown converter is well-tested, but its code-region scanner diverges from CommonMark in two places, so markup inside what markdown renders as code can be converted and the displayed code changes.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/agents/markdown-html-scan.ts 67 Indented code after a non-paragraph block is not masked, so its HTML converts and the displayed code changes.

SUGGESTION

File Line Issue
apps/mobile/src/components/agents/markdown-html-scan.ts 39 FENCE_CLOSE accepts a fence indented four or more spaces, closing early and converting markup still inside the fence.
Files Reviewed (19 files)
  • apps/mobile/src/components/agents/markdown-html-scan.ts - 2 issues
  • apps/mobile/src/components/agents/markdown-html-convert.ts
  • apps/mobile/src/components/agents/markdown-html-convert.test.ts
  • apps/mobile/src/components/agents/markdown-html-tree.ts
  • apps/mobile/src/components/agents/markdown-html-inline.ts
  • apps/mobile/src/components/agents/markdown-html-block.ts
  • apps/mobile/src/components/agents/markdown-html-details.tsx
  • apps/mobile/src/components/agents/markdown-html.tsx
  • apps/mobile/src/components/agents/markdown-html.mounted.test.tsx
  • apps/mobile/src/components/agents/markdown-mermaid.tsx
  • apps/mobile/src/components/agents/markdown-palette.ts
  • apps/mobile/src/components/agents/markdown-text.tsx
  • apps/mobile/src/components/agents/markdown-text.test.tsx
  • apps/mobile/src/lib/case-guard.test.ts
  • apps/mobile/package.json
  • apps/mobile/.oxlintrc.json
  • apps/mobile/AGENTS.md
  • dev/seed/app/mobile-markdown-fixture.ts
  • pnpm-lock.yaml (generated)

Fix these issues in Kilo Cloud

Previous review (commit 4e4f73e)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The Mermaid script is no longer inlined and the per-diagram memory duplication is fixed, but the host page is cached by Mermaid version alone, so a future edit to the app-owned page can be served stale.

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
apps/mobile/src/components/agents/markdown-mermaid.tsx 71 Host page is cached by Mermaid version only; editing HOST_PAGE without bumping the version serves a stale page.
Files Reviewed (3 files)
  • .gitattributes
  • apps/mobile/AGENTS.md
  • apps/mobile/src/components/agents/markdown-mermaid.tsx - 1 issue

Fix these issues in Kilo Cloud

Previous review (commit 60fefc2)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The Mermaid port is correct and removes the runtime CDN dependency, but inlining the full ~2.7 MB library into every diagram's WebView HTML multiplies memory across multiple fences.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/agents/markdown-mermaid.tsx 71 The full 2.7 MB Mermaid build is inlined into every diagram's WebView HTML, so N fences keep N copies alive in the JS heap and on the RN bridge.

Fix these issues in Kilo Cloud

Files Reviewed (6 files)
  • apps/mobile/src/components/agents/markdown-mermaid.tsx - 1 issue
  • apps/mobile/assets-env.d.ts
  • apps/mobile/metro.config.js
  • apps/mobile/vitest.mounted.config.ts
  • apps/mobile/vitest.pure.config.ts
  • apps/mobile/assets/vendor/mermaid-11.12.0.min.txt

Previous review (commit 7b18ce0)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental changes upgrade mobile dependencies (AppsFlyer 7, Reanimated 4.7.1 / Worklets 0.13.0, TypeScript 7, Sentry 8.29.0, intl-durationformat 0.11.1, expo-speech-recognition 57.1.0) and port apps/mobile/src/lib/appsflyer.ts to the AppsFlyer 7 manual-start API; the referenced 7.x method and param shapes and the ported create() promise patch match the published packages, so no new issues were found.

Files Reviewed (11 files)
  • apps/mobile/src/lib/appsflyer.ts
  • apps/mobile/src/lib/appsflyer.test.ts
  • apps/mobile/package.json
  • apps/mobile/src/lib/minimum-release-age-policy.test.ts
  • apps/mobile/src/lib/telemetry/no-sdk-before-decision.test.ts
  • apps/mobile/src/lib/telemetry/discard-boundary.test.ts
  • apps/mobile/src/lib/telemetry/transport-spy.test.ts
  • patches/react-native-appsflyer@7.0.2-v2.patch
  • patches/react-native-appsflyer@6.18.0.patch (deleted)
  • pnpm-workspace.yaml
  • pnpm-lock.yaml

Previous review (commit b8f417f)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental changes add a periodic expo-background-task glanceable refresh (registered from the app entry, lazy-loading the notifications graph) and remove the Rozenite DevTools panels; the refresh reads the tray once and republishes every sink, skips cleanly when signed out, reports Failed on a read or native failure, and fences a sign-out that lands during the read by constructing the publisher before the fetch.

Files Reviewed (17 files)
  • apps/mobile/src/lib/glanceable-refresh-task.ts
  • apps/mobile/src/lib/glanceable-refresh-task.test.ts
  • apps/mobile/src/lib/glanceable/tray-refresh.ts
  • apps/mobile/src/lib/notifications.ts
  • apps/mobile/src/lib/notifications.test.ts
  • apps/mobile/src/lib/notification-background-task.ts
  • apps/mobile/index.js
  • apps/mobile/app.config.ts
  • apps/mobile/metro.config.js
  • apps/mobile/package.json
  • apps/mobile/src/components/app-root-providers.tsx
  • apps/mobile/src/components/app-unlock-screen.test-helpers.tsx
  • apps/mobile/src/glanceable-android/approve-task.test.ts
  • apps/mobile/vitest.setup.ts
  • apps/mobile/AGENTS.md
  • patches/expo-background-task@57.0.21.patch
  • pnpm-workspace.yaml

Previous review (commit ab78107)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental change caps the image gate's whole-value lexer probes at eight per pass and falls back to rewriting every copy, which removes the quadratic re-lex on untrusted markdown without weakening the rewrite guarantee; the added regression test covers the budget path.

Files Reviewed (2 files)
  • apps/mobile/src/components/agents/markdown-image-gate.ts
  • apps/mobile/src/components/agents/markdown-image-gate.test.ts

Previous review (commit 23385a0)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The prior gate-bypass and Mermaid injection findings are fixed; the one remaining concern is a quadratic re-lex in the new image/literal disambiguation on untrusted markdown.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/agents/markdown-image-gate.ts 138 The probe re-lexes the entire value once per occurrence of raw, so repeated identical image syntax plus one escaped copy drives O(occurrences × value length) work on the render path.
Files Reviewed (3 files)
  • apps/mobile/src/components/agents/markdown-image-gate.ts - 1 issue
  • apps/mobile/src/components/agents/markdown-mermaid.tsx
  • apps/mobile/src/components/agents/markdown-image-gate.test.ts

Fix these issues in Kilo Cloud

Previous review (commit 89da13d)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

CRITICAL

File Line Issue
apps/mobile/src/components/agents/markdown-image-gate.ts 191 codeRanges and marked disagree about what is code, so an untrusted image can survive gating and be fetched by the native markdown view.

WARNING

File Line Issue
apps/mobile/src/components/agents/markdown-mermaid.tsx 28 JSON.stringify output is embedded in an inline <script>; a </script> in a mermaid fence escapes the element and injects markup/JS into the WebView.

SUGGESTION

File Line Issue
apps/mobile/src/components/agents/markdown-mermaid.tsx 81 Unguarded JSON.parse of WebView messages; a non-JSON payload throws in the handler.
Files Reviewed (29 files)
  • apps/mobile/src/components/agents/markdown-image-gate.ts - 1 issue
  • apps/mobile/src/components/agents/markdown-enriched.tsx
  • apps/mobile/src/components/agents/markdown-image-src.ts
  • apps/mobile/src/components/agents/markdown-mermaid.tsx - 2 issues
  • apps/mobile/src/components/agents/markdown-text.tsx
  • apps/mobile/src/components/agents/markdown-parse-cache.ts
  • apps/mobile/src/components/agents/markdown-html.tsx
  • apps/mobile/src/components/agents/code-block.tsx
  • apps/mobile/src/components/agents/code-block-chunk-content.tsx
  • apps/mobile/src/components/agents/markdown-image-confirm.ts
  • apps/mobile/src/components/agents/message-bubble.tsx
  • apps/mobile/src/components/agents/part-renderer.tsx
  • apps/mobile/src/components/agents/text-part-renderer.tsx
  • apps/mobile/src/components/agents/markdown-link.ts
  • apps/mobile/src/components/agents/markdown-image.tsx
  • apps/mobile/src/components/agents/markdown-palette.ts
  • apps/mobile/src/components/agents/markdown-handlers.ts
  • apps/mobile/src/components/kilo-chat/message-bubble-content.tsx
  • apps/mobile/src/components/kilo-chat/message-bubble.tsx
  • apps/mobile/src/components/kilo-chat/message-markdown.tsx
  • apps/mobile/src/components/kilo-chat/message-list-newest-scroll.ts
  • apps/mobile/src/lib/rozenite-devtools.tsx
  • apps/mobile/src/components/app-root-providers.tsx
  • apps/mobile/metro.config.js
  • apps/mobile/package.json
  • apps/mobile/vitest.setup.ts
  • apps/mobile/.oxlintrc.json
  • apps/mobile/src/lib/minimum-release-age-policy.test.ts
  • apps/mobile/src/i18n/locales/en.json

Fix these issues in Kilo Cloud

Previous review (commit 0c39bde)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit since 97a253baf only deletes apps/mobile/src/app/(app)/app-layout-foreground.mounted.test.tsx; the AppState single-listener contract remains covered by use-app-lifecycle.mounted.test.tsx, and the logout/push reconciliation behavior by the retained logout-reconciliation.test.ts and push-registration-reconciliation.test.ts, so no new defect was found in the changed lines.

Files Reviewed (1 file)
  • apps/mobile/src/app/(app)/app-layout-foreground.mounted.test.tsx (deleted)

Previous review (commit 97a253b)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit removes the redundant advanced-config profile selector and active-profile indicator, migrates the typing indicator and composer bottom-padding to useKeyboardState/KeyboardProvider, switches the shared Input (and every migrated caller) from logical px-* to physical pl-*/pr-* padding, constrains Android searchable formSheet detents, and scopes PR form headers to their own safe-area provider; the accompanying i18n key retirements and test updates are consistent, and no new defects were found in the changed lines.

Files Reviewed (incremental commit 97a253b, 148 files)
  • apps/mobile/src/app/(app)/_layout.tsx
  • apps/mobile/src/app/(auth)/_layout.tsx
  • apps/mobile/src/components/agents/advanced-config-panel.tsx
  • apps/mobile/src/components/agents/new-session-configure-form.tsx
  • apps/mobile/src/components/agents/profile-selector-model.ts
  • apps/mobile/src/components/agents/model-picker-content.tsx
  • apps/mobile/src/components/agents/session-detail-content.tsx
  • apps/mobile/src/components/agents/session-preview-transcript.tsx
  • apps/mobile/src/components/kilo-chat/message-input-layout.ts
  • apps/mobile/src/components/kilo-chat/message-input-content.tsx
  • apps/mobile/src/components/kilo-chat/typing-indicator.tsx
  • apps/mobile/src/components/kilo-chat/conversation-screen.tsx
  • apps/mobile/src/components/ui/input.tsx
  • apps/mobile/src/components/empty-state.tsx
  • apps/mobile/src/components/pr-review/pr-form-sheet-chrome.tsx
  • apps/mobile/src/components/pr-review/discussion/discussion-thread.tsx
  • apps/mobile/src/components/pr-review/pr-review-pending-comment-row.tsx
  • apps/mobile/src/components/pr-review/pr-review-overview.tsx
  • apps/mobile/src/components/pr-review/pr-review-overview-parts.tsx
  • apps/mobile/src/components/security-agent/* (notification, sla, settings-overview)
  • apps/mobile/src/components/profiles/*, apps/mobile/src/lib/agent-attachments/*
  • apps/mobile/src/i18n/locales/*.json + catalog-parity.test.ts (retired keys)
  • Deleted profile-selector-row.tsx and the superseded keyboard/listener test suites

Previous review (commit 25be731)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental fix adds the Android top inset (insets.top + 20) to the session filter sheet content, clearing the status bar while preserving the existing p-5 padding on iOS, and the accompanying test mock sets Platform.OS accordingly; no new defects found in the changed lines.

Files Reviewed (2 files)
  • apps/mobile/src/components/agents/platform-filter-modal.tsx
  • apps/mobile/src/components/agents/platform-filter-modal.mounted.test.tsx

Previous review (commit 978d619)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

Incremental review of 978d619ce ("refresh searched sessions after mutation") finds the added cliSessionsV2.search invalidation and its rewritten test sound; the single remaining finding is carried forward from the prior review - the full-window session filter sheet still lacks the Android top inset.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/agents/platform-filter-modal.tsx 27 Full-window ['100%'] detent puts the title under the Android status bar; add the insets.top header inset used by the other 100% sheets
Files Reviewed (3 files)
  • apps/mobile/AGENTS.md
  • apps/mobile/src/lib/agent-session-cache.test.ts
  • apps/mobile/src/lib/agent-session-cache.ts

Fix these issues in Kilo Cloud

Previous review (commit ad708c7)

Status: 1 Issues Found | Recommendation: Address before merge

Executive Summary

Changing the session filter sheet to a single ['100%'] detent makes Android expand it over the status bar, but the header still lacks the top inset the other full-window sheets apply, so the title can sit under the status bar/cutout.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/mobile/src/components/agents/platform-filter-modal.tsx 27 Full-window ['100%'] detent puts the title under the Android status bar; add the insets.top header inset used by the other 100% sheets
Files Reviewed (1 files)
  • apps/mobile/src/components/agents/platform-filter-modal.tsx - 1 issue

Fix these issues in Kilo Cloud

Previous review (commit 888d46f)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of 888d46fc3 ("apply multiline padding on Android native inputs") found no new issues. The multiline inset moves from logical px-3 py-2.5 to physical pl-3 pr-3 pt-2.5 pb-2.5 so Android applies it, while tailwind-merge still lets callers override it with px-*/py-*/p-*; the single-line path is unchanged. All eight prior findings remain fixed on current HEAD.

Files Reviewed (2 files)
  • apps/mobile/AGENTS.md
  • apps/mobile/src/components/ui/input.tsx

Previous review (commit dbd216f)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of the native sheet/dialog/input/keyboard fix commit 3ed1ff9a6 (plus fd87eaeff, dbd216f25) confirms all eight prior Code Review Findings are resolved and the changed code introduces no new issues; remaining risk is the unrun device pass, which is behavioral rather than a code defect.

Files Reviewed (39 files)
  • apps/mobile/.oxlintrc.json
  • apps/mobile/AGENTS.md
  • apps/mobile/src/app/(app)/agent-chat/repo-picker.tsx
  • apps/mobile/src/app/(app)/kiloclaw/[instance-id]/settings/model-list.tsx
  • apps/mobile/src/components/agents/child-session-sheet.mounted.test.tsx
  • apps/mobile/src/components/agents/markdown-table.test.ts
  • apps/mobile/src/components/agents/markdown-table.tsx
  • apps/mobile/src/components/agents/model-picker-content.tsx
  • `apps/mobile/src/components/agents/new-session-confi

[Snapshot truncated.]

Additional previous summary content was truncated to keep this comment within platform limits.


Reviewed by deepseek-v4.1-flash · Input: 106.8K · Output: 25.6K · Cached: 1.7M

Review guidance: REVIEW.md from base branch main

The diagram page loaded mermaid.min.js from jsDelivr at runtime. The same
11.12.0 bytes (SHA-256 07e37dfa…3c4b) now ship as an app asset that is read
once and inlined, so a diagram makes no network request and works offline.
Kilobot found that every diagram inlined the 2.7 MB library into its page, so
N fences kept N copies in the JS heap and sent them over the bridge. The
script and one static host page now sit in the cache directory; each
diagram WebView loads the page by file URL and receives only its own source.
The vendored build is marked generated so reviews collapse it.
Fixtures stay dev-only, mirror actual usage, fall back to real backend
state when they cannot, and are committed for reuse.
Common tags (emphasis, strikethrough, code, links, HTTPS images, breaks,
paragraphs, headings, lists, quotes, pre, rules, simple tables) become
markdown; code spans, fences, indented code, and comments are never
touched, and anything without a lossless markdown form stays HTML. An
element still streaming in converts as if it closed at the end.
MarkdownText converts HTML to markdown before the split, so converted
images and links go through the markdown image gate and link
confirmation. The rest renders with @native-html/render 1.0.3, which
replaces the deprecated react-native-render-html, with renderers for
details/summary (collapsible), kbd, sub, and sup. A details element
with a blank-line markdown body renders as one HTML block, and the
incremental split reuses its head when only the tail was rewritten.
pnpm dev:seed app:mobile-markdown-fixture <email> seeds one agent turn
covering markdown, Mermaid, and HTML in markdown (converted tags,
details, kbd, sub/sup, an unknown tag, a literal tag in a fence) and
returns its deep link.
The HTML engine has no model for an unknown tag and draws nothing,
dropping its text; read it as a span, as a browser does. Drop the
subscript a little lower.
An inline view's bottom sits on the baseline, which lifts its glyphs. The
subscript moves down further, and kbd keys move down so their labels share
the line's baseline. Tuned on an Android emulator.
Expo's react-native-web augmentation (expo-env.d.ts, written by expo start)
narrows TextStyle keys that @native-html/render types loosely, so the
sub/sup/kbd renderers failed typecheck on any machine that had run Expo.
They now restate the library's style once. The tag-name lowercasing in
markdown-html-tree.ts joins the case-guard allowlist.
iOS clipped the offset inline views used for <sub> and <kbd>. Keys now
convert to inline code and digits/signs/simple letters in <sub>/<sup> to
Unicode script characters, so the native markdown draws them on the line.
Anything else stays HTML and draws as smaller or code-colored text without
an offset. Also from kilobot and CI: a dash setext underline ends a
paragraph for the code scan, and the details label applies the RTL writing
direction (its file joins the raw-Text exemptions; two stale entries go).
@iscekic
iscekic enabled auto-merge (squash) October 8, 2026 15:58
@iscekic
iscekic merged commit 70da80b into main Oct 8, 2026
85 checks passed
@iscekic
iscekic deleted the kwf/mobile-ui-element-unification branch October 8, 2026 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-by-human the merge bot routed this PR to a human

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants