export type NodeType = 'fact' | 'goal' | 'decision' | 'change' | 'vote'; export type FactCategory = 'bug' | 'refactor' | 'security' | 'test' | 'perf' | 'deps' | 'architecture' | 'quality'; export type GoalStatus = 'pending' | 'in_progress' | 'blocked' | 'done' | 'failed'; export type GoalPriority = 'critical' | 'high' | 'medium' | 'low'; export type ChangeStatus = 'proposed' | 'approved' | 'rejected' | 'applied' | 'rolled_back'; export type VoteValue = 'approve' | 'reject' | 'abstain'; type DecisionType = 'spawn' | 'assign' | 'approve_change' | 'reject_change' | 'escalate' | 'rollback' | 'merge_results'; export interface FactNode { id: string; type: 'fact'; category: FactCategory; subject: string; detail: string; file?: string; line?: number; severity?: 'critical' | 'high' | 'medium' | 'low'; discoveredBy: string; discoveredAt: string; tags: string[]; /** Stable key — dedup facts about the same subject */ key: string; /** References to other nodes this fact relates to */ related: string[]; } export interface GoalNode { id: string; type: 'goal'; title: string; description: string; status: GoalStatus; priority: GoalPriority; assignee?: string; blockedBy: string[]; dependsOn: string[]; createdBy: string; createdAt: string; updatedAt: string; tags: string[]; /** Sub-goals spawned from this goal */ children: string[]; /** The top-level goal this belongs to (for hierarchy) */ parentGoal?: string; result?: string; } export interface DecisionNode { id: string; type: 'decision'; decisionType: DecisionType; question: string; options: { id: string; label: string; risk?: string; }[]; chosen: string; rationale: string; madeBy: string; madeAt: string; context?: string; } export interface ChangeNode { id: string; type: 'change'; title: string; description: string; files: { path: string; action: 'create' | 'modify' | 'delete'; }[]; status: ChangeStatus; proposedBy: string; proposedAt: string; approvedBy: string[]; rejectedBy: string[]; appliedAt?: string; rolledBackAt?: string; rollbackReason?: string; votes: VoteRecord[]; qualityGate: QualityGateResult; /** Goals satisfied by this change */ satisfiesGoals: string[]; } export interface VoteRecord { agentId: string; agentName: string; value: VoteValue; rationale?: string | undefined; votedAt: string; } export interface QualityGateResult { passed: boolean; checks: QualityCheck[]; } export interface QualityCheck { name: string; passed: boolean; detail?: string; } export interface VoteNode { id: string; type: 'vote'; changeId: string; voterId: string; voterName: string; value: VoteValue; rationale?: string; votedAt: string; } export type GraphNode = FactNode | GoalNode | DecisionNode | ChangeNode | VoteNode; export interface GraphSubscription { id: string; agentId: string; /** JSONPath-like filter */ filter: NodeFilter; /** Channel for this specific subscription */ channel: string; } export interface NodeFilter { type?: NodeType; category?: FactCategory; status?: GoalStatus | ChangeStatus; tags?: string[]; assignee?: string; discoveredBy?: string; proposedBy?: string; /** Only nodes added after this timestamp */ since?: string; } export declare class KnowledgeGraph { private readonly nodes; private readonly index; private readonly subs; private readonly pendingDeliveries; private readonly filePath; private readonly graphFilePath; private readonly maxNodes; private readonly compactEveryWrites; private writesSinceCompaction; private graphDirReady; /** * Stable per-node insertion sequence. `nodes` (a Map) preserves insertion * order even across `update()` (Map.set on an existing key keeps its slot), * but the type index's `Set` does NOT — `update()` removes then * re-adds a node's id, moving it to the set's tail. Index-routed queries sort * by this sequence so they return nodes in creation order, matching the old * `nodes.values()` scan that callers like decision-history `slice(-10)` rely on. */ private readonly seq; private seqCounter; /** Assign a stable insertion sequence the first time a node id is seen. */ private _trackSeq; /** Exposed for unit-testing only: read current index contents. */ getIndex(): ReadonlyMap>; constructor(sessionDir: string, maxNodes?: number, compactEveryWrites?: number); /** * Add a node. Fires to all matching subscriptions synchronously. * Returns the node with its assigned id. */ add(node: Omit): Promise; /** Update an existing node by id. Returns updated node or null if not found. */ update(id: string, patch: Partial): Promise; /** * True when the node is in a terminal / settled state — no future mutations * are expected. Such nodes are the first to be evicted when the in-memory * cap is reached. The JSONL file on disk retains the full history. */ private static _isTerminal; /** * Evict oldest terminal-state nodes when the in-memory cap is exceeded. * The JSONL file retains the latest version of every node; eviction only * affects the in-memory working set. */ private _prune; get(id: string): GraphNode | undefined; getAll(filter?: NodeFilter): GraphNode[]; getGoals(filter?: Partial<{ status: GoalStatus; assignee: string; priority: GoalPriority; }>): GoalNode[]; getFacts(filter?: Partial<{ category: FactCategory; severity: string; }>): FactNode[]; getChanges(filter?: Partial<{ status: ChangeStatus; }>): ChangeNode[]; getOpenGoals(): GoalNode[]; getTopLevelGoals(): GoalNode[]; getBlockedGoals(): GoalNode[]; getPendingChanges(): ChangeNode[]; getDecisions(since?: string): DecisionNode[]; searchFacts(query: string): FactNode[]; getRelatedFacts(factId: string): FactNode[]; /** * Subscribe to nodes matching a filter. Returns a channel id that can be * used to poll for new nodes since the last check. */ subscribe(agentId: string, filter: NodeFilter): string; /** * Poll for new nodes delivered to a channel since last check. * Clears the delivery buffer after reading. */ poll(channel: string): GraphNode[]; unsubscribe(channel: string): void; /** * Create a quality gate result. Call this when a change is being proposed * so the change node carries the gate result. */ static makeQualityGate(checks: { name: string; passed: boolean; detail?: string; }[]): QualityGateResult; /** Pure: compute the set of index keys a node would belong to. */ private _indexKeys; /** Mutate the index: add a node's id to every set for the given keys. */ private _addToIndex; /** Remove a node's id from all index sets for the given keys. */ private _removeFromIndex; private _matches; private _deliver; private _persist; private _append; private _writeRecord; /** Collapse historical update records to the latest version of every node. */ private _compactLogLocked; /** Rebuild in-memory state from the log file. Call on startup. */ load(): Promise; /** Snapshot for serialization. */ snapshot(): { nodes: GraphNode[]; subs: number; }; } export {}; //# sourceMappingURL=knowledge-graph.d.ts.map