refactor(sdk): introduce session-based architecture (#19180)

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
Michael Bleigh
2026-02-19 16:47:35 -08:00
committed by GitHub
parent 6351352e54
commit f1c0a695f8
21 changed files with 612 additions and 268 deletions
+80
View File
@@ -180,6 +180,86 @@ describe('Storage additional helpers', () => {
expect(storageWithSession.getProjectTempPlansDir()).toBe(expected);
});
describe('Session and JSON Loading', () => {
beforeEach(async () => {
await storage.initialize();
});
it('listProjectChatFiles returns sorted sessions from chats directory', async () => {
const readdirSpy = vi
.spyOn(fs.promises, 'readdir')
/* eslint-disable @typescript-eslint/no-explicit-any */
.mockResolvedValue([
'session-1.json',
'session-2.json',
'not-a-session.txt',
] as any);
const statSpy = vi
.spyOn(fs.promises, 'stat')
.mockImplementation(async (p: any) => {
if (p.toString().endsWith('session-1.json')) {
return {
mtime: new Date('2026-02-01'),
mtimeMs: 1000,
} as any;
}
return {
mtime: new Date('2026-02-02'),
mtimeMs: 2000,
} as any;
});
/* eslint-enable @typescript-eslint/no-explicit-any */
const sessions = await storage.listProjectChatFiles();
expect(readdirSpy).toHaveBeenCalledWith(expect.stringContaining('chats'));
expect(sessions).toHaveLength(2);
// Sorted by mtime desc
expect(sessions[0].filePath).toBe(path.join('chats', 'session-2.json'));
expect(sessions[1].filePath).toBe(path.join('chats', 'session-1.json'));
expect(sessions[0].lastUpdated).toBe(
new Date('2026-02-02').toISOString(),
);
readdirSpy.mockRestore();
statSpy.mockRestore();
});
it('loadProjectTempFile loads and parses JSON from relative path', async () => {
const readFileSpy = vi
.spyOn(fs.promises, 'readFile')
.mockResolvedValue(JSON.stringify({ hello: 'world' }));
const result = await storage.loadProjectTempFile<{ hello: string }>(
'some/file.json',
);
expect(readFileSpy).toHaveBeenCalledWith(
expect.stringContaining(path.join(PROJECT_SLUG, 'some/file.json')),
'utf8',
);
expect(result).toEqual({ hello: 'world' });
readFileSpy.mockRestore();
});
it('loadProjectTempFile returns null if file does not exist', async () => {
const error = new Error('File not found');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(error as any).code = 'ENOENT';
const readFileSpy = vi
.spyOn(fs.promises, 'readFile')
.mockRejectedValue(error);
const result = await storage.loadProjectTempFile('missing.json');
expect(result).toBeNull();
readFileSpy.mockRestore();
});
});
describe('getPlansDir', () => {
interface TestCase {
name: string;