mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 18:44:45 +00:00
fix(chat): resume session on coordinator.selectedSessionId, not just pendingProjectChat
Clicking a session in the Projects Sessions tab routed to the Chat section (correct — we want interactive resume, not the read-only Sessions browser), but the session didn't actually load and the project chip didn't appear. Root cause: ChatView only observed `coordinator.pendingProjectChat` (for new chats), not `selectedSessionId` (for resumes). Setting the id had no effect because no consumer existed on the Chat side. Every other session-click site in Scarf routes to `.sessions`, and SessionsView consumes selectedSessionId at its `.task` + clears it. Projects is the exception — the whole point of the per-project Sessions tab is to resume chats interactively rather than browse them, so we route to `.chat`. That routing was right; the Chat side just needed to grow the symmetrical consumer. This commit adds two handoff paths in ChatView (mirrors the existing `pendingProjectChat` pattern): - `.task` picks up a selectedSessionId that was set before ChatView mounted (cold-launch handoff from Projects). - `.onChange(of: coord.selectedSessionId)` picks up mid-session navigation (user clicks a session while already in Chat). Both call `viewModel.resumeSession(id)` then clear the coordinator field. The project chip rendering + navTitle update then happen automatically inside ChatViewModel.resumeSession -> startACPSession, which already looks up attribution via SessionAttributionService.projectPath(for: resolvedSessionId) — that plumbing was in from Part B. The bug was entirely in the trigger, not the side-effect. `else if` between pendingProjectChat and selectedSessionId makes precedence explicit — new-chat wins over resume if both are somehow set. In practice only one is ever populated per navigation, but the explicit ordering avoids surprise. No race with SessionsView's own consumer: `coordinator.selectedSection` ensures only one view is rendering at a time, and both consumers clear the field on consume. 93/93 Swift tests still pass. No test change — this is a view- wiring integration fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,19 @@ struct ChatView: View {
|
||||
coordinator.pendingProjectChat = nil
|
||||
viewModel.startNewSession(projectPath: pending)
|
||||
}
|
||||
// Same story for resume-session handoff: the user clicked
|
||||
// a session in the Projects Sessions tab (routes to `.chat`
|
||||
// rather than `.sessions` so the chat actually reopens).
|
||||
// SessionsView consumes `selectedSessionId` for its own
|
||||
// routing; Chat now consumes it too. Mutually exclusive at
|
||||
// any given render because only one section is active per
|
||||
// `coordinator.selectedSection`. `else if` makes precedence
|
||||
// explicit — pendingProjectChat (new) outranks
|
||||
// selectedSessionId (resume) when both are somehow set.
|
||||
else if let pendingId = coordinator.selectedSessionId {
|
||||
coordinator.selectedSessionId = nil
|
||||
viewModel.resumeSession(pendingId)
|
||||
}
|
||||
}
|
||||
.onChange(of: fileWatcher.lastChangeDate) {
|
||||
Task { await viewModel.loadRecentSessions() }
|
||||
@@ -56,6 +69,17 @@ struct ChatView: View {
|
||||
viewModel.startNewSession(projectPath: projectPath)
|
||||
}
|
||||
}
|
||||
// Live handoff for resume: user clicked an existing session in
|
||||
// the Projects Sessions tab while already in the Chat section
|
||||
// (or switched back to Chat after). Project-chip rendering
|
||||
// happens automatically inside ChatViewModel.resumeSession ->
|
||||
// startACPSession via the attribution.projectPath(for:) lookup.
|
||||
.onChange(of: coord.selectedSessionId) { _, new in
|
||||
if let sessionId = new {
|
||||
coordinator.selectedSessionId = nil
|
||||
viewModel.resumeSession(sessionId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Banner rendered between the toolbar and the chat area when either
|
||||
|
||||
Reference in New Issue
Block a user