Files
pi/packages/coding-agent/test/session-discovery.test.ts
2026-06-04 09:41:42 +02:00

99 lines
3.3 KiB
TypeScript

import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "fs";
import { tmpdir } from "os";
import { basename, join, relative } from "path";
import { afterEach, describe, expect, it } from "vitest";
import {
discoverSessionFiles,
discoverSessions,
type SessionDiscoveryProgress,
} from "../src/core/session-discovery.ts";
const tempDirs: string[] = [];
function createTempDir(): string {
const dir = mkdtempSync(join(tmpdir(), "pi-session-discovery-"));
tempDirs.push(dir);
return dir;
}
afterEach(() => {
for (const dir of tempDirs.splice(0)) {
rmSync(dir, { recursive: true, force: true });
}
});
function writeJsonl(path: string, lines: unknown[]): void {
writeFileSync(path, `${lines.map((line) => JSON.stringify(line)).join("\n")}\n`);
}
describe("session discovery", () => {
it("finds session jsonl files recursively", async () => {
const root = createTempDir();
const projectA = join(root, "--project-a--");
const projectB = join(root, "--project-b--", "nested");
mkdirSync(projectA, { recursive: true });
mkdirSync(projectB, { recursive: true });
writeJsonl(join(projectA, "a.jsonl"), [
{ type: "session", version: 3, id: "a", timestamp: "2026-01-01T00:00:00.000Z", cwd: "/a" },
]);
writeJsonl(join(projectB, "b.jsonl"), [
{ type: "session", version: 3, id: "b", timestamp: "2026-01-02T00:00:00.000Z", cwd: "/b" },
]);
writeFileSync(join(projectA, "notes.txt"), "not a session");
const files = await discoverSessionFiles({ sessionsRoot: root });
expect(files.map((file) => relative(root, file))).toEqual([
join("--project-a--", "a.jsonl"),
join("--project-b--", "nested", "b.jsonl"),
]);
});
it("returns metadata for valid sessions and skips invalid jsonl files", async () => {
const root = createTempDir();
const projectA = join(root, "--project-a--");
const projectB = join(root, "--project-b--");
mkdirSync(projectA, { recursive: true });
mkdirSync(projectB, { recursive: true });
writeJsonl(join(projectA, "a.jsonl"), [
{
type: "session",
version: 3,
id: "session-a",
timestamp: "2026-01-01T00:00:00.000Z",
cwd: "/work/a",
parentSession: "/parent/session.jsonl",
},
]);
writeJsonl(join(projectB, "b.jsonl"), [
{ type: "session", version: 3, id: "session-b", timestamp: "2026-01-02T00:00:00.000Z", cwd: "/work/b" },
]);
writeFileSync(join(projectB, "invalid.jsonl"), "not json\n");
const progress: SessionDiscoveryProgress[] = [];
const sessions = await discoverSessions({ sessionsRoot: root, onProgress: (update) => progress.push(update) });
expect(sessions.map((session) => session.sessionId)).toEqual(["session-a", "session-b"]);
expect(sessions[0]).toMatchObject({
path: join(projectA, "a.jsonl"),
relativePath: join("--project-a--", "a.jsonl"),
sessionDir: projectA,
sessionDirName: basename(projectA),
sessionId: "session-a",
cwd: "/work/a",
header: {
type: "session",
version: 3,
id: "session-a",
timestamp: "2026-01-01T00:00:00.000Z",
cwd: "/work/a",
parentSession: "/parent/session.jsonl",
},
});
expect(sessions[0].createdAt?.toISOString()).toBe("2026-01-01T00:00:00.000Z");
expect(sessions[0].modifiedAt).toBeInstanceOf(Date);
expect(sessions[0].sizeBytes).toBeGreaterThan(0);
expect(progress.at(-1)).toMatchObject({ phase: "read", foundFiles: 3, processedFiles: 3, sessions: 2 });
});
});