mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-18 01:51:20 -07:00
fix(plan): clean up session directories and plans on deletion (#20914)
This commit is contained in:
@@ -919,6 +919,32 @@ describe('Session Cleanup', () => {
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('should delete the session-specific directory', async () => {
|
||||
const config = createMockConfig();
|
||||
const settings: Settings = {
|
||||
general: {
|
||||
sessionRetention: {
|
||||
enabled: true,
|
||||
maxAge: '1d', // Very short retention to trigger deletion of all but current
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Mock successful file operations
|
||||
mockFs.access.mockResolvedValue(undefined);
|
||||
mockFs.unlink.mockResolvedValue(undefined);
|
||||
mockFs.rm.mockResolvedValue(undefined);
|
||||
|
||||
await cleanupExpiredSessions(config, settings);
|
||||
|
||||
// Verify that fs.rm was called with the session directory for the deleted session that has sessionInfo
|
||||
// recent456 should be deleted and its directory removed
|
||||
expect(mockFs.rm).toHaveBeenCalledWith(
|
||||
path.join('/tmp/test-project', 'recent456'),
|
||||
expect.objectContaining({ recursive: true, force: true }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseRetentionPeriod format validation', () => {
|
||||
|
||||
@@ -115,6 +115,17 @@ export async function cleanupExpiredSessions(
|
||||
} catch {
|
||||
/* ignore if doesn't exist */
|
||||
}
|
||||
|
||||
// ALSO cleanup the session-specific directory (contains plans, tasks, etc.)
|
||||
const sessionDir = path.join(
|
||||
config.storage.getProjectTempDir(),
|
||||
sessionId,
|
||||
);
|
||||
try {
|
||||
await fs.rm(sessionDir, { recursive: true, force: true });
|
||||
} catch {
|
||||
/* ignore if doesn't exist */
|
||||
}
|
||||
}
|
||||
|
||||
if (config.getDebugMode()) {
|
||||
|
||||
@@ -309,23 +309,33 @@ describe('ChatRecordingService', () => {
|
||||
});
|
||||
|
||||
describe('deleteSession', () => {
|
||||
it('should delete the session file and tool outputs if they exist', () => {
|
||||
it('should delete the session file, tool outputs, session directory, and logs if they exist', () => {
|
||||
const sessionId = 'test-session-id';
|
||||
const chatsDir = path.join(testTempDir, 'chats');
|
||||
const logsDir = path.join(testTempDir, 'logs');
|
||||
const toolOutputsDir = path.join(testTempDir, 'tool-outputs');
|
||||
const sessionDir = path.join(testTempDir, sessionId);
|
||||
|
||||
fs.mkdirSync(chatsDir, { recursive: true });
|
||||
const sessionFile = path.join(chatsDir, 'test-session-id.json');
|
||||
fs.mkdirSync(logsDir, { recursive: true });
|
||||
fs.mkdirSync(toolOutputsDir, { recursive: true });
|
||||
fs.mkdirSync(sessionDir, { recursive: true });
|
||||
|
||||
const sessionFile = path.join(chatsDir, `${sessionId}.json`);
|
||||
fs.writeFileSync(sessionFile, '{}');
|
||||
|
||||
const toolOutputDir = path.join(
|
||||
testTempDir,
|
||||
'tool-outputs',
|
||||
'session-test-session-id',
|
||||
);
|
||||
const logFile = path.join(logsDir, `session-${sessionId}.jsonl`);
|
||||
fs.writeFileSync(logFile, '{}');
|
||||
|
||||
const toolOutputDir = path.join(toolOutputsDir, `session-${sessionId}`);
|
||||
fs.mkdirSync(toolOutputDir, { recursive: true });
|
||||
|
||||
chatRecordingService.deleteSession('test-session-id');
|
||||
chatRecordingService.deleteSession(sessionId);
|
||||
|
||||
expect(fs.existsSync(sessionFile)).toBe(false);
|
||||
expect(fs.existsSync(logFile)).toBe(false);
|
||||
expect(fs.existsSync(toolOutputDir)).toBe(false);
|
||||
expect(fs.existsSync(sessionDir)).toBe(false);
|
||||
});
|
||||
|
||||
it('should not throw if session file does not exist', () => {
|
||||
|
||||
@@ -569,6 +569,13 @@ export class ChatRecordingService {
|
||||
fs.unlinkSync(sessionPath);
|
||||
}
|
||||
|
||||
// Cleanup Activity logs in the project logs directory
|
||||
const logsDir = path.join(tempDir, 'logs');
|
||||
const logPath = path.join(logsDir, `session-${sessionId}.jsonl`);
|
||||
if (fs.existsSync(logPath)) {
|
||||
fs.unlinkSync(logPath);
|
||||
}
|
||||
|
||||
// Cleanup tool outputs for this session
|
||||
const safeSessionId = sanitizeFilenamePart(sessionId);
|
||||
const toolOutputDir = path.join(
|
||||
@@ -585,6 +592,13 @@ export class ChatRecordingService {
|
||||
) {
|
||||
fs.rmSync(toolOutputDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
// ALSO cleanup the session-specific directory (contains plans, tasks, etc.)
|
||||
const sessionDir = path.join(tempDir, safeSessionId);
|
||||
// Robustness: Ensure the path is strictly within the temp root
|
||||
if (fs.existsSync(sessionDir) && sessionDir.startsWith(tempDir)) {
|
||||
fs.rmSync(sessionDir, { recursive: true, force: true });
|
||||
}
|
||||
} catch (error) {
|
||||
debugLogger.error('Error deleting session file.', error);
|
||||
throw error;
|
||||
|
||||
Reference in New Issue
Block a user