import { z } from "zod"; import type { Message } from "../providers/types.js"; /** * Mirrors the `Message` union (providers/types.ts:135-139). Variant order * matters — see the ordering note above. Keep this schema in sync if the * `Message` union ever changes shape. */ export declare const MessageSchema: z.ZodType; export declare const SessionRecordSchema: z.ZodObject<{ sessionId: z.ZodString; model: z.ZodString; createdAt: z.ZodString; updatedAt: z.ZodString; turnsUsed: z.ZodNumber; messages: z.ZodArray, "many">; }, "strip", z.ZodTypeAny, { createdAt: string; model: string; updatedAt: string; messages: Message[]; turnsUsed: number; sessionId: string; }, { createdAt: string; model: string; updatedAt: string; messages: Message[]; turnsUsed: number; sessionId: string; }>; export type SessionRecord = z.infer; /** * Input to `SessionStore.save` — `createdAt`/`updatedAt` are stamped * internally from the store's injected clock, so callers never read the * clock themselves (no argless `new Date()` in core). */ export type SessionSaveInput = Omit; /** * Derive a deterministic fork id from a source `sessionId` + an injected * timestamp. Mirrors `job-store.ts`'s `jobId()` content-hash pattern — no * argless `randomUUID()`/`Date.now()`. Used by `forkSession()` * (agentic-loop.ts) when the caller omits an explicit `newId`. */ export declare function sessionForkId(sessionId: string, now: string): string; export interface SessionStoreOptions { /** Absolute project root; sessions are written under `/.bober/sessions/`. */ projectRoot: string; /** Clock injection. Defaults to `() => new Date().toISOString()`. No argless `new Date()` in core. */ now?: () => string; } /** * Persists agentic-loop transcripts to `.bober/sessions/.json`. * Mirrors `src/research/job-store.ts`: validates with Zod before every * write; reads return `null` on both missing AND malformed JSON (never * throws) — this is what lets `resumeSession` fail soft (sc-6-5). */ export declare class SessionStore { private readonly projectRoot; private readonly clock; constructor(opts: SessionStoreOptions); /** Current time from the injected clock — exposed for deterministic fork-id derivation. */ now(): string; /** Absolute path to the session file for `sessionId`. */ path(sessionId: string): string; /** * Persist a session record. Validates with `SessionRecordSchema` before * writing so an invalid record never reaches disk (mirrors job-store.ts). * `createdAt` is preserved from the existing file on disk when one exists * (first save for a given `sessionId` stamps it fresh); `updatedAt` is * always stamped fresh from the injected clock. * * bober: re-reads the existing file on every save to preserve `createdAt` * — an O(1) extra read per turn, fine at this scale. If this ever needs to * avoid the extra read, cache `createdAt` in-memory in the caller (the * loop already holds a `session` handle across turns) and pass it through * explicitly instead. */ save(record: SessionSaveInput): Promise; /** * Load a session record by id. Returns `null` if not found or malformed — * NEVER throws. This null-on-corrupt result is what `resumeSession` maps * to its typed `{ error }` result (sc-6-5); a corrupt file is never * silently overwritten with an empty session. */ load(sessionId: string): Promise; /** * Copy the transcript at `sessionId` into a new session file under * `newId`. Writes ONLY the new file — the source is only ever read, never * rewritten, so continuing the fork leaves the original byte-identical * (sc-6-3). Throws if the source session does not exist or is corrupt * (nothing to fork). */ fork(sessionId: string, newId: string): Promise; } //# sourceMappingURL=session-store.d.ts.map