226 lines
8.1 KiB
TypeScript
226 lines
8.1 KiB
TypeScript
/**
|
|
* AutoMemoryBridge - Bidirectional sync between Claude Code Auto Memory and AgentDB
|
|
*
|
|
* Per ADR-048: Bridges Claude Code's auto memory (markdown files at
|
|
* ~/.claude/projects/<project>/memory/) with claude-flow's unified memory
|
|
* system (AgentDB + HNSW).
|
|
*
|
|
* Auto memory files are human-readable markdown that Claude loads into its
|
|
* system prompt. MEMORY.md (first 200 lines) is the entrypoint; topic files
|
|
* store detailed notes and are read on demand.
|
|
*
|
|
* @module @claude-flow/memory/auto-memory-bridge
|
|
*/
|
|
import { EventEmitter } from 'node:events';
|
|
import { type IMemoryBackend } from './types.js';
|
|
import { type LearningBridgeConfig } from './learning-bridge.js';
|
|
import { type MemoryGraphConfig } from './memory-graph.js';
|
|
/** Insight category for organization in MEMORY.md */
|
|
export type InsightCategory = 'project-patterns' | 'debugging' | 'architecture' | 'performance' | 'security' | 'preferences' | 'swarm-results';
|
|
/** Sync direction */
|
|
export type SyncDirection = 'to-auto' | 'from-auto' | 'bidirectional';
|
|
/** Sync mode determines when syncs occur */
|
|
export type SyncMode = 'on-write' | 'on-session-end' | 'periodic';
|
|
/** Prune strategy for keeping MEMORY.md under line limit */
|
|
export type PruneStrategy = 'confidence-weighted' | 'fifo' | 'lru';
|
|
/** Configuration for AutoMemoryBridge */
|
|
export interface AutoMemoryBridgeConfig {
|
|
/** Auto memory directory path (auto-resolved if not provided) */
|
|
memoryDir?: string;
|
|
/** Working directory for git root detection */
|
|
workingDir?: string;
|
|
/** Max lines for MEMORY.md index (default: 180, Claude reads first 200) */
|
|
maxIndexLines?: number;
|
|
/** Topic file mapping: category → filename */
|
|
topicMapping?: Partial<Record<InsightCategory, string>>;
|
|
/** Sync mode (default: 'on-session-end') */
|
|
syncMode?: SyncMode;
|
|
/** Periodic sync interval in ms (if syncMode is 'periodic') */
|
|
syncIntervalMs?: number;
|
|
/** Minimum confidence for syncing to auto memory (default: 0.7) */
|
|
minConfidence?: number;
|
|
/** Maximum lines per topic file (default: 500) */
|
|
maxTopicFileLines?: number;
|
|
/** Prune strategy for MEMORY.md (default: 'confidence-weighted') */
|
|
pruneStrategy?: PruneStrategy;
|
|
/** Learning bridge config (ADR-049). When set, insights trigger neural learning. */
|
|
learning?: LearningBridgeConfig;
|
|
/** Knowledge graph config (ADR-049). When set, graph-aware curation is enabled. */
|
|
graph?: MemoryGraphConfig;
|
|
}
|
|
/** A memory insight to record */
|
|
export interface MemoryInsight {
|
|
/** Category for organization */
|
|
category: InsightCategory;
|
|
/** One-line summary for MEMORY.md index */
|
|
summary: string;
|
|
/** Detailed content (goes in topic file if > 2 lines) */
|
|
detail?: string;
|
|
/** Source: which agent/hook discovered this */
|
|
source: string;
|
|
/** Confidence score (0-1), used for curation priority */
|
|
confidence: number;
|
|
/** AgentDB entry ID for cross-reference */
|
|
agentDbId?: string;
|
|
}
|
|
/** Result of a sync operation */
|
|
export interface SyncResult {
|
|
/** Number of entries synced */
|
|
synced: number;
|
|
/** Categories that were updated */
|
|
categories: string[];
|
|
/** Duration of sync in milliseconds */
|
|
durationMs: number;
|
|
/** Any errors encountered */
|
|
errors: string[];
|
|
}
|
|
/** Result of an import operation */
|
|
export interface ImportResult {
|
|
/** Number of entries imported */
|
|
imported: number;
|
|
/** Number of entries skipped (already in AgentDB) */
|
|
skipped: number;
|
|
/** Files processed */
|
|
files: string[];
|
|
/** Duration in milliseconds */
|
|
durationMs: number;
|
|
}
|
|
/** Parsed markdown entry from a topic file */
|
|
interface ParsedEntry {
|
|
heading: string;
|
|
content: string;
|
|
metadata: Record<string, string>;
|
|
}
|
|
/**
|
|
* Bidirectional bridge between Claude Code auto memory and AgentDB.
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* const bridge = new AutoMemoryBridge(memoryBackend, {
|
|
* workingDir: '/workspaces/my-project',
|
|
* });
|
|
*
|
|
* // Record an insight
|
|
* await bridge.recordInsight({
|
|
* category: 'debugging',
|
|
* summary: 'HNSW index requires initialization before search',
|
|
* source: 'agent:tester',
|
|
* confidence: 0.95,
|
|
* });
|
|
*
|
|
* // Sync to auto memory files
|
|
* await bridge.syncToAutoMemory();
|
|
*
|
|
* // Import auto memory into AgentDB
|
|
* await bridge.importFromAutoMemory();
|
|
* ```
|
|
*/
|
|
export declare class AutoMemoryBridge extends EventEmitter {
|
|
private config;
|
|
private backend;
|
|
private lastSyncTime;
|
|
private syncTimer;
|
|
private insights;
|
|
/** Track AgentDB keys of insights already written to files during this session */
|
|
private syncedInsightKeys;
|
|
/** Monotonic counter to prevent key collisions within the same ms */
|
|
private insightCounter;
|
|
/** Optional learning bridge (ADR-049) */
|
|
private learningBridge?;
|
|
/** Optional knowledge graph (ADR-049) */
|
|
private memoryGraph?;
|
|
constructor(backend: IMemoryBackend, config?: AutoMemoryBridgeConfig);
|
|
/** Get the resolved auto memory directory path */
|
|
getMemoryDir(): string;
|
|
/** Get the path to MEMORY.md */
|
|
getIndexPath(): string;
|
|
/** Get the path to a topic file */
|
|
getTopicPath(category: InsightCategory): string;
|
|
/**
|
|
* Record a memory insight.
|
|
* Stores in the in-memory buffer and optionally writes immediately.
|
|
*/
|
|
recordInsight(insight: MemoryInsight): Promise<void>;
|
|
/**
|
|
* Sync high-confidence AgentDB entries to auto memory files.
|
|
* Called on session-end or periodically.
|
|
*/
|
|
syncToAutoMemory(): Promise<SyncResult>;
|
|
/**
|
|
* Import auto memory files into AgentDB.
|
|
* Called on session-start to hydrate AgentDB with previous learnings.
|
|
* Uses bulk insert for efficiency.
|
|
*/
|
|
importFromAutoMemory(): Promise<ImportResult>;
|
|
/**
|
|
* Curate MEMORY.md to stay under the line limit.
|
|
* Groups entries by category and prunes low-confidence items.
|
|
*/
|
|
curateIndex(): Promise<void>;
|
|
/**
|
|
* Get auto memory status: directory info, file count, line counts.
|
|
*/
|
|
getStatus(): {
|
|
memoryDir: string;
|
|
exists: boolean;
|
|
files: {
|
|
name: string;
|
|
lines: number;
|
|
}[];
|
|
totalLines: number;
|
|
indexLines: number;
|
|
lastSyncTime: number;
|
|
bufferedInsights: number;
|
|
};
|
|
/** Stop periodic sync and clean up */
|
|
destroy(): void;
|
|
private ensureMemoryDir;
|
|
private storeInsightInAgentDB;
|
|
private writeInsightToFiles;
|
|
private queryRecentInsights;
|
|
private classifyEntry;
|
|
private appendToTopicFile;
|
|
/** Fetch all existing content hashes from the auto-memory namespace in one query */
|
|
private fetchExistingContentHashes;
|
|
private startPeriodicSync;
|
|
}
|
|
/**
|
|
* Resolve the auto memory directory for a given working directory.
|
|
* Mirrors Claude Code's path derivation from git root.
|
|
*/
|
|
export declare function resolveAutoMemoryDir(workingDir: string): string;
|
|
/**
|
|
* Find the git root directory by walking up from workingDir.
|
|
*/
|
|
export declare function findGitRoot(dir: string): string | null;
|
|
/**
|
|
* Parse markdown content into structured entries.
|
|
* Splits on ## headings and extracts content under each.
|
|
*/
|
|
export declare function parseMarkdownEntries(content: string): ParsedEntry[];
|
|
/**
|
|
* Extract clean one-line summaries from a topic file.
|
|
* Returns bullet-point items (lines starting with '- '), stripping
|
|
* metadata annotations like _(source, date, conf: 0.95)_.
|
|
*/
|
|
export declare function extractSummaries(content: string): string[];
|
|
/**
|
|
* Format an insight as a markdown line for topic files.
|
|
*/
|
|
export declare function formatInsightLine(insight: MemoryInsight): string;
|
|
/**
|
|
* Hash content for deduplication.
|
|
*/
|
|
export declare function hashContent(content: string): string;
|
|
/**
|
|
* Prune a topic file to stay under the line limit.
|
|
* Removes oldest entries (those closest to the top after the header).
|
|
*/
|
|
export declare function pruneTopicFile(content: string, maxLines: number): string;
|
|
/**
|
|
* Check if a summary already exists as a bullet line in topic file content.
|
|
* Uses exact bullet prefix matching (not substring) to avoid false positives.
|
|
*/
|
|
export declare function hasSummaryLine(content: string, summary: string): boolean;
|
|
export default AutoMemoryBridge;
|
|
//# sourceMappingURL=auto-memory-bridge.d.ts.map
|