/** * Storage backend interfaces — the contract between engines and persistence. * * Engines and tools type against these interfaces, never against the concrete * file-backed classes, so an alternative backend (the planned SQLite store, * docs/FOUNDATION-PLAN.md W2.2) can be swapped in without touching engine * code. TypeScript's structural typing alone is not enough here: the concrete * classes have private fields, which makes their class types nominal. * * Every method mirrors the corresponding file-store class verbatim — this * extraction is behavior-neutral by construction. */ import type { AgentRecord, BlackboardEntry, Decision, DecisionIndexEntry, DecisionAmendment, DecisionStatus, Entity, HandoffIndexEntry, HandoffRecord, Relation, ToolUsageSummary, UsageBucket } from "../utils/types.js"; import type { EmbeddingIndex, IndexName } from "../embeddings/index-manager.js"; /** Append-only blackboard persistence (blackboard.jsonl today). */ export interface IBlackboardStore { append(entry: Omit): Promise; read(filters?: { entry_types?: string[]; tags?: string[]; scope?: string; since?: string; limit?: number; }): Promise<{ entries: BlackboardEntry[]; total_count: number; }>; recent(n?: number, entry_types?: string[]): Promise; dismiss(ids: string[]): Promise<{ dismissed: string[]; not_found: string[]; }>; /** * Mark entries resolved in place (D2). Idempotent: an already-resolved * entry counts as resolved but keeps its original audit stamp. Unknown * ids land in not_found. */ resolve(ids: string[], opts: { by?: string; note?: string; }): Promise<{ resolved: string[]; not_found: string[]; }>; } /** Decision persistence (decisions/.json + index.json today). */ export interface IDecisionStore { create(input: Omit & { status?: "active" | "provisional"; }): Promise; get(id: string): Promise; getByScope(scope: string): Promise; /** * Returns whether the target existed and the write persisted — a missing * id is reported, never a silent no-op (field D14 fail-loud). Callers * whose contract requires the write MUST check `persisted`. */ updateStatus(id: string, status: DecisionStatus, extra?: Partial): Promise<{ persisted: boolean; }>; getIndex(): Promise; linkCommit(id: string, commitHash: string): Promise; getByCommitHash(commitHash: string): Promise; /** * Persist an append-only metadata amendment (field D11). Receives DELTAS * and merges them against the freshly-read record INSIDE the backend's * critical section — an engine-computed union would be a lost-update under * concurrent amends (the withWriteTxn doc's exact hazard class). Must keep * every index the backend maintains consistent: the file backend's index * carries affected_files/affected_symbols that getByScope reads, so a * record-only write would be a half-repair retrieval cannot see. */ amendMetadata(id: string, delta: { add_affected_files: string[]; add_affected_symbols: string[]; amendment: DecisionAmendment; }): Promise; } /** Knowledge-graph persistence (graph/entities.json + relations.json today). */ export interface IGraphStore { addEntity(input: { name: string; type: Entity["type"]; properties?: Record; }): Promise; addRelation(input: { source: string; target: string; type: Relation["type"]; properties?: Record; }): Promise; getEntities(): Promise; getRelations(): Promise; getEntityById(id: string): Promise; getEntityByName(name: string, type?: string): Promise; removeEntities(entityIds: Set): Promise<{ removedEntities: number; removedRelations: number; }>; /** Remove relations by id (wave-2 dedup pass). Unknown ids are ignored. */ removeRelations(relationIds: Set): Promise<{ removed: number; }>; } /** Agent registry persistence (agents/registry.json today). */ export interface IAgentStore { upsert(input: { agent_id: string; capabilities?: string[]; role?: string; description?: string; }): Promise; touch(agentId: string): Promise; get(agentId: string): Promise; getAll(): Promise; findByCapabilities(tags: string[]): Promise; } /** Handoff persistence (handoffs/.json + index.jsonl today). */ export interface IHandoffStore { create(input: Omit): Promise; get(id: string): Promise; list(filters?: { source_agent?: string; target_agent?: string; scope?: string; since?: string; limit?: number; }): Promise; acknowledge(id: string, acknowledgedBy: string): Promise; } /** Embedding-index persistence (embeddings/*.index today). */ export interface IIndexManager { load(indexName: IndexName): Promise; save(indexName: IndexName, index: EmbeddingIndex): Promise; /** * contentHash (sha256 of the embed text, see embed-text.ts) lets the * sqlite backend's reconciler skip re-embedding unchanged records after * ingest. The file backend has no ingest and ignores it. */ addEntry(indexName: IndexName, id: string, vector: number[], contentHash?: string): Promise; removeEntries(indexName: IndexName, ids: string[]): Promise; getVector(indexName: IndexName, id: string): Promise; } /** Tool-metrics read model (metrics.jsonl today). */ export interface IMetricsStore { getToolUsageSummary(since?: string): Promise; getUsageOverTime(bucketMinutes?: number): Promise; getErrorBreakdown(): Promise>; } //# sourceMappingURL=interfaces.d.ts.map