import type { Database } from "./database.js"; import type { Memory, MemoryCategory, MemoryTier, MemoryKind } from "../types/index.js"; export declare class MemoryStore { private db; private insertStmt; private getByIdStmt; private getAllStmt; private getByCategoryStmt; private deleteStmt; private updateStmt; private searchFtsStmt; private touchAccessStmt; private markStaleStmt; private getStaleStmt; private invalidateStmt; private getCoreStmt; private setTierStmt; private getActiveStmt; private setPinsStmt; private setTrajectoryStmt; constructor(db: Database); /** P2-18: attach a JSON-serialised trajectory to a memory row. */ setTrajectory(id: number, trajectoryJson: string): void; getTrajectory(id: number): string | null; insert(category: MemoryCategory, content: string, tags: string[] | null, confidence: number, gitSha: string | null, gitBranch: string | null, relatedFiles: string[] | null, tier?: MemoryTier, kind?: MemoryKind): number; /** Filter active memories by kind. */ getByKind(kind: MemoryKind, limit?: number): Memory[]; /** Update a memory's kind in place. */ setKind(id: number, kind: MemoryKind): void; /** * Run multiple memory writes atomically against the underlying SQLite * connection. Callers pass a sync function — async work has to happen * outside the transaction. Used by `sverklo prune` so consolidation * can't half-commit a new memory without invalidating its originals. */ transact(fn: () => T): T; getById(id: number): Memory | undefined; getAll(limit?: number): Memory[]; getByCategory(category: MemoryCategory, limit?: number): Memory[]; /** * Find pairs of active memories that may contradict each other. * * v0.20 introduces conflict detection on the bi-temporal memory layer. * Two memories are flagged as a conflict-candidate when they: * 1. are both active (`valid_until_sha IS NULL`) * 2. share at least one pin (file path or symbol name) * 3. have category "decision", "preference", or "pattern" — the * categories where contradiction is meaningful (procedural and * context memories are usually additive, not contradicting) * 4. were authored at different times (different `valid_from_sha`) * * The detection is intentionally conservative: it surfaces *candidates*, * not confirmed contradictions. The agent or human reviewer decides * whether the pair actually contradicts (e.g., "JWT in middleware" vs * "JWT in route handler" pinned to the same file IS a contradiction; * "validate input" vs "log all errors" pinned to the same file IS NOT). * * Returns pairs sorted by: * 1. number of shared pins (more shared = stronger signal) * 2. recency of the older memory (older = more likely to be stale) * * The semantic-similarity component (cosine over content embeddings) * is intentionally NOT in this first version — it requires loading * embeddings during the query, and the pin-overlap signal is already * load-bearing enough on real corpora. Adding embedding-similarity * is a v0.21 extension if pin-overlap proves too noisy in practice. */ findConflicts(limit?: number): Array<{ a: Memory; b: Memory; sharedPins: string[]; }>; delete(id: number): boolean; /** * Bi-temporal invalidation — marks a memory as superseded rather than deleting it. * Preserves history so users can query "what we believed at commit X". */ invalidate(id: number, currentSha: string | null, supersededBy?: number | null): void; getCore(limit?: number): Memory[]; setTier(id: number, tier: MemoryTier): void; update(id: number, content: string, tags?: string[]): void; searchFts(query: string, limit?: number): (Memory & { rank: number; })[]; touchAccess(id: number): void; markStale(id: number, stale: boolean): void; getStale(): Memory[]; setPins(id: number, pins: string[]): void; /** * Find active memories pinned to a given target (file path or symbol name). * Scans the `pins` JSON array column with a LIKE match. */ getByPin(target: string, limit?: number): Memory[]; count(): number; /** * Returns all memories including invalidated ones, for bi-temporal timeline views. */ getTimeline(limit?: number): Memory[]; }