import { afterEach, describe, expect, test } from "bun:test" import { mkdtempSync, rmSync } from "node:fs" import { join } from "node:path" import { tmpdir } from "node:os" import { readContinuationMarker } from "../../features/run-continuation-state" import { createStopContinuationGuardHook } from "./index" describe("stop-continuation-guard", () => { const tempDirs: string[] = [] function createTempDir(): string { const directory = mkdtempSync(join(tmpdir(), "omo-stop-guard-")) tempDirs.push(directory) return directory } afterEach(() => { while (tempDirs.length > 0) { const directory = tempDirs.pop() if (directory) { rmSync(directory, { recursive: true, force: true }) } } }) function createMockPluginInput() { return { client: { tui: { showToast: async () => ({}), }, }, directory: createTempDir(), } as any } test("should mark session as stopped", () => { // given - a guard hook with no stopped sessions const input = createMockPluginInput() const guard = createStopContinuationGuardHook(input) const sessionID = "test-session-1" // when - we stop continuation for the session guard.stop(sessionID) // then - session should be marked as stopped expect(guard.isStopped(sessionID)).toBe(true) const marker = readContinuationMarker(input.directory, sessionID) expect(marker?.sources.stop?.state).toBe("stopped") }) test("should return false for non-stopped sessions", () => { // given - a guard hook with no stopped sessions const guard = createStopContinuationGuardHook(createMockPluginInput()) // when - we check a session that was never stopped // then - it should return false expect(guard.isStopped("non-existent-session")).toBe(false) }) test("should clear stopped state for a session", () => { // given - a session that was stopped const guard = createStopContinuationGuardHook(createMockPluginInput()) const sessionID = "test-session-2" guard.stop(sessionID) // when - we clear the session guard.clear(sessionID) // then - session should no longer be stopped expect(guard.isStopped(sessionID)).toBe(false) }) test("should handle multiple sessions independently", () => { // given - multiple sessions with different stop states const guard = createStopContinuationGuardHook(createMockPluginInput()) const session1 = "session-1" const session2 = "session-2" const session3 = "session-3" // when - we stop some sessions but not others guard.stop(session1) guard.stop(session2) // then - each session has its own state expect(guard.isStopped(session1)).toBe(true) expect(guard.isStopped(session2)).toBe(true) expect(guard.isStopped(session3)).toBe(false) }) test("should clear session on session.deleted event", async () => { // given - a session that was stopped const guard = createStopContinuationGuardHook(createMockPluginInput()) const sessionID = "test-session-3" guard.stop(sessionID) // when - session is deleted await guard.event({ event: { type: "session.deleted", properties: { info: { id: sessionID } }, }, }) // then - session should no longer be stopped (cleaned up) expect(guard.isStopped(sessionID)).toBe(false) }) test("should not affect other sessions on session.deleted", async () => { // given - multiple stopped sessions const guard = createStopContinuationGuardHook(createMockPluginInput()) const session1 = "session-keep" const session2 = "session-delete" guard.stop(session1) guard.stop(session2) // when - one session is deleted await guard.event({ event: { type: "session.deleted", properties: { info: { id: session2 } }, }, }) // then - other session should remain stopped expect(guard.isStopped(session1)).toBe(true) expect(guard.isStopped(session2)).toBe(false) }) test("should clear stopped state on new user message (chat.message)", async () => { // given - a session that was stopped const guard = createStopContinuationGuardHook(createMockPluginInput()) const sessionID = "test-session-4" guard.stop(sessionID) expect(guard.isStopped(sessionID)).toBe(true) // when - user sends a new message await guard["chat.message"]({ sessionID }) // then - stop state should be cleared (one-time only) expect(guard.isStopped(sessionID)).toBe(false) }) test("should not affect non-stopped sessions on chat.message", async () => { // given - a session that was never stopped const guard = createStopContinuationGuardHook(createMockPluginInput()) const sessionID = "test-session-5" // when - user sends a message (session was never stopped) await guard["chat.message"]({ sessionID }) // then - should not throw and session remains not stopped expect(guard.isStopped(sessionID)).toBe(false) }) test("should handle undefined sessionID in chat.message", async () => { // given - a guard with a stopped session const guard = createStopContinuationGuardHook(createMockPluginInput()) guard.stop("some-session") // when - chat.message is called without sessionID await guard["chat.message"]({ sessionID: undefined }) // then - should not throw and stopped session remains stopped expect(guard.isStopped("some-session")).toBe(true) }) })