import { MemoryFrontmatter } from './types.js';
import { StorageManager } from './storage.js';
import './index-1qIcnbG1.js';
import './page-versioning.js';
import './consolidation-operator.js';
import './memory-projection-store-CY8TU40w.js';
import 'better-sqlite3';

/**
 * Temporal Supersession (issue #375)
 *
 * When a new fact lands with `structuredAttributes` keyed on a known
 * `entityRef`, any prior fact whose supersession key collides with the new
 * fact's key is marked `status: "superseded"` and linked via
 * `supersededBy` / `supersededAt`.  Recall filters those superseded memories
 * by default so agents see only the "current" value per entity attribute.
 *
 * The algorithm is intentionally O(N) over the memory corpus per write, but
 * skips cheaply when the new fact has no structuredAttributes.  It reuses the
 * cached `readAllMemories()` path so cost is amortized with the rest of the
 * write pipeline.
 */

/**
 * Shared normalization for supersession key components.
 *
 * Trims surrounding whitespace, lowercases, then collapses any run of
 * whitespace OR hyphens to a single hyphen, and strips any leading/trailing
 * hyphens that result.  Both `computeSupersessionKey` and
 * `lookupAttributeByNormalizedKey` must use this so that keys produced at
 * write time and keys used at lookup time are identical regardless of how
 * the LLM encoded whitespace, hyphens, or casing (Finding B fix).
 *
 * Symmetry guarantee: `"foo bar"`, `"foo-bar"`, `"foo - bar"`, and
 * `"foo  bar"` all canonicalize to `"foo-bar"`.
 *
 * Exported so external tests can verify the canonical form.
 */
declare function normalizeSupersessionKey(raw: string): string;
/**
 * Stable supersession key for an (entityRef, attributeName) pair.
 *
 * The algorithm is:
 *  - normalize the entityRef (trim, lower-case, collapse whitespace)
 *  - normalize the attributeName the same way
 *  - join with `::`
 *
 * Exported so tests and tools can recompute it without depending on storage.
 */
declare function computeSupersessionKey(entityRef: string | undefined, attributeName: string): string | null;
/**
 * Compute the full set of supersession keys for a fact with structured
 * attributes.  Returns an empty array if no keys can be derived.
 */
declare function supersessionKeysForFact(spec: {
    entityRef?: string;
    structuredAttributes?: Record<string, string>;
}): string[];
/**
 * Look up a structured-attribute value by a raw key, normalizing both sides
 * with `normalizeSupersessionKey` before comparing.  This ensures that keys
 * written by the LLM with mixed case, surrounding whitespace, or internal
 * whitespace (e.g. `"City"`, `" city "`, `"job   title"`, `"job-title"`)
 * are all matched against normalized keys produced by `computeSupersessionKey`
 * (Finding B fix — uses the same helper so both sides are identical).
 *
 * The storage format is NOT changed — we only normalize at lookup time.
 */
declare function lookupAttributeByNormalizedKey(attributes: Record<string, unknown>, rawKey: string): unknown;
/**
 * Decide whether an existing memory should be superseded by a newly-written
 * memory that carries the supplied supersession key set.
 *
 * Only memories that:
 *  - are currently `active`
 *  - share an `entityRef` with the new fact
 *  - share at least one supersession key with the new fact
 *  - are older than the new fact
 *  - have a conflicting value (different string) for the overlapping key
 * are eligible.  This keeps supersession local to the attribute that actually
 * changed — if fact A sets `{city: Austin, tool: vim}` and fact B sets
 * `{city: NYC}`, only the city attribute is superseded, not the tool.
 */
declare function shouldSupersedeExisting(args: {
    candidate: MemoryFrontmatter;
    newEntityRef: string;
    newAttributes: Record<string, string>;
    newCreatedAt: string;
    newMemoryId: string;
}): {
    matchedKeys: string[];
} | null;
interface TemporalSupersessionResult {
    supersededIds: string[];
    matchedKeys: string[];
}
/**
 * Scan existing memories and mark any that are superseded by the
 * just-written memory.  Fails open on I/O errors — the new memory is already
 * on disk, and supersession is a best-effort hygiene step.
 */
declare function applyTemporalSupersession(args: {
    storage: StorageManager;
    newMemoryId: string;
    entityRef?: string;
    structuredAttributes?: Record<string, string>;
    createdAt: string;
    enabled: boolean;
    /**
     * When true, skip the persisted `frontmatter.created` lookup and use
     * `args.createdAt` directly as the ordering anchor.  Set this on the
     * hash-dedup short-circuit path where `newMemoryId` points to an existing
     * OLD fact (no new file is written) and its persisted timestamp would be
     * stale relative to the incoming promotion event (PR #402 Finding Uyui).
     */
    useCallerTimestamp?: boolean;
}): Promise<TemporalSupersessionResult>;
/**
 * Recall-side filter: returns true when the candidate should be excluded
 * from recall because it has been temporally superseded.  When
 * `includeInRecall` is true, this always returns false (the fact is kept),
 * matching the audit/history opt-in described in the config.
 */
declare function shouldFilterSupersededFromRecall(frontmatter: MemoryFrontmatter, options: {
    enabled: boolean;
    includeInRecall: boolean;
}): boolean;

export { type TemporalSupersessionResult, applyTemporalSupersession, computeSupersessionKey, lookupAttributeByNormalizedKey, normalizeSupersessionKey, shouldFilterSupersededFromRecall, shouldSupersedeExisting, supersessionKeysForFact };
