From e5c92b71d69c61684f5c7de0dccba9cde4e0ccc1 Mon Sep 17 00:00:00 2001 From: touch2be Date: Wed, 17 Jun 2026 16:18:48 +0200 Subject: [PATCH] fix: improve session timestamps and sidebar sort order Derive session created/lastModified from message timestamps with file mtime fallback, and sort sidebar sessions by newest update across all Harnesses instead of preferring the active Harness. --- BetterSDK/src/sessions.ts | 26 ++++++++++++++++--- .../sidebar/use-sidebar-model.test.ts | 4 +-- src/components/sidebar/use-sidebar-model.ts | 10 ++----- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/BetterSDK/src/sessions.ts b/BetterSDK/src/sessions.ts index 7cec7b4..75aacb3 100644 --- a/BetterSDK/src/sessions.ts +++ b/BetterSDK/src/sessions.ts @@ -1,4 +1,4 @@ -import { mkdir, readdir, readFile, unlink, writeFile } from "node:fs/promises"; +import { mkdir, readdir, readFile, stat, unlink, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { homedir } from "node:os"; import { createHash, randomUUID } from "node:crypto"; @@ -62,6 +62,7 @@ export async function getSessionInfo( sessionId: string, opts: { dir?: string } = {}, ): Promise { + const file = sessionFile(sessionId, opts.dir); const messages = await getSessionMessages(sessionId, { dir: opts.dir, includeSystemMessages: true, @@ -71,6 +72,9 @@ export async function getSessionInfo( last = messages[messages.length - 1] as any; const firstUser = messages.find((m: any) => m.type === "user") as any; const firstPrompt = contentText(firstUser?.message?.content); + const fileMtime = await stat(file) + .then((s) => s.mtimeMs) + .catch(() => undefined); return { sessionId, summary: first?.summary ?? firstPrompt?.slice(0, 80), @@ -78,8 +82,8 @@ export async function getSessionInfo( customTitle: first?.customTitle, cwd: first?.cwd ?? opts.dir, model: last?.message?.model ?? first?.model, - createdAt: timestamp(first) ?? Date.now(), - lastModified: timestamp(last) ?? Date.now(), + createdAt: firstTimestampInMessages(messages) ?? fileMtime ?? Date.now(), + lastModified: lastTimestampInMessages(messages) ?? fileMtime ?? Date.now(), }; } @@ -127,6 +131,22 @@ export async function forkSession( return { sessionId: newId }; } +function firstTimestampInMessages(messages: any[]): number | undefined { + for (const m of messages) { + const t = timestamp(m); + if (t !== undefined) return t; + } + return undefined; +} + +function lastTimestampInMessages(messages: any[]): number | undefined { + for (let i = messages.length - 1; i >= 0; i--) { + const t = timestamp(messages[i]); + if (t !== undefined) return t; + } + return undefined; +} + function timestamp(m: any): number | undefined { const t = m?.timestamp ?? m?.created_at ?? m?.time; const n = typeof t === "string" ? Date.parse(t) : typeof t === "number" ? t : NaN; diff --git a/src/components/sidebar/use-sidebar-model.test.ts b/src/components/sidebar/use-sidebar-model.test.ts index 050f86c..2ec414e 100644 --- a/src/components/sidebar/use-sidebar-model.test.ts +++ b/src/components/sidebar/use-sidebar-model.test.ts @@ -16,14 +16,14 @@ function session(id: string, harnessId: HarnessId, updated: number): Session { } describe("sortSessionsForSidebar", () => { - test("keeps preferred Harness sessions above newer sessions from other Harnesses", () => { + test("sorts by newest update regardless of Harness", () => { const sorted = sortSessionsForSidebar( [session("claude-new", "claude-code", 20), session("open-old", "opencode", 10)], {}, "opencode", ); - expect(sorted.map((item) => item.id)).toEqual(["open-old", "claude-new"]); + expect(sorted.map((item) => item.id)).toEqual(["claude-new", "open-old"]); }); test("sorts by newest update inside the same Harness", () => { diff --git a/src/components/sidebar/use-sidebar-model.ts b/src/components/sidebar/use-sidebar-model.ts index 5c2d692..af95819 100644 --- a/src/components/sidebar/use-sidebar-model.ts +++ b/src/components/sidebar/use-sidebar-model.ts @@ -13,7 +13,7 @@ import { } from "@/lib/worktree-placement"; import { getProjectName, normalizeProjectPath } from "@/lib/utils"; import type { ConnectionStatus, Workspace } from "@/types/electron"; -import { getSessionHarnessId, parseProjectKey } from "@/hooks/agent-session-utils"; +import { parseProjectKey } from "@/hooks/agent-session-utils"; import type { HarnessId } from "@/agents"; function getSidebarSessionSortTime(session: Session, sessionMeta: SessionMetaMap) { @@ -46,15 +46,9 @@ export function shouldShowSessionInChatList({ export function sortSessionsForSidebar( items: Session[], sessionMeta: SessionMetaMap, - preferredHarnessId?: HarnessId | null, + _preferredHarnessId?: HarnessId | null, ) { return [...items].sort((a, b) => { - if (preferredHarnessId) { - const aPreferred = getSessionHarnessId(a) === preferredHarnessId; - const bPreferred = getSessionHarnessId(b) === preferredHarnessId; - if (aPreferred !== bPreferred) return aPreferred ? -1 : 1; - } - const byUpdated = getSidebarSessionSortTime(b, sessionMeta) - getSidebarSessionSortTime(a, sessionMeta); if (byUpdated !== 0) return byUpdated;