import type { AiDriver } from '../../components/ai-driver/ai-driver';
import type { SessionStoreReturn } from '../session-store';
import { type DiagnosticEntry } from './diagnostics';
import type { SessionPersistenceConfig, SessionPreferences } from './session-persistence-provider';
/**
 * Dependencies the persister reads through — all getters so it always sees current
 * state and never holds a stale reference (the driver can be rebuilt on
 * agents-change, and the creating view can disconnect). Injected rather than read
 * from the module registries directly so the class is unit-testable with fakes.
 *
 * @internal
 */
export interface SessionPersisterDeps {
    /** Session identity — stable for the persister's lifetime. */
    stateKey: string;
    /** Current host persistence config (`enabled` + `provider`). Read fresh each op. */
    getPersistence: () => SessionPersistenceConfig;
    /** Names of the currently-configured agents (for the restore orphan check). */
    getAgentNames: () => string[];
    /** The session's shared driver, or `undefined` before it exists. */
    getDriver: () => AiDriver | undefined;
    /** The session's shared store, or `undefined` before it exists. */
    getStore: () => SessionStoreReturn | undefined;
    /**
     * Build the current diagnostic entries (message/turn/event/meta-snapshot). Stays
     * element-owned — it reads the host's agents, active-agent debug snapshot, meta
     * events, etc. — and is diffed against the shared cursors here (GENC-1351 §5.10).
     */
    getDiagnosticEntries: () => DiagnosticEntry[];
}
/**
 * Owns **restore-core** persistence for one session (GENC-1351 §5.10) — the
 * save/restore/freeze of the {@link PersistedSession} snapshot plus the
 * carry-forward cache. Created once per session via `persister-registry.ts` and
 * shared by every element view, so there is a single save timer and a single
 * cache: the per-view double-write races (and the corruption they caused under a
 * non-atomic backend) are gone by construction.
 *
 * Owns all provider I/O for the session: the restore-core snapshot (save/restore/
 * freeze), the user-preferences blob (load/save — the element keeps only the
 * `chatConfig`-defaults reconciler), and the diagnostics-append scheduling (one
 * timer per session; entry-building stays element-owned via `getDiagnosticEntries`).
 *
 * @internal
 */
export declare class SessionPersister {
    private deps;
    private _saveTimer?;
    private _lastSaveAt;
    private _diagnosticsTimer?;
    private _lastDiagnosticsAt;
    /**
     * The flow-owner's last-known-good serialized image, carried forward when a
     * post-restore autosave fires before the agent re-activates (its live capture is
     * empty). Seeded on restore. See {@link reconcileAgentSnapshots}.
     */
    private _cache;
    /**
     * The loaded preferences blob (GENC-1351 §5.10 Phase 2), owned here so it's
     * **shared per session** — the element's `applyPreferenceBaseline` reconciler reads
     * it via {@link storedPreferences}. Kept fresh on every save, so a later re-reconcile
     * uses the latest choices, not the stale startup blob. `null` = loaded, none stored.
     */
    private _storedPreferences;
    /**
     * Whether the user has changed any preference this session. **Shared per session**
     * (was per-element, which let the two views disagree and one clobber the other's
     * choice — issue #1). Once set, the reconciler freezes so `chatConfig` defaults
     * can't overwrite a live user choice, regardless of which view toggled it.
     */
    private _preferencesUserChanged;
    constructor(deps: SessionPersisterDeps);
    /**
     * Re-point the dependency getters at the currently-live element view. The
     * persister outlives any single element (it's cached per session in
     * `persister-registry.ts`), so when a later element mounts on the same session
     * — e.g. an SPA teardown + remount — it MUST rebind, or the persister keeps
     * calling the torn-down creator's `getDiagnosticEntries`/`getPersistence`/
     * `getAgentNames` (which read a detached driver/store → empty), silently halting
     * diagnostics + autosave capture (GENC-1351 §5.10). `stateKey` is unchanged.
     *
     * @internal
     */
    rebindDeps(deps: SessionPersisterDeps): void;
    /** The loaded preferences blob (shared per session); read by the element's reconciler. */
    get storedPreferences(): SessionPreferences | null;
    /** True once the user has changed any preference this session (shared per session). */
    get preferencesUserChanged(): boolean;
    private get stateKey();
    private logMeta;
    /**
     * Throttled autosave. Called by every view on each transcript change; the single
     * shared timer coalesces them into at most one save per the provider's
     * `saveDebounceMs`. `saveDebounceMs: 0` (e.g. `sessionStorage`) means save as
     * soon as the current tick settles.
     */
    scheduleSave(): void;
    /**
     * Cancel a pending debounced autosave **without flushing it** (GENC-1351 §5.12).
     * Called before a session switch/re-key so the outgoing transcript can never be
     * written to the incoming session's file after the key changes — the clobber
     * guard for in-place project switching.
     */
    cancelPendingSave(): void;
    /**
     * Capture the current session to durable storage (GENC-1351 §5.1). Reads the
     * full transcript from the driver and the restorable scalars from the store, and
     * captures the active stateful agent's `serialize()` into `agentSnapshots`.
     */
    private persistSession;
    /**
     * Page-reload restore (GENC-1351 §5.3). With a stored snapshot for this session,
     * hydrate the store and reseed the driver so the conversation continues. No-op
     * when disabled, absent, or version/host mismatched. An `interrupted` snapshot
     * (§5.9) restores the conversation but shows a "start again" assistant message
     * instead of rehydrating the mid-flight flow.
     */
    restore(): Promise<void>;
    /**
     * Surface a non-fatal "couldn't restore" notice after a failed restore (load
     * timeout/error, or an unusable snapshot) so a vanished conversation isn't a
     * silent mystery on reload (GENC-1351 §6). Reuses the display-only `system-event`
     * divider (like the "Restored…" one) — stripped before persist, so it never lands
     * in the fresh session's saved history. `loadHistory` is safe here: this path only
     * runs when nothing was restored, so the driver is empty.
     */
    private showRestoreFailedNotice;
    /**
     * Drop the restore-core snapshot (the "remember chat" toggle-off and the Clear
     * action) and reset the carry-forward cache. Diagnostics + preferences are
     * separate and untouched here.
     */
    clearRestoreCore(): Promise<void>;
    /**
     * Load the remembered preferences blob (bounded by {@link RESTORE_TIMEOUT_MS}) into
     * {@link storedPreferences}. A throw propagates to the caller (the element wraps it
     * and falls back to config defaults); on success `null` = no provider / none stored.
     */
    loadPreferences(): Promise<void>;
    /**
     * Persist the preferences blob. Only ever called on a genuine user change, so it
     * also records that (freezing the reconciler — shared per session) and keeps
     * {@link storedPreferences} fresh. Fires **regardless of "remember chat"** — display
     * choices are the user's — needing only a provider that implements `savePreferences`.
     */
    savePreferences(prefs: SessionPreferences): void;
    /**
     * Throttled diagnostics append (GENC-1351 §5.8). On each transcript change, if the
     * provider persists diagnostics, coalesce and append the new activity since the
     * last flush (coarser than the restore-core save — the log is heavy). Keyed on
     * provider capability only, **independent of "remember chat"**. No-op without a
     * diagnostics-capable provider, so it's free for other consumers.
     */
    scheduleDiagnostics(): void;
    /**
     * Append the diagnostic entries created since the last flush to the provider's
     * forward-only stream. Best-effort — a failed write is logged and never touches
     * the chat. (The cursors advance on collect, so a dropped batch isn't retried;
     * acceptable for a forensic stream that isn't the source of truth.) Also called
     * directly by the download path to land the current delta before reassembly.
     */
    flushDiagnostics(): Promise<void>;
    /**
     * The diagnostic entries not yet appended this load — the forward-capture delta
     * (§5.8). Skips messages present at restore or already appended; emits each turn
     * (by turn-index) and meta-event (by index) once; appends a `meta-snapshot` only
     * when the block changed. Advances the shared per-session cursors as it goes.
     *
     * TODO(GENC-1461, longer-term): this whole delta step exists only because the element *pulls* the
     * ENTIRE debug log on every throttled flush (`getDiagnosticEntries()` returns the full timeline),
     * so we must diff it against per-session cursors to append only the new tail — and messages, unlike
     * events (monotonic `index`) and turns (`turnIndex`), have no stable positional cursor (compaction
     * rewrites ranges, tool-call messages are annotated in place, synthetic messages are spliced in,
     * restore reloads them), forcing a content-derived identity (`diagnosticsMessageKey`). That
     * identity is inherently fragile: it was too coarse for the reasoning/answer/tool-call split and
     * silently dropped co-timestamped messages (GENC-1461; fixed for now by adding `category`). The
     * robust fix is to invert the flow — have the driver *push* each diagnostic entry exactly once at
     * creation (an append-only event stream) instead of the element pulling-and-diffing — which removes
     * the message-identity key and this dedup entirely. Bigger change; deferred.
     */
    private collectDiagnosticsDelta;
    /** Cancel any pending timers. Called on explicit session teardown. */
    dispose(): void;
}
//# sourceMappingURL=session-persister.d.ts.map