From aa7a9d7a6e9fd2432a1ca4a9eb53a2f89d2985b7 Mon Sep 17 00:00:00 2001 From: Seonghyeok Date: Sun, 29 Mar 2026 23:27:13 +0900 Subject: [PATCH] fix: enable Gemini CLI session deletion and UI state update The delete endpoint only handled UI sessions (~/.gemini/sessions/) but not CLI sessions (~/.gemini/tmp/chats/). Also, handleSessionDelete only filtered project.sessions, leaving geminiSessions and codexSessions untouched so the UI didn't reflect the deletion without a refresh. Co-Authored-By: Claude Opus 4.6 (1M context) --- server/projects.js | 39 +++++++++++++++++++++++++++++++++++ server/routes/gemini.js | 14 ++++++++++++- src/hooks/useProjectsState.ts | 2 ++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/server/projects.js b/server/projects.js index d8ccaeb7b..79db27ffe 100755 --- a/server/projects.js +++ b/server/projects.js @@ -2538,6 +2538,44 @@ async function getGeminiCliSessionMessages(sessionId) { return []; } +async function deleteGeminiCliSession(sessionId) { + const geminiTmpDir = path.join(os.homedir(), '.gemini', 'tmp'); + let projectDirs; + try { + projectDirs = await fs.readdir(geminiTmpDir); + } catch { + throw new Error(`Gemini CLI session not found: ${sessionId}`); + } + + for (const projectDir of projectDirs) { + const chatsDir = path.join(geminiTmpDir, projectDir, 'chats'); + let chatFiles; + try { + chatFiles = await fs.readdir(chatsDir); + } catch { + continue; + } + + for (const chatFile of chatFiles) { + if (!chatFile.endsWith('.json')) continue; + try { + const filePath = path.join(chatsDir, chatFile); + const data = await fs.readFile(filePath, 'utf8'); + const session = JSON.parse(data); + const fileSessionId = session.sessionId || chatFile.replace('.json', ''); + if (fileSessionId === sessionId) { + await fs.unlink(filePath); + return true; + } + } catch { + continue; + } + } + } + + throw new Error(`Gemini CLI session file not found: ${sessionId}`); +} + export { getProjects, getSessions, @@ -2557,5 +2595,6 @@ export { deleteCodexSession, getGeminiCliSessions, getGeminiCliSessionMessages, + deleteGeminiCliSession, searchConversations }; diff --git a/server/routes/gemini.js b/server/routes/gemini.js index ff7f36633..1d3f6be65 100644 --- a/server/routes/gemini.js +++ b/server/routes/gemini.js @@ -1,6 +1,7 @@ import express from 'express'; import sessionManager from '../sessionManager.js'; import { sessionNamesDb } from '../database/db.js'; +import { deleteGeminiCliSession } from '../projects.js'; const router = express.Router(); @@ -12,7 +13,18 @@ router.delete('/sessions/:sessionId', async (req, res) => { return res.status(400).json({ success: false, error: 'Invalid session ID format' }); } - await sessionManager.deleteSession(sessionId); + // Try deleting from UI sessions and CLI sessions + let deleted = false; + try { + await sessionManager.deleteSession(sessionId); + deleted = true; + } catch { } + + try { + await deleteGeminiCliSession(sessionId); + deleted = true; + } catch { } + sessionNamesDb.deleteName(sessionId, 'gemini'); res.json({ success: true }); } catch (error) { diff --git a/src/hooks/useProjectsState.ts b/src/hooks/useProjectsState.ts index 28cf682e7..f97534e1d 100644 --- a/src/hooks/useProjectsState.ts +++ b/src/hooks/useProjectsState.ts @@ -436,6 +436,8 @@ export function useProjectsState({ prevProjects.map((project) => ({ ...project, sessions: project.sessions?.filter((session) => session.id !== sessionIdToDelete) ?? [], + codexSessions: project.codexSessions?.filter((session) => session.id !== sessionIdToDelete) ?? [], + geminiSessions: project.geminiSessions?.filter((session) => session.id !== sessionIdToDelete) ?? [], sessionMeta: { ...project.sessionMeta, total: Math.max(0, (project.sessionMeta?.total as number | undefined ?? 0) - 1),