diff --git a/src/server/sessions/sessionArchiveStore.test.ts b/src/server/sessions/sessionArchiveStore.test.ts index d08186f..c11f579 100644 --- a/src/server/sessions/sessionArchiveStore.test.ts +++ b/src/server/sessions/sessionArchiveStore.test.ts @@ -1,6 +1,6 @@ import { constants } from "node:fs"; import { access, mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises"; -import { join } from "node:path"; +import { join, resolve } from "node:path"; import { tmpdir } from "node:os"; import { afterEach, describe, expect, it } from "vitest"; import { SessionArchiveStore } from "./sessionArchiveStore.js"; @@ -118,6 +118,54 @@ describe("SessionArchiveStore", () => { } await expect(store.list()).resolves.toEqual([]); }); + + it("prefers exact persisted session IDs over prefix matches and canonicalizes stored cwd", async () => { + const root = await mkdtemp(join(tmpdir(), "pi-web-archive-prefix-")); + tempRoots.push(root); + const archiveFile = join(root, "archived-sessions.json"); + const rawCwd = join(root, "workspace", "..", "workspace"); + await writeFile(archiveFile, JSON.stringify({ + sessions: [ + { + sessionId: "abc123", + cwd: rawCwd, + archivedAt: "2026-01-01T00:00:00.000Z", + originalPath: "/sessions/abc123.jsonl", + archivePath: "/archive/abc123.jsonl", + messageCount: 3, + firstMessage: "prefix", + name: "Prefix match", + parentSessionPath: "/sessions/root.jsonl", + }, + { + sessionId: "abc", + cwd: rawCwd, + archivedAt: "2026-01-01T00:00:00.000Z", + originalPath: "/sessions/abc.jsonl", + archivePath: "/archive/abc.jsonl", + messageCount: 1, + firstMessage: "exact", + }, + ], + }), "utf8"); + + const store = new SessionArchiveStore(archiveFile, join(root, "archived-files")); + + await expect(store.get("abc")).resolves.toMatchObject({ + sessionId: "abc", + cwd: resolve(rawCwd), + firstMessage: "exact", + }); + await expect(store.get("abc1")).resolves.toMatchObject({ + sessionId: "abc123", + cwd: resolve(rawCwd), + firstMessage: "prefix", + name: "Prefix match", + parentSessionPath: "/sessions/root.jsonl", + }); + await expect(store.isArchived("abc1")).resolves.toBe(true); + await expect(store.isArchived("missing")).resolves.toBe(false); + }); }); async function exists(path: string): Promise { diff --git a/src/server/sessions/sessionArchiveTree.test.ts b/src/server/sessions/sessionArchiveTree.test.ts index f34db41..086445a 100644 --- a/src/server/sessions/sessionArchiveTree.test.ts +++ b/src/server/sessions/sessionArchiveTree.test.ts @@ -11,11 +11,11 @@ function candidate(id: string, options: Partial = { } describe("session archive tree planning", () => { - it("finds candidates by full id or prefix", () => { - const candidates = [candidate("abcdef"), candidate("xyz")]; + it("finds candidates by exact id before falling back to a prefix", () => { + const candidates = [candidate("abcdef"), candidate("abc"), candidate("xyz")]; - expect(findArchiveCandidateByIdOrPrefix(candidates, "abcdef")?.id).toBe("abcdef"); - expect(findArchiveCandidateByIdOrPrefix(candidates, "abc")?.id).toBe("abcdef"); + expect(findArchiveCandidateByIdOrPrefix(candidates, "abc")?.id).toBe("abc"); + expect(findArchiveCandidateByIdOrPrefix(candidates, "abcd")?.id).toBe("abcdef"); expect(findArchiveCandidateByIdOrPrefix(candidates, "missing")).toBeUndefined(); });