Skip to content

Commit 62d5003

Browse files
wesmclaude
andcommitted
fix: centralize activeSessionId mutations through setActiveSession
Route all activeSessionId writes through a private setActiveSession() helper that bumps refreshVersion and childSessionsVersion on every change. This closes the stale-response race for all session switch paths (selectSession, navigateToSession, filter changes, keyboard navigation, delete) not just deselectSession. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 17ed5f3 commit 62d5003

1 file changed

Lines changed: 23 additions & 20 deletions

File tree

frontend/src/lib/stores/sessions.svelte.ts

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ class SessionsStore {
160160
this.invalidateFilterCaches();
161161
}
162162
if (this.pendingNavTarget) {
163-
this.activeSessionId = this.pendingNavTarget;
163+
this.setActiveSession(this.pendingNavTarget);
164164
this.pendingNavTarget = null;
165165
} else {
166-
this.activeSessionId = null;
166+
this.setActiveSession(null);
167167
}
168168
}
169169

@@ -321,8 +321,15 @@ class SessionsStore {
321321
return this.agentsPromise;
322322
}
323323

324-
selectSession(id: string) {
324+
private setActiveSession(id: string | null) {
325+
if (id === this.activeSessionId) return;
325326
this.activeSessionId = id;
327+
this.refreshVersion++;
328+
this.childSessionsVersion++;
329+
}
330+
331+
selectSession(id: string) {
332+
this.setActiveSession(id);
326333
}
327334

328335
/**
@@ -339,16 +346,12 @@ class SessionsStore {
339346
// Session not found - still attempt to select
340347
}
341348
}
342-
this.activeSessionId = id;
349+
this.setActiveSession(id);
343350
}
344351

345352
deselectSession() {
346-
this.activeSessionId = null;
353+
this.setActiveSession(null);
347354
this.childSessions = new Map();
348-
// Invalidate in-flight refreshes so stale responses from
349-
// the previous session are discarded.
350-
this.refreshVersion++;
351-
this.childSessionsVersion++;
352355
}
353356

354357
async refreshActiveSession() {
@@ -411,19 +414,19 @@ class SessionsStore {
411414
// an unstarred session while starred-only filter is on) — jump to
412415
// an edge so the keyboard shortcut doesn't silently fail.
413416
const edge = delta > 0 ? 0 : list.length - 1;
414-
this.activeSessionId = list[edge]!.id;
417+
this.setActiveSession(list[edge]!.id);
415418
return;
416419
}
417420
const next = idx + delta;
418421
if (next >= 0 && next < list.length) {
419-
this.activeSessionId = list[next]!.id;
422+
this.setActiveSession(list[next]!.id);
420423
}
421424
}
422425

423426
setProjectFilter(project: string) {
424427
const wasOneShot = this.filters.includeOneShot;
425428
this.filters = { ...defaultFilters(), project, agent: this.filters.agent };
426-
this.activeSessionId = null;
429+
this.setActiveSession(null);
427430
if (wasOneShot) this.invalidateFilterCaches();
428431
this.load();
429432
}
@@ -434,7 +437,7 @@ class SessionsStore {
434437
} else {
435438
this.filters.agent = agent;
436439
}
437-
this.activeSessionId = null;
440+
this.setActiveSession(null);
438441
this.load();
439442
}
440443

@@ -449,7 +452,7 @@ class SessionsStore {
449452
current.push(agent);
450453
}
451454
this.filters.agent = current.join(",");
452-
this.activeSessionId = null;
455+
this.setActiveSession(null);
453456
this.load();
454457
}
455458

@@ -465,13 +468,13 @@ class SessionsStore {
465468

466469
setRecentlyActiveFilter(active: boolean) {
467470
this.filters.recentlyActive = active;
468-
this.activeSessionId = null;
471+
this.setActiveSession(null);
469472
this.load();
470473
}
471474

472475
setMinUserMessagesFilter(n: number) {
473476
this.filters.minUserMessages = n;
474-
this.activeSessionId = null;
477+
this.setActiveSession(null);
475478
this.load();
476479
}
477480

@@ -480,13 +483,13 @@ class SessionsStore {
480483
if (hide && this.filters.project === "unknown") {
481484
this.filters.project = "";
482485
}
483-
this.activeSessionId = null;
486+
this.setActiveSession(null);
484487
this.load();
485488
}
486489

487490
setIncludeOneShotFilter(include: boolean) {
488491
this.filters.includeOneShot = include;
489-
this.activeSessionId = null;
492+
this.setActiveSession(null);
490493
this.invalidateFilterCaches();
491494
this.load();
492495
}
@@ -509,7 +512,7 @@ class SessionsStore {
509512
const project = this.filters.project;
510513
const wasOneShot = this.filters.includeOneShot;
511514
this.filters = { ...defaultFilters(), project };
512-
this.activeSessionId = null;
515+
this.setActiveSession(null);
513516
if (wasOneShot) this.invalidateFilterCaches();
514517
this.load();
515518
}
@@ -527,7 +530,7 @@ class SessionsStore {
527530
this.total = Math.max(0, this.total - removed);
528531
}
529532
if (this.activeSessionId === id) {
530-
this.activeSessionId = null;
533+
this.setActiveSession(null);
531534
}
532535
const timer = setTimeout(() => {
533536
this.recentlyDeleted = this.recentlyDeleted.filter(

0 commit comments

Comments
 (0)