/** * hmem v2 — sessions table + binding-segment algebra. * * A session is a first-class row, NOT a tree node (master-plan Goal #2: no global * mutable "active project" state — the current project is per-session, the open * binding segment). This module owns `bind`/`currentProject`/`projectAt` and reads * the `events` table directly via raw SQL for `maxEventSeq` — it deliberately does * NOT import `events.ts` (D5: avoids a circular dependency with `summarize/`). * * `bind` is a total segment-algebra operation (D3): it closes the open segment at * `from-1` (flushing it via `onSegmentClose`), overwrites any segments at/after the * new boundary, splits a straddling segment, and opens `[from, NULL]`. Attribution * is purely derived from these `[from_seq, to_seq]` ranges — no event row is ever * moved (D2, scenario 6). */ import type Database from 'better-sqlite3'; import type { BindingRow, ClosedSegment, SessionRow } from './types.js'; export interface SessionsApiOpts { /** Invoked when `bind` closes a non-empty segment that has un-flushed events. */ onSegmentClose?: (c: ClosedSegment) => void; } export interface SessionsApi { createSession(p: { session_id?: string; device_id?: string; harness?: string; }): { session_id: string; }; getSession(session_id: string): SessionRow | null; touchSession(session_id: string): void; updateSessionSummary(session_id: string, summary: string, summary_node_uid: string | null): void; bind(session_id: string, project_uid: string, since?: number): void; currentProject(session_id: string): string | null; projectAt(session_id: string, seq: number): string | null; segmentsForSession(session_id: string): BindingRow[]; } export declare function createSessionsApi(db: Database.Database, opts?: SessionsApiOpts): SessionsApi;