From a91023961c4840bc3a2d9ad2c22cfdd6438e91fb Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Tue, 28 Apr 2026 10:45:41 +0900 Subject: [PATCH] feat(team-mode): add team session registry with tests --- .../team-mode/team-session-registry.test.ts | 89 +++++++++++++++++++ .../team-mode/team-session-registry.ts | 33 +++++++ 2 files changed, 122 insertions(+) create mode 100644 src/features/team-mode/team-session-registry.test.ts create mode 100644 src/features/team-mode/team-session-registry.ts diff --git a/src/features/team-mode/team-session-registry.test.ts b/src/features/team-mode/team-session-registry.test.ts new file mode 100644 index 000000000..785202175 --- /dev/null +++ b/src/features/team-mode/team-session-registry.test.ts @@ -0,0 +1,89 @@ +/// + +import { afterEach, describe, expect, test } from "bun:test" + +import { + clearTeamSessionRegistry, + lookupTeamSession, + registerTeamSession, + unregisterTeamSession, + unregisterTeamSessionsByTeam, +} from "./team-session-registry" + +describe("team-session-registry", () => { + afterEach(() => { + clearTeamSessionRegistry() + }) + + test("registers a session and looks it up by sessionId", () => { + // given + registerTeamSession("ses_alpha", { teamRunId: "team-1", memberName: "worker-1", role: "member" }) + + // when + const entry = lookupTeamSession("ses_alpha") + + // then + expect(entry).toEqual({ teamRunId: "team-1", memberName: "worker-1", role: "member" }) + }) + + test("returns undefined when the sessionId is not registered", () => { + // given - nothing registered + // when + const entry = lookupTeamSession("ses_missing") + + // then + expect(entry).toBeUndefined() + }) + + test("unregisters a single session by sessionId", () => { + // given + registerTeamSession("ses_alpha", { teamRunId: "team-1", memberName: "lead", role: "lead" }) + registerTeamSession("ses_beta", { teamRunId: "team-1", memberName: "worker-1", role: "member" }) + + // when + unregisterTeamSession("ses_alpha") + + // then + expect(lookupTeamSession("ses_alpha")).toBeUndefined() + expect(lookupTeamSession("ses_beta")).toEqual({ teamRunId: "team-1", memberName: "worker-1", role: "member" }) + }) + + test("unregisters every session that belongs to the given teamRunId", () => { + // given + registerTeamSession("ses_alpha", { teamRunId: "team-1", memberName: "lead", role: "lead" }) + registerTeamSession("ses_beta", { teamRunId: "team-1", memberName: "worker-1", role: "member" }) + registerTeamSession("ses_gamma", { teamRunId: "team-2", memberName: "solo", role: "member" }) + + // when + unregisterTeamSessionsByTeam("team-1") + + // then + expect(lookupTeamSession("ses_alpha")).toBeUndefined() + expect(lookupTeamSession("ses_beta")).toBeUndefined() + expect(lookupTeamSession("ses_gamma")).toEqual({ teamRunId: "team-2", memberName: "solo", role: "member" }) + }) + + test("clearTeamSessionRegistry removes every entry", () => { + // given + registerTeamSession("ses_alpha", { teamRunId: "team-1", memberName: "lead", role: "lead" }) + registerTeamSession("ses_beta", { teamRunId: "team-2", memberName: "worker", role: "member" }) + + // when + clearTeamSessionRegistry() + + // then + expect(lookupTeamSession("ses_alpha")).toBeUndefined() + expect(lookupTeamSession("ses_beta")).toBeUndefined() + }) + + test("registering the same sessionId twice overwrites the previous entry", () => { + // given + registerTeamSession("ses_alpha", { teamRunId: "team-1", memberName: "worker-1", role: "member" }) + + // when + registerTeamSession("ses_alpha", { teamRunId: "team-2", memberName: "promoted-lead", role: "lead" }) + + // then + expect(lookupTeamSession("ses_alpha")).toEqual({ teamRunId: "team-2", memberName: "promoted-lead", role: "lead" }) + }) +}) diff --git a/src/features/team-mode/team-session-registry.ts b/src/features/team-mode/team-session-registry.ts new file mode 100644 index 000000000..63f1657b9 --- /dev/null +++ b/src/features/team-mode/team-session-registry.ts @@ -0,0 +1,33 @@ +export type TeamSessionRole = "lead" | "member" + +export type TeamSessionEntry = { + teamRunId: string + memberName: string + role: TeamSessionRole +} + +const registry = new Map() + +export function registerTeamSession(sessionId: string, entry: TeamSessionEntry): void { + registry.set(sessionId, entry) +} + +export function lookupTeamSession(sessionId: string): TeamSessionEntry | undefined { + return registry.get(sessionId) +} + +export function unregisterTeamSession(sessionId: string): void { + registry.delete(sessionId) +} + +export function unregisterTeamSessionsByTeam(teamRunId: string): void { + for (const [sessionId, entry] of registry.entries()) { + if (entry.teamRunId === teamRunId) { + registry.delete(sessionId) + } + } +} + +export function clearTeamSessionRegistry(): void { + registry.clear() +}