From ce0dfad638682ff2c8105eb018a3f67752c310ba Mon Sep 17 00:00:00 2001 From: Haileyesus Date: Sat, 28 Mar 2026 11:06:37 +0300 Subject: [PATCH] refactor: remove sessions names db --- server/src/modules/codex/codex.routes.js | 6 +- server/src/modules/cursor/cursor.routes.js | 4 +- server/src/modules/gemini/gemini.routes.js | 4 +- .../projects/projects.inline.routes.js | 6 +- .../providers/claude/claude.session-parser.ts | 19 ++- .../providers/codex/codex.session-parser.ts | 19 ++- .../providers/cursor/cursor.session-parser.ts | 18 ++- .../providers/gemini/gemini.session-parser.ts | 18 ++- .../sessions/sessions.inline.routes.js | 4 +- .../src/modules/sessions/sessions.watcher.ts | 19 ++- .../src/services/notification-orchestrator.ts | 5 +- server/src/shared/database/migrations.ts | 11 +- .../database/repositories/session-names.ts | 106 ------------- .../database/repositories/sessions.db.ts | 139 +++++++++++------- server/src/shared/database/schema.ts | 17 +-- server/src/shared/database/types.ts | 2 + 16 files changed, 196 insertions(+), 201 deletions(-) delete mode 100644 server/src/shared/database/repositories/session-names.ts diff --git a/server/src/modules/codex/codex.routes.js b/server/src/modules/codex/codex.routes.js index a9b9303d..5f91c798 100644 --- a/server/src/modules/codex/codex.routes.js +++ b/server/src/modules/codex/codex.routes.js @@ -5,7 +5,7 @@ import path from 'path'; import os from 'os'; import TOML from '@iarna/toml'; import { getCodexSessions, deleteCodexSession } from '../../../projects.js'; -import { applyCustomSessionNames, sessionNamesDb } from '@/shared/database/repositories/session-names.js'; +import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; const router = express.Router(); @@ -60,7 +60,7 @@ router.get('/sessions', async (req, res) => { } const sessions = await getCodexSessions(projectPath); - applyCustomSessionNames(sessions, 'codex'); + sessionsDb.applyCustomSessionNames(sessions, 'codex'); res.json({ success: true, sessions }); } catch (error) { console.error('Error fetching Codex sessions:', error); @@ -72,7 +72,7 @@ router.delete('/sessions/:sessionId', async (req, res) => { try { const { sessionId } = req.params; await deleteCodexSession(sessionId); - sessionNamesDb.deleteSessionName(sessionId, 'codex'); + sessionsDb.deleteSession(sessionId); res.json({ success: true }); } catch (error) { console.error(`Error deleting Codex session ${req.params.sessionId}:`, error); diff --git a/server/src/modules/cursor/cursor.routes.js b/server/src/modules/cursor/cursor.routes.js index 35317717..eaf61180 100644 --- a/server/src/modules/cursor/cursor.routes.js +++ b/server/src/modules/cursor/cursor.routes.js @@ -7,7 +7,7 @@ import sqlite3 from 'sqlite3'; import { open } from 'sqlite'; import crypto from 'crypto'; import { CURSOR_MODELS } from '../../../../shared/modelConstants.js'; -import { applyCustomSessionNames } from '@/shared/database/repositories/session-names.js'; +import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; const router = express.Router(); @@ -561,7 +561,7 @@ router.get('/sessions', async (req, res) => { return new Date(b.createdAt) - new Date(a.createdAt); }); - applyCustomSessionNames(sessions, 'cursor'); + sessionsDb.applyCustomSessionNames(sessions, 'cursor'); res.json({ success: true, diff --git a/server/src/modules/gemini/gemini.routes.js b/server/src/modules/gemini/gemini.routes.js index b93e342f..753fb8b2 100644 --- a/server/src/modules/gemini/gemini.routes.js +++ b/server/src/modules/gemini/gemini.routes.js @@ -1,6 +1,6 @@ import express from 'express'; import sessionManager from '../../../sessionManager.js'; -import { sessionNamesDb } from '@/shared/database/repositories/session-names.js'; +import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; const router = express.Router(); @@ -13,7 +13,7 @@ router.delete('/sessions/:sessionId', async (req, res) => { } await sessionManager.deleteSession(sessionId); - sessionNamesDb.deleteSessionName(sessionId, 'gemini'); + sessionsDb.deleteSession(sessionId); res.json({ success: true }); } catch (error) { console.error(`Error deleting Gemini session ${req.params.sessionId}:`, error); diff --git a/server/src/modules/projects/projects.inline.routes.js b/server/src/modules/projects/projects.inline.routes.js index 9154d4ad..429a166a 100644 --- a/server/src/modules/projects/projects.inline.routes.js +++ b/server/src/modules/projects/projects.inline.routes.js @@ -10,7 +10,7 @@ import { deleteProject, searchConversations } from '../../../projects.js'; -import { applyCustomSessionNames, sessionNamesDb } from '@/shared/database/repositories/session-names.js'; +import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; import { workspaceOriginalPathsDb } from '@/shared/database/repositories/workspace-original-paths.db.js'; import { authenticateToken } from '../auth/auth.middleware.js'; import { getWorkspaceNameFromPath, WORKSPACES_ROOT, validateWorkspacePath } from './projects.utils.js'; @@ -46,7 +46,7 @@ router.get('/api/projects/:projectName/sessions', authenticateToken, async (req, try { const { limit = 5, offset = 0 } = req.query; const result = await getSessions(req.params.projectName, parseInt(limit), parseInt(offset)); - applyCustomSessionNames(result.sessions, 'claude'); + sessionsDb.applyCustomSessionNames(result.sessions, 'claude'); res.json(result); } catch (error) { res.status(500).json({ error: error.message }); @@ -70,7 +70,7 @@ router.delete('/api/projects/:projectName/sessions/:sessionId', authenticateToke const { projectName, sessionId } = req.params; console.log(`[API] Deleting session: ${sessionId} from project: ${projectName}`); await deleteSession(projectName, sessionId); - sessionNamesDb.deleteSessionName(sessionId, 'claude'); + sessionsDb.deleteSession(sessionId); console.log(`[API] Session ${sessionId} deleted successfully`); res.json({ success: true }); } catch (error) { diff --git a/server/src/modules/providers/claude/claude.session-parser.ts b/server/src/modules/providers/claude/claude.session-parser.ts index 3c2ee93b..62c0e538 100644 --- a/server/src/modules/providers/claude/claude.session-parser.ts +++ b/server/src/modules/providers/claude/claude.session-parser.ts @@ -1,5 +1,6 @@ import os from 'os'; import path from 'path'; +import fsp from 'node:fs/promises'; import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; import { buildLookupMap, extractFirstValidJsonlData, findFilesRecursivelyCreatedAfterLastScan } from '@/modules/providers/shared/session-parser.utils.js'; import { SessionData } from '@/shared/types/session.js'; @@ -28,7 +29,23 @@ export async function processClaudeSessions() { const result = await processClaudeSessionFile(file, nameMap); if (result) { - sessionsDb.createSession(result.sessionId, 'claude', result.workspacePath, result.sessionName); + let createdAt: string | undefined; + let updatedAt: string | undefined; + try { + const stat = await fsp.stat(file); + createdAt = stat.birthtime.toISOString(); + updatedAt = stat.mtime.toISOString(); + } catch { + // Ignore stat failures and let DB defaults handle created_at/updated_at. + } + sessionsDb.createSession( + result.sessionId, + 'claude', + result.workspacePath, + result.sessionName, + createdAt, + updatedAt, + ); } } } diff --git a/server/src/modules/providers/codex/codex.session-parser.ts b/server/src/modules/providers/codex/codex.session-parser.ts index 1a3aa047..5dbc05e6 100644 --- a/server/src/modules/providers/codex/codex.session-parser.ts +++ b/server/src/modules/providers/codex/codex.session-parser.ts @@ -1,5 +1,6 @@ import os from 'os'; import path from 'path'; +import fsp from 'node:fs/promises'; import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; import { buildLookupMap, extractFirstValidJsonlData, findFilesRecursivelyCreatedAfterLastScan } from '@/modules/providers/shared/session-parser.utils.js'; import { SessionData } from '@/shared/types/session.js'; @@ -29,7 +30,23 @@ export async function processCodexSessions() { const result = await processCodexSessionFile(file, nameMap); if (result) { - sessionsDb.createSession(result.sessionId, 'codex', result.workspacePath, result.sessionName); + let createdAt: string | undefined; + let updatedAt: string | undefined; + try { + const stat = await fsp.stat(file); + createdAt = stat.birthtime.toISOString(); + updatedAt = stat.mtime.toISOString(); + } catch { + // Ignore stat failures and let DB defaults handle created_at/updated_at. + } + sessionsDb.createSession( + result.sessionId, + 'codex', + result.workspacePath, + result.sessionName, + createdAt, + updatedAt, + ); } } } diff --git a/server/src/modules/providers/cursor/cursor.session-parser.ts b/server/src/modules/providers/cursor/cursor.session-parser.ts index b4810049..03c7125e 100644 --- a/server/src/modules/providers/cursor/cursor.session-parser.ts +++ b/server/src/modules/providers/cursor/cursor.session-parser.ts @@ -80,7 +80,23 @@ export async function processCursorSessions() { const result = await processCursorSessionFile(file); if (result) { - sessionsDb.createSession(result.sessionId, 'cursor', result.workspacePath, result.sessionName); + let createdAt: string | undefined; + let updatedAt: string | undefined; + try { + const stat = await fsp.stat(file); + createdAt = stat.birthtime.toISOString(); + updatedAt = stat.mtime.toISOString(); + } catch { + // Ignore stat failures and let DB defaults handle created_at/updated_at. + } + sessionsDb.createSession( + result.sessionId, + 'cursor', + result.workspacePath, + result.sessionName, + createdAt, + updatedAt, + ); } } } diff --git a/server/src/modules/providers/gemini/gemini.session-parser.ts b/server/src/modules/providers/gemini/gemini.session-parser.ts index 705c0927..69bcbc5e 100644 --- a/server/src/modules/providers/gemini/gemini.session-parser.ts +++ b/server/src/modules/providers/gemini/gemini.session-parser.ts @@ -31,7 +31,23 @@ export async function processGeminiSessions() { for (const file of files) { const result = await processGeminiSessionFile(file); if (result) { - sessionsDb.createSession(result.sessionId, 'gemini', result.workspacePath, result.sessionName); + let createdAt: string | undefined; + let updatedAt: string | undefined; + try { + const stat = await fsp.stat(file); + createdAt = stat.birthtime.toISOString(); + updatedAt = stat.mtime.toISOString(); + } catch { + // Ignore stat failures and let DB defaults handle created_at/updated_at. + } + sessionsDb.createSession( + result.sessionId, + 'gemini', + result.workspacePath, + result.sessionName, + createdAt, + updatedAt, + ); } } } diff --git a/server/src/modules/sessions/sessions.inline.routes.js b/server/src/modules/sessions/sessions.inline.routes.js index 03fe1c4c..ee0a1176 100644 --- a/server/src/modules/sessions/sessions.inline.routes.js +++ b/server/src/modules/sessions/sessions.inline.routes.js @@ -2,7 +2,7 @@ import express from 'express'; import path from 'path'; import os from 'os'; import { promises as fsPromises } from 'fs'; -import { sessionNamesDb } from '@/shared/database/repositories/session-names.js'; +import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; import { extractProjectDirectory } from '../../../projects.js'; import { authenticateToken } from '../auth/auth.middleware.js'; @@ -27,7 +27,7 @@ router.put('/api/sessions/:sessionId/rename', authenticateToken, async (req, res if (!provider || !VALID_PROVIDERS.includes(provider)) { return res.status(400).json({ error: `Provider must be one of: ${VALID_PROVIDERS.join(', ')}` }); } - sessionNamesDb.createSessionName(safeSessionId, provider, summary.trim()); + sessionsDb.createSessionName(safeSessionId, provider, summary.trim()); res.json({ success: true }); } catch (error) { console.error(`[API] Error renaming session ${req.params.sessionId}:`, error); diff --git a/server/src/modules/sessions/sessions.watcher.ts b/server/src/modules/sessions/sessions.watcher.ts index 79eb2d54..7eaab745 100644 --- a/server/src/modules/sessions/sessions.watcher.ts +++ b/server/src/modules/sessions/sessions.watcher.ts @@ -100,7 +100,24 @@ const onUpdate = async ( } if (sessionId && workspacePath) { - sessionsDb.createSession(sessionId, provider, workspacePath, sessionName); + let createdAt: string | undefined; + let updatedAt: string | undefined; + try { + const stat = await fsPromises.stat(filePath); + createdAt = stat.birthtime.toISOString(); + updatedAt = stat.mtime.toISOString(); + } catch { + // Ignore stat failures and let DB defaults handle created_at/updated_at. + } + + sessionsDb.createSession( + sessionId, + provider, + workspacePath, + sessionName, + createdAt, + updatedAt, + ); } break; } diff --git a/server/src/services/notification-orchestrator.ts b/server/src/services/notification-orchestrator.ts index 6b4d5bb2..aa03cc69 100644 --- a/server/src/services/notification-orchestrator.ts +++ b/server/src/services/notification-orchestrator.ts @@ -2,7 +2,7 @@ import webPush from 'web-push'; import { notificationPreferencesDb } from '@/shared/database/repositories/notification-preferences.js'; import { pushSubscriptionsDb } from '@/shared/database/repositories/push-subscriptions.js'; -import { sessionNamesDb } from '@/shared/database/repositories/session-names.js'; +import { sessionsDb } from '@/shared/database/repositories/sessions.db.js'; type NotificationKind = 'action_required' | 'stop' | 'error' | 'info' | string; @@ -126,7 +126,7 @@ function resolveSessionName(event: NotificationEvent): string | null { return null; } - return normalizeSessionName(sessionNamesDb.getSessionName(event.sessionId, event.provider)); + return normalizeSessionName(sessionsDb.getSessionName(event.sessionId, event.provider)); } function buildPushBody(event: NotificationEvent) { @@ -314,4 +314,3 @@ export { notifyRunStopped, notifyRunFailed, }; - diff --git a/server/src/shared/database/migrations.ts b/server/src/shared/database/migrations.ts index 7b4b391b..0fa2ba8c 100644 --- a/server/src/shared/database/migrations.ts +++ b/server/src/shared/database/migrations.ts @@ -3,7 +3,6 @@ import { APP_CONFIG_TABLE_SCHEMA_SQL, LAST_SCANNED_AT_SQL, PUSH_SUBSCRIPTIONS_TABLE_SCHEMA_SQL, - SESSION_NAMES_TABLE_SCHEMA_SQL, SESSIONS_TABLE_SCHEMA_SQL, USER_NOTIFICATION_PREFERENCES_TABLE_SCHEMA_SQL, VAPID_KEYS_TABLE_SCHEMA_SQL, @@ -45,15 +44,17 @@ export const runMigrations = (db: Database) => { db.exec(PUSH_SUBSCRIPTIONS_TABLE_SCHEMA_SQL); db.exec("CREATE INDEX IF NOT EXISTS idx_push_subscriptions_user_id ON push_subscriptions(user_id)"); - // Create session_names table if it doesn't exist (for existing installations) - db.exec(SESSION_NAMES_TABLE_SCHEMA_SQL); - db.exec("CREATE INDEX IF NOT EXISTS idx_session_names_lookup ON session_names(session_id, provider)"); - // Create sessions table if it doesn't exist (for existing installations) db.exec(SESSIONS_TABLE_SCHEMA_SQL); db.exec( "CREATE INDEX IF NOT EXISTS idx_session_ids_lookup ON sessions(session_id)" ); + const sessionsTableInfo = db.prepare("PRAGMA table_info(sessions)").all() as { name: string }[]; + const sessionColumnNames = sessionsTableInfo.map((col) => col.name); + addColumnToTableIfNotExists(db, "sessions", sessionColumnNames, "created_at", "DATETIME"); + addColumnToTableIfNotExists(db, "sessions", sessionColumnNames, "updated_at", "DATETIME"); + db.exec("UPDATE sessions SET created_at = COALESCE(created_at, CURRENT_TIMESTAMP)"); + db.exec("UPDATE sessions SET updated_at = COALESCE(updated_at, CURRENT_TIMESTAMP)"); db.exec(WORK_SPACE_PATH_SQL); const workspaceOriginalPathsTableInfo = db.prepare("PRAGMA table_info(workspace_original_paths)").all() as { name: string }[]; diff --git a/server/src/shared/database/repositories/session-names.ts b/server/src/shared/database/repositories/session-names.ts deleted file mode 100644 index 285798d1..00000000 --- a/server/src/shared/database/repositories/session-names.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Session names repository. - * - * Stores provider-scoped custom names for sessions and exposes helpers - * to overlay those names onto in-memory session lists. - */ - -import { getConnection } from '@/shared/database/connection.js'; -import type { - SessionNameLookupRow, - SessionWithSummary, -} from '@/shared/database/types.js'; - -export const sessionNamesDb = { - /** Upserts a custom session name for a provider-scoped session id. */ - createSessionName(sessionId: string, provider: string, customName: string): void { - const db = getConnection(); - db.prepare( - `INSERT INTO session_names (session_id, provider, custom_name) - VALUES (?, ?, ?) - ON CONFLICT(session_id, provider) - DO UPDATE SET custom_name = excluded.custom_name, updated_at = CURRENT_TIMESTAMP` - ).run(sessionId, provider, customName); - }, - - /** Alias to keep write semantics explicit when callers perform edits. */ - updateSessionName(sessionId: string, provider: string, customName: string): void { - sessionNamesDb.createSessionName(sessionId, provider, customName); - }, - - /** Returns a custom name for one session/provider pair or null if unset. */ - getSessionName(sessionId: string, provider: string): string | null { - const db = getConnection(); - const row = db - .prepare( - 'SELECT custom_name FROM session_names WHERE session_id = ? AND provider = ?' - ) - .get(sessionId, provider) as { custom_name: string } | undefined; - return row?.custom_name ?? null; - }, - - /** - * Batch lookup for multiple session ids. - * Returns a Map for efficient overlay onto lists. - */ - getSessionNames(sessionIds: string[], provider: string): Map { - if (sessionIds.length === 0) return new Map(); - - const db = getConnection(); - const placeholders = sessionIds.map(() => '?').join(','); - const rows = db - .prepare( - `SELECT session_id, custom_name FROM session_names - WHERE session_id IN (${placeholders}) AND provider = ?` - ) - .all(...sessionIds, provider) as SessionNameLookupRow[]; - - return new Map(rows.map((row) => [row.session_id, row.custom_name])); - }, - - /** Deletes a custom name. Returns true if a row was removed. */ - deleteSessionName(sessionId: string, provider: string): boolean { - const db = getConnection(); - return ( - db - .prepare( - 'DELETE FROM session_names WHERE session_id = ? AND provider = ?' - ) - .run(sessionId, provider).changes > 0 - ); - }, - - // Legacy aliases used by existing routes/services - setName(sessionId: string, provider: string, customName: string): void { - sessionNamesDb.createSessionName(sessionId, provider, customName); - }, - getName(sessionId: string, provider: string): string | null { - return sessionNamesDb.getSessionName(sessionId, provider); - }, - getNames(sessionIds: string[], provider: string): Map { - return sessionNamesDb.getSessionNames(sessionIds, provider); - }, - deleteName(sessionId: string, provider: string): boolean { - return sessionNamesDb.deleteSessionName(sessionId, provider); - }, -}; - -/** - * Overlay custom names onto a session list in place. - * If a custom name exists, `summary` is replaced. - */ -export function applyCustomSessionNames( - sessions: SessionWithSummary[] | undefined | null, - provider: string -): void { - if (!sessions?.length) return; - - const ids = sessions.map((session) => session.id); - const customNames = sessionNamesDb.getSessionNames(ids, provider); - for (const session of sessions) { - const customName = customNames.get(session.id); - if (customName) { - session.summary = customName; - } - } -} diff --git a/server/src/shared/database/repositories/sessions.db.ts b/server/src/shared/database/repositories/sessions.db.ts index 21e787be..40d71df9 100644 --- a/server/src/shared/database/repositories/sessions.db.ts +++ b/server/src/shared/database/repositories/sessions.db.ts @@ -1,22 +1,92 @@ import { workspaceOriginalPathsDb } from '@/shared/database/repositories/workspace-original-paths.db.js'; import { getConnection } from '@/shared/database/connection.js'; +import type { SessionWithSummary } from '@/shared/database/types.js'; // --------------------------------------------------------------------------- // Queries // --------------------------------------------------------------------------- +type SessionNameLookupRow = { + session_id: string; + custom_name: string; +}; + +function normalizeTimestamp(value?: string): string | null { + if (!value) return null; + + const parsed = new Date(value); + if (Number.isNaN(parsed.getTime())) { + return null; + } + + return parsed.toISOString(); +} + export const sessionsDb = { - createSession(session_id: string, provider: string, workspacePath: string, customName?: string): void { + createSession( + session_id: string, + provider: string, + workspacePath: string, + customName?: string, + createdAt?: string, + updatedAt?: string, + ): void { const db = getConnection(); + const createdAtValue = normalizeTimestamp(createdAt); + const updatedAtValue = normalizeTimestamp(updatedAt); // First, ensure the workspace path is recorded in the workspace_original_paths table // since it's a foreign key in the sessions table. workspaceOriginalPathsDb.createWorkspacePath(workspacePath); db.prepare( - 'INSERT OR IGNORE INTO sessions (session_id, provider, custom_name, workspace_path) VALUES (?, ?, ?, ?)' - ).run(session_id, provider, customName, workspacePath); + `INSERT INTO sessions (session_id, provider, custom_name, workspace_path, created_at, updated_at) + VALUES (?, ?, ?, ?, COALESCE(?, CURRENT_TIMESTAMP), COALESCE(?, CURRENT_TIMESTAMP)) + ON CONFLICT(session_id) DO UPDATE SET updated_at = excluded.updated_at + WHERE sessions.provider = excluded.provider` + ).run(session_id, provider, customName, workspacePath, createdAtValue, updatedAtValue); + }, + + /** Updates a custom session name for an existing session row. */ + createSessionName(sessionId: string, provider: string, customName: string): void { + const db = getConnection(); + db.prepare( + `UPDATE sessions + SET custom_name = ?, updated_at = CURRENT_TIMESTAMP + WHERE session_id = ? AND provider = ?` + ).run(customName, sessionId, provider); + }, + + getSessionName(sessionId: string, provider: string): string | null { + const db = getConnection(); + const row = db + .prepare( + `SELECT custom_name + FROM sessions + WHERE session_id = ? AND provider = ?` + ) + .get(sessionId, provider) as { custom_name: string | null } | undefined; + + return row?.custom_name ?? null; + }, + + getSessionNames(sessionIds: string[], provider: string): Map { + if (sessionIds.length === 0) return new Map(); + + const db = getConnection(); + const placeholders = sessionIds.map(() => '?').join(','); + const rows = db + .prepare( + `SELECT session_id, custom_name + FROM sessions + WHERE session_id IN (${placeholders}) + AND provider = ? + AND custom_name IS NOT NULL` + ) + .all(...sessionIds, provider) as SessionNameLookupRow[]; + + return new Map(rows.map((row) => [row.session_id, row.custom_name])); }, deleteSession(session_id: string): void { @@ -24,59 +94,18 @@ export const sessionsDb = { db.prepare('DELETE FROM sessions WHERE session_id = ?').run(session_id); }, + applyCustomSessionNames(sessions: SessionWithSummary[] | undefined | null, provider: string): void { + if (!sessions?.length) return; - // /** Inserts or updates a custom session name (upsert on session_id + provider). */ - // setName(sessionId: string, provider: string, customName: string): void { - // const db = getConnection(); - // db.prepare( - // `INSERT INTO session_names (session_id, provider, custom_name) - // VALUES (?, ?, ?) - // ON CONFLICT(session_id, provider) - // DO UPDATE SET custom_name = excluded.custom_name, - // updated_at = CURRENT_TIMESTAMP` - // ).run(sessionId, provider, customName); - // }, + const ids = sessions.map((session) => session.id); + const customNames = sessionsDb.getSessionNames(ids, provider); - /** Returns the custom name for a single session, or null if unset. */ - // getName(sessionId: string, provider: string): string | null { - // const db = getConnection(); - // const row = db - // .prepare( - // 'SELECT custom_name FROM session_names WHERE session_id = ? AND provider = ?' - // ) - // .get(sessionId, provider) as { custom_name: string } | undefined; - // return row?.custom_name ?? null; - // }, - - /** - * Batch lookup for multiple session IDs. - * Returns a Map for efficient overlay onto session lists. - */ - // getNames(sessionIds: string[], provider: string): Map { - // if (sessionIds.length === 0) return new Map(); - - // const db = getConnection(); - // const placeholders = sessionIds.map(() => '?').join(','); - // const rows = db - // .prepare( - // `SELECT session_id, custom_name FROM session_names - // WHERE session_id IN (${placeholders}) AND provider = ?` - // ) - // .all(...sessionIds, provider) as SessionNameLookupRow[]; - - // return new Map(rows.map((r) => [r.session_id, r.custom_name])); - // }, - - /** Removes a custom session name. Returns true if a row was deleted. */ - // deleteName(sessionId: string, provider: string): boolean { - // const db = getConnection(); - // return ( - // db - // .prepare( - // 'DELETE FROM session_names WHERE session_id = ? AND provider = ?' - // ) - // .run(sessionId, provider).changes > 0 - // ); - // }, + for (const session of sessions) { + const customName = customNames.get(session.id); + if (customName) { + session.summary = customName; + } + } + }, }; diff --git a/server/src/shared/database/schema.ts b/server/src/shared/database/schema.ts index 37e38461..ba36d873 100644 --- a/server/src/shared/database/schema.ts +++ b/server/src/shared/database/schema.ts @@ -69,24 +69,14 @@ CREATE TABLE IF NOT EXISTS push_subscriptions ( ); `; -export const SESSION_NAMES_TABLE_SCHEMA_SQL = ` -CREATE TABLE IF NOT EXISTS session_names ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - session_id TEXT NOT NULL, - provider TEXT NOT NULL DEFAULT 'claude', - custom_name TEXT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, - UNIQUE(session_id, provider) -); -`; - export const SESSIONS_TABLE_SCHEMA_SQL = ` CREATE TABLE IF NOT EXISTS sessions ( session_id TEXT PRIMARY KEY NOT NULL, provider TEXT NOT NULL, custom_name TEXT, workspace_path TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (workspace_path) REFERENCES workspace_original_paths(workspace_path) ON DELETE CASCADE ON UPDATE CASCADE @@ -143,9 +133,6 @@ ${VAPID_KEYS_TABLE_SCHEMA_SQL} ${PUSH_SUBSCRIPTIONS_TABLE_SCHEMA_SQL} CREATE INDEX IF NOT EXISTS idx_push_subscriptions_user_id ON push_subscriptions(user_id); -${SESSION_NAMES_TABLE_SCHEMA_SQL} -CREATE INDEX IF NOT EXISTS idx_session_names_lookup ON session_names(session_id, provider); - ${SESSIONS_TABLE_SCHEMA_SQL} CREATE INDEX IF NOT EXISTS idx_session_ids_lookup ON sessions(session_id); diff --git a/server/src/shared/database/types.ts b/server/src/shared/database/types.ts index 7e4da1bd..fa009e80 100644 --- a/server/src/shared/database/types.ts +++ b/server/src/shared/database/types.ts @@ -101,6 +101,8 @@ export type SessionsRow = { provider: LLMProvider; workspace_path: string; custom_name: string | null; + created_at: string; + updated_at: string; }; export type SessionNameRow = {