Skip to content

Commit 8d68570

Browse files
committed
perf: ensure stable session ordering with secondary sort and reliable timestamp fallbacks
1 parent 0de8565 commit 8d68570

2 files changed

Lines changed: 31 additions & 4 deletions

File tree

packages/cli/src/ui/components/SessionBrowser/utils.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ export const sortSessions = (
2424
): SessionInfo[] => {
2525
const sorted = [...sessions].sort((a, b) => {
2626
switch (sortBy) {
27-
case 'date':
27+
case 'date': {
28+
const diff =
29+
new Date(b.lastUpdated).getTime() - new Date(a.lastUpdated).getTime();
30+
if (diff !== 0) return diff;
31+
// Stable secondary sort by startTime
2832
return (
29-
new Date(b.lastUpdated).getTime() - new Date(a.lastUpdated).getTime()
33+
new Date(b.startTime).getTime() - new Date(a.startTime).getTime()
3034
);
35+
}
3136
case 'messages':
3237
return b.messageCount - a.messageCount;
3338
case 'name':

packages/core/src/services/chatRecordingService.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,32 @@ export async function loadConversationRecord(
162162

163163
const sessionId = getMatch(headStr, /"sessionId"\s*:\s*"([^"]+)"/);
164164
const projectHash = getMatch(headStr, /"projectHash"\s*:\s*"([^"]+)"/);
165-
const startTime = getMatch(headStr, /"startTime"\s*:\s*"([^"]+)"/);
165+
let startTime = getMatch(headStr, /"startTime"\s*:\s*"([^"]+)"/);
166+
let filenameTimestamp: string | undefined;
167+
168+
// Fallback: Extract startTime from filename if not in header (format: session-YYYY-MM-DDTHH-MM-8CHARS.jsonl)
169+
if (!startTime || !getMatch(tailStr, /"lastUpdated"\s*:\s*"([^"]+)"/)) {
170+
const basename = path.basename(filePath);
171+
const timeMatch = basename.match(
172+
/session-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2})/,
173+
);
174+
if (timeMatch) {
175+
// Convert session-2026-05-10T11-45-... to valid ISO 2026-05-10T11:45:00Z
176+
filenameTimestamp =
177+
timeMatch[1].replace(/-/g, (m, offset) =>
178+
offset > 10 ? ':' : '-',
179+
) + ':00Z';
180+
}
181+
}
182+
183+
if (!startTime) {
184+
startTime = filenameTimestamp;
185+
}
186+
166187
const lastUpdated =
167188
getMatch(tailStr, /"lastUpdated"\s*:\s*"([^"]+)"/) ||
168-
getMatch(headStr, /"lastUpdated"\s*:\s*"([^"]+)"/);
189+
getMatch(headStr, /"lastUpdated"\s*:\s*"([^"]+)"/) ||
190+
filenameTimestamp;
169191
const summary =
170192
getMatch(tailStr, /"summary"\s*:\s*"((?:[^"\\\\]|\\\\.)*)"/) ||
171193
getMatch(headStr, /"summary"\s*:\s*"((?:[^"\\\\]|\\\\.)*)"/);

0 commit comments

Comments
 (0)