Skip to content

Sync model picker state across ADE surfaces#493

Merged
arul28 merged 2 commits into
mainfrom
ship/tui-model-picker-nav-sync
Jun 1, 2026
Merged

Sync model picker state across ADE surfaces#493
arul28 merged 2 commits into
mainfrom
ship/tui-model-picker-nav-sync

Conversation

@arul28
Copy link
Copy Markdown
Owner

@arul28 arul28 commented May 31, 2026

Summary

  • Persist model picker favorites and recents in the per-project ADE database so desktop, CLI, sync, and iOS bootstrap agree on state.
  • Tighten TUI model picker behavior: provider-lock guard, provider alias normalization, ordered favorites, preserved in-progress new-chat picker state, and immediate Claude terminal model command sync.
  • Document the DB-backed model picker flow across architecture, ADE code, chat UI, and sync docs.

Validation

  • npm --prefix apps/desktop run typecheck
  • npm --prefix apps/ade-cli run typecheck
  • npm --prefix apps/web run typecheck
  • npm --prefix apps/desktop run lint
  • npm run test:desktop:sharded, with isolated reruns for resource-flake files: linearAuth, localRuntimeConnectionPool, App.workKeepAlive
  • npm --prefix apps/ade-cli run test, with isolated reruns for resource-flake files: stdioRpcDaemon, TerminalPane, appPolling
  • npm --prefix apps/desktop run build
  • npm --prefix apps/ade-cli run build
  • npm --prefix apps/web run build
  • node scripts/validate-docs.mjs
  • git diff --check and control-byte scan

Risks

  • Model picker preferences migrate from the legacy JSON file into SQLite once per project; the migration marker is durable to avoid stale resurrection.
  • iOS bootstrap/schema comments were updated to match the desktop DB tables, but no mobile runtime behavior changes were needed beyond schema parity.

ADE   Open in ADE  ·  ship/tui-model-picker-nav-sync branch  ·  PR #493

Summary by CodeRabbit

  • New Features

    • Model picker favorites and recents now synchronize across desktop, TUI, and iOS within a project.
  • Improvements

    • Redesigned TUI model picker interface with enhanced provider branding and improved layout geometry.
    • Automatic one-time migration of existing model preferences on first use.

Greptile Summary

This PR replaces the file-based (~/.ade/modelPicker.json) model picker persistence with a per-project cr-sqlite DB, enabling CRR replication so desktop, TUI, and iOS converge on the same favorites/recents for a project. It also tightens TUI model picker behavior and geometry.

  • DB migration: Adds model_picker_favorites / model_picker_recents tables to kvDb.ts and DatabaseBootstrap.sql, with a one-time best-effort import of the legacy JSON file wrapped in a proper SQLite transaction; a durable kv marker prevents stale re-import after rows are cleared.
  • Store rewrite: createModelPickerStore now operates synchronously against the DB, with stamped-index ordering for favorites and a module-level sequence counter (sequencedNowStamp) to keep recents ordered within the same millisecond.
  • TUI UX improvements: Provider-locked guard, alias normalization (normalizeCatalogProvider), wider right pane for the model picker, a two-column rail/list nav model with railFocused, and mergeNewChatModelPickerContext to preserve in-progress picker state across lane refreshes.

Confidence Score: 5/5

Safe to merge; the store rewrite is correct, the migration is atomic, and all three previous blocking concerns have been resolved.

The DB migration is wrapped in a proper SQLite transaction, the millisecond timestamp collision is fixed with the stamped-sequence counter, and the legacy file migration marker is durable. The TUI geometry and layout changes are well-unit-tested. No new correctness issues were found.

No files require special attention — the core store and sync wiring are straightforward and covered by the new test suite.

Important Files Changed

Filename Overview
apps/ade-cli/src/services/modelPickerStore.ts Core store rewrite: file persistence replaced with synchronous DB reads/writes; legacy migration wrapped in a transaction; millisecond ordering fixed via sequencedNowStamp; setFavorites reconciles the desired set atomically.
apps/ade-cli/src/services/sync/syncRemoteCommandService.ts db added to SyncRemoteCommandServiceArgs; requireModelPickerStore falls back to getSharedModelPickerStore(db) when no injected accessor is present; "runtime" 4th arg removed from register() calls for model picker commands (appears intentional).
apps/desktop/src/main/services/state/kvDb.ts Two new CRR-eligible tables added at the end of the migration function; both added to PHONE_CRITICAL_CRR_TABLES so they sync to iOS.
apps/ade-cli/src/tuiClient/app.tsx New exports: modelPickerPaneContentOrigin, modelPickerProviderSwitchBlocked, mergeNewChatModelPickerContext, normalizeCatalogProvider; railFocused state added; MODEL_PICKER_RIGHT_PANE_MAX_WIDTH widens pane for model picker; printableMultilineInput regex bug fixed (was removing spaces).
apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.ts Static registry fallback entries for claude/codex added so the picker shows models before the runtime catalog loads; rail always uses PROVIDER_ORDER; showAll flag removed; isAvailable now gates on authStatus.
apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerGeometry.ts RAIL_WIDTH expanded to 16 cols; MODEL_LIST_ROWS reduced to 5 (2-line entries) vs 8 in compact provider view (1-line); showAll HitRect removed; header line count simplified.
apps/ios/ADE/Resources/DatabaseBootstrap.sql model_picker_favorites and model_picker_recents tables added at the end of the iOS bootstrap SQL, mirroring kvDb.ts migration; indentation corrected to 2 spaces.
apps/ade-cli/src/services/modelPickerStore.test.ts Tests migrated from file-backed to openKvDb; covers migration marker, same-millisecond ordering, setFavorites reconciliation, and cross-instance persistence.

Sequence Diagram

sequenceDiagram
    participant iOS
    participant SyncHost as Sync Host (ade-cli)
    participant DB as cr-sqlite DB
    participant TUI
    participant Desktop

    Note over DB: model_picker_favorites<br/>model_picker_recents<br/>(CRR tables)

    TUI->>DB: pushRecent / toggleFavorite (sync write)
    DB-->>TUI: OK

    iOS->>SyncHost: modelPicker.setFavorites (WS sync cmd)
    SyncHost->>DB: requireModelPickerStore().setFavorites()
    DB-->>SyncHost: OK
    SyncHost-->>iOS: "{ favorites: [...] }"

    Desktop->>DB: CRR replication pull
    DB-->>Desktop: merged state

    Note over DB,iOS: CRR replication pushes<br/>changes back to iOS
Loading

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/ade-cli/src/services/modelPickerStore.ts:188-194
The `setFavorites` reconciliation reads `readFavoritesFromDb(db)` before beginning the transaction, then re-queries inside the same call with the post-transaction `readFavoritesFromDb(db)` return. In a CRR-replicated context a concurrent CRR merge could insert a row between the pre-transaction read and the `begin`, causing that row to survive the "delete dropped" loop (since it wasn't in `existing`). That's the correct CRR behaviour — but it also means the returned snapshot may include the concurrent row even though the caller passed a definite desired list. Wrapping the initial `readFavoritesFromDb` inside the same transaction would eliminate the window and make the return value a faithful reflection of the committed state.

```suggestion
    setFavorites: (favorites) => {
      const desired = sanitizeIdList(favorites);
      const desiredSet = new Set(desired);
      db.run("begin");
      const existing = new Set(readFavoritesFromDb(db));
      // Reconcile to the desired set: delete dropped and restamp every desired
      // row so the caller's order is preserved even for existing favorites.
```

### Issue 2 of 2
apps/ade-cli/src/tuiClient/app.tsx:1748-1749
The `printableMultilineInput` regex was silently removing spaces and printable characters like `!`, `"`, `#`, `$` (code points 0x20–0x2D). The new pattern `[\x00-\x08\x0b-\x1f\x7f]` is correct, but the inline comment above it is stale — it still refers to `"x"` instead of the `x\x7f` burst the comment intends to document.

```suggestion
// DEL/BS byte as backspace — so a burst like "x\x7f" (type then delete) arrives
// as plain text with no backspace flag, and naive insertion would drop the \x7f;
```

Reviews (4): Last reviewed commit: "fix: address model picker review finding..." | Re-trigger Greptile

@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jun 1, 2026 12:39am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 31, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR migrates model picker favorites/recents storage from process-wide in-memory + ~/.ade/modelPicker.json to per-project CR-SQLite databases with one-time legacy import. It threads database instances through sync services, refactors the TUI model picker with provider branding and two-line entries, and updates type contracts to remove the showAll flag in favor of query/searchMode state fields.

Changes

Model Picker DB-Backed Storage & TUI Enhancement

Layer / File(s) Summary
Database Schema: Model Picker Tables
apps/desktop/src/main/services/state/kvDb.ts, apps/ios/ADE/Resources/DatabaseBootstrap.sql
Two new per-project CRR tables (model_picker_favorites, model_picker_recents) are added to desktop KV DB schema and iOS bootstrap SQL, keyed by model_id with timestamp fields (created_at, used_at).
Model Picker Store: DB-Backed Implementation
apps/ade-cli/src/services/modelPickerStore.ts, apps/ade-cli/src/services/modelPickerStore.test.ts
Store refactored from file persistence to DB-backed reads/writes. Adds one-time legacy modelPicker.json import with durable marker, reconciles favorites by restamping, caps recents to MAX_RECENTS, and manages per-DB singleton caching. Tests rewritten for DB behavior with no-migration paths.
Service Layer: DB Threading & RPC Integration
apps/ade-cli/src/adeRpcServer.ts, apps/ade-cli/src/bootstrap.ts, apps/ade-cli/src/services/sync/syncHostService.ts, apps/ade-cli/src/services/sync/syncRemoteCommandService.ts, apps/ade-cli/src/services/sync/syncService.ts
DB instance is threaded through bootstrap, sync services, and RPC handlers so each operational context can construct DB-backed model picker stores. Fallback logic requires DB or throws when store accessor is unavailable.
Type Contracts & State Shape
apps/ade-cli/src/tuiClient/types.ts, apps/ade-cli/src/tuiClient/components/ModelPicker/types.ts
ModelPickerState replaces showAll: boolean with query: string and searchMode: boolean fields. ModelPickerRightPaneContent removes showAll and adds optional railFocused: boolean for two-column focus tracking. SetupPaneRowKind removes "open-settings" option.
Geometry Constants & Layout Math
apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerGeometry.ts, apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerGeometry.test.ts
Geometry constants now support distinct provider-row sizing (PROVIDER_MODEL_ENTRY_HEIGHT, PROVIDER_MODEL_LIST_ROWS). headerLineCount no longer adds "active model now" line. New helpers (usesCompactProviderRows, modelEntryHeightForState, etc.) derive layout from state. showAll rectangle removed. Footer placement reworked to use state-specific body line counts; settings layout changed from wrapping chips to vertical rows.
Entry Building & Model Availability
apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.ts, apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.test.ts
Entry construction now merges runtime catalog with static registry fallback entries via entryFromDescriptor and staticRegistryFallbackEntries helpers. Auth-based availability (isAvailable from authStatus) replaces intrinsic availability. Provider aliasing normalized (e.g., anthropicclaude). visibleEntries always shows all entries; showAll filtering removed. New tests verify Anthropic fallback and provider normalization.
TUI Model Picker Components & Layout
apps/ade-cli/src/tuiClient/components/ModelPicker/ModelPickerPane.tsx, apps/ade-cli/src/tuiClient/components/RightPane.tsx
ModelPickerPane substantially refactored: adds provider branding system (SVG logos, mark rendering, title-casing helpers), DOM measurement for hit-rect accuracy via measurePaneOrigin, two-line entry layout with optional logo/subtitle, compact sub-provider tab strip replacing prior selector UI, and per-row settings footer layout. Props updated: railFocused bool and onMeasureOrigin callback added. RightPane wires onModelPickerMeasureOrigin and passes railFocused to pane.
API Model Availability & Input Handling
apps/ade-cli/src/tuiClient/adeApi.ts, apps/ade-cli/src/tuiClient/__tests__/appInput.test.ts, apps/ade-cli/src/tuiClient/__tests__/RightPane.test.tsx
getAvailableModels expands activateRuntime probing to include droid provider (in addition to cursor). appInput.test.ts expands coverage: adds tests for pane-content origin, provider normalization, provider-switch blocking, and context-merge behavior. Updated test fixtures remove showAll: false.
Documentation Updates
apps/ios/ADE/Services/SyncService.swift, apps/ios/ADE/Models/RemoteModels.swift
Inline documentation updated to reflect per-project CR-SQLite storage on ade-cli host instead of ~/.ade/modelPicker.json. No functional code changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

desktop, ios

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Sync model picker state across ADE surfaces' clearly and concisely summarizes the main change: implementing cross-surface persistence of model picker favorites/recents via a per-project database, affecting desktop, TUI, and iOS.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ship/tui-model-picker-nav-sync

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@arul28 arul28 changed the title Primary Sync model picker state across ADE surfaces May 31, 2026
@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 31, 2026

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented May 31, 2026

@copilot review but do not make fixes

Comment thread apps/ade-cli/src/services/modelPickerStore.ts Outdated
Comment thread apps/ade-cli/src/services/sync/syncRemoteCommandService.ts
Comment thread apps/ade-cli/src/services/modelPickerStore.ts
Comment thread apps/ios/ADE/Resources/DatabaseBootstrap.sql Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/ade-cli/src/services/sync/syncRemoteCommandService.ts (1)

2315-2355: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make modelPicker.* project-scoped.

These handlers now read/write per-project state, but they’re still registered as scope: "runtime". In syncHostService.handleCommand, only project-scoped commands require/validate projectId, so a missing or stale project id here will silently mutate the host’s current DB instead of the intended project after a switch.

Proposed fix
-  register("modelPicker.getFavorites", { viewerAllowed: true }, async () => ({
+  register("modelPicker.getFavorites", { viewerAllowed: true }, async () => ({
     favorites: requireModelPickerStore().getFavorites(),
-  }), "runtime");
+  }), "project");
   register("modelPicker.setFavorites", { viewerAllowed: true }, async (payload) => {
     const rawFavorites = (payload as { favorites?: unknown }).favorites;
     const favoritesInput = Array.isArray(rawFavorites)
       ? rawFavorites.filter((entry): entry is string => typeof entry === "string")
       : [];
     return { favorites: requireModelPickerStore().setFavorites(favoritesInput) };
-  }, "runtime");
+  }, "project");
   register("modelPicker.toggleFavorite", { viewerAllowed: true }, async (payload) => {
     const modelId = typeof (payload as { modelId?: unknown }).modelId === "string"
       ? ((payload as { modelId?: string }).modelId as string)
       : "";
     return requireModelPickerStore().toggleFavorite(modelId);
-  }, "runtime");
+  }, "project");
   register("modelPicker.getRecents", { viewerAllowed: true }, async () => ({
     recents: requireModelPickerStore().getRecents(),
-  }), "runtime");
+  }), "project");
   register("modelPicker.pushRecent", { viewerAllowed: true }, async (payload) => {
     const modelId = typeof (payload as { modelId?: unknown }).modelId === "string"
       ? ((payload as { modelId?: string }).modelId as string)
       : "";
     return { recents: requireModelPickerStore().pushRecent(modelId) };
-  }, "runtime");
+  }, "project");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/services/sync/syncRemoteCommandService.ts` around lines 2315
- 2355, The modelPicker handlers in registerModelPickerRemoteCommands are
currently registered with scope "runtime" so they bypass projectId validation
and can mutate the wrong DB; update each register call for
"modelPicker.getFavorites", "modelPicker.setFavorites",
"modelPicker.toggleFavorite", "modelPicker.getRecents", and
"modelPicker.pushRecent" to use scope "project" (replace the final "runtime"
argument with "project") so syncHostService.handleCommand will require/validate
projectId and the handlers operate on the correct per-project store.
apps/ade-cli/src/tuiClient/types.ts (1)

118-119: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Inconsistent export/import for ChatInfoPlanStep.

Line 118 exports ChatInfoPlanStep but line 119 no longer imports it, which will cause a TypeScript error. Remove ChatInfoPlanStep from the export statement on line 118 to match the import.

🐛 Proposed fix
-export type { SubagentSnapshot, ChatInfoPlan, ChatInfoPlanStep } from "../../../desktop/src/shared/chatSubagents";
+export type { SubagentSnapshot, ChatInfoPlan } from "../../../desktop/src/shared/chatSubagents";
 import type { SubagentSnapshot, ChatInfoPlan } from "../../../desktop/src/shared/chatSubagents";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/tuiClient/types.ts` around lines 118 - 119, The export
currently lists ChatInfoPlanStep but the file only imports SubagentSnapshot and
ChatInfoPlan; remove ChatInfoPlanStep from the export statement so the exported
symbols match the imported ones (i.e., export only SubagentSnapshot and
ChatInfoPlan) to eliminate the TypeScript error; update the export line that
currently reads "export type { SubagentSnapshot, ChatInfoPlan, ChatInfoPlanStep
}" to omit ChatInfoPlanStep.
🧹 Nitpick comments (3)
apps/ade-cli/src/tuiClient/components/ModelPicker/ModelPickerPane.tsx (1)

552-559: 💤 Low value

Effects run on every render; consider dependency arrays.

Both useEffect hooks lack dependency arrays, so they execute after every render. For measurement (onMeasureOrigin) this ensures responsiveness to layout changes, but drawInlineLogo performs stdout writes on each render. If performance becomes a concern in terminals supporting inline images, consider memoizing or adding dependencies.

Also applies to: 578-601

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/tuiClient/components/ModelPicker/ModelPickerPane.tsx` around
lines 552 - 559, Both useEffect hooks run after every render because they lack
dependency arrays; update the effect that measures the pane to include the
dependencies it uses (e.g., onMeasureOrigin, rootRef.current and
measurePaneOrigin) so it only re-runs when measurement inputs change, and update
the effect that calls drawInlineLogo to include its inputs (e.g.,
drawInlineLogo, logo data, terminal capability flag) or guard/memoize the
drawInlineLogo call so it does not perform stdout writes on every render; locate
the hooks in ModelPickerPane (the useEffect that references
onMeasureOrigin/rootRef/measurePaneOrigin and the other useEffect that calls
drawInlineLogo) and add appropriate dependency arrays or a memo/guard to prevent
unnecessary re-runs and terminal writes.
apps/ade-cli/src/services/modelPickerStore.ts (2)

170-189: ⚡ Quick win

Wrap setFavorites reconciliation in a transaction for atomicity.

The current implementation performs multiple separate operations (deletes followed by inserts/updates) without an explicit transaction. While SQLite provides some default transactional behavior, concurrent calls could observe partial state during the reconciliation.

Consider wrapping the reconciliation logic in a transaction:

db.run("BEGIN");
try {
  for (const id of existing) {
    if (!desiredSet.has(id)) {
      db.run("delete from model_picker_favorites where model_id = ?", [id]);
    }
  }
  // ... rest of reconciliation
  db.run("COMMIT");
} catch (err) {
  db.run("ROLLBACK");
  throw err;
}

This ensures all-or-nothing semantics and prevents intermediate states from being visible to concurrent readers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/services/modelPickerStore.ts` around lines 170 - 189, The
setFavorites reconciliation (in setFavorites, which uses sanitizeIdList,
readFavoritesFromDb, nowIso and multiple db.run calls) must be wrapped in an
explicit transaction so deletes and inserts/updates are atomic; modify
setFavorites to issue "BEGIN" before performing the existing deletion loop and
insert/update loop, "COMMIT" after successful completion, and "ROLLBACK" in a
catch/finally path on error (rethrow the error), ensuring all db.run operations
use the same db handle so the caller never observes partial state.

123-131: 💤 Low value

Consider using sequential integers instead of timestamp staggering for ordering.

The current approach uses synthesized timestamps like 2026-05-31T23:30:15.000Z#0000 to preserve ordering. While this works (string comparison sorts correctly), it's unconventional and might confuse future maintainers. Consider instead:

  • Add an order_index integer column to both tables
  • Maintain explicit ordering with simple incrementing integers
  • This would be more self-documenting and avoid the non-standard # delimiter

The current implementation is correct, just less intuitive than sequential integers.

Also applies to: 135-140, 181-187

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/services/modelPickerStore.ts` around lines 123 - 131,
Replace the synthesized timestamp-with-hash ordering with an explicit integer
order column: add an order_index column to the model_picker_favorites (and the
other affected table referenced at lines 135-140 and 181-187) and when importing
legacy.favorites use a simple incremental counter (e.g., start at 0 and
increment per item) instead of building createdAt via nowIso() and
String(index).padStart(...); update the INSERT in db.run that targets
"model_picker_favorites (model_id, created_at)" to instead insert into
"model_picker_favorites (model_id, order_index)" (and similarly for the other
table), ensure any queries that previously ordered by created_at now order by
order_index, and remove or stop synthesizing the createdAt string in the import
logic (the functions/variables to change are nowIso(), legacy.favorites, the
createdAt construction, and the INSERTs referencing model_picker_favorites).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.ts`:
- Around line 190-191: The builders produce inconsistent availability flags:
entriesFromCatalog sets isAvailable using model.isAvailable && authStatus !==
"unavailable" while entryFromDescriptor and entryFromModelInfo use only
authStatus !== "unavailable"; unify them by applying the same rule across all
entry builders—either include the intrinsic model.isAvailable check (use
model.isAvailable when present alongside authStatus !== "unavailable") in
entryFromDescriptor and entryFromModelInfo, or remove the model.isAvailable
check from entriesFromCatalog so all three functions rely solely on authStatus
!== "unavailable"; update the availability assignment in entriesFromCatalog,
entryFromDescriptor, and entryFromModelInfo accordingly and ensure any
null/undefined model.isAvailable is treated as true if you choose the
authStatus-only semantics.

---

Outside diff comments:
In `@apps/ade-cli/src/services/sync/syncRemoteCommandService.ts`:
- Around line 2315-2355: The modelPicker handlers in
registerModelPickerRemoteCommands are currently registered with scope "runtime"
so they bypass projectId validation and can mutate the wrong DB; update each
register call for "modelPicker.getFavorites", "modelPicker.setFavorites",
"modelPicker.toggleFavorite", "modelPicker.getRecents", and
"modelPicker.pushRecent" to use scope "project" (replace the final "runtime"
argument with "project") so syncHostService.handleCommand will require/validate
projectId and the handlers operate on the correct per-project store.

In `@apps/ade-cli/src/tuiClient/types.ts`:
- Around line 118-119: The export currently lists ChatInfoPlanStep but the file
only imports SubagentSnapshot and ChatInfoPlan; remove ChatInfoPlanStep from the
export statement so the exported symbols match the imported ones (i.e., export
only SubagentSnapshot and ChatInfoPlan) to eliminate the TypeScript error;
update the export line that currently reads "export type { SubagentSnapshot,
ChatInfoPlan, ChatInfoPlanStep }" to omit ChatInfoPlanStep.

---

Nitpick comments:
In `@apps/ade-cli/src/services/modelPickerStore.ts`:
- Around line 170-189: The setFavorites reconciliation (in setFavorites, which
uses sanitizeIdList, readFavoritesFromDb, nowIso and multiple db.run calls) must
be wrapped in an explicit transaction so deletes and inserts/updates are atomic;
modify setFavorites to issue "BEGIN" before performing the existing deletion
loop and insert/update loop, "COMMIT" after successful completion, and
"ROLLBACK" in a catch/finally path on error (rethrow the error), ensuring all
db.run operations use the same db handle so the caller never observes partial
state.
- Around line 123-131: Replace the synthesized timestamp-with-hash ordering with
an explicit integer order column: add an order_index column to the
model_picker_favorites (and the other affected table referenced at lines 135-140
and 181-187) and when importing legacy.favorites use a simple incremental
counter (e.g., start at 0 and increment per item) instead of building createdAt
via nowIso() and String(index).padStart(...); update the INSERT in db.run that
targets "model_picker_favorites (model_id, created_at)" to instead insert into
"model_picker_favorites (model_id, order_index)" (and similarly for the other
table), ensure any queries that previously ordered by created_at now order by
order_index, and remove or stop synthesizing the createdAt string in the import
logic (the functions/variables to change are nowIso(), legacy.favorites, the
createdAt construction, and the INSERTs referencing model_picker_favorites).

In `@apps/ade-cli/src/tuiClient/components/ModelPicker/ModelPickerPane.tsx`:
- Around line 552-559: Both useEffect hooks run after every render because they
lack dependency arrays; update the effect that measures the pane to include the
dependencies it uses (e.g., onMeasureOrigin, rootRef.current and
measurePaneOrigin) so it only re-runs when measurement inputs change, and update
the effect that calls drawInlineLogo to include its inputs (e.g.,
drawInlineLogo, logo data, terminal capability flag) or guard/memoize the
drawInlineLogo call so it does not perform stdout writes on every render; locate
the hooks in ModelPickerPane (the useEffect that references
onMeasureOrigin/rootRef/measurePaneOrigin and the other useEffect that calls
drawInlineLogo) and add appropriate dependency arrays or a memo/guard to prevent
unnecessary re-runs and terminal writes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7a91bfdd-379c-49ea-93f1-2d9068173d83

📥 Commits

Reviewing files that changed from the base of the PR and between 840acb7 and c57cab4.

⛔ Files ignored due to path filters (4)
  • docs/ARCHITECTURE.md is excluded by !docs/**
  • docs/features/ade-code/README.md is excluded by !docs/**
  • docs/features/chat/composer-and-ui.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/README.md is excluded by !docs/**
📒 Files selected for processing (23)
  • apps/ade-cli/src/adeRpcServer.ts
  • apps/ade-cli/src/bootstrap.ts
  • apps/ade-cli/src/services/modelPickerStore.test.ts
  • apps/ade-cli/src/services/modelPickerStore.ts
  • apps/ade-cli/src/services/sync/syncHostService.ts
  • apps/ade-cli/src/services/sync/syncRemoteCommandService.ts
  • apps/ade-cli/src/services/sync/syncService.ts
  • apps/ade-cli/src/tuiClient/__tests__/RightPane.test.tsx
  • apps/ade-cli/src/tuiClient/__tests__/appInput.test.ts
  • apps/ade-cli/src/tuiClient/adeApi.ts
  • apps/ade-cli/src/tuiClient/app.tsx
  • apps/ade-cli/src/tuiClient/components/ModelPicker/ModelPickerPane.tsx
  • apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerGeometry.test.ts
  • apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerGeometry.ts
  • apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.test.ts
  • apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.ts
  • apps/ade-cli/src/tuiClient/components/ModelPicker/types.ts
  • apps/ade-cli/src/tuiClient/components/RightPane.tsx
  • apps/ade-cli/src/tuiClient/types.ts
  • apps/desktop/src/main/services/state/kvDb.ts
  • apps/ios/ADE/Models/RemoteModels.swift
  • apps/ios/ADE/Resources/DatabaseBootstrap.sql
  • apps/ios/ADE/Services/SyncService.swift
💤 Files with no reviewable changes (2)
  • apps/ade-cli/src/tuiClient/components/ModelPicker/types.ts
  • apps/ade-cli/src/tuiClient/tests/RightPane.test.tsx

Comment thread apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.ts Outdated
@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented May 31, 2026

@copilot review but do not make fixes

@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented Jun 1, 2026

@copilot review but do not make fixes

@arul28 arul28 force-pushed the ship/tui-model-picker-nav-sync branch from 102da52 to f66b95d Compare June 1, 2026 00:39
@arul28
Copy link
Copy Markdown
Owner Author

arul28 commented Jun 1, 2026

@copilot review but do not make fixes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant