Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

83 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { AgentApproval, WorkspaceSession } from "@g1t/contracts";
5
6import { filterSessions, recentSessions, shortRecents } from "./recents.ts";
7
8const session = (id: string, at: string, over: Partial<WorkspaceSession> = {}): WorkspaceSession => ({
9 kind: "hosted",
10 id,
11 repo: "acme/web",
12 repoId: "rep_1",
13 title: `Session ${id}`,
14 actor: "ada",
15 harness: "claude_managed_agents",
16 agent: null,
17 branch: null,
18 item: null,
19 itemTitle: null,
20 pull: null,
21 pullTitle: null,
22 pullStatus: null,
23 state: "active",
24 startedAt: at,
25 lastActivityAt: at,
26 subagents: 0,
27 step: null,
28 session: null,
29 ...over,
30});
31
32const waitingOn = (sessionId: string) => ({ sessionId, status: "waiting" }) as AgentApproval;
33
34test("Sessions in the sidebar are the viewer's, those on their work items and those waiting on them, each once, newest first", () => {
35 const sessions = recentSessions({
36 me: "Ada",
37 mine: [session("ses_mine", "2026-10-21T12:00:00Z", { state: "ended" }), session("ses_both", "2026-10-21T12:03:00Z")],
38 live: [
39 session("ses_both", "2026-10-21T12:03:00Z"),
40 session("ses_item", "2026-10-21T12:02:00Z", { actor: "bea", item: 4, state: "idle" }),
41 session("ses_asks", "2026-10-21T12:01:00Z", { actor: "bea" }),
42 session("ses_other", "2026-10-21T12:04:00Z", { actor: "bea", item: 5 }),
43 session("run_1", "2026-10-21T12:05:00Z", { kind: "agent", actor: "ada" }),
44 ],
45 items: [4],
46 approvals: [waitingOn("ses_asks")],
47 });
48 assert.deepEqual(
49 sessions.map((s) => [s.id, s.status]),
50 [
51 ["ses_both", "working"],
52 ["ses_item", "idle"],
53 ["ses_asks", "waiting"],
54 ["ses_mine", "ended"],
55 ],
56 );
57 // The calls could not be read: no session reads as waiting, and one only waiting on the viewer is not listed.
58 const unread = recentSessions({ me: "ada", mine: [], live: [session("ses_asks", "2026-10-21T12:01:00Z", { actor: "bea" })], items: [], approvals: null });
59 assert.deepEqual(unread, []);
60});
61
62test("Sessions is short, but what must stay in view stays; the filter and search reach sessions", () => {
63 const { shown, more } = shortRecents(["a", "b", "c", "d"], 2, (row) => row === "d");
64 assert.deepEqual(shown, ["a", "b", "d"]);
65 assert.equal(more, 1);
66 const sessions = recentSessions({
67 me: "ada",
68 mine: [session("ses_1", "2026-10-21T12:00:00Z", { title: "Fix login" }), session("ses_2", "2026-10-21T12:01:00Z", { title: "Docs" })],
69 live: [],
70 items: [],
71 approvals: [waitingOn("ses_2")],
72 });
73 assert.deepEqual(filterSessions(sessions, "all", "").length, 2);
74 assert.deepEqual(
75 filterSessions(sessions, "unread", "").map((s) => s.id),
76 ["ses_2"],
77 );
78 assert.deepEqual(filterSessions(sessions, "mentions", ""), []);
79 assert.deepEqual(
80 filterSessions(sessions, "all", "LOGIN").map((s) => s.id),
81 ["ses_1"],
82 );
83});