/**
 * Temporal and Tag Indexes (v8.1 — SwiftMem-inspired)
 *
 * Maintains two fast on-disk lookup structures in `state/`:
 *   index_time.json — maps YYYY-MM-DD date buckets to memory file paths
 *   index_tags.json — maps tag strings to memory file paths
 *
 * Used as an optional prefilter in the retrieval pipeline:
 * given a time range or a set of tags, narrow the candidate set
 * before the QMD hybrid search so we can pass a smaller pool to scoring.
 *
 * Design constraints:
 * - Must be fail-open (any error returns empty / unfiltered)
 * - Reads/writes are batched per extraction run
 * - Both indexes are plain JSON; no external dependencies
 */
interface TemporalIndex {
    /** version bumped when schema changes */
    version: number;
    /** Last full rebuild timestamp (ISO string) */
    lastRebuildAt?: string;
    /** Map from YYYY-MM-DD → array of memory paths */
    dates: Record<string, string[]>;
}
interface TagIndex {
    version: number;
    lastRebuildAt?: string;
    /** Map from canonical tag string → node metadata */
    tags: Record<string, TagNode | string[]>;
    /** Map from alias string → canonical tags */
    aliases?: Record<string, string[]>;
}
interface TagNode {
    paths: string[];
    aliases?: string[];
    parents?: string[];
}
/**
 * Add (or update) a memory file in both indexes.
 *
 * @param memoryDir Root memory directory
 * @param memoryPath Absolute path to the memory file
 * @param createdAt ISO timestamp of the memory's creation date
 * @param tags Array of tag strings from the memory's frontmatter
 */
declare function indexMemory(memoryDir: string, memoryPath: string, createdAt: string, tags: string[]): void;
/**
 * Remove a memory file from both indexes (called on deletion/archival).
 */
declare function deindexMemory(memoryDir: string, memoryPath: string, createdAt: string, tags: string[]): void;
/**
 * Reset both index files to empty state.
 * Called before a full-corpus rebuild so stale paths in any surviving index
 * file do not persist after the rebuild completes.
 */
declare function clearIndexes(memoryDir: string): void;
/**
 * Returns true when both index files exist on disk.
 * Used to detect first-time enablement so callers can trigger a full rebuild.
 */
declare function indexesExist(memoryDir: string): boolean;
/**
 * Batch-add multiple memories to both indexes in a single read-modify-write cycle.
 * More efficient than calling indexMemory() per file when adding many at once.
 */
declare function indexMemoriesBatch(memoryDir: string, entries: Array<{
    path: string;
    createdAt: string;
    tags: string[];
}>): void;
/**
 * Return the set of memory paths whose index date falls in [fromDate, toDate).
 *
 * Boundary semantics (exclusive upper bound):
 * - `fromDate` is INCLUSIVE — entries on this date ARE returned.
 * - `toDate`   is EXCLUSIVE — entries on this date are NOT returned.
 *   Pass `recencyWindowBoundsFromPrompt(query).toDate` to get the correct
 *   exclusive boundary; do NOT add +1 day yourself.
 * - Default `toDate` = tomorrow, so omitting it includes all of today.
 *
 * @param memoryDir - root memory directory (contains state/index_time.json)
 * @param fromDate  - inclusive start date, YYYY-MM-DD
 * @param toDate    - exclusive end date, YYYY-MM-DD (default: tomorrow)
 * @returns Set of matching file paths, or null if the index is unavailable.
 */
declare function queryByDateRangeAsync(memoryDir: string, fromDate: string, toDate?: string): Promise<Set<string> | null>;
/**
 * Async version of queryByTags — uses non-blocking fs.promises.readFile
 * to avoid blocking the Node.js event loop.
 */
declare function queryByTagsAsync(memoryDir: string, tags: string[]): Promise<Set<string> | null>;
/**
 * Extract tags from a prompt for tag-based prefiltering.
 * Looks for hashtag-style tokens (#foo).
 * Returns lowercase, deduplicated list.
 */
declare function extractTagsFromPrompt(prompt: string): string[];
declare function resolvePromptTagPrefilterAsync(memoryDir: string, prompt: string): Promise<{
    matchedTags: string[];
    expandedTags: string[];
    paths: Set<string> | null;
}>;
/**
 * Detect if a prompt is time-sensitive (mentions specific time references).
 * Used to decide whether to activate the temporal prefilter.
 */
declare function isTemporalQuery(prompt: string): boolean;
/**
 * Compute a "from date" string (YYYY-MM-DD) for a recency-based temporal query.
 * For "recent" / "lately" returns 7 days ago; for today/yesterday the obvious window.
 */
declare function recencyWindowFromPrompt(prompt: string, nowMs?: number): string;
/**
 * Returns both the start and end of the temporal window implied by the prompt.
 *
 * `fromDate` is computed by delegating to `recencyWindowFromPrompt`, so the two
 * functions cannot diverge on the lower bound.  `toDate` is computed independently
 * here using the same pattern-priority ordering, because the upper-bound arithmetic
 * differs (exclusive end vs. inclusive start) and would not be expressible as a
 * simple wrapper.
 *
 * Known divergence to be aware of: for "N hours ago", `recencyWindowFromPrompt`
 * uses `Math.max(1, Math.ceil(hours/24))` days back, so `fromDate` = yesterday for
 * sub-24h values.  `toDate` here is always `tomorrow` when no explicit date is
 * specified (see the `toDaysBack === 0` branch), giving a 2-day window.  This is
 * intentional — the window must cover both yesterday and today for recent hour-level
 * queries.  Any fix to the hours formula in `recencyWindowFromPrompt` must be
 * manually reflected here.
 *
 * - `fromDate`: first day of the implied window (same as `recencyWindowFromPrompt`)
 * - `toDate`: first day NOT in the window (exclusive upper bound), so callers
 *   should filter with `date >= fromDate && date < toDate`.
 */
declare function recencyWindowBoundsFromPrompt(prompt: string, nowMs?: number): {
    fromDate: string;
    toDate: string;
};

export { type TagIndex, type TagNode, type TemporalIndex, clearIndexes, deindexMemory, extractTagsFromPrompt, indexMemoriesBatch, indexMemory, indexesExist, isTemporalQuery, queryByDateRangeAsync, queryByTagsAsync, recencyWindowBoundsFromPrompt, recencyWindowFromPrompt, resolvePromptTagPrefilterAsync };
