From f1ada04bcc7dd430f8175fe5ad61eedaf54a6dcf Mon Sep 17 00:00:00 2001 From: hbrooks Date: Thu, 20 Aug 2026 13:53:12 -0400 Subject: [PATCH] . --- src/lib/sessions.ts | 22 ++++++++++++++++++++++ src/ui/SessionsApp.tsx | 7 ++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/lib/sessions.ts b/src/lib/sessions.ts index 16e1323..7c1d5be 100644 --- a/src/lib/sessions.ts +++ b/src/lib/sessions.ts @@ -226,6 +226,28 @@ export function sessionBarQuery( // How many rows the session list fetches to fill its screen from. export const SESSION_BAR_FETCH = 50 +// The picker header's description of the bar's active filters — the answer to +// "where are the rest of my sessions?". Mirrors sessionBarQuery exactly: a +// clause appears here iff the matching filter went into the query. null when +// the list is unfiltered. +export function sessionBarFilterLabel( + bar: { + days: number + repo: 'cwd' | 'any' + statuses: 'all' | 'unfinished' + sources: string[] | undefined + }, + detectedRepo: string | null, +): string | null { + const clauses: string[] = [] + if (bar.repo === 'cwd' && detectedRepo) clauses.push(detectedRepo) + if (bar.days > 0) clauses.push(`last ${bar.days === 1 ? 'day' : `${bar.days} days`}`) + if (bar.statuses === 'unfinished') clauses.push('unfinished') + if (bar.sources) clauses.push(`source ${bar.sources.join('/')}`) + if (clauses.length === 0) return null + return `filtering to ${clauses.join(' · ')}` +} + // Attention transitions: a session that WAS in flight and now waits for a // human (waiting/sleeping/idle) deserves the sidebar dot. Pure step function // over consecutive poll snapshots. diff --git a/src/ui/SessionsApp.tsx b/src/ui/SessionsApp.tsx index 1a1a81a..649c311 100644 --- a/src/ui/SessionsApp.tsx +++ b/src/ui/SessionsApp.tsx @@ -35,6 +35,7 @@ import { rowMeta, rowStatusWord, navSlice, + sessionBarFilterLabel, sessionBarQuery, sessionSource, SELECTION_GLYPH, @@ -494,6 +495,10 @@ export function SessionsApp(props: SessionsAppProps): React.ReactElement { const whoText = props.ghLogin ? `@${props.ghLogin} in ${customerLogin}` : customerLogin + // Over the picker the right edge answers "why is this list short?" instead + // of carrying the focused session's meta: the filters are why sessions are + // missing, and the list is the one screen where that question comes up. + const filterText = navOpen ? sessionBarFilterLabel(sessionBar, props.detectedRepo) : null const header = ( // Unpainted, like every other surface: its own blank rows above and below // are what set the title apart, not a tint. @@ -524,7 +529,7 @@ export function SessionsApp(props: SessionsAppProps): React.ReactElement { {/* Armed, the bar carries the ctrl+c prompt: the nav and the new-session form have no notice line of their own, and the header is the one band always on screen. */} - {navArmed || paneArmed ? CTRL_C_QUIT_HINT : (metaText ?? whoText)} + {navArmed || paneArmed ? CTRL_C_QUIT_HINT : (filterText ?? metaText ?? whoText)}