feat(mobile): provider-aware new-session and layout extract - #5479
Merged
Conversation
Map build/architect aliases to code/plan, widen isValidSessionConfig to accept any non-empty slug after normalization, and derive the mode picker from runtime and profile agents. The empty control shows Select mode instead of Code. The web Jest test runs in CI (workerSetup provisions Postgres).
Provider-aware new-session repository picker for GitHub, GitLab, and Bitbucket (org-only), with recents and per-provider status. Selection carries platform plus fullName, so create sends the matching repo field. Fixes the review findings: platform-aware create lookup, per-provider loading, keyed provider groups, live status helper coverage, and Bitbucket connect-error copy. Built-in mode parity satisfied.
Assert the intentFingerprint repo field stays the bare fullName so persisted safe-retry rows written by the deployed app keep matching getStoredOperationKey.
This was referenced Aug 25, 2026
Contributor
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (10 files)
Previous Review Summaries (3 snapshots, latest commit c7cbe4e)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit c7cbe4e)Status: No Issues Found | Recommendation: Merge Files Reviewed (8 files)
Previous review (commit 4702af6)Status: 2 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (24 files)
Fix these issues in Kilo Cloud Previous review (commit 58dd6b4)Status: 3 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (16 files)
Reviewed by grok-4.6 · Input: 83.9K · Output: 11.1K · Cached: 551K Review guidance: REVIEW.md from base branch |
pandemicsyn
approved these changes
Aug 25, 2026
iscekic
marked this pull request as draft
August 25, 2026 17:09
…cts-dffd # Conflicts: # apps/mobile/src/lib/hooks/use-code-reviews.ts # apps/mobile/src/lib/pr-review/merge/merge-blocked-reasons.ts
…cts-dffd-s2 # Conflicts: # apps/mobile/src/lib/hooks/use-code-reviews.ts # apps/mobile/src/lib/pr-review/merge/merge-blocked-reasons.ts
Read isFetchNextPageError on the org ledger screens so a failed background refetch keeps the rows and the Load more button instead of showing a Retry that calls fetchNextPage and can never clear. Match the org tRPC prefix in the security finding list, so an org-scoped screen actually invalidates its findings on focus.
…ontracts-dffd-s5 # Conflicts: # apps/mobile/src/components/organization/credit-activity-screen.mounted.test.tsx # apps/mobile/src/components/organization/invoices-screen.mounted.test.tsx
Delete the legacy bare-name outbox row only after the scoped row is written, so a crash between the two writes can no longer lose the operation key and mint a duplicate session on relaunch.
Page the organization credit ledger by keyset ((created_at, id) of the last row) instead of by OFFSET. The ledger grows at the head, so a transaction inserted between two requests shifted every later page and page 2 repeated a row page 1 already showed. Return a Stripe invoice cursor only when Stripe reports has_more, so a full final page no longer advertises a next page that is always empty.
clearDiffSelection wiped every stored selection, so leaving one PR discarded the selection a second PR entry on the stack was still holding. Take the PR identity and clear that route key.
Page the organization credit ledger by keyset ((created_at, id) of the last row) instead of by OFFSET. The ledger grows at the head, so a transaction inserted between two requests shifted every later page and page 2 repeated a row page 1 already showed. Return a Stripe invoice cursor only when Stripe reports has_more, so a full final page no longer advertises a next page that is always empty.
…' into audit-w7b-data-contracts-dffd-s3 # Conflicts: # apps/mobile/src/app/(app)/pr-review/[owner]/[repo]/[number]/index.tsx
…cts-dffd-s5 # Conflicts: # apps/mobile/src/app/(app)/agent-chat/repo-picker.tsx # apps/mobile/src/components/agents/repo-selector.tsx # apps/mobile/src/components/organization/credit-activity-screen.mounted.test.tsx # apps/mobile/src/components/organization/credit-activity-screen.tsx # apps/mobile/src/components/organization/invoices-screen.mounted.test.tsx # apps/mobile/src/components/organization/invoices-screen.tsx # apps/mobile/src/components/profile-credits-card.mounted.test.tsx # apps/mobile/src/components/profile-credits-card.tsx # apps/mobile/src/lib/picker-bridge.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The new-session repository row becomes provider-aware.
NewSessionRepositoryrequires aplatformand carries optional Bitbucket workspace and repository uuids, and per-provider state is aRepositoryProviderStatusunion (loading, error, connect, connected-empty, repos) resolved byresolveProviderStatusfor GitHub and GitLab and byresolveBitbucketStatusfor Bitbucket's discriminated-union response; the oldRepositorySectionViewand its connect-fallback status are retired.resolveRepositoryGroupsorders GitHub, GitLab, then Bitbucket only when an organization is set, anddedupeRepositoriesByPlatformAndFullNamekeys deduping on platform plus fullName.Files
apps/mobile/src/components/agents/new-session-repository-state.ts— defines NewSessionRepository, RepositoryProviderStatus, RepositoryGroup, RepositoryGroups, the two status resolvers, grouping, deduping, and platform detection; removes RepositorySectionView and shouldShowRepositoryError.useNewSessionReposqueries GitHub, GitLab (personal and organization), and organization-only Bitbucket, then merges recently used rows that resolve against a connected row, recents first. Its result replaces the singleviewandopenGitHubIntegrationpair withgroups,repositories,recents,reposSettled,openIntegration, andrefreshReposForceFresh; GitLab and Bitbucket connect and force-fresh refresh run through a foreground return listener, and a Bitbucket connect failure toasts thebitbucketErrorstring.Files
apps/mobile/src/lib/use-new-session-repos.ts— runs the three provider queries plus the recents query, maps rows to NewSessionRepository, resolves per-provider status, and drives per-provider connect and force-fresh refresh.The repository section renders one card per provider group, and the picker treats the selection value as
platform:fullName. A provider in connect or connected-empty shows its own connect or refresh card, an error shows a retryable query error per provider, and repos groups feed rows into the shared picker trigger; the picker shows Recently used plus per-provider sections when the search box is empty, the flat filtered list while searching, and a platform label on each row.Files
apps/mobile/src/components/agents/new-session-repository-section.tsx— replaces the single GitHub view card with per-group connect, connected-empty, and error cards driven by groups and onConnect(platform).apps/mobile/src/components/agents/new-session-configure-form.tsx— swaps the view, onOpenGitHubIntegration, and {fullName, isPrivate}[] props for groups, onConnectProvider, repositories, recents, and NewSessionRepository.apps/mobile/src/components/agents/repo-selector.tsx— builds the Recently used plus per-provider sections, shows the platform next to the fullName, and forwards workspace and repository uuids.apps/mobile/src/app/(app)/agent-chat/repo-picker.tsx— renders grouped headers and platform-labeled rows, matching the selection by platform:fullName.The create body writes exactly one platform-specific repository field.
PrepareSessionInput.githubRepobecomes optional and gainsgitlabProjectandbitbucketRepo, written bysetRepositoryFieldfrom the selected row's platform; the safe-retry fingerprint now includes the platform and Bitbucket uuids and still matches pre-change GitHub rows through a legacy bare-name fallback that migrates the consumed outbox row.resolvePrefillRepoSelectionreturns agithub:fullNamekey, and the Start gate disables when the selected key no longer resolves to a row.Files
apps/mobile/src/components/agents/use-new-session-creator.ts— takes selectedRepository, writes the platform field via setRepositoryField, and keys the fingerprint on platform plus uuids with a GitHub-only legacy fallback.apps/mobile/src/components/agents/new-session-prefill.ts— adds resolvePrefillRepoSelection returning a GitHub-qualified key.apps/mobile/src/components/agents/use-new-session-prefill.ts— resolves the prefill through resolvePrefillRepoSelection and reports the matched state.apps/mobile/src/lib/new-session-submit.ts— disables Start when the selected key does not resolve to a row.The new-session route is thin, and its screen logic lives in a new screen body.
NewSessionScreenBodyowns the form, draft, model, attachment, profile, and repository wiring and resolves the platform-qualified selection to a full row for the creator, while the route keeps only the model provider and the body.Files
apps/mobile/src/app/(app)/agent-chat/new.tsx— reduced to NewSessionModelProvider wrapping NewSessionScreenBody.apps/mobile/src/components/agents/new-session-screen-body.tsx— new; holds all screen state and effects and wires useNewSessionRepos into the form.A route-scoped registry replaces the process-global navigation bridges. Each bridge value is stored under a
routeKey— a session id, a PR owner, repo, and number, or a branded scope — anduseRouteRegistry(routeKey)clears every slot under that key when the route unmounts, so a stale bridge never leaks into the next visit; picker screens receive theirrouteKeythrough route params. The picker-bridge module now exports only types and pure selection helpers, and the diff-selection and file-navigator bridges store per PR.Files
apps/mobile/src/lib/route-registry.ts— new; defines the per-kind slot maps, the picker, PR, and security slots, prRouteKey, and useRouteRegistry.apps/mobile/src/lib/picker-bridge.ts— keeps the bridge types, RepoPlatform, RepoOption, RepoPickerSection, and the selection helpers; drops the module-level set/get/clear functions.apps/mobile/src/lib/security-finding-filter-bridge.ts— stores the filter bridge under the securityFilterSlot fixed key.apps/mobile/src/lib/pr-review/diff-selection-bridge.ts— stores and reads the diff selection under the PR route key.apps/mobile/src/lib/pr-review/file-navigator-bridge.ts— stores per-PR listener sets under the PR route key.apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/filter.tsx— reads and clears the filter slot via the registry.apps/mobile/src/app/(app)/agent-chat/instance-picker.tsx— reads and clears the instance slot and registers the unscoped key.apps/mobile/src/app/(app)/agent-chat/mode-picker.tsx— reads the mode slot keyed by the routeKey param.apps/mobile/src/components/agents/model-picker-content.tsx— reads and clears the model slot keyed by the routeKey param.apps/mobile/src/components/agents/instance-selector.tsx— sets the instance slot under the unscoped key.apps/mobile/src/components/agents/mode-selector.tsx— sets the mode slot under the session-id key and passes it to the picker route.apps/mobile/src/components/agents/model-selector.tsx— sets the model slot under the session-id key and passes it to the picker route.Route-param parsing becomes strict and typed.
parseReviewerPlatformreturns aReviewerScopePlatformdiscriminated union — a personalgithuborgitlabvariant, or an org variant carrying the organization id — and rejects personal Bitbucket, andtoPersonalPlatformmoves into the config module and throws on Bitbucket instead of aliasing it to GitHub. The PR review route validates owner, repo, and number and renders the invalid-route state for malformed params.Files
apps/mobile/src/lib/code-reviewer-config.ts— adds ReviewerScopePlatform, rewrites parseReviewerPlatform, moves and hardens toPersonalPlatform, and derives ReviewConfigData and ConfigPatch from the router outputs.apps/mobile/src/lib/hooks/use-reviewer-route-params.ts— returns ReviewerScopePlatform or null.apps/mobile/src/lib/hooks/use-code-reviewer.ts— invokes toPersonalPlatform only for the active personal scope and re-exports it.apps/mobile/src/app/(app)/pr-review/[owner]/[repo]/[number]/index.tsx— parses owner, repo, and number with parseParam and renders InvalidRouteState when they are invalid.Organization credit activity and invoices become cursor-paginated. Two new procedures,
creditTransactionsPageandinvoicesPage, page 25 rows at a time and returnentries,hasMore, and a cursor; the web helpers addgetCreditTransactionsForOrganizationPage(with a summary) andgetStripeInvoicesPage, and the old array-form helpers remain for non-paged clients. The mobile screens switch to infinite-query hooks with a Load more footer and permanent not-found and permission error variants.Files
apps/web/src/routers/organizations/organization-router.ts— adds creditTransactionsPage and invoicesPage with cursor input schemas.apps/web/src/lib/creditTransactions.ts— adds getCreditTransactionsSummaryForOrganization and getCreditTransactionsForOrganizationPage with a 25-row offset cursor.apps/web/src/lib/stripe/index.ts— extracts mapStripeInvoicesToUnified and adds getStripeInvoicesPage with a starting_after cursor.apps/mobile/src/lib/hooks/use-organization-queries.ts— adds useOrgCreditTransactionsPage and useOrgInvoicesPage and derives CreditTransaction and OrgInvoice from the router outputs.apps/mobile/src/components/organization/credit-activity-screen.tsx— renders the load-more footer, later-page retry, and permanent error variants.apps/mobile/src/components/organization/invoices-screen.tsx— renders the load-more footer, later-page retry, and permanent error variants.The profile credits card keys its balance query on the signed-in owner. It waits for the current user id before enabling the balance, credit-blocks, and org credit queries, so an account switch can no longer render the previous account's balance, and it treats a failed user query as a balance failure that retry re-resolves.
Files
apps/mobile/src/components/profile-credits-card.tsx— gates the three queries on useCurrentUserId, fails fast on a regressed query key, and merges the user error into the balance error surface.The code-review and security-finding lists refresh when their route returns to the foreground, through the existing foreground-refresh helper.
Files
apps/mobile/src/components/code-reviewer/review-list-screen.tsx— registers the codeReviews refresh key.apps/mobile/src/components/security-agent/finding-list-screen.tsx— registers the securityAgent refresh key.Hand-rolled wire response casts become zod-parsed contracts. The stream-ticket, admission-challenge, openrouter models, and org-defaults responses are parsed with exported schemas, so a malformed body fails at parse time instead of propagating a wrong shape.
Files
apps/mobile/src/components/agents/mobile-session-manager.ts— adds StreamTicketResponseSchema and parses the stream-ticket response.apps/mobile/src/lib/auth/admission.ts— adds AdmissionChallengeResponseSchema and parses the challenge response.apps/mobile/src/lib/hooks/use-available-models.ts— adds OpenRouterModelsResponseSchema and OrganizationDefaultsResponseSchema and parses both endpoints.PR review wire types are derived from the tRPC router instead of hand-written duplicates. Merge, check-run, review-comment, and review-submit inputs plus the merge result and overview DTO come from the inferred router types, so the client types cannot drift from the server contract; the merge-result union re-adds the branch-delete-error variant that declaration emit folds away.
Files
apps/mobile/src/components/pr-review/merge/pr-merge-sheet.tsx— derives MergePullRequestInput and AutoMergeInput from the router.apps/mobile/src/components/pr-review/pr-review-checks-section.tsx— derives CheckRun from the listChecks output.apps/mobile/src/lib/pr-review/merge/merge-blocked-reasons.ts— derives PrOverviewDto and PrOverviewRepoSettings from getPullRequest.apps/mobile/src/lib/pr-review/merge/merge-result-gate.ts— derives MergePullRequestResult and re-adds the branch-delete-error variant.apps/mobile/src/lib/pr-review/merge/use-pr-merge-mutations.ts— derives MergePullRequestInput.apps/mobile/src/lib/pr-review/use-pr-review-mutations.ts— derives CreateReviewCommentInput, SubmitReviewInput, and SubmitReviewComment.apps/mobile/src/lib/hooks/use-code-reviews.ts— derives CreateManualReviewInput.The web chat mode control resumes the session's real mode and supports legacy aliases.
normalizeAliasmapsbuildtocodeandarchitecttoplan,modeControlValueturns an empty mode into the Select mode placeholder, and the provider and the send path normalize the stored mode the same way. The chat picker builds custom options from the session's runtime agents plus the effective profile's visible agents, but only profile agents whose slug is already in the frozen runtime-agents set are offered — a newer profile agent would be rejected on send — and the options are deduped with the selected slug always present.Files
apps/web/src/components/cloud-agent-next/session-config.ts— adds normalizeAlias, modeControlValue, isBuiltinAgentMode, dedupeCustomModeOptions, ensureSelectedCustomOption, and CustomModeOption.apps/web/src/components/cloud-agent-next/CloudAgentProvider.tsx— normalizes the runtime mode alias when building the session config.apps/web/src/components/cloud-agent-next/CloudChatPage.tsx— resolves the mode via modeControlValue, filters profile agents to the runtime-agents slugs, and builds custom options from both sources.Full mobile-artifact inspection now prints a signed-artifact size table alongside the existing contract checks. The script unzips the IPA and AAB and lists JS bundles, fonts, and highlight grammar modules with byte sizes sorted descending; a measurement or unzip failure logs a warning and never changes the exit code.
Files
scripts/inspect-mobile-artifacts.mjs— adds classify, walkFiles, measureArtifactSizes, and printSizeTable; full mode calls printSizeTable before exiting.The mobile catalog gains the strings for the three-provider repository picker, the Bitbucket connect error, and the org ledger Load more footers. The non-English catalogs receive the same keys translated.
Files
apps/mobile/src/i18n/locales/en.json— adds bitbucketError, the provider connect, empty, error, and platform-label keys, and the credit-activity and invoice loadMore, truncated, and loadMoreFailed keys.Tests: 19 test files changed (5 new, 14 updated).
Generated: 86 locale catalogs updated.
Visual Changes
Profile credits card (mobile). The card shows the signed-in account's own balance, and a zero-balance personal account offers an Add credits action. In the picture, the CREDITS section reads $0.00 above the "Add credits to keep usage running." line and the Add credits button, with the linked account zero-balance-w7b@kilocode.dev below.

Org credit ledger (mobile). The Credit activity screen lists the organization's credit rows in one list, and the empty state does not cover them. In the picture, eight "Dev seed org credit" rows each show +$1.00; the load-more footer sits below the visible frame.

New-session repo picker (mobile). The picker groups repositories under Recently used and platform headers and puts a platform label on each row. In the picture, the open Select repository sheet shows the RECENTLY USED header above the selected row and the GITHUB header above the remaining labeled rows.

Personal Bitbucket route (mobile). The invalid personal Bitbucket link shows a Page not found screen with a Go back action instead of GitHub settings. In the picture, the screen center reads "Page not found" and "This link is no longer valid." above the Go back button.

Home saved-sessions banner (mobile). No picture shows this change. The banner "Showing saved sessions — live status may be out of date" never rendered in any round; the candidate pictures show only the generic "No internet connection" banner with the saved rows retained and no promo, so the screen is not pictured.
Cloud chat Mode control (web). The Mode control resolves the session's mode and shows its label instead of a fallback. In the picture, the composer's Mode control reads "Audit W7B Custom" next to the model selector.

Verification
Rounds 1-3 tracked 13 cases on backend, iOS, Android, and web; 11 ran and passed, 2 were not run.
Defects reproduced on the unfixed build:
Recording: none.
Human steps
No human steps needed.
Reviewer Notes
This is level 5 (the tip) of a 5-level stack. Full E2E verification, the simplify pass, and bot review run on this PR over every level.
Stacked PRs — merge bottom to top. Each level shows only its own diff.
Full verification (E2E, user advocacy, simplify, bot review) runs on the tip PR over every level.
A finding on a level is repaired on that level, then carried upward with stack.sh forward.
audit-w7b-data-contracts-dffd— refactor(mobile): parse raw HTTP and infer review contracts #5460audit-w7b-data-contracts-dffd-s2— feat(web): add org credit and invoice page procedures #5462audit-w7b-data-contracts-dffd-s3— feat(mobile): owner-keyed credits, ledger paging, list freshness #5468audit-w7b-data-contracts-dffd-s4— refactor: route-scoped registry and live custom mode #5472audit-w7b-data-contracts-dffd-s5— feat(mobile): provider-aware new-session and layout extract #5479 ← this PR (tip)