import type { SessionSurface } from '../runtime/session-surface.js'; /** One recorded turn boundary, the rewind coordinator's per-turn anchor. */ export interface TurnAnchor { /** The turn engine's turn id, shared with the workspace checkpoint's `turnId`. */ readonly turnId: string; /** A short human label (the truncated user prompt) for the recent-turns picker. */ readonly label: string; /** `conversation.getMessageCount()` captured at this turn's completion, the conversation truncation boundary. */ readonly messageCount: number; /** Wall-clock ms at capture, for ordering + age display. */ readonly at: number; } /** Trim a user prompt to a single compact line for the picker. */ export declare function summarizeTurnLabel(text: string | null | undefined, max?: number): string; /** * Record a completed turn's anchor. Idempotent per turnId: a repeated turnId * updates the existing entry in place (the checkpoint engine can re-snapshot a * turn) rather than duplicating it. */ export declare function recordTurnAnchor(sessionId: string, anchor: TurnAnchor): void; /** All recorded anchors for a session, oldest first (chronological). */ export declare function getTurnAnchors(sessionId: string): readonly TurnAnchor[]; /** Resolve an anchor by exact turnId, or null when this run never recorded it. */ export declare function resolveTurnAnchor(sessionId: string, turnId: string): TurnAnchor | null; /** Drop a session's anchors. Exposed for tests and session reset. */ export declare function clearTurnAnchors(sessionId: string): void; /** * Write the current in-memory anchors for a session to its sidecar so they * survive a resume. Best-effort and atomic (temp file + rename): a failed or * torn write must never break the turn that triggered it. Called after each * `recordTurnAnchor` at TURN_COMPLETED. */ export declare function persistTurnAnchors(sessionId: string, surface: SessionSurface): void; /** * Reload a session's persisted anchors into the in-memory registry on resume. * Returns the number of anchors restored (0 when no sidecar exists or it is * unreadable). Idempotent via `recordTurnAnchor`'s per-turnId dedup, so a resume * that later re-records the same turn keeps a single entry. */ export declare function restoreTurnAnchors(sessionId: string, surface: SessionSurface): number; /** * How long a staging file is tolerated before it is treated as crash residue: * 1 hour. `persistTurnAnchors` renames within microseconds of writing, so * anything this old was interrupted, and the completed sidecar (if the write * ever finished) is a separate file. */ export declare const ANCHOR_TMP_MAX_AGE_MS: number; /** * How settled a sidecar must be before this sweep will delete it: 1 hour. * * Another instance can be persisting anchors for a session this process knows * nothing about, and the window between reading a sidecar's content and * unlinking it is not atomic. Requiring the file to have been untouched for an * hour means a sidecar that some other instance is actively rewriting is never * a candidate, while genuine residue, whose writer is long gone, always is. * The sweep repeats, so the delay costs nothing. */ export declare const ANCHOR_SIDECAR_SETTLE_MS: number; export interface AnchorSidecarReapResult { /** Sidecar and staging files examined this sweep. */ readonly scanned: number; /** Files deleted this sweep. */ readonly reaped: number; } export interface AnchorSidecarReapOptions { /** The session this process is using right now; its sidecar is never reaped. */ readonly currentSessionId?: string | null; readonly now?: () => number; /** Override the staging-file age window (tests). */ readonly tmpMaxAgeMs?: number; /** Override how long a sidecar must be untouched before it can be reaped (tests). */ readonly settleMs?: number; } /** * Delete anchor sidecars whose owning session file is gone, sidecars that hold * nothing readable, and abandoned staging files. * * A sidecar survives when `/.jsonl` still exists AND * the sidecar itself parses into at least one usable anchor, content, not * mere existence, because a sidecar truncated by a crash restores nothing and * would otherwise sit there indefinitely looking like valid state. It also * survives while it is still fresh (see `ANCHOR_SIDECAR_SETTLE_MS`), which * keeps a sidecar another instance is mid-rewrite out of reach. * * The current session's sidecar is never touched, and an unreadable or absent * sessions directory simply reclaims nothing. Idempotent and concurrency-safe: * a file another sweeper unlinked first (ENOENT) counts as reaped. */ export declare function reapOrphanedAnchorSidecars(surface: SessionSurface, options?: AnchorSidecarReapOptions): AnchorSidecarReapResult; //# sourceMappingURL=turn-anchors.d.ts.map