UNPKG

@nanocollective/nanocoder

Version:

A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter

108 lines 4.96 kB
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { Box, Text, useInput } from 'ink'; import SelectInput from 'ink-select-input'; import { useEffect, useState } from 'react'; import { useResponsiveTerminal } from '../hooks/useTerminalWidth.js'; import { sessionManager } from '../session/session-manager.js'; export function formatTimeAgo(dateString) { const date = new Date(dateString); const now = new Date(); const diffInMs = now.getTime() - date.getTime(); const diffInMinutes = diffInMs / (1000 * 60); const diffInHours = diffInMinutes / 60; const diffInDays = diffInHours / 24; if (diffInMinutes < 5) { return 'just now'; } else if (diffInMinutes < 60) { const minutes = Math.floor(diffInMinutes); return `${minutes} minute${minutes > 1 ? 's' : ''} ago`; } else if (diffInHours < 24) { const hours = Math.floor(diffInHours); return `${hours} hour${hours > 1 ? 's' : ''} ago`; } else if (diffInDays < 7) { const days = Math.floor(diffInDays); return `${days} day${days > 1 ? 's' : ''} ago`; } else { const weeks = Math.floor(diffInDays / 7); return `${weeks} week${weeks > 1 ? 's' : ''} ago`; } } export function formatMessageCount(count) { return `${count} message${count !== 1 ? 's' : ''}`; } const SessionSelector = ({ onSelect, onCancel, showAll, }) => { const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(true); const [hasOtherSessions, setHasOtherSessions] = useState(false); const { actualWidth, truncate } = useResponsiveTerminal(); useEffect(() => { const loadSessions = async () => { try { const filter = showAll ? undefined : { workingDirectory: process.cwd() }; const sessionList = await sessionManager.listSessions(filter); // Sort by lastAccessedAt descending (most recent first) const sortedSessions = sessionList.sort((a, b) => new Date(b.lastAccessedAt).getTime() - new Date(a.lastAccessedAt).getTime()); setSessions(sortedSessions); // Check if there are sessions in other projects if (!showAll && sortedSessions.length === 0) { const allSessions = await sessionManager.listSessions(); setHasOtherSessions(allSessions.length > 0); } } catch (error) { console.error('Failed to load sessions:', error); } finally { setLoading(false); } }; loadSessions(); }, [showAll]); useInput((_input, key) => { if (key.escape) { if (!loading) { onCancel(); } return; } if (!loading && sessions.length === 0) { onCancel(); } }); if (loading) { return (_jsx(Box, { flexDirection: "column", marginY: 1, children: _jsx(Text, { children: "Loading sessions..." }) })); } if (sessions.length === 0) { return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [hasOtherSessions ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: "No sessions for this project." }), _jsx(Text, { dimColor: true, children: "Use /resume --all to see all sessions." })] })) : (_jsx(Text, { children: "No saved sessions found." })), _jsx(Text, { dimColor: true, children: "Press any key to continue..." })] })); } const items = sessions.map((session, index) => { const prefix = `[${index + 1}] `; const suffix = ` (${formatMessageCount(session.messageCount)}) - ${formatTimeAgo(session.lastAccessedAt)}`; // 4 accounts for the `> ` selector indicator + margin const maxTitleLength = actualWidth - prefix.length - suffix.length - 4; const truncatedTitle = maxTitleLength > 10 ? truncate(session.title, maxTitleLength) : session.title; return { label: `${prefix}${truncatedTitle}${suffix}`, value: session.id, }; }); const handleSelect = (item) => { const selectedSession = sessions.find(s => s.id === item.value); if (selectedSession) { onSelect(selectedSession); } else { onCancel(); } }; return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, children: "Recent Sessions:" }), _jsx(Box, { marginTop: 1, children: _jsx(SelectInput, { items: items, onSelect: handleSelect, limit: Math.min(items.length, 10) }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191/\u2193 to navigate \u2022 Enter to select \u2022 Esc to cancel" }) })] })); }; export default SessionSelector; //# sourceMappingURL=session-selector.js.map