export type HistorySearchDirection = "backward" | "forward"; /** Deterministic prompt-history state kept separate from Pi editor internals. */ export class PiHistoryAdapter { readonly #entries: string[] = []; #index = -1; #draft = ""; #query: string | undefined; #searchIndex = -1; #ignoreCase = false; get entries(): readonly string[] { return [...this.#entries]; } setSearchIgnoreCase(enabled: boolean): void { this.#ignoreCase = enabled; } add(text: string): void { const value = text.trim(); if (value.length === 0 || this.#entries[0] === value) return; this.#entries.unshift(value); if (this.#entries.length > 100) this.#entries.pop(); } previous(current: string): string | undefined { if (this.#entries.length === 0 || this.#index + 1 >= this.#entries.length) return undefined; if (this.#index === -1) this.#draft = current; this.#index += 1; return this.#entries[this.#index]; } next(): string | undefined { if (this.#index < 0) return undefined; this.#index -= 1; return this.#index < 0 ? this.#draft : this.#entries[this.#index]; } fetchOldest(): string | undefined { if (this.#entries.length === 0) return undefined; this.#index = this.#entries.length - 1; return this.#entries[this.#index]; } search(query: string, direction: HistorySearchDirection): string | undefined { this.#query = query; this.#searchIndex = direction === "backward" ? -1 : this.#entries.length; return this.repeatSearch(direction); } repeatSearch(direction: HistorySearchDirection): string | undefined { if (this.#query === undefined) return undefined; const step = direction === "backward" ? 1 : -1; for ( let index = this.#searchIndex + step; index >= 0 && index < this.#entries.length; index += step ) { const entry = this.#entries[index]; const query = this.#query; const matches = entry !== undefined && (this.#ignoreCase ? entry.toLocaleLowerCase().includes(query.toLocaleLowerCase()) : entry.includes(query)); if (matches) { this.#searchIndex = index; return this.#entries[index]; } } return undefined; } resetNavigation(): void { this.#index = -1; this.#draft = ""; } }