import { describe, expect, it } from "vitest"; import { describeSessions } from "./agent.js"; import { groupSessions } from "./groups.js"; import { type LiveSession, type Priority, resolveTarget } from "./live.js"; import { currentBranch, tailParts } from "./peek.js"; import { promptLabel } from "./reporter.js"; function session( pid: number, fields: Omit, "project"> & { project?: string; priority?: Priority } = {}, ): LiveSession { const { project = "pi-shit", ...rest } = fields; return { v: 1, pid, sessionId: `0000000${pid}-aaaa-bbbb-cccc-dddddddddddd`, cwd: `/repo/${project}`, project: { key: `github.com/me/${project}`, name: project }, label: `session ${pid}`, status: "idle", statusSince: "2026-10-28T10:00:00.000Z", startedAt: `2026-10-28T10:00:0${pid}.000Z`, updatedAt: "2026-10-28T10:00:00.000Z", ...rest, }; } describe("groupSessions", () => { const layout = [ { id: "s1", label: "work", tabs: [ { id: "w1", label: "", blocks: ["t3"] }, { id: "w2", label: "", blocks: ["t1", "t2"] }, ], }, { id: "s2", label: "urgent", tabs: [{ id: "w3", label: "", blocks: ["t4"] }] }, ]; it("groups by Rex session in tab order, titled by its label, sorted by their best priority", () => { const groups = groupSessions( [ session(1, { terminalId: "t1" }), session(2, { terminalId: "t2", project: "dotfiles" }), session(3, { terminalId: "t3" }), session(4, { terminalId: "t4", priority: 0 }), ], layout, ); expect(groups.map((group) => group.title)).toEqual(["urgent", "work"]); expect(groups[0]!.priority).toBe(0); expect(groups[1]!.sessions.map((member) => member.pid)).toEqual([3, 1, 2]); }); it("groups sessions outside Rex by project, after the Rex sessions", () => { const groups = groupSessions( [ session(1, { terminalId: "t1" }), session(2, { project: "mobile" }), session(3, { project: "mobile" }), session(5, { terminalId: "gone" }), ], layout, ); expect(groups.map((group) => [group.title, group.sessions.map((member) => member.pid)])).toEqual([ ["work", [1]], ["mobile", [2, 3]], ["pi-shit", [5]], ]); }); it("groups everything by project when there is no Rex layout", () => { const groups = groupSessions([session(1, { terminalId: "t1" }), session(2, { project: "mobile" })], undefined); expect(groups.map((group) => group.title)).toEqual(["mobile", "pi-shit"]); }); }); describe("resolveTarget", () => { const sessions = [ session(1, { label: "fix the e2e login test" }), session(2, { label: "e2e flaky checkout" }), session(3, { label: "release pi-web" }), ]; it("finds a session by id prefix, exact label or unique label substring", () => { expect(resolveTarget(sessions, "00000003-aaaa")).toMatchObject({ pid: 3 }); expect(resolveTarget(sessions, "Release pi-web")).toMatchObject({ pid: 3 }); expect(resolveTarget(sessions, "checkout")).toMatchObject({ pid: 2 }); }); it("lists the live sessions when the target is ambiguous or unknown", () => { expect(resolveTarget(sessions, "e2e")).toContain("matches more than one session"); const unknown = resolveTarget(sessions, "nope"); expect(unknown).toContain("matches no live session"); expect(unknown).toContain('"release pi-web"'); }); }); describe("peek", () => { it("shows the last two user turns with replies and tool calls on the current branch", () => { const at = "2026-10-28T10:00:00.000Z"; const user = (id: string, parentId: string | null, text: string) => ({ type: "message" as const, id, parentId, timestamp: at, message: { role: "user" as const, content: text, timestamp: 0 }, }); const assistant = (id: string, parentId: string, content: unknown[], stopReason = "stop") => ({ type: "message" as const, id, parentId, timestamp: at, message: { role: "assistant", content, stopReason, timestamp: 0 }, }); const entries = [ { type: "session", version: 3, id: "s", timestamp: at, cwd: "/" }, user("u1", null, "first task"), assistant("a1", "u1", [{ type: "text", text: "done one" }]), user("u2", "a1", "second task"), assistant("a2", "u2", [ { type: "text", text: "looking" }, { type: "toolCall", id: "c", name: "bash", arguments: { command: "git status\nmore" } }, ]), user("u3", "a2", "third task"), assistant("a3", "u3", [], "error"), // An abandoned branch that is not the leaf's ancestor. user("x", "a1", "abandoned"), user("u4", "a3", "fourth"), ] as unknown as Parameters[0]; const markdown = tailParts(currentBranch(entries)).join("\n\n"); expect(markdown).not.toContain("second task"); expect(markdown).not.toContain("abandoned"); expect(markdown).toContain("**You:** third task"); expect(markdown).toContain("**Error:** the request failed"); expect(markdown).toContain("**You:** fourth"); }); it("shows a message from another session as that, not as yours", () => { const at = "2026-10-28T10:00:00.000Z"; const header = "[Message from another Pi session (project app, session s1)]\n\n"; const entries = [ { type: "session", version: 3, id: "s", timestamp: at, cwd: "/" }, { type: "message", id: "u1", parentId: null, timestamp: at, message: { role: "user", content: `${header}please review`, timestamp: 0 }, }, ] as unknown as Parameters[0]; const markdown = tailParts(currentBranch(entries)).join("\n\n"); expect(markdown).toBe("**✉ Message from another Pi session (project app, session s1):** please review"); }); }); describe("promptLabel", () => { it("labels a prompt by your own text, skipping files attached with @", () => { const file = '\n# The Dude: first slice\n'; expect(promptLabel(`${file}\nRead the brief, then propose the plan.`)).toBe( "Read the brief, then propose the plan.", ); expect(promptLabel(file)).toBe("slice-1-brief.md"); expect(promptLabel("fix the login test\nmore")).toBe("fix the login test"); }); }); describe("describeSessions", () => { it("lists sessions by Rex session in sidebar order with their tab, then the ones outside Rex", () => { const now = Date.parse("2026-10-28T10:05:00.000Z"); const listed = describeSessions( [ session(1, { terminalId: "t1", label: "fix login", priority: 0, recap: { text: "Fixing it.", at: "" }, }), session(2, { terminalId: "t2", tank: true }), session(3, { label: "in tmux" }), ], [ { id: "s1", label: "tank", tabs: [{ id: "w1", label: "", blocks: ["t2"] }] }, { id: "s2", label: "work", tabs: [ { id: "w2", label: "", blocks: ["x"] }, { id: "w3", label: "", blocks: ["t1"] }, ], }, ], now, ); expect(listed.split("\n")).toEqual([ 'Rex session "tank":', '- 00000002-aaaa-bbbb-cccc-dddddddddddd · pi-shit · "session 2" · idle 5m · this is you · tab 1', " cwd: /repo/pi-shit · model: unknown · file: (not saved yet)", 'Rex session "work":', '- 00000001-aaaa-bbbb-cccc-dddddddddddd · pi-shit · "fix login" · idle 5m · p0 · tab 2', " recap: Fixing it.", " cwd: /repo/pi-shit · model: unknown · file: (not saved yet)", "Not in Rex:", '- 00000003-aaaa-bbbb-cccc-dddddddddddd · pi-shit · "in tmux" · idle 5m', " cwd: /repo/pi-shit · model: unknown · file: (not saved yet)", ]); }); });