feat(session-manager): add version-gated SDK read path for OpenCode beta
- Add SDK client injection via setStorageClient() - Version-gate getMainSessions(), getAllSessions(), readSessionMessages(), readSessionTodos() - Add comprehensive tests for SDK path (beta mode) - Maintain backward compatibility with JSON fallback
This commit is contained in:
@@ -26,6 +26,11 @@ mock.module("./constants", () => ({
|
||||
TOOL_NAME_PREFIX: "session_",
|
||||
}))
|
||||
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => false,
|
||||
resetSqliteBackendCache: () => {},
|
||||
}))
|
||||
|
||||
const { getAllSessions, getMessageDir, sessionExists, readSessionMessages, readSessionTodos, getSessionInfo } =
|
||||
await import("./storage")
|
||||
|
||||
@@ -314,3 +319,169 @@ describe("session-manager storage - getMainSessions", () => {
|
||||
expect(sessions.length).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe("session-manager storage - SDK path (beta mode)", () => {
|
||||
const mockClient = {
|
||||
session: {
|
||||
list: mock(() => Promise.resolve({ data: [] })),
|
||||
messages: mock(() => Promise.resolve({ data: [] })),
|
||||
todo: mock(() => Promise.resolve({ data: [] })),
|
||||
},
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset mocks
|
||||
mockClient.session.list.mockClear()
|
||||
mockClient.session.messages.mockClear()
|
||||
mockClient.session.todo.mockClear()
|
||||
})
|
||||
|
||||
test("getMainSessions uses SDK when beta mode is enabled", async () => {
|
||||
// given
|
||||
const mockSessions = [
|
||||
{ id: "ses_1", directory: "/test", parentID: null, time: { created: 1000, updated: 2000 } },
|
||||
{ id: "ses_2", directory: "/test", parentID: "ses_1", time: { created: 1000, updated: 1500 } },
|
||||
]
|
||||
mockClient.session.list.mockImplementation(() => Promise.resolve({ data: mockSessions }))
|
||||
|
||||
// Mock isSqliteBackend to return true
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => true,
|
||||
resetSqliteBackendCache: () => {},
|
||||
}))
|
||||
|
||||
// Re-import to get fresh module with mocked isSqliteBackend
|
||||
const { setStorageClient, getMainSessions } = await import("./storage")
|
||||
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
|
||||
|
||||
// when
|
||||
const sessions = await getMainSessions({ directory: "/test" })
|
||||
|
||||
// then
|
||||
expect(mockClient.session.list).toHaveBeenCalled()
|
||||
expect(sessions.length).toBe(1)
|
||||
expect(sessions[0].id).toBe("ses_1")
|
||||
})
|
||||
|
||||
test("getAllSessions uses SDK when beta mode is enabled", async () => {
|
||||
// given
|
||||
const mockSessions = [
|
||||
{ id: "ses_1", directory: "/test", time: { created: 1000, updated: 2000 } },
|
||||
{ id: "ses_2", directory: "/test", time: { created: 1000, updated: 1500 } },
|
||||
]
|
||||
mockClient.session.list.mockImplementation(() => Promise.resolve({ data: mockSessions }))
|
||||
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => true,
|
||||
resetSqliteBackendCache: () => {},
|
||||
}))
|
||||
|
||||
const { setStorageClient, getAllSessions } = await import("./storage")
|
||||
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
|
||||
|
||||
// when
|
||||
const sessionIDs = await getAllSessions()
|
||||
|
||||
// then
|
||||
expect(mockClient.session.list).toHaveBeenCalled()
|
||||
expect(sessionIDs).toEqual(["ses_1", "ses_2"])
|
||||
})
|
||||
|
||||
test("readSessionMessages uses SDK when beta mode is enabled", async () => {
|
||||
// given
|
||||
const mockMessages = [
|
||||
{
|
||||
info: { id: "msg_1", role: "user", agent: "test", time: { created: 1000 } },
|
||||
parts: [{ id: "part_1", type: "text", text: "Hello" }],
|
||||
},
|
||||
{
|
||||
info: { id: "msg_2", role: "assistant", agent: "oracle", time: { created: 2000 } },
|
||||
parts: [{ id: "part_2", type: "text", text: "Hi there" }],
|
||||
},
|
||||
]
|
||||
mockClient.session.messages.mockImplementation(() => Promise.resolve({ data: mockMessages }))
|
||||
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => true,
|
||||
resetSqliteBackendCache: () => {},
|
||||
}))
|
||||
|
||||
const { setStorageClient, readSessionMessages } = await import("./storage")
|
||||
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
|
||||
|
||||
// when
|
||||
const messages = await readSessionMessages("ses_test")
|
||||
|
||||
// then
|
||||
expect(mockClient.session.messages).toHaveBeenCalledWith({ path: { id: "ses_test" } })
|
||||
expect(messages.length).toBe(2)
|
||||
expect(messages[0].id).toBe("msg_1")
|
||||
expect(messages[1].id).toBe("msg_2")
|
||||
expect(messages[0].role).toBe("user")
|
||||
expect(messages[1].role).toBe("assistant")
|
||||
})
|
||||
|
||||
test("readSessionTodos uses SDK when beta mode is enabled", async () => {
|
||||
// given
|
||||
const mockTodos = [
|
||||
{ id: "todo_1", content: "Task 1", status: "pending", priority: "high" },
|
||||
{ id: "todo_2", content: "Task 2", status: "completed", priority: "medium" },
|
||||
]
|
||||
mockClient.session.todo.mockImplementation(() => Promise.resolve({ data: mockTodos }))
|
||||
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => true,
|
||||
resetSqliteBackendCache: () => {},
|
||||
}))
|
||||
|
||||
const { setStorageClient, readSessionTodos } = await import("./storage")
|
||||
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
|
||||
|
||||
// when
|
||||
const todos = await readSessionTodos("ses_test")
|
||||
|
||||
// then
|
||||
expect(mockClient.session.todo).toHaveBeenCalledWith({ path: { id: "ses_test" } })
|
||||
expect(todos.length).toBe(2)
|
||||
expect(todos[0].content).toBe("Task 1")
|
||||
expect(todos[1].content).toBe("Task 2")
|
||||
expect(todos[0].status).toBe("pending")
|
||||
expect(todos[1].status).toBe("completed")
|
||||
})
|
||||
|
||||
test("SDK path returns empty array on error", async () => {
|
||||
// given
|
||||
mockClient.session.messages.mockImplementation(() => Promise.reject(new Error("API error")))
|
||||
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => true,
|
||||
resetSqliteBackendCache: () => {},
|
||||
}))
|
||||
|
||||
const { setStorageClient, readSessionMessages } = await import("./storage")
|
||||
setStorageClient(mockClient as unknown as Parameters<typeof setStorageClient>[0])
|
||||
|
||||
// when
|
||||
const messages = await readSessionMessages("ses_test")
|
||||
|
||||
// then
|
||||
expect(messages).toEqual([])
|
||||
})
|
||||
|
||||
test("SDK path returns empty array when client is not set", async () => {
|
||||
// given - beta mode enabled but no client set
|
||||
mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => true,
|
||||
resetSqliteBackendCache: () => {},
|
||||
}))
|
||||
|
||||
// Re-import without setting client
|
||||
const { readSessionMessages } = await import("./storage")
|
||||
|
||||
// when - calling readSessionMessages without client set
|
||||
const messages = await readSessionMessages("ses_test")
|
||||
|
||||
// then - should return empty array since no client and no JSON fallback
|
||||
expect(messages).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user