Files
claude-mem/src/services/sqlite/sessions/get.ts
T
huakson 4f6fb9e614 fix: address platform source review feedback
Tighten platform source persistence so legacy callers cannot silently relabel existing sessions, repair migration 24 when schema_versions drifts from the real schema, and polish the follow-up UI/error-handler review nits.

- only backfill platform_source when it is blank and raise on explicit source conflicts for an existing session
- make migration 24 verify both the sdk_sessions column and its index before treating it as applied
- expose platform_source from the functional session getters and add regression tests for source preservation and schema drift recovery
- add the required APPROVED OVERRIDE annotation for centralized HTTP error translation
- keep mobile source pills on a single horizontal row
2026-03-24 10:46:48 -03:00

112 lines
2.9 KiB
TypeScript

/**
* Session retrieval functions
* Database-first parameter pattern for functional composition
*/
import type { Database } from 'bun:sqlite';
import { logger } from '../../../utils/logger.js';
import type {
SessionBasic,
SessionFull,
SessionWithStatus,
SessionSummaryDetail,
} from './types.js';
/**
* Get session by ID (basic fields only)
*/
export function getSessionById(db: Database, id: number): SessionBasic | null {
const stmt = db.prepare(`
SELECT id, content_session_id, memory_session_id, project,
COALESCE(platform_source, 'claude') as platform_source,
user_prompt, custom_title
FROM sdk_sessions
WHERE id = ?
LIMIT 1
`);
return (stmt.get(id) as SessionBasic | undefined) || null;
}
/**
* Get SDK sessions by memory session IDs
* Used for exporting session metadata
*/
export function getSdkSessionsBySessionIds(
db: Database,
memorySessionIds: string[]
): SessionFull[] {
if (memorySessionIds.length === 0) return [];
const placeholders = memorySessionIds.map(() => '?').join(',');
const stmt = db.prepare(`
SELECT id, content_session_id, memory_session_id, project,
COALESCE(platform_source, 'claude') as platform_source,
user_prompt, custom_title,
started_at, started_at_epoch, completed_at, completed_at_epoch, status
FROM sdk_sessions
WHERE memory_session_id IN (${placeholders})
ORDER BY started_at_epoch DESC
`);
return stmt.all(...memorySessionIds) as SessionFull[];
}
/**
* Get recent sessions with their status and summary info
* Returns sessions ordered oldest-first for display
*/
export function getRecentSessionsWithStatus(
db: Database,
project: string,
limit: number = 3
): SessionWithStatus[] {
const stmt = db.prepare(`
SELECT * FROM (
SELECT
s.memory_session_id,
s.status,
s.started_at,
s.started_at_epoch,
s.user_prompt,
CASE WHEN sum.memory_session_id IS NOT NULL THEN 1 ELSE 0 END as has_summary
FROM sdk_sessions s
LEFT JOIN session_summaries sum ON s.memory_session_id = sum.memory_session_id
WHERE s.project = ? AND s.memory_session_id IS NOT NULL
GROUP BY s.memory_session_id
ORDER BY s.started_at_epoch DESC
LIMIT ?
)
ORDER BY started_at_epoch ASC
`);
return stmt.all(project, limit) as SessionWithStatus[];
}
/**
* Get full session summary by ID (includes request_summary and learned_summary)
*/
export function getSessionSummaryById(
db: Database,
id: number
): SessionSummaryDetail | null {
const stmt = db.prepare(`
SELECT
id,
memory_session_id,
content_session_id,
project,
user_prompt,
request_summary,
learned_summary,
status,
created_at,
created_at_epoch
FROM sdk_sessions
WHERE id = ?
LIMIT 1
`);
return (stmt.get(id) as SessionSummaryDetail | undefined) || null;
}