import { describe, test, expect } from "bun:test" import { TmuxPollingManager } from "./polling-manager" import type { TrackedSession } from "./types" describe("TmuxPollingManager overlap", () => { test("skips overlapping pollSessions executions", async () => { //#given const sessions = new Map() sessions.set("ses-1", { sessionId: "ses-1", paneId: "%1", description: "test", createdAt: new Date(), lastSeenAt: new Date(), closePending: false, closeRetryCount: 0, }) let activeCalls = 0 let maxActiveCalls = 0 let statusCallCount = 0 let releaseStatus: (() => void) | undefined const statusGate = new Promise((resolve) => { releaseStatus = resolve }) const client = { session: { status: async () => { statusCallCount += 1 activeCalls += 1 maxActiveCalls = Math.max(maxActiveCalls, activeCalls) await statusGate activeCalls -= 1 return { data: { "ses-1": { type: "running" } } } }, messages: async () => ({ data: [] }), }, } const manager = new TmuxPollingManager( client as unknown as import("../../tools/delegate-task/types").OpencodeClient, sessions, async () => {}, ) //#when const firstPoll = (manager as unknown as { pollSessions: () => Promise }).pollSessions() await Promise.resolve() const secondPoll = (manager as unknown as { pollSessions: () => Promise }).pollSessions() releaseStatus?.() await Promise.all([firstPoll, secondPoll]) //#then expect(maxActiveCalls).toBe(1) expect(statusCallCount).toBe(1) }) test("closes stable idle sessions without fetching full messages when activity was already observed from events", async () => { //#given const sessions = new Map() sessions.set("ses-1", { sessionId: "ses-1", paneId: "%1", description: "test", createdAt: new Date(Date.now() - 15_000), lastSeenAt: new Date(), closePending: false, closeRetryCount: 0, activityVersion: 0, stableIdlePolls: 2, observedIdleActivityVersion: 0, }) let messagesCallCount = 0 const closedSessionIds: string[] = [] const client = { session: { status: async () => ({ data: { "ses-1": { type: "idle" } } }), messages: async () => { messagesCallCount += 1 return { data: [] } }, }, } const manager = new TmuxPollingManager( client as unknown as import("../../tools/delegate-task/types").OpencodeClient, sessions, async (sessionId) => { closedSessionIds.push(sessionId) }, ) manager.handleEvent({ type: "message.part.delta", properties: { sessionID: "ses-1", field: "text", delta: "done" }, }) //#when const pollSessions = (manager as unknown as { pollSessions: () => Promise }).pollSessions await pollSessions.call(manager) await pollSessions.call(manager) await pollSessions.call(manager) //#then expect(messagesCallCount).toBe(0) expect(closedSessionIds).toEqual(["ses-1"]) }) test("does not close sessions missing from one poll until the longer grace window elapses", async () => { // given const now = Date.now() const sessions = new Map() sessions.set("ses-1", { sessionId: "ses-1", paneId: "%1", description: "test", createdAt: new Date(now - 1_000), lastSeenAt: new Date(now - 7_000), closePending: false, closeRetryCount: 0, activityVersion: 0, }) const closedSessionIds: string[] = [] const client = { session: { status: async () => ({ data: {} }), messages: async () => ({ data: [] }), }, } const manager = new TmuxPollingManager( client as unknown as import("../../tools/delegate-task/types").OpencodeClient, sessions, async (sessionId) => { closedSessionIds.push(sessionId) }, ) // when const pollSessions = (manager as unknown as { pollSessions: () => Promise }).pollSessions await pollSessions.call(manager) // then expect(closedSessionIds).toEqual([]) }) test("does not time out active sessions after only eleven minutes", async () => { // given const now = Date.now() const sessions = new Map() sessions.set("ses-1", { sessionId: "ses-1", paneId: "%1", description: "test", createdAt: new Date(now - 11 * 60 * 1000), lastSeenAt: new Date(now), closePending: false, closeRetryCount: 0, activityVersion: 0, }) const closedSessionIds: string[] = [] const client = { session: { status: async () => ({ data: { "ses-1": { type: "running" } } }), messages: async () => ({ data: [] }), }, } const manager = new TmuxPollingManager( client as unknown as import("../../tools/delegate-task/types").OpencodeClient, sessions, async (sessionId) => { closedSessionIds.push(sessionId) }, ) // when const pollSessions = (manager as unknown as { pollSessions: () => Promise }).pollSessions await pollSessions.call(manager) // then expect(closedSessionIds).toEqual([]) }) test("does not close when activityVersion changes before the idle recheck resolves", async () => { // given const sessions = new Map() sessions.set("ses-1", { sessionId: "ses-1", paneId: "%1", description: "test", createdAt: new Date(Date.now() - 15_000), lastSeenAt: new Date(), closePending: false, closeRetryCount: 0, activityVersion: 0, }) const closedSessionIds: string[] = [] let statusCallCount = 0 let manager: TmuxPollingManager const client = { session: { status: async () => { statusCallCount += 1 if (statusCallCount === 2) { manager.handleEvent({ type: "message.part.delta", properties: { sessionID: "ses-1", field: "text", delta: "new activity" }, }) } return { data: { "ses-1": { type: "idle" } } } }, messages: async () => ({ data: [] }), }, } manager = new TmuxPollingManager( client as unknown as import("../../tools/delegate-task/types").OpencodeClient, sessions, async (sessionId) => { closedSessionIds.push(sessionId) }, ) const pollSessions = (manager as unknown as { pollSessions: () => Promise }).pollSessions // when await pollSessions.call(manager) // then expect(closedSessionIds).toEqual([]) }) })