feat(ios): browse and resume existing on-disk sessions from home - #330
Open
kingbootoshi wants to merge 2 commits into
Open
feat(ios): browse and resume existing on-disk sessions from home#330kingbootoshi wants to merge 2 commits into
kingbootoshi wants to merge 2 commits into
Conversation
The server side already surfaces every on-disk CLI session through thread/list: the alleycat claude bridge hydrates ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl into its thread index at startup, and codex app-server enumerates ~/.codex/sessions rollouts directly. SessionsScreen already lists those threads grouped by workspace with previews and resumes them over the existing thread/resume path (claude --resume <session-id> under the hood). What was missing was reachability and persistence: SessionsScreen was only navigable from inside an open conversation, and the home list shows pinned threads only, so sessions started on the Mac never surfaced and never stuck. Add an All Sessions button to the home toolbar that pushes the existing SessionsScreen (scoped to the selected server, or all servers when none is selected), allow the sessions route to carry no server filter, and pin a thread when it is opened from the browser so a resumed on-disk session registers as a durable litter thread on the home list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ot stall the UI At real scale (thousands of on-disk sessions in ~/.claude/projects and ~/.codex/sessions) the All Sessions screen froze the main thread for minutes: list_threads drained every thread/list page whenever no limit was set, and each of the thousands of resulting ThreadUpserted events pays an O(n) scan plus a full snapshot copy on the main actor, so total hydration cost grew quadratically while SwiftUI re-diffed the growing list underneath. Give list_threads a hydration budget at the fan-out source: page draining stops once the requested limit (or a 200-thread default for legacy nil-limit callers such as the pinned-listing repair paths) is reached per runtime. Cursor, search, and state-db-only queries keep their existing single-page behavior. The finalize prune now requires every runtime to have fully exhausted its cursor, since a truncated drain cannot know the true thread set. SessionsScreen requests 100 most recent per runtime and grows the budget only through an explicit Load more row, so worst-case work per user action is one bounded page instead of the entire session history. Search stays a local filter over loaded rows and triggers no hydration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lets you browse every existing claude/codex session already on the connected machine and continue any of them as a litter thread - instead of only seeing chats started in the app.
What
thread/resumepath), opens it with full history, and pins it to home so it persists as a durable litter threadWhy this shape
Litter threads already ARE claude/codex sessions, and the server already enumerates
~/.claude/projectsand~/.codex/sessionsintothread/list- the browsing and resume machinery existed with no entry point from home, and the home list only ever showed app-created (pinned) threads. This PR is wiring, not new machinery: +18/-5 for the whole feature surface.The perf commit (needed at scale)
On a machine with thousands of on-disk sessions, opening the browser hard-froze the UI for minutes:
list_threadswithlimit: nildrained everythread/listcursor page, and each drained thread emitted an unbatched.threadUpserteddoing O(n) main-thread work - O(n²) overall.Second commit bounds hydration at the fan-out source: page draining stops at the caller's limit (200-per-runtime default when legacy callers pass nil, so no caller can reintroduce drain-all), the sessions browser requests 100 with an explicit "Load more sessions" row, and the finalize prune only runs when every runtime's cursor is exhausted so a truncated drain never deletes threads. Search stays a pure local filter.
Verification
cargo test -p codex-mobile-client --lib: 784 passed, 0 failed (includes new hydration-budget test)Demo
resume-existing-sessions.mp4
Demo: home → All Sessions → live search over on-disk sessions → a 7-day-old CLI session (never opened in the app) resumes with full history and a live composer.
🤖 Generated with Claude Code