/**
 * Sparse N-gram Index Engine
 *
 * Fast text search using trigram decomposition with probabilistic masks,
 * inspired by Cursor's fast regex search and GitHub's Project Blackbird.
 *
 * Instead of scanning every document, queries decompose into trigrams,
 * look up posting lists, intersect them, and only full-match on candidates.
 * Probabilistic masks (locMask + nextMask) provide "3.5-gram" specificity
 * from 3-gram keys, dramatically reducing false positives.
 *
 * Persistence: SQLite (same pattern as memory.db / graph.db)
 */
export declare const NGRAM_WARMUP_MAX_DB_BYTES: number;
export declare const NGRAM_DEFAULT_ROTATE_BYTES: number;
export declare const NGRAM_DEFAULT_FOOTPRINT_BYTES: number;
export declare function getNgramWalPath(dbPath: string): string;
export declare function getNgramShmPath(dbPath: string): string;
export declare function getNgramFootprintBytes(dbPath: string): number;
export interface Posting {
    docId: string;
    locMask: number;
    nextMask: number;
}
export interface SearchResult {
    docId: string;
    score: number;
}
export interface SearchStats {
    totalQueries: number;
    totalTokensSaved: number;
    totalResultsReturned: number;
    recentQueries: Array<{
        query: string;
        resultCount: number;
        tokensSaved: number;
        timestamp: number;
    }>;
}
export interface NgramIndexOptions {
    /** Skip synchronous hash-set warmup on init. Safe to use in startup-sensitive
     *  modes (e.g. MCP-only). Searches fall back to DB lookup until warmed. */
    deferWarm?: boolean;
}
export type NgramMaintenanceAction = 'none' | 'vacuum' | 'rotated';
export interface NgramMaintenanceResult {
    action: NgramMaintenanceAction;
    dbPath: string;
    sizeBytes: number;
    previousPath?: string;
    reason?: string;
}
export declare class NgramIndex {
    private db;
    private dbPath;
    private storageDirty;
    private readonly deferWarm;
    private knownHashes;
    private insertStmt;
    private deleteStmt;
    private lookupStmt;
    private docExistsStmt;
    private writesSinceCheckpoint;
    private lastCheckpointAt;
    private quotaSkipNoticeShown;
    private _searchStats;
    constructor(dbPath?: string, options?: NgramIndexOptions);
    private rotateOversizeDbIfNeeded;
    private initSchema;
    private prepareStatements;
    /** Load known trigram hashes into memory for fast existence checks.
     *  Call warmHashSetDeferred() later if init was skipped. */
    private warmHashSet;
    /** Warm the hash set after a deferred init. No-op if already warm. */
    warmHashSetDeferred(): void;
    /** Run an opportunistic WAL checkpoint. PASSIVE first, escalate to TRUNCATE
     *  if the WAL is still over its configured limit. Returns the WAL byte size
     *  observed after the attempt so callers can report progress. */
    private checkpointIfNeeded;
    /** Footprint quota check before a write. Returns true if the write should
     *  proceed; false if it should be skipped. Throws when NEXUS_NGRAM_STRICT_QUOTA=1
     *  so callers can surface hard quota failures during tests/CI. */
    private allowWrite;
    /** Index a document's text content */
    addDocument(docId: string, text: string): void;
    /** Trigger a passive checkpoint when either the doc or time interval threshold
     *  is hit. Cheap on a healthy DB, prevents WAL growth on bulk indexing. */
    private maybePeriodicCheckpoint;
    /** Remove a document from the index */
    removeDocument(docId: string): void;
    /** Check if a document is already indexed */
    isIndexed(docId: string): boolean;
    /** Get count of indexed documents */
    getDocCount(): number;
    /** Path to the underlying SQLite database file. */
    getDbPath(): string;
    /** Bytes occupied by the .db file alone. */
    getDbBytes(): number;
    /** Bytes occupied by the .db-wal file. */
    getWalBytes(): number;
    /** Bytes occupied by the .db-shm file. */
    getShmBytes(): number;
    /** Total SQLite footprint = db + wal + shm. Use this for quota checks. */
    getSqliteFootprintBytes(): number;
    /**
     * Search for documents matching a text query.
     * Returns candidate document IDs ranked by trigram match count.
     *
     * The caller should do full text matching on these candidates —
     * this is a pre-filter, not a final answer.
     */
    search(query: string, limit?: number): SearchResult[];
    /**
     * Search with a minimum trigram match threshold.
     * Only returns documents matching at least `minMatches` trigrams.
     */
    searchStrict(query: string, minMatches?: number, limit?: number): string[];
    /**
     * Fast existence check: does any document contain this exact substring?
     * Uses trigram intersection for speed, then verifies against doc text
     * that the caller must provide.
     */
    candidatesForSubstring(substring: string, limit?: number): string[];
    /**
     * Search with token savings tracking. Returns results + estimated tokens saved.
     * Use this method from MCP tools to get visible savings metrics.
     */
    searchWithStats(query: string, limit?: number): {
        results: SearchResult[];
        tokensSaved: number;
        totalCandidateTokens: number;
    };
    /**
     * Sparse n-gram search: uses variable-length segments weighted by CRC32
     * character-pair rarity for higher selectivity on rare patterns.
     */
    searchSparse(query: string, limit?: number): SearchResult[];
    /** Get accumulated search statistics */
    getSearchStats(): SearchStats;
    /** Batch index multiple documents efficiently */
    addDocuments(docs: Array<{
        id: string;
        text: string;
    }>): number;
    /** Rebuild the entire index from scratch */
    rebuild(docs: Array<{
        id: string;
        text: string;
    }>): number;
    optimizeStorage(force?: boolean): void;
    /**
     * Operator-focused maintenance for the on-disk ngram DB.
     * - Bounds runaway DB growth via rotation, counting the
     *   full SQLite footprint (db + wal + shm) so a runaway WAL triggers it.
     * - Vacuums only when safe (<= vacuumMaxBytes) and either forced or dirty.
     */
    maintainBounded(options?: {
        force?: boolean;
    }): NgramMaintenanceResult;
    getStats(): {
        docCount: number;
        postingCount: number;
        uniqueTrigramCount: number;
        dbSizeBytes: number;
    };
    /** Close the database connection.
     *
     *  Always truncates the WAL so the .db-wal sibling can never outgrow the
     *  configured cap on shutdown — the failure mode that produced the 84GB
     *  WAL on a user machine. VACUUM is only run when the operator has both a
     *  small DB and explicitly opts in via NEXUS_NGRAM_VACUUM_ON_CLOSE=1, since
     *  blind VACUUM on multi-GB DBs blocks shutdown indefinitely. */
    close(): void;
}
/** Get or create the shared NgramIndex instance */
export declare function getSharedNgramIndex(dbPath?: string): NgramIndex;
