import { useEffect, useMemo, useRef, useState } from 'react' import type { SessionSummary } from '@/types/api' import type { ApiClient } from '@/api/client' import { useLongPress } from '@/hooks/useLongPress' import { usePlatform } from '@/hooks/usePlatform' import { useSessionActions } from '@/hooks/mutations/useSessionActions' import { SessionActionMenu } from '@/components/SessionActionMenu' import { SessionExportDialog } from '@/components/SessionExportDialog' import { RenameSessionDialog } from '@/components/RenameSessionDialog' import { ConfirmDialog } from '@/components/ui/ConfirmDialog' import { CopyIcon, CheckIcon } from '@/components/icons' import { cn } from '@/lib/utils' import { useTranslation } from '@/lib/use-translation' import { DEFAULT_SESSION_PREVIEW_LIMIT, useSessionPreviewLimit } from '@/hooks/useSessionPreviewLimit' import { useSessionListStatusMode } from '@/hooks/useSessionListStatusMode' import { useShowActiveSessionsOnly } from '@/hooks/useShowActiveSessionsOnly' import { classifySessionAttention } from '@/lib/sessionAttention' import { getSessionLastSeenAt } from '@/lib/sessionLastSeen' import { useSessionRowTooltipIds } from '@/components/HoverTooltip' import { subscribeCodexImportedSessions } from '@/lib/codexImportedSessions' import { formatReopenError } from '@/lib/reopenError' import { getSessionTitle } from '@/lib/sessionTitle' import { getWorktreeSessionLabel } from '@/lib/sessionWorktreeLabel' import type { Machine } from '@/types/api' import { getMachinePlatform, presentMachineHealth } from '@/lib/machineHealth' import { MachineFilterBar, MachineFilterMenu } from '@/components/MachineFilterBar' import { useSessionListMachineFilter } from '@/hooks/useSessionListMachineFilter' import { useCursorChatStoreStatus } from '@/hooks/queries/useCursorChatStoreStatus' import { SessionRowSummary } from '@/components/SessionRowSummary' import { Spinner } from '@/components/Spinner' export { getWorktreeSessionLabel } from '@/lib/sessionWorktreeLabel' type SessionGroup = { key: string directory: string displayName: string machineId: string | null sessions: SessionSummary[] latestUpdatedAt: number hasActiveSession: boolean } export type SessionTimeRange = { start: number | null end: number | null } function parseLocalDate(value: string): Date | null { const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value) if (!match) return null const year = Number(match[1]) const month = Number(match[2]) const day = Number(match[3]) const date = new Date(year, month - 1, day) if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) return null return date } export function getSessionTimeRange(start: string, end: string): SessionTimeRange | null { const startDate = parseLocalDate(start) const endDate = parseLocalDate(end) if (!startDate || !endDate) return null if (endDate) endDate.setDate(endDate.getDate() + 1) return { start: startDate.getTime(), end: endDate.getTime() } } export function sessionMatchesTimeRange(session: SessionSummary, range: SessionTimeRange | null): boolean { if (!range) return true if (range.start !== null && session.updatedAt < range.start) return false if (range.end !== null && session.updatedAt >= range.end) return false return true } function SessionsEmptyState(props: { onNewSession: () => void onBrowse?: () => void }) { const { t } = useTranslation() return (