Skip to content

feat(mobile): rebuild the chat tab on the harness SDK - #5895

Merged
iscekic merged 21 commits into
feat/kilo-harness-sdkfrom
feat/mobile-harness-chat
Oct 10, 2026
Merged

iscekic merged 21 commits into
feat/kilo-harness-sdkfrom
feat/mobile-harness-chat

Conversation

@iscekic

@iscekic iscekic commented Sep 5, 2026 •

Copy link
Copy Markdown
Collaborator

Changelog for users

  • The chat tab now runs on the harness SDK: it lists your chats newest first, each titled by the first thing you said.
  • Start a chat from +, reopen one you had, retry a question that never got an answer, and long press a chat to delete it.
  • Switch models mid-conversation: the conversation carries over and the list still shows one chat. Deleting that chat stops the answer that was still arriving.
  • Several chats run at once, so leaving the screen does not stop an answer that is still arriving.
  • Removing the old quick chat leaves the new tab empty, with nothing migrated. The tab keeps its label and icon and gains a BETA pill, behind FEATURE_FLAG_CHAT, off by default.
  • Kilo Pass now shows the settled layout while it loads: the description, three product-card-height placeholders, a disabled Restore Purchases row, and the legal links. The product cards replace the placeholders without moving the rows below.
  • A failed Kilo Pass load reads "Couldn't load Kilo Pass." and keeps its Retry action. A centered modal header keeps the back control beside the centered title.
  • The KiloClaw access-required screen again offers "Email our team" and "Review your plan on kilo.ai". The Kilo Pass subscription description now matches the current English copy in every language.

Changelog for maintainers

  • Stacked on feat(harness-sdk): the kilo harness SDK #5878; review that first. The device proof is on the tip and covers the stack. iOS was not run: the change forks on no platform, so the Android run proves both.
  • The SDK owns one conversation (ask, store, resume, compact) and the Expo SQLite store plugin. The app owns many conversations, including listing, titles, ordering, deletion, account and organization scope, and the sign-out wipe.
  • The app's store reads the app's chats table and the SDK's sessions/turns/parts on the one encrypted database. The token comes from the app's auth, randomness from expo-crypto, and the data is SQLCipher-encrypted at rest.
  • This change removes the quick chat screens, the tRPC router, and the two tables; a migration drops the tables and migrates no data. The branch's quickChat removals and modelChat additions are preserved, and the harness SDK builds before the jobs that typecheck or build the app.
  • The i18n-leftover failure is repaired per key: the two reviewed KiloClaw access-required CTA keys are restored, and nine keys that en.json does not define are removed. The removed keys are profile.signOut, securityAgent.settingsSave.keepEditing, agentChat.filePart.imageUnavailableWithAlt, agentChat.modelSelector.thinkingEffortXhigh, agentChat.modelSelector.thinkingEffortMedium, agentChat.composer.messagePlaceholder, kiloPass.unavailableDescription, kiloPass.webManagementDescription, and organization.invoices.loadMoreFailed. A file that also holds an unreviewed value keeps its approved restored values instead of being reverted whole.
  • This change rewrites the 12 truncated Kilo Pass subscription descriptions against the current English and each catalog's existing terminology. In am, hy, and km the reviewed wording ends with the language's own final punctuation. The English kiloPass.unavailable copy becomes "Couldn't load Kilo Pass."; the English subscription description is unchanged.
  • Both format checks stay, and the PostHog analytics re-export is collapsed to one line. Mobile vitest projects raise test and hook timeouts to 30 seconds, and the auth-context bootstrap settles on 1250 act passes instead of a wall-clock budget. New unit tests cover the Kilo Pass loading and failure states, the centered-header spacer, and the card content state. The chat list, delete, scope wipe, and transcript carry unit tests against the real schema of both owners, including the added release-path test. Review the catalog guard first. The new Azerbaijani device probe replaces the earlier English-only subscription-description capture. The Kilo Pass layout captures date from 2026-09-10 and were reused from an earlier commit.
  • apps/mobile/src/lib/chat/registry.test.ts:125 — accepted. releaseChat released the id a chat moved off, which no longer named a running session, so the cleanup cleared nothing. It now resolves the id through the move pointer and ends the chat that carried on, dropping the live state and the pointer. The added test reads both halves after that release: the live chat resets to opening, and the moved-off id stops resolving to it. Review releaseChat first: it resolves with snapshotOf(sessionId).sessionId, so a caller naming a moved-off id ends the live session instead of forgetting a state that no longer exists. The new Android device run is the tip proof for the delete path, replacing the earlier unit-test-only claim for it.

E2E proof

[e1] Open Kilo Pass on the iOS E2E device: during store load three muted skeleton placeholders render at the final product card height, then three product cards with tier and price replace them without… — prior/e1-presentation-settled.png

[e1] Open Kilo Pass on the iOS E2E device: during store load three muted skeleton placeholders render at the final product card height, then three product cards with tier and price replace them without… — prior/e1-settled.png

[e1] quickChat removal and Chat tab gate — prior/e1.png

[e2] With the mobile tRPC backend faulted (fault.sh down) and a cold app start, Kilo Pass shows 'Couldn't load Kilo Pass.' with a Retry button that recovers the screen after the service returns — prior/e2-recover.png

[e2] English kiloPass.subscriptionHeaderDescription — prior/e2.png

[e2] With the mobile tRPC backend faulted (fault.sh down) and a cold app start, Kilo Pass shows 'Couldn't load Kilo Pass.' with a Retry button that recovers the screen after the service returns — prior/e2-error.png

Comment thread apps/mobile/src/lib/chat/registry.ts Resolved
@kilo-code-bot

kilo-code-bot Bot commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Since the previous review at 9319f7a6, the branch adds a keyboard-controller migration for the chat screen, a one-shot feature-flag reader, a corrected credits-purchase import, and regenerated migration/MCP catalog artifacts; all were verified against current HEAD and introduce no new defects.

Files Reviewed (12 files)
  • apps/mobile/src/components/chat/chat-screen.tsx
  • apps/mobile/src/components/chat/chat-screen.mounted.test.tsx
  • apps/mobile/src/lib/analytics/posthog.ts
  • apps/mobile/src/lib/auth/auth-context.tsx
  • apps/mobile/src/lib/session-pr-navigation.ts
  • apps/mobile/src/components/app-root-providers.tsx
  • apps/mobile/src/app/(app)/(tabs)/_layout.tsx
  • apps/mobile/package.json
  • .github/workflows/ci.yml
  • .github/workflows/kilo-app-ci.yml
  • packages/db/src/migrations/0274_drop_quick_chat.sql
  • .kilo/skills/kilo-mcp/SKILL.md
Previous Review Summaries (18 snapshots, latest commit 9319f7a)

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

Previous review (commit 9319f7a)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The only change since f2f1ea651 is a test-only fix in apps/mobile/src/lib/config.test.ts: the MCP URL test now uses vi.importActual to load the real config module over the vitest.setup.ts stub, and adds a type-only import for it. The change is correct and introduces no new issues.

Files Reviewed (1 file)
  • apps/mobile/src/lib/config.test.ts

Previous review (commit f2f1ea6)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The two follow-up commits since db90d791 were verified at HEAD f2f1ea651: the toaster now passes segments to shouldHideTabBar so the tab-bar height check cannot throw, and the account-switch test reads the hoisted queryClient mock directly. Both are correct and cover the change, and no new issues were found in the changed code.

Files Reviewed (2 files)
  • apps/mobile/src/components/app-root-providers.tsx
  • apps/mobile/src/lib/auth/auth-context.lifecycle.test.tsx

Previous review (commit db90d79)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The six follow-up commits since f5ccfb5c were verified at HEAD 4337859: each prior finding is fixed in the changed lines (per-caller discovery deadlines, cache-hit publish, the abort link held until stop, the credential bounded by the deadline, a 60s call deadline above the 15s inline wait, and a switch disabled when there is nothing to toggle). No new issues were found in the changed code.

Files Reviewed (11 files)
  • apps/mobile/src/lib/chat/kilo-mcp.ts
  • apps/mobile/src/lib/chat/kilo-mcp.test.ts
  • apps/mobile/src/components/chat/mcp-settings-state.ts
  • apps/mobile/src/components/chat/mcp-settings-state.test.ts
  • apps/mobile/src/components/chat/mcp-settings-sheet.tsx
  • apps/mobile/src/components/chat/chat-screen.mounted.test.tsx
  • packages/harness-sdk/src/plugins/remote-mcp/http.ts
  • packages/harness-sdk/src/plugins/remote-mcp/client.ts
  • packages/harness-sdk/src/plugins/remote-mcp/credential.ts
  • packages/harness-sdk/src/plugins/remote-mcp/tools.ts
  • packages/harness-sdk/src/plugins/remote-mcp/remote-mcp.test.ts

Previous review (commit f5ccfb5)

Status: 6 Issues Found | Recommendation: Address before merge

Executive Summary

The new Kilo MCP path is well-fenced for tokens and cross-account state, but five timing/lifecycle gaps remain: a joined discovery ignores the caller's deadline, the remote-MCP client fetches its credential outside the deadline it documents, its abort link is dropped before a streamed body is read, a slow tool call can never be backgrounded as documented, and the MCP sheet renders an inert switch in the unavailable state.

Overview

Severity Count
CRITICAL 0
WARNING 5
SUGGESTION 1

Fix these issues in Kilo Cloud: https://app.kilo.ai/cloud-agent-fork/review/39691b24-1e79-4dcf-989d-5049d6139dc7

Issue Details (click to expand)

CRITICAL

None.

WARNING

File Line Issue
apps/mobile/src/lib/chat/kilo-mcp.ts 215 An in-flight discovery join adopts the first caller's deadline, so a chat open can wait 15s (or a Retry is cut to 4s)
packages/harness-sdk/src/plugins/remote-mcp/http.ts 117 The library's abort signal is unlinked once fetch resolves, so close() cannot stop an open stream until the deadline fires
packages/harness-sdk/src/plugins/remote-mcp/client.ts 252 credentialFor runs before the deadline, so deps.token() is unbounded by timeoutMs/discoverTimeoutMs
packages/harness-sdk/src/plugins/remote-mcp/tools.ts 112 inlineFor (15s) equals the client's default timeoutMs, so a slow call is aborted as it is backgrounded and never answers later
apps/mobile/src/components/chat/mcp-settings-sheet.tsx 138 disabled={false} leaves an off-looking switch that does nothing in the unavailable/idle state and cannot turn the setting off

SUGGESTION

File Line Issue
apps/mobile/src/lib/chat/kilo-mcp.ts 211 A cache hit returns the state without republishing it, so the module snapshot can diverge from what the registry reads
Files Reviewed (32 files)
  • apps/mobile/src/lib/chat/kilo-mcp.ts - 3 issues (2 WARNING, 1 SUGGESTION)
  • apps/mobile/src/components/chat/mcp-settings-sheet.tsx - 1 issue
  • packages/harness-sdk/src/plugins/remote-mcp/http.ts - 1 issue
  • packages/harness-sdk/src/plugins/remote-mcp/client.ts - 1 issue
  • packages/harness-sdk/src/plugins/remote-mcp/tools.ts - 1 issue
  • packages/harness-sdk/src/plugins/remote-mcp/server.ts, index.ts
  • packages/harness-sdk/src/core/resume.ts
  • packages/harness-sdk/package.json, scripts/check-package.ts, README.md, AGENTS.md, .oxlintrc.json
  • apps/mobile/src/lib/chat/registry.ts, layers.ts, tools.ts, turns.ts, store.ts, sign-out.ts
  • apps/mobile/src/components/chat/chat-screen.tsx, chat-list-screen.tsx, mcp-settings-state.ts
  • apps/mobile/src/app/(app)/(tabs)/_layout.tsx
  • apps/mobile/src/lib/config.ts, env-keys.js, feature-flags.ts, analytics/posthog.ts
  • apps/mobile/.env.local.example
  • services/kilo-mcp/src/auth.ts, index.ts
  • apps/mobile/src/i18n/locales/*.json (87 catalogs: all 15 new modelChat.mcp.* keys present in every locale, none extra)
  • pnpm-lock.yaml (generated)

Previous review (commit 203212f)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The branch was force-pushed and rebased, so the previously reviewed SHA cffb1a155 is no longer an ancestor, but every file this PR authors is byte-identical to that commit's tree: the only differences in the range are main-merge content (tour, tool-summary-translation, the kilo-mcp catalog workflow) and a CI-generated services/kilo-mcp/catalog.json refresh. No new issues found, and every previously raised finding is present as a fix at HEAD.

Files Reviewed (12 files)
  • apps/mobile/src/lib/chat/registry.ts - verifies the prior findings are fixed (move pointer, scope close on a failed open, { text, model } waiting queue, releaseChat resolving through the move pointer and forgetting unopened state)
  • apps/mobile/src/lib/chat/state.ts - verifies moveState resolution with no second copy of the turns
  • apps/mobile/src/lib/chat/scope.ts - verifies the account-scoped places cache with forgetChatPlaces
  • apps/mobile/src/lib/chat/use-chat.ts - verifies the stable place object and following the moved session
  • apps/mobile/src/lib/chat/sign-out.ts - verifies forgetChatPlaces on sign-out and account switch
  • apps/mobile/src/lib/auth/auth-context.tsx - verifies releaseChatsForAccountSwitch() before queryClient.clear()
  • apps/mobile/src/lib/analytics/posthog.ts - verifies FEATURE_FLAG_CHAT is its own key (mobile-chat, minimum 1.0.11)
  • .github/workflows/kilo-app-ci.yml - verifies check-unused builds @kilocode/harness-sdk
  • apps/mobile/src/i18n/locales/*.json - main-merge content only
  • apps/web/src/lib/feature-detection.ts (and test) - main-merge content only
  • apps/mobile/vitest.pure.config.ts - main-merge content only
  • pnpm-lock.yaml - main-merge content only

Previous review (commit cffb1a1)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental delta from the previously reviewed commit (1d2b9b77c) to HEAD (cffb1a155) contains one author change: chat-list-screen.mounted.test.tsx now imports act and the ReactTestRenderer type from the shared @/test/renderer helper instead of react-test-renderer. Both symbols are exported by that module, and the change matches the pattern used by the other mounted tests, so no new issues were raised.

Files Reviewed (1 file)
  • apps/mobile/src/components/chat/chat-list-screen.mounted.test.tsx

Previous review (commit 1d2b9b7)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental delta from the previously reviewed commit (9c1ceed) to HEAD (1d2b9b77c) carries no new author changes to this PR: every PR file that differs is merge/rebase content from origin/main (test-renderer migration, new preference hooks, the native-build workflow refactor, locale additions, and the SQLCipher WAL changes), the chat feature code is byte-identical, and encryptedDatabase() already existed at the previous commit. No new issues were raised.

Files Reviewed (14 files)
  • .github/workflows/mobile-native-build.yml - main merge content
  • apps/mobile/.oxlintrc.json - main merge content
  • apps/mobile/package.json - main merge content
  • apps/mobile/src/components/kilo-pass/kilo-pass-subscription-screen.test.ts - main merge content
  • apps/mobile/src/components/screen-header.tsx - identical to the main merge parent
  • apps/mobile/src/lib/analytics/posthog.ts - main merge content
  • apps/mobile/src/lib/analytics/posthog.feature-flags.test.ts - main merge content
  • apps/mobile/src/lib/auth/auth-context.tsx - main merge content
  • apps/mobile/src/lib/auth/auth-context.test.tsx - main merge content
  • apps/mobile/src/lib/auth/credentials.test.ts - main merge content
  • apps/mobile/src/lib/persist/encrypted-kv.ts - main merge content
  • apps/mobile/vitest.mounted.config.ts - main merge content
  • apps/mobile/vitest.pure.config.ts - main merge content
  • apps/mobile/src/i18n/locales/*.json - main merge content

Previous review (commit 9c1ceed)

Status: No Issues Found | Recommendation: Merge

Executive Summary

The follow-up fix resolves the prior moved-chat cleanup finding: releaseChat now resolves a moved-off id to the chat that carried on, ends it, and drops the stale move pointer, and the added test covers both halves.

Files Reviewed (2 files)
  • apps/mobile/src/lib/chat/registry.ts
  • apps/mobile/src/lib/chat/registry.test.ts

Previous review (commit 465cc6c)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The fix commit resolves the three prior findings; the only new issue is that the moved-chat test cleanup is a no-op, leaving the move pointer and a live session across tests.

Overview

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

SUGGESTION

File Line Issue
apps/mobile/src/lib/chat/registry.test.ts 125 releaseChat(opened) does not clear the moved-off pointer or the live session, so the new cleanup is ineffective
Files Reviewed (7 files)
  • apps/mobile/src/lib/chat/registry.ts
  • apps/mobile/src/lib/chat/registry.test.ts - 1 issue
  • apps/mobile/src/lib/chat/scope.ts
  • apps/mobile/src/lib/chat/sign-out.ts
  • apps/mobile/src/lib/chat/sign-out.test.ts
  • apps/mobile/src/lib/chat/state.ts
  • apps/mobile/src/lib/chat/use-chat.ts

Fix these issues in Kilo Cloud

Previous review (commit 2573d62)

Status: 3 Issues Found | Recommendation: Address before merge

Executive Summary

Three residual issues in the new chat registry and hook: a failed reopen leaks its session scope, the places cache is never emptied, and clearing the moved chat's turns can flash an empty transcript.

Overview

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

WARNING

File Line Issue
apps/mobile/src/lib/chat/registry.ts 172 A failed reopen leaks the session scope opened by inOwnScope

SUGGESTION

File Line Issue
apps/mobile/src/lib/chat/use-chat.ts 36 The places cache never empties on sign-out or account switch
apps/mobile/src/lib/chat/registry.ts 388 Clearing the old chat's turns can flash an empty transcript on a model switch
Files Reviewed (14 files)
  • .github/workflows/kilo-app-ci.yml
  • apps/mobile/src/app/(app)/(tabs)/_layout.tsx
  • apps/mobile/src/components/chat/chat-list-screen.mounted.test.tsx
  • apps/mobile/src/components/chat/chat-list-screen.tsx
  • apps/mobile/src/lib/analytics/posthog.feature-flags.test.ts
  • apps/mobile/src/lib/analytics/posthog.ts
  • apps/mobile/src/lib/chat/layers.test.ts
  • apps/mobile/src/lib/chat/layers.ts
  • apps/mobile/src/lib/chat/registry.test.ts
  • apps/mobile/src/lib/chat/registry.ts - 2 issues
  • apps/mobile/src/lib/chat/state.ts
  • apps/mobile/src/lib/chat/use-chat.ts - 1 issue
  • apps/mobile/src/lib/feature-flags.test.ts
  • apps/mobile/src/lib/feature-flags.ts

Fix these issues in Kilo Cloud

Previous review (commit 8f2d387)

Status: 7 Issues Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
apps/mobile/src/lib/chat/use-chat.ts 121 enterChat effect re-runs every render because place is a new object; reopens a just-moved session
apps/mobile/src/lib/chat/use-chat.ts 119 A failed enterChat is unhandled and leaves the chat stuck on opening
apps/mobile/src/lib/chat/registry.ts 376 Model switch leaks the old ChatState (and its turns) plus watchers
apps/mobile/src/lib/chat/registry.ts 425 Deleting an unopened chat never calls forgetState, leaking its state
apps/mobile/src/lib/analytics/posthog.ts 84 Reusing the mobile-quick-chat flag key breaks already-shipped builds after the quickChat endpoints/tables are removed
.github/workflows/kilo-app-ci.yml 69 The check-unused job is missing the harness SDK build, so knip fails to resolve the new imports

SUGGESTION

File Line Issue
apps/mobile/src/components/chat/chat-list-screen.tsx 88 A failed newChat is swallowed, so the button silently does nothing
Files Reviewed (45 files)
  • .github/workflows/kilo-app-ci.yml - 1 issue
  • apps/mobile/src/app/(app)/(tabs)/(4_chat)/[id].tsx
  • apps/mobile/src/app/(app)/(tabs)/(4_chat)/_layout.tsx
  • apps/mobile/src/app/(app)/(tabs)/(4_chat)/index.tsx
  • apps/mobile/src/app/(app)/(tabs)/_layout.tsx
  • apps/mobile/src/components/chat/beta-pill.tsx
  • apps/mobile/src/components/chat/chat-list-screen.tsx - 1 issue
  • apps/mobile/src/components/chat/chat-row.tsx
  • apps/mobile/src/components/chat/chat-screen.tsx
  • apps/mobile/src/components/kilo-pass/kilo-pass-subscription-screen.tsx
  • apps/mobile/src/components/screen-header.tsx
  • apps/mobile/src/lib/analytics/posthog.ts - 1 issue
  • apps/mobile/src/lib/auth/auth-context.tsx
  • apps/mobile/src/lib/chat/fetch.ts
  • apps/mobile/src/lib/chat/layers.ts
  • apps/mobile/src/lib/chat/pending.ts
  • apps/mobile/src/lib/chat/registry.ts - 2 issues
  • apps/mobile/src/lib/chat/scope.ts
  • apps/mobile/src/lib/chat/sign-out.ts
  • apps/mobile/src/lib/chat/state.ts
  • apps/mobile/src/lib/chat/store.ts
  • apps/mobile/src/lib/chat/tools.ts
  • apps/mobile/src/lib/chat/turns.ts
  • apps/mobile/src/lib/chat/use-chat.ts - 2 issues
  • apps/mobile/src/lib/persist/encrypted-kv.ts
  • apps/mobile/src/lib/persist/schema.ts
  • apps/mobile/src/lib/tab-bar-layout.ts
  • apps/mobile/src/i18n/locales/en.json and other catalogs
  • apps/web/src/lib/feature-detection.ts
  • apps/web/src/lib/user/index.ts
  • apps/web/src/routers/quick-chat-router.ts (deleted)
  • apps/web/src/routers/root-router.ts
  • packages/db/src/migrations/0243_drop_quick_chat.sql
  • packages/db/src/schema.ts
  • packages/trpc/src/mobile.ts
  • scripts/typecheck-all.sh
  • plus mobile tests, Drizzle snapshots/journals, and the lockfile

Fix these issues in Kilo Cloud

Previous review (commit b374fb3)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (5 files)
  • apps/mobile/src/components/chat/chat-list-screen.tsx
  • apps/mobile/src/components/chat/chat-row.tsx
  • apps/mobile/src/components/chat/chat-screen.tsx
  • apps/mobile/src/i18n/locales/en.json
  • packages/harness-sdk/e2e/image.ts

Previous review (commit e585a7e)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (31 files)
  • apps/mobile/src/lib/chat/registry.ts
  • apps/mobile/src/lib/chat/registry.test.ts
  • apps/mobile/src/lib/chat/use-chat.ts
  • apps/mobile/src/lib/chat/store.ts
  • apps/mobile/src/lib/chat/store.test.ts
  • apps/mobile/src/lib/chat/state.ts
  • apps/mobile/src/lib/chat/turns.ts
  • apps/mobile/src/lib/chat/turns.test.ts
  • apps/mobile/src/lib/chat/pending.ts
  • apps/mobile/src/lib/chat/layers.ts
  • apps/mobile/src/lib/chat/tools.ts
  • apps/mobile/src/lib/chat/tools.test.ts
  • apps/mobile/src/lib/chat/fetch.ts
  • apps/mobile/src/lib/chat/scope.ts
  • apps/mobile/src/lib/chat/sign-out.ts
  • apps/mobile/src/components/chat/chat-screen.tsx
  • apps/mobile/src/components/chat/chat-list-screen.tsx
  • apps/mobile/src/components/chat/chat-row.tsx
  • apps/mobile/src/components/chat/beta-pill.tsx
  • apps/mobile/src/lib/auth/auth-context.tsx
  • apps/mobile/src/lib/tab-bar-layout.ts
  • apps/mobile/src/lib/tab-bar-layout.test.ts
  • apps/mobile/src/app/(app)/(tabs)/_layout.tsx
  • apps/mobile/src/app/(app)/(tabs)/(4_chat)/[id].tsx
  • apps/mobile/src/lib/analytics/posthog.ts
  • apps/mobile/src/lib/persist/schema.ts
  • packages/db/src/migrations/0238_drop_quick_chat.sql
  • packages/db/src/schema.ts
  • packages/trpc/src/mobile.ts
  • apps/web/src/routers/root-router.ts
  • apps/web/src/lib/feature-detection.ts

Previous review (commit 326f2c3)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (3 files)
  • packages/harness-sdk/AGENTS.md
  • packages/harness-sdk/e2e/shapes.ts
  • packages/harness-sdk/e2e/stop.ts

Previous review (commit a7e6c90)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (3 files)
  • apps/mobile/src/components/chat/chat-screen.tsx
  • apps/mobile/src/lib/chat/registry.ts
  • apps/mobile/src/lib/chat/use-chat.ts

Previous review (commit 02d4575)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
apps/mobile/src/lib/chat/registry.ts 341 Drain drops the cloned session after a queued model switch
apps/mobile/src/components/chat/chat-screen.tsx 134 Optimistic clear plus void send drops the draft
Files Reviewed (10 files)
  • apps/mobile/AGENTS.md
  • apps/mobile/src/app/(app)/(tabs)/_layout.tsx
  • apps/mobile/src/components/chat/chat-screen.tsx - 1 issue
  • apps/mobile/src/lib/chat/layers.ts
  • apps/mobile/src/lib/chat/registry.test.ts
  • apps/mobile/src/lib/chat/registry.ts - 1 issue
  • apps/mobile/src/lib/chat/tools.test.ts
  • apps/mobile/src/lib/chat/tools.ts
  • apps/mobile/src/lib/tab-bar-layout.test.ts
  • apps/mobile/src/lib/tab-bar-layout.ts

Fix these issues in Kilo Cloud

Previous review (commit fee11c2)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
apps/mobile/src/lib/chat/registry.ts 341 Drain drops the cloned session after a queued model switch
apps/mobile/src/components/chat/chat-screen.tsx 134 Optimistic clear plus void send drops the draft
Files Reviewed (10 files)
  • apps/mobile/AGENTS.md
  • apps/mobile/src/app/(app)/(tabs)/_layout.tsx
  • apps/mobile/src/components/chat/chat-screen.tsx - 1 issue
  • apps/mobile/src/lib/chat/layers.ts
  • apps/mobile/src/lib/chat/registry.test.ts
  • apps/mobile/src/lib/chat/registry.ts - 1 issue
  • apps/mobile/src/lib/chat/tools.test.ts
  • apps/mobile/src/lib/chat/tools.ts
  • apps/mobile/src/lib/tab-bar-layout.test.ts
  • apps/mobile/src/lib/tab-bar-layout.ts

Fix these issues in Kilo Cloud

Previous review (commit 5c686fd)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
apps/mobile/src/lib/chat/registry.ts 336 Drain drops the cloned session after a queued model switch
apps/mobile/src/components/chat/chat-screen.tsx 134 Optimistic clear plus void send drops the draft
Files Reviewed (3 files)
  • apps/mobile/src/components/chat/chat-list-screen.tsx
  • apps/mobile/src/components/chat/chat-row.tsx
  • apps/mobile/src/lib/chat/use-chat.ts

Fix these issues in Kilo Cloud

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


Reviewed by deepseek-v4.1-flash · Input: 91.9K · Output: 24.6K · Cached: 1.4M

Review guidance: REVIEW.md from base branch feat/kilo-harness-sdk

Comment thread apps/mobile/src/lib/chat/registry.ts Resolved
Comment thread apps/mobile/src/lib/chat/registry.ts Resolved
Comment thread apps/mobile/src/lib/chat/registry.ts Resolved
@iscekic iscekic closed this Sep 5, 2026
@iscekic iscekic reopened this Sep 5, 2026
@iscekic
iscekic force-pushed the feat/mobile-harness-chat branch from ef4251c to 326f2c3 Compare September 5, 2026 23:04
@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 6, 2026
@iscekic
iscekic force-pushed the feat/mobile-harness-chat branch from 326f2c3 to 2bf4d8d Compare September 6, 2026 02:11
@iscekic iscekic self-assigned this Sep 9, 2026
@iscekic iscekic removed the human-ready The PR is ready for human review. label Sep 10, 2026
@iscekic
iscekic marked this pull request as draft September 10, 2026 00:35
@iscekic
iscekic force-pushed the feat/mobile-harness-chat branch from 62dae71 to 0eb98d1 Compare September 10, 2026 00:39
@iscekic
iscekic force-pushed the feat/mobile-harness-chat branch from 0eb98d1 to 5c5a68c Compare September 10, 2026 04:26
@iscekic
iscekic force-pushed the feat/mobile-harness-chat branch from 5c5a68c to 84e71c4 Compare September 10, 2026 18:24
@iscekic
iscekic force-pushed the feat/mobile-harness-chat branch from 84e71c4 to 4ae54a0 Compare September 12, 2026 11:58
@iscekic
iscekic force-pushed the feat/mobile-harness-chat branch from 4ae54a0 to 8f2d387 Compare September 12, 2026 14:12
@iscekic
iscekic marked this pull request as ready for review September 12, 2026 14:55
Comment thread apps/mobile/src/lib/chat/use-chat.ts Resolved
Comment thread apps/mobile/src/lib/chat/use-chat.ts Resolved
Comment thread apps/mobile/src/lib/chat/registry.ts Resolved
Comment thread apps/mobile/src/lib/chat/registry.ts Resolved
Comment thread .github/workflows/kilo-app-ci.yml Resolved
@iscekic
iscekic marked this pull request as draft September 12, 2026 15:18
@iscekic
iscekic force-pushed the feat/mobile-harness-chat branch from 8f2d387 to 2573d62 Compare September 13, 2026 03:38
…on inline

A remote tool is waited on for 15 s before the session backgrounds it, and the
call's own default deadline was also 15 s, so a backgrounded call failed at
that moment instead of answering. A call now defaults to 60 s; discovery keeps
15 s.
The registry builds a chat from the snapshot, not from the return value. A
cache hit returned the ready answer while another scope's discovery had
published connecting over it, so the chat opened on the base tools.
A caller that joined a running discovery took the first caller's deadline, so
an open that met a Retry waited fifteen seconds and a Retry that met an open
was cut to four. A caller now joins only a discovery with its own deadline,
and only the latest discovery is published.
In the unavailable state the switch read off while the chat's setting was on,
so a tap wrote the value already stored and the switch snapped back. The view
now says whether the switch can move, and the sheet disables it when not.
Main added a shouldHideTabBar call in app-root-providers.tsx with the old
one-argument form. This branch reads the chat conversation from the segments,
so the call now passes them too.
…h test

Main's lifecycle file already holds queryClientMock at module scope. The
branch's test declared it again from a dynamic import, which lint refuses as a
shadow and as an unbound method.
vitest.setup.ts now stubs @/lib/config for every pure suite, so the plain
dynamic import in config.test.ts returned the stub and KILO_MCP_URL read as
undefined. The test now loads the module through vi.importActual.
@iscekic iscekic removed the human-ready The PR is ready for human review. label Sep 27, 2026
…/mobile-harness-chat

# Conflicts:
#	apps/mobile/AGENTS.md
#	apps/mobile/package.json
#	apps/mobile/src/components/kilo-pass/kilo-pass-subscription-screen.test.ts
#	apps/mobile/src/components/kilo-pass/kilo-pass-subscription-screen.tsx
#	apps/mobile/src/components/quick-chat/quick-chat-screen.mounted.test.tsx
#	apps/mobile/src/components/quick-chat/quick-chat-screen.tsx
#	apps/mobile/src/i18n/locales/am.json
#	apps/mobile/src/i18n/locales/az.json
#	apps/mobile/src/i18n/locales/fa.json
#	apps/mobile/src/i18n/locales/gu.json
#	apps/mobile/src/i18n/locales/hy.json
#	apps/mobile/src/i18n/locales/km.json
#	apps/mobile/src/i18n/locales/ml.json
#	apps/mobile/src/i18n/locales/mn.json
#	apps/mobile/src/i18n/locales/my.json
#	apps/mobile/src/i18n/locales/ne.json
#	apps/mobile/src/i18n/locales/or.json
#	apps/mobile/src/i18n/locales/pa.json
#	apps/mobile/src/i18n/locales/si.json
#	apps/mobile/src/i18n/locales/te.json
#	apps/mobile/src/i18n/locales/uz.json
#	apps/web/src/routers/quick-chat-router.test.ts
#	apps/web/src/routers/quick-chat-router.ts
#	packages/db/src/migrations/meta/0263_snapshot.json
#	packages/db/src/migrations/meta/_journal.json
#	pnpm-lock.yaml
@socket-security

socket-security Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​modelcontextprotocol/​sdk@​1.30.0998510098100

View full report

@socket-security

socket-security Bot commented Oct 10, 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 security risk (AI signal): npm @modelcontextprotocol/sdk is 70.0% likely risky

Notes: No strong evidence of intentional malware/backdoor behavior in this code fragment (no command execution or covert remote exfiltration). However, the module contains multiple high-impact security anti-patterns: (1) it logs a user-submitted API key in plaintext, (2) it interpolates untrusted values (userSession.name and cartId) directly into HTML without escaping (XSS risk), (3) CORS is configured permissively (origin '*', credentials:true), and (4) elicitation completion appears weakly bound to the presenting MCP session/user context in the shown endpoints. Treat this as high security risk if used beyond a tightly controlled demo environment.

Confidence: 0.70

Severity: 0.73

From: packages/harness-sdk/package.json → npm/@modelcontextprotocol/sdk@1.30.0

ℹ Read more on: This package | This alert | What are AI-detected potential security risks?

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: An AI system identified potential security problems in this package. It is advised to review the package thoroughly and assess the potential risks before installation. You may also consider reporting the issue to the package maintainer or seeking alternative solutions with a stronger security posture.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@modelcontextprotocol/sdk@1.30.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

View full report

@iscekic
iscekic merged commit fc19184 into main Oct 10, 2026
65 checks passed
@iscekic
iscekic deleted the feat/mobile-harness-chat branch October 10, 2026 23:09
iscekic added a commit that referenced this pull request Oct 11, 2026
…uick Chat (#7338)

* feat(harness-sdk): the kilo harness SDK

#5878

* feat(mobile): rebuild the chat tab on the harness SDK

#5895

* chore(kilo-mcp): refresh catalog.json from CI

* feat(mobile): connect chat to the Kilo MCP server with the signed-in session (#6420)

#6420

* chore: publish the verified app-agent settings tools + remote MCP stack as one PR (level 1)

* fix(mobile): preserve settings and remote MCP state across cold loads

* fix(mobile): satisfy async and control-flow lint rules

* fix(harness-sdk): keep the library's abort link until the operation ends

fetch resolves when the headers arrive, so the per-request unlink let close()
leave an open stream running until the deadline timer fired. The deadline now
holds each joined signal once and removes it at stop.

* fix(harness-sdk): bound the credential by the operation's deadline

The token was asked before the deadline existed, so a slow refresh could hold
a chat open past the discovery bound. The deadline now comes first and the
credential races it.

* fix(harness-sdk): give a call a deadline above the time it is waited on inline

A remote tool is waited on for 15 s before the session backgrounds it, and the
call's own default deadline was also 15 s, so a backgrounded call failed at
that moment instead of answering. A call now defaults to 60 s; discovery keeps
15 s.

* fix(mobile): publish the Kilo tools answer that a cache hit serves

The registry builds a chat from the snapshot, not from the return value. A
cache hit returned the ready answer while another scope's discovery had
published connecting over it, so the chat opened on the base tools.

* fix(mobile): keep each Kilo tools discovery on its caller's deadline

A caller that joined a running discovery took the first caller's deadline, so
an open that met a Retry waited fifteen seconds and a Retry that met an open
was cut to four. A caller now joins only a discovery with its own deadline,
and only the latest discovery is published.

* fix(mobile): lock the Kilo tools switch when there is nothing to use

In the unavailable state the switch read off while the chat's setting was on,
so a tap wrote the value already stored and the switch snapped back. The view
now says whether the switch can move, and the sheet disables it when not.

* fix(deps): rebuild the lockfile on main's pins

The merge rebuilt the lockfile from the branch side, so pnpm resolved again
every package main had added since. That moved @peculiar/asn1-* to 2.9.5 and
broke the passkey verification tests in apps/web. The lockfile is now main's,
with only the harness SDK's own entries added.

* fix(mobile): pass the segments to the toaster's tab bar check

Main added a shouldHideTabBar call in app-root-providers.tsx with the old
one-argument form. This branch reads the chat conversation from the segments,
so the call now passes them too.

* test(mobile): read the hoisted query client mock in the account switch test

Main's lifecycle file already holds queryClientMock at module scope. The
branch's test declared it again from a dynamic import, which lint refuses as a
shadow and as an unbound method.

* fix(mobile): describe the spend alerts notification setting

Main added the spendAlerts notification category. The agent settings catalog
maps every category to a description, so typecheck failed on the missing one.

* fix(mobile): use the shared MCP servers copy in the chat sheet

Main added profiles.mcp.title and profiles.mcp.add with the same English copy
as modelChat.mcp.serversSection and modelChat.mcp.addServer, and the catalog
check refuses two keys for one copy. The chat section now reads the profile
keys, and the two chat keys are removed from every catalog.

* test(mobile): load the real config module in the MCP URL test

vitest.setup.ts now stubs @/lib/config for every pure suite, so the plain
dynamic import in config.test.ts returned the stub and KILO_MCP_URL read as
undefined. The test now loads the module through vi.importActual.

* test(mobile): allow the remote MCP id slug in the case guard

slugFor in remote-mcp-store.ts lowercases a server name to build the callable
tool-name id. The id is never shown, so the file joins the non-display list.

* feat(mobile): support configurable Quick Chat backends

* test(harness): construct synthetic credential URL explicitly

* fix(mobile): address Quick Chat backend review findings

* fix(mobile): reopen a failed chat from Retry

* test(mobile): allow protocol-identifier case normalization in backend files

* fix(mobile): wait for stored backends before the send check

* feat(mobile): add on-device Apple Foundation Models to Quick Chat

* feat(mobile): add on-device Gemini Nano to Quick Chat on Android

* fix(mobile): reference the Retry label in the on-device background copy

* feat(mobile): add llama.rn GGUF models to Quick Chat

* style(mobile): format the on-device GGUF files

* test(mobile): allow the GGUF file-extension comparison in the case guard

* fix(mobile): keep unreadable model entries from deleting downloads

* test(mobile): split the model-index policy tests into their own suite

* fix(mobile): never rewrite a model list holding an unreadable entry

* fix(mobile): keep any list that did not parse in full from being rewritten

* fix(mobile): read a GGUF result that carries nulls or only text

* fix(mobile): treat a null parsed content as absent

* test(mobile): pin the null-heavy llama.rn result at the client level

* feat(mobile): open message details and recover a failed question in Quick Chat

A long-press on a Quick Chat message opens the message details sheet.
The unanswered question carries Retry and Copy to composer inline.
A failed answer reads as a failed response, not as a stopped message.
The chat row under the transcript states the reason and keeps its Retry
only when no question waits for an answer.

Quick Chat messages carry no model and no time. A model switch copies
every turn into a new session, so the details sheet omits those rows.

* fix(mobile): drop the duplicate llama.rn proguard rule

The merge of main added a second extraProguardRules next to main's combined
rule, which app.config.ts rejects as a duplicate key. Keep main's combined rule.

* ci(trufflehog): exclude the synthetic-credential test fixture

security.test.ts builds a credential URL from the literal
'user:private-key@provider.example'. The commit that added it stays in this
branch's history, so trufflehog reports it on every base..head scan even though
a later commit replaced it with a constructed value. Exclude the fixture path.

* fix(db): drop the stale duplicate 0263_drop_quick_chat migration

main lands the drop as 0274_drop_quick_chat.sql (registered in the journal). The
same drop sits in this branch's lineage as 0263_drop_quick_chat.sql, unregistered
and colliding with 0263_spend_alerts_rollup_covering_index. The merge kept it
because main never had that path. Remove it; the tree now matches main.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
iscekic added a commit that referenced this pull request Oct 11, 2026
* feat(harness-sdk): the kilo harness SDK

#5878

* feat(mobile): rebuild the chat tab on the harness SDK

#5895

* chore(kilo-mcp): refresh catalog.json from CI

* feat(mobile): connect chat to the Kilo MCP server with the signed-in session (#6420)

#6420

* chore: publish the verified app-agent settings tools + remote MCP stack as one PR (level 1)

* fix(mobile): preserve settings and remote MCP state across cold loads

* fix(mobile): satisfy async and control-flow lint rules

* fix(harness-sdk): keep the library's abort link until the operation ends

fetch resolves when the headers arrive, so the per-request unlink let close()
leave an open stream running until the deadline timer fired. The deadline now
holds each joined signal once and removes it at stop.

* fix(harness-sdk): bound the credential by the operation's deadline

The token was asked before the deadline existed, so a slow refresh could hold
a chat open past the discovery bound. The deadline now comes first and the
credential races it.

* fix(harness-sdk): give a call a deadline above the time it is waited on inline

A remote tool is waited on for 15 s before the session backgrounds it, and the
call's own default deadline was also 15 s, so a backgrounded call failed at
that moment instead of answering. A call now defaults to 60 s; discovery keeps
15 s.

* fix(mobile): publish the Kilo tools answer that a cache hit serves

The registry builds a chat from the snapshot, not from the return value. A
cache hit returned the ready answer while another scope's discovery had
published connecting over it, so the chat opened on the base tools.

* fix(mobile): keep each Kilo tools discovery on its caller's deadline

A caller that joined a running discovery took the first caller's deadline, so
an open that met a Retry waited fifteen seconds and a Retry that met an open
was cut to four. A caller now joins only a discovery with its own deadline,
and only the latest discovery is published.

* fix(mobile): lock the Kilo tools switch when there is nothing to use

In the unavailable state the switch read off while the chat's setting was on,
so a tap wrote the value already stored and the switch snapped back. The view
now says whether the switch can move, and the sheet disables it when not.

* fix(deps): rebuild the lockfile on main's pins

The merge rebuilt the lockfile from the branch side, so pnpm resolved again
every package main had added since. That moved @peculiar/asn1-* to 2.9.5 and
broke the passkey verification tests in apps/web. The lockfile is now main's,
with only the harness SDK's own entries added.

* fix(mobile): pass the segments to the toaster's tab bar check

Main added a shouldHideTabBar call in app-root-providers.tsx with the old
one-argument form. This branch reads the chat conversation from the segments,
so the call now passes them too.

* test(mobile): read the hoisted query client mock in the account switch test

Main's lifecycle file already holds queryClientMock at module scope. The
branch's test declared it again from a dynamic import, which lint refuses as a
shadow and as an unbound method.

* fix(mobile): describe the spend alerts notification setting

Main added the spendAlerts notification category. The agent settings catalog
maps every category to a description, so typecheck failed on the missing one.

* fix(mobile): use the shared MCP servers copy in the chat sheet

Main added profiles.mcp.title and profiles.mcp.add with the same English copy
as modelChat.mcp.serversSection and modelChat.mcp.addServer, and the catalog
check refuses two keys for one copy. The chat section now reads the profile
keys, and the two chat keys are removed from every catalog.

* test(mobile): load the real config module in the MCP URL test

vitest.setup.ts now stubs @/lib/config for every pure suite, so the plain
dynamic import in config.test.ts returned the stub and KILO_MCP_URL read as
undefined. The test now loads the module through vi.importActual.

* test(mobile): allow the remote MCP id slug in the case guard

slugFor in remote-mcp-store.ts lowercases a server name to build the callable
tool-name id. The id is never shown, so the file joins the non-display list.

* feat(mobile): support configurable Quick Chat backends

* test(harness): construct synthetic credential URL explicitly

* fix(mobile): address Quick Chat backend review findings

* fix(mobile): reopen a failed chat from Retry

* test(mobile): allow protocol-identifier case normalization in backend files

* fix(mobile): wait for stored backends before the send check

* feat(mobile): add on-device Apple Foundation Models to Quick Chat

* feat(mobile): add on-device Gemini Nano to Quick Chat on Android

* fix(mobile): reference the Retry label in the on-device background copy

* feat(mobile): add llama.rn GGUF models to Quick Chat

* style(mobile): format the on-device GGUF files

* test(mobile): allow the GGUF file-extension comparison in the case guard

* fix(mobile): keep unreadable model entries from deleting downloads

* test(mobile): split the model-index policy tests into their own suite

* fix(mobile): never rewrite a model list holding an unreadable entry

* fix(mobile): keep any list that did not parse in full from being rewritten

* fix(mobile): read a GGUF result that carries nulls or only text

* fix(mobile): treat a null parsed content as absent

* test(mobile): pin the null-heavy llama.rn result at the client level

* fix(mobile): remove the mode chip from the Quick Chat composer

Quick Chat is not an agent session, so modes do not apply. The toolbar and
the composer take one optional modeControl object. Without it, the toolbar
draws no mode chip and the model chip starts the row.

* test(mobile): pin the mode control on the session composer

* fix(mobile): drop the duplicate llama.rn proguard rule

The merge of main added a second extraProguardRules next to main's combined
rule, which app.config.ts rejects as a duplicate key. Keep main's combined rule.

* ci(trufflehog): exclude the synthetic-credential test fixture

security.test.ts builds a credential URL from the literal
'user:private-key@provider.example'. The commit that added it stays in this
branch's history, so trufflehog reports it on every base..head scan even though
a later commit replaced it with a constructed value. Exclude the fixture path.

* fix(db): drop the stale duplicate 0263_drop_quick_chat migration

main lands the drop as 0274_drop_quick_chat.sql (registered in the journal). The
same drop sits in this branch's lineage as 0263_drop_quick_chat.sql, unregistered
and colliding with 0263_spend_alerts_rollup_covering_index. The merge kept it
because main never had that path. Remove it; the tree now matches main.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
iscekic added a commit that referenced this pull request Oct 11, 2026
* feat(harness-sdk): the kilo harness SDK

#5878

* feat(mobile): rebuild the chat tab on the harness SDK

#5895

* chore(kilo-mcp): refresh catalog.json from CI

* feat(mobile): connect chat to the Kilo MCP server with the signed-in session (#6420)

#6420

* chore: publish the verified app-agent settings tools + remote MCP stack as one PR (level 1)

* fix(mobile): preserve settings and remote MCP state across cold loads

* fix(mobile): satisfy async and control-flow lint rules

* fix(harness-sdk): keep the library's abort link until the operation ends

fetch resolves when the headers arrive, so the per-request unlink let close()
leave an open stream running until the deadline timer fired. The deadline now
holds each joined signal once and removes it at stop.

* fix(harness-sdk): bound the credential by the operation's deadline

The token was asked before the deadline existed, so a slow refresh could hold
a chat open past the discovery bound. The deadline now comes first and the
credential races it.

* fix(harness-sdk): give a call a deadline above the time it is waited on inline

A remote tool is waited on for 15 s before the session backgrounds it, and the
call's own default deadline was also 15 s, so a backgrounded call failed at
that moment instead of answering. A call now defaults to 60 s; discovery keeps
15 s.

* fix(mobile): publish the Kilo tools answer that a cache hit serves

The registry builds a chat from the snapshot, not from the return value. A
cache hit returned the ready answer while another scope's discovery had
published connecting over it, so the chat opened on the base tools.

* fix(mobile): keep each Kilo tools discovery on its caller's deadline

A caller that joined a running discovery took the first caller's deadline, so
an open that met a Retry waited fifteen seconds and a Retry that met an open
was cut to four. A caller now joins only a discovery with its own deadline,
and only the latest discovery is published.

* fix(mobile): lock the Kilo tools switch when there is nothing to use

In the unavailable state the switch read off while the chat's setting was on,
so a tap wrote the value already stored and the switch snapped back. The view
now says whether the switch can move, and the sheet disables it when not.

* fix(deps): rebuild the lockfile on main's pins

The merge rebuilt the lockfile from the branch side, so pnpm resolved again
every package main had added since. That moved @peculiar/asn1-* to 2.9.5 and
broke the passkey verification tests in apps/web. The lockfile is now main's,
with only the harness SDK's own entries added.

* fix(mobile): pass the segments to the toaster's tab bar check

Main added a shouldHideTabBar call in app-root-providers.tsx with the old
one-argument form. This branch reads the chat conversation from the segments,
so the call now passes them too.

* test(mobile): read the hoisted query client mock in the account switch test

Main's lifecycle file already holds queryClientMock at module scope. The
branch's test declared it again from a dynamic import, which lint refuses as a
shadow and as an unbound method.

* fix(mobile): describe the spend alerts notification setting

Main added the spendAlerts notification category. The agent settings catalog
maps every category to a description, so typecheck failed on the missing one.

* fix(mobile): use the shared MCP servers copy in the chat sheet

Main added profiles.mcp.title and profiles.mcp.add with the same English copy
as modelChat.mcp.serversSection and modelChat.mcp.addServer, and the catalog
check refuses two keys for one copy. The chat section now reads the profile
keys, and the two chat keys are removed from every catalog.

* test(mobile): load the real config module in the MCP URL test

vitest.setup.ts now stubs @/lib/config for every pure suite, so the plain
dynamic import in config.test.ts returned the stub and KILO_MCP_URL read as
undefined. The test now loads the module through vi.importActual.

* test(mobile): allow the remote MCP id slug in the case guard

slugFor in remote-mcp-store.ts lowercases a server name to build the callable
tool-name id. The id is never shown, so the file joins the non-display list.

* feat(mobile): support configurable Quick Chat backends

* test(harness): construct synthetic credential URL explicitly

* fix(mobile): address Quick Chat backend review findings

* fix(mobile): reopen a failed chat from Retry

* test(mobile): allow protocol-identifier case normalization in backend files

* fix(mobile): wait for stored backends before the send check

* feat(mobile): add on-device Apple Foundation Models to Quick Chat

* feat(mobile): add on-device Gemini Nano to Quick Chat on Android

* fix(mobile): reference the Retry label in the on-device background copy

* feat(mobile): add llama.rn GGUF models to Quick Chat

* style(mobile): format the on-device GGUF files

* test(mobile): allow the GGUF file-extension comparison in the case guard

* fix(mobile): keep unreadable model entries from deleting downloads

* test(mobile): split the model-index policy tests into their own suite

* fix(mobile): never rewrite a model list holding an unreadable entry

* fix(mobile): keep any list that did not parse in full from being rewritten

* fix(mobile): read a GGUF result that carries nulls or only text

* fix(mobile): treat a null parsed content as absent

* test(mobile): pin the null-heavy llama.rn result at the client level

* feat(mobile): send images to Quick Chat models that read them

Quick Chat accepts images from the picker and the clipboard when the
selected model reads images. The images stay on the device: the composer
reads them as bounded JPEG base64 and hands them to the send path. The
Cloud Agent upload path does not change.

Capability contract:
- backend-capabilities.ts: targetSupportsImages(targetId),
  resolvedTargetSupportsImages(target), rememberKiloImageModels(models)
  and useTargetSupportsImages(targetId).
- LocalModelProvider.supportsImages(modelId). Every on-device provider
  returns false.
- Kilo models read image support from the gateway catalog
  (architecture.input_modalities). Custom backend models get an images
  flag with a toggle. A stored model without the flag reads as text-only.

The router replaces image parts with a short text marker for a target
that does not read images, so a model switch after an image does not
fail at the provider. The unanswered question keeps its images for
Retry, and the transcript shows them.

* feat(mobile): read images with downloaded vision models

A downloaded GGUF model can now read images when it has a vision
projector (mmproj). The catalog adds SmolVLM 500M Instruct with its
projector, both pinned to one Hugging Face revision with size, SHA-256
and licence.

- Downloads: a vision model downloads the model file, then the
  projector, as one download with one progress bar and one storage
  check. Cancel, failure and delete remove both files.
- Records: a record has a vision flag. A record saved before this
  change reads as text-only.
- Inspection: a vision model loads in full with its projector, and the
  download is accepted only when llama.cpp reports vision support.
- Runtime: the context loads the projector after init with ctx_shift
  off. supportsImages is true only for a verified vision record.
- Template: a user turn with an image goes to llama.rn as content parts
  with a base64 data URL. llama.rn decodes it, so no image file is
  written. A model without a projector does not get images.

Direct-link models stay text-only.

* fix(mobile): keep the catalog file type private

* fix(mobile): show no upload progress on a local Quick Chat image

A local image never uploads, so its chip starts with no progress value
and the strip does not read "0%".

* fix(mobile): release the native image on every encode path

The encoder now releases the rendered image after a failed read or a
failed save, not only after a successful one. Tests pin the release on
each path, and that the images flag survives a backend save.

* test(mobile): pin the native image release and the backend image flag

Tests: the encoder releases each rendered image after a read, a resize, a
failed save and a too-large result; a backend save keeps the image flag.

* fix(mobile): a local Quick Chat image is not an upload

A locally delivered image chip had status 'pending', which the strip
treats as an upload in flight: a permanent spinner and an "Uploading…"
announcement for an image that never leaves the device. Local chips now
carry a 'local' status that starts no upload, shows no progress and
announces the file size instead.

* fix(mobile): drop the duplicate llama.rn proguard rule

The merge of main added a second extraProguardRules next to main's combined
rule, which app.config.ts rejects as a duplicate key. Keep main's combined rule.

* ci(trufflehog): exclude the synthetic-credential test fixture

security.test.ts builds a credential URL from the literal
'user:private-key@provider.example'. The commit that added it stays in this
branch's history, so trufflehog reports it on every base..head scan even though
a later commit replaced it with a constructed value. Exclude the fixture path.

* fix(db): drop the stale duplicate 0263_drop_quick_chat migration

main lands the drop as 0274_drop_quick_chat.sql (registered in the journal). The
same drop sits in this branch's lineage as 0263_drop_quick_chat.sql, unregistered
and colliding with 0263_spend_alerts_rollup_covering_index. The merge kept it
because main never had that path. Remove it; the tree now matches main.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
iscekic added a commit that referenced this pull request Oct 11, 2026
* feat(harness-sdk): the kilo harness SDK

#5878

* feat(mobile): rebuild the chat tab on the harness SDK

#5895

* chore(kilo-mcp): refresh catalog.json from CI

* feat(mobile): connect chat to the Kilo MCP server with the signed-in session (#6420)

#6420

* chore: publish the verified app-agent settings tools + remote MCP stack as one PR (level 1)

* fix(mobile): preserve settings and remote MCP state across cold loads

* fix(mobile): satisfy async and control-flow lint rules

* fix(harness-sdk): keep the library's abort link until the operation ends

fetch resolves when the headers arrive, so the per-request unlink let close()
leave an open stream running until the deadline timer fired. The deadline now
holds each joined signal once and removes it at stop.

* fix(harness-sdk): bound the credential by the operation's deadline

The token was asked before the deadline existed, so a slow refresh could hold
a chat open past the discovery bound. The deadline now comes first and the
credential races it.

* fix(harness-sdk): give a call a deadline above the time it is waited on inline

A remote tool is waited on for 15 s before the session backgrounds it, and the
call's own default deadline was also 15 s, so a backgrounded call failed at
that moment instead of answering. A call now defaults to 60 s; discovery keeps
15 s.

* fix(mobile): publish the Kilo tools answer that a cache hit serves

The registry builds a chat from the snapshot, not from the return value. A
cache hit returned the ready answer while another scope's discovery had
published connecting over it, so the chat opened on the base tools.

* fix(mobile): keep each Kilo tools discovery on its caller's deadline

A caller that joined a running discovery took the first caller's deadline, so
an open that met a Retry waited fifteen seconds and a Retry that met an open
was cut to four. A caller now joins only a discovery with its own deadline,
and only the latest discovery is published.

* fix(mobile): lock the Kilo tools switch when there is nothing to use

In the unavailable state the switch read off while the chat's setting was on,
so a tap wrote the value already stored and the switch snapped back. The view
now says whether the switch can move, and the sheet disables it when not.

* fix(deps): rebuild the lockfile on main's pins

The merge rebuilt the lockfile from the branch side, so pnpm resolved again
every package main had added since. That moved @peculiar/asn1-* to 2.9.5 and
broke the passkey verification tests in apps/web. The lockfile is now main's,
with only the harness SDK's own entries added.

* fix(mobile): pass the segments to the toaster's tab bar check

Main added a shouldHideTabBar call in app-root-providers.tsx with the old
one-argument form. This branch reads the chat conversation from the segments,
so the call now passes them too.

* test(mobile): read the hoisted query client mock in the account switch test

Main's lifecycle file already holds queryClientMock at module scope. The
branch's test declared it again from a dynamic import, which lint refuses as a
shadow and as an unbound method.

* fix(mobile): describe the spend alerts notification setting

Main added the spendAlerts notification category. The agent settings catalog
maps every category to a description, so typecheck failed on the missing one.

* fix(mobile): use the shared MCP servers copy in the chat sheet

Main added profiles.mcp.title and profiles.mcp.add with the same English copy
as modelChat.mcp.serversSection and modelChat.mcp.addServer, and the catalog
check refuses two keys for one copy. The chat section now reads the profile
keys, and the two chat keys are removed from every catalog.

* test(mobile): load the real config module in the MCP URL test

vitest.setup.ts now stubs @/lib/config for every pure suite, so the plain
dynamic import in config.test.ts returned the stub and KILO_MCP_URL read as
undefined. The test now loads the module through vi.importActual.

* test(mobile): allow the remote MCP id slug in the case guard

slugFor in remote-mcp-store.ts lowercases a server name to build the callable
tool-name id. The id is never shown, so the file joins the non-display list.

* feat(mobile): support configurable Quick Chat backends

* test(harness): construct synthetic credential URL explicitly

* fix(mobile): address Quick Chat backend review findings

* fix(mobile): reopen a failed chat from Retry

* test(mobile): allow protocol-identifier case normalization in backend files

* fix(mobile): wait for stored backends before the send check

* feat(mobile): add on-device Apple Foundation Models to Quick Chat

* feat(mobile): add on-device Gemini Nano to Quick Chat on Android

* fix(mobile): reference the Retry label in the on-device background copy

* feat(mobile): add llama.rn GGUF models to Quick Chat

* style(mobile): format the on-device GGUF files

* test(mobile): allow the GGUF file-extension comparison in the case guard

* fix(mobile): keep unreadable model entries from deleting downloads

* test(mobile): split the model-index policy tests into their own suite

* fix(mobile): never rewrite a model list holding an unreadable entry

* fix(mobile): keep any list that did not parse in full from being rewritten

* fix(mobile): read a GGUF result that carries nulls or only text

* fix(mobile): treat a null parsed content as absent

* test(mobile): pin the null-heavy llama.rn result at the client level

* feat(mobile): give the Apple on-device model the chat's tools

Foundation Models calls harness tools through dynamic tools. The model's
calls go to JavaScript as harness toolCall parts with the transcript ids.
The generation waits while the harness runs them, and the next request
resumes it with the results. Later requests rebuild the transcript with
the tool calls and their outputs.

JavaScript reduces each JSON Schema to what DynamicGenerationSchema can
express. A tool that does not fit is left out and logged. Gemini Nano
stays text-only because the ML Kit Prompt API has no function calling.

* fix(mobile): keep native schema and message types module-private

* fix(mobile): count tokens for a request that ends on tool outputs

A resumed tool round sends a request whose last entry is a tool output.
The Apple module refused to count it, so usage fell back to the estimate.
Only generation now needs a user prompt last.

* fix(mobile): drop the duplicate llama.rn proguard rule

The merge of main added a second extraProguardRules next to main's combined
rule, which app.config.ts rejects as a duplicate key. Keep main's combined rule.

* fix(kilo-app): build the harness SDK before the EAS bundle

The release EAS build bundles apps/mobile with Metro, which resolves
@kilocode/harness-sdk through its package.json exports to dist/index.js. The
workspace package is not built on EAS, so the Android and iOS bundles fail with
'none of these files exist' and the release never submits.

Add the eas-build-post-install hook the EAS build runs after install. It builds
the SDK, so Metro finds dist before it bundles. Verified with
expo export:embed --eager --platform android: it fails without dist and
succeeds after the hook builds it.

* ci(trufflehog): exclude the synthetic-credential test fixture

security.test.ts builds a credential URL from the literal
'user:private-key@provider.example'. The commit that added it stays in this
branch's history, so trufflehog reports it on every base..head scan even though
a later commit replaced it with a constructed value. Exclude the fixture path.

* fix(db): drop the stale duplicate 0263_drop_quick_chat migration

main lands the drop as 0274_drop_quick_chat.sql (registered in the journal). The
same drop sits in this branch's lineage as 0263_drop_quick_chat.sql, unregistered
and colliding with 0263_spend_alerts_rollup_covering_index. The merge kept it
because main never had that path. Remove it; the tree now matches main.

* fix(mobile): keep NativeImage module-private

knip flags the export as unused: only native-request.ts builds an image part.
Drop the export keyword.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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