Improve TUI timestamp consistency and formatting

This commit is contained in:
William Valentin
2026-02-21 09:25:14 -08:00
parent e582132ba8
commit c6731c8e20
3 changed files with 39 additions and 21 deletions
+14 -3
View File
@@ -78,10 +78,19 @@ export function App({
onTransfer,
onExit,
}: AppProps): React.ReactElement {
const ensureTimestamp = useCallback((message: Message): Message => ({
...message,
timestamp: message.timestamp ?? Date.now(),
}), []);
const ensureTimestamps = useCallback((history: Message[]): Message[] => (
history.map(ensureTimestamp)
), [ensureTimestamp]);
const ctrlCExitWindowMs = 1_500;
const { exit } = useApp();
const [input, setInput] = useState('');
const [messages, setMessages] = useState<Message[]>(session.getHistory());
const [messages, setMessages] = useState<Message[]>(ensureTimestamps(session.getHistory()));
const [isStreaming, setIsStreaming] = useState(false);
const [streamingContent, setStreamingContent] = useState('');
const [scrollOffset, setScrollOffset] = useState(0);
@@ -682,7 +691,7 @@ export function App({
const messageWithTimestamp = session.addMessage(userMessage);
setMessages(prev => [...prev, messageWithTimestamp]);
} else {
setMessages(prev => [...prev, { ...userMessage, timestamp: Date.now() }]);
setMessages(prev => [...prev, ensureTimestamp(userMessage)]);
}
setScrollOffset(0);
@@ -696,7 +705,7 @@ export function App({
await agent.process(command.content);
const usage = agent.getUsage();
setTokenUsage({ inputTokens: usage.inputTokens, outputTokens: usage.outputTokens });
setMessages(session.getHistory());
setMessages(ensureTimestamps(session.getHistory()));
} else if (modelClient.chatStream) {
let fullContent = '';
@@ -757,6 +766,8 @@ export function App({
exit,
onExit,
isStreaming,
ensureTimestamp,
ensureTimestamps,
messages.length,
tokenUsage.inputTokens,
tokenUsage.outputTokens,
+7 -11
View File
@@ -13,16 +13,12 @@ export interface MessageListProps {
}
// Helper to format timestamp in human-readable way
function formatTimestamp(timestamp: number): string {
function formatTimestampParts(timestamp: number): { date: string; time: string } {
const date = new Date(timestamp);
const now = new Date();
const isSameDay = date.toDateString() === now.toDateString();
if (isSameDay) {
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}
return date.toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
return {
date: date.toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' }),
time: date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
};
}
// Individual message component
@@ -35,7 +31,7 @@ const MessageItem = memo(function MessageItem({
}): React.ReactElement {
const isUser = message.role === 'user';
const accentColor = isUser ? 'blue' : '#ff8c00';
const timestampText = message.timestamp ? formatTimestamp(message.timestamp) : 'unknown time';
const timestamp = formatTimestampParts(message.timestamp ?? Date.now());
return (
<Box
@@ -55,7 +51,7 @@ const MessageItem = memo(function MessageItem({
<Text color={accentColor} bold>
{isUser ? 'You' : 'Flynn'}
</Text>
<Text color="gray">| {timestampText}</Text>
<Text color="gray">| {timestamp.date} | {timestamp.time}</Text>
</Box>
{/* Content */}
+18 -7
View File
@@ -48,12 +48,16 @@ export function formatPrompt(state: 'default' | 'thinking'): string {
return `${colors.orange}${colors.bold}flynn>${colors.reset} `;
}
function formatMessageTime(timestamp: number): string {
return new Date(timestamp).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
function formatMessageTimestampParts(timestamp: number): { date: string; time: string } {
const date = new Date(timestamp);
return {
date: date.toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' }),
time: date.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
}),
};
}
export interface MinimalTuiConfig {
@@ -1237,9 +1241,16 @@ export class MinimalTui {
}
private async handleMessage(content: string): Promise<void> {
const userTimestamp = formatMessageTimestampParts(Date.now());
process.stdout.write(
`\n${colors.blue}${colors.bold}You${colors.reset} ${colors.gray}[${userTimestamp.date} | ${userTimestamp.time}]${colors.reset}\n`,
);
process.stdout.write(`${content}\n`);
const assistantTimestamp = formatMessageTimestampParts(Date.now());
// Print Flynn label before response
process.stdout.write(
`\n${colors.orange}${colors.bold}Flynn${colors.reset} ${colors.gray}[${formatMessageTime(Date.now())}]${colors.reset}\n`,
`\n${colors.orange}${colors.bold}Flynn${colors.reset} ${colors.gray}[${assistantTimestamp.date} | ${assistantTimestamp.time}]${colors.reset}\n`,
);
this.startBusyIndicator();