/** * Global input recall: persistent cross-session entries plus this process's * submissions, with Codex `ChatComposerHistory` semantics — empty submissions * are ignored, adjacent duplicates collapse, the recall space skips * persistent entries that duplicate a local one (local wins), and Up/Down * navigation is gated so interior cursor movement never hijacks the draft. * * @module @deepseek-ai/dsh-tui/history */ /** Maximum entries retained in the persistent history file and the local recall pool. */ export declare const HISTORY_MAX_ENTRIES = 100; /** Encode one entry for the history file (JSON keeps multi-line drafts intact). */ export declare function serializeHistoryEntry(text: string): string; /** * Parse a persisted history file (one JSON entry per line): invalid lines * drop out, empty entries are ignored, adjacent duplicates collapse, and the * result keeps only the newest `max` entries. * @param raw - file content, empty for a missing file. * @param max - entry cap. * @returns persistent entries, oldest first. */ export declare function parseHistoryFile(raw: string, max?: number): readonly string[]; /** * The append unit for the persistent file: one JSON line, so a multi-line * draft still occupies exactly one physical line. Each submission appends * this unit at the end of the file, so concurrent terminals add entries * after each other. Node chunks one append at 512 KiB: a pasted entry * beyond that size could interleave mid-line with another writer's * chunks, and the damaged line then drops out at the next parse — * recall tolerates the loss by design. */ export declare function historyLine(text: string): string; /** * Whether the file on disk differs from its canonical form (deduped and * capped). True means stale lines have accumulated and the next boot * should rewrite it once, atomically. */ export declare function needsCompaction(raw: string, max?: number): boolean; /** * Record one in-session submission: empty text is ignored and an adjacent * duplicate collapses (Codex `record_local_submission` semantics). The local * pool shares the persistent pool's cap so the recall space stays bounded. * @param local - current in-session entries, oldest first. * @param text - the submitted prompt. * @param max - the local pool cap. * @returns the updated local list. */ export declare function recordLocalEntry(local: readonly string[], text: string, max?: number): readonly string[]; /** * Serialize a capped entry list to the history file format (one JSON line * per entry, trailing newline). The boot-time compaction writes this * canonical form once when stale lines have accumulated; submissions * themselves only ever append a single line. * @param entries - the entries to persist, oldest first. * @returns the file content, '' for an empty list. */ export declare function serializeHistoryList(entries: readonly string[]): string; /** * Build the recall space, newest first: local entries, then persistent * entries whose text is not duplicated locally (the local copy wins and the * persistent twin is skipped — Codex's replay-seed dedup, applied to the * whole local set). * @param persistent - cross-session entries, oldest first. * @param local - this process's submissions, oldest first. * @returns recall entries, newest first. */ export declare function recallEntries(persistent: readonly string[], local: readonly string[]): readonly string[]; /** Shell-style recall navigation over a fixed recall space. */ export interface RecallState { /** Recall entries, newest first (frozen at navigation start). */ entries: readonly string[]; /** Current recall index; null when not browsing. */ index: number | null; /** Draft saved when browsing started; restored on Down past the newest. */ savedDraft: string; /** The recalled text currently in the composer (the boundary gate's anchor). */ lastRecalled: string | null; } /** Fresh navigation state over one recall space. */ export declare function beginRecall(entries: readonly string[], draft: string): RecallState; /** * Join a panel-recalled entry onto the draft already in the composer: the * draft is extended, never replaced, so picking a history row cannot discard * work in progress. An empty draft takes the entry as-is; otherwise the entry * starts on its own line unless the draft already ends one. * @param draft - the composer text before the recall. * @param entry - the sanitized text of the accepted row. * @returns the text to place in the composer. */ export declare function appendRecall(draft: string, entry: string): string; /** The outcome of one recall step. */ export interface RecallStep { state: RecallState; /** The text to place in the composer; undefined means "no movement". */ entry: string | undefined; } /** * Move one entry older (Up, toward index +1 in the newest-first space). The * first Up saves the current draft so Down past the newest can restore it * (Claude-Code shell recall — the draft is never lost); the oldest entry * stays put. * @param state - current navigation state. * @param draft - the composer text to preserve when browsing starts. */ export declare function recallOlder(state: RecallState, draft: string): RecallStep; /** Move one entry newer (Down, toward index 0); past the newest, browsing ends and the saved draft returns. */ export declare function recallNewer(state: RecallState): RecallStep;