open-mem 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- import{rmSync as b}from"fs";import{parseArgs as pJ}from"util";import{existsSync as EJ,readFileSync as kJ}from"fs";var OJ={dbPath:".open-mem/memory.db",provider:"google",apiKey:void 0,model:"gemini-2.5-flash-lite",maxTokensPerCompression:1024,compressionEnabled:!0,contextInjectionEnabled:!0,maxContextTokens:4000,batchSize:5,batchIntervalMs:30000,ignoredTools:[],minOutputLength:50,maxIndexEntries:20,sensitivePatterns:[],retentionDays:90,maxDatabaseSizeMb:500,logLevel:"warn",contextShowTokenCosts:!0,contextObservationTypes:"all",contextFullObservationCount:3,maxObservations:50,contextShowLastSummary:!0,rateLimitingEnabled:!0,folderContextEnabled:!0,folderContextMaxDepth:5,folderContextMode:"dispersed",folderContextFilename:"AGENTS.md",daemonEnabled:!1,dashboardEnabled:!1,dashboardPort:3737,platformOpenCodeEnabled:!0,platformClaudeCodeEnabled:!1,platformCursorEnabled:!1,mcpCompatibilityMode:"strict",mcpProtocolVersion:"2024-11-05",mcpSupportedProtocolVersions:["2024-11-05"],embeddingDimension:void 0,conflictResolutionEnabled:!1,conflictSimilarityBandLow:0.7,conflictSimilarityBandHigh:0.92,userMemoryEnabled:!1,userMemoryDbPath:"~/.config/open-mem/user-memory.db",userMemoryMaxContextTokens:1000,rerankingEnabled:!1,rerankingMaxCandidates:20,entityExtractionEnabled:!1,fallbackProviders:void 0};function SJ(){let J={};if(process.env.OPEN_MEM_DB_PATH)J.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)J.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)J.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)J.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")J.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")J.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)J.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((Z)=>Z.trim());if(process.env.OPEN_MEM_BATCH_SIZE)J.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)J.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)J.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")J.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)J.contextObservationTypes=process.env.OPEN_MEM_CONTEXT_TYPES==="all"?"all":process.env.OPEN_MEM_CONTEXT_TYPES.split(",").map((Z)=>Z.trim());if(process.env.OPEN_MEM_CONTEXT_FULL_COUNT)J.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)J.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")J.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")J.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")J.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)J.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="single")J.folderContextMode="single";if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="dispersed")J.folderContextMode="dispersed";if(process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME)J.folderContextFilename=process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME;if(process.env.OPEN_MEM_DAEMON==="true")J.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")J.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)J.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_PLATFORM_OPENCODE==="false")J.platformOpenCodeEnabled=!1;if(process.env.OPEN_MEM_PLATFORM_CLAUDE_CODE==="true")J.platformClaudeCodeEnabled=!0;if(process.env.OPEN_MEM_PLATFORM_CURSOR==="true")J.platformCursorEnabled=!0;if(process.env.OPEN_MEM_MCP_COMPAT_MODE)J.mcpCompatibilityMode=process.env.OPEN_MEM_MCP_COMPAT_MODE;if(process.env.OPEN_MEM_MCP_PROTOCOL_VERSION)J.mcpProtocolVersion=process.env.OPEN_MEM_MCP_PROTOCOL_VERSION;if(process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS)J.mcpSupportedProtocolVersions=process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS.split(",").map((Z)=>Z.trim()).filter(Boolean);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)J.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);if(process.env.OPEN_MEM_CONFLICT_RESOLUTION==="true")J.conflictResolutionEnabled=!0;if(process.env.OPEN_MEM_CONFLICT_BAND_LOW){let Z=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_LOW);if(!Number.isNaN(Z))J.conflictSimilarityBandLow=Z}if(process.env.OPEN_MEM_CONFLICT_BAND_HIGH){let Z=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_HIGH);if(!Number.isNaN(Z))J.conflictSimilarityBandHigh=Z}if(process.env.OPEN_MEM_USER_MEMORY==="true")J.userMemoryEnabled=!0;if(process.env.OPEN_MEM_USER_MEMORY_DB_PATH)J.userMemoryDbPath=process.env.OPEN_MEM_USER_MEMORY_DB_PATH;if(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS)J.userMemoryMaxContextTokens=Number.parseInt(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS,10);if(process.env.OPEN_MEM_RERANKING==="true")J.rerankingEnabled=!0;if(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES)J.rerankingMaxCandidates=Number.parseInt(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES,10);if(process.env.OPEN_MEM_ENTITY_EXTRACTION==="true")J.entityExtractionEnabled=!0;if(process.env.OPEN_MEM_FALLBACK_PROVIDERS)J.fallbackProviders=process.env.OPEN_MEM_FALLBACK_PROVIDERS.split(",").map((Z)=>Z.trim()).filter(Boolean);return J}function RJ(J){let Z=`${J}/.open-mem/config.json`;if(!EJ(Z))return{};try{let $=kJ(Z,"utf-8"),K=JSON.parse($);if(!K||typeof K!=="object"||Array.isArray(K))return{};return K}catch{return{}}}function AJ(J){switch(J){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;case"openrouter":return 0;default:return 768}}function x(J,Z){let $=RJ(J),K=SJ(),X={...OJ,...$,...K,...Z};if(!X.dbPath.startsWith("/"))X.dbPath=`${J}/${X.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!Z?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)X.provider="google";else if(process.env.ANTHROPIC_API_KEY)X.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)X.provider="bedrock";else if(process.env.OPENROUTER_API_KEY)X.provider="openrouter"}if(!X.apiKey)switch(X.provider){case"google":X.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":X.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":X.apiKey=process.env.OPENAI_API_KEY;break;case"openrouter":X.apiKey=process.env.OPENROUTER_API_KEY;break;case"bedrock":break}if(X.provider==="openrouter"&&X.model==="gemini-2.5-flash-lite")X.model="google/gemini-2.5-flash-lite";if(X.embeddingDimension===void 0)X.embeddingDimension=AJ(X.provider);return X}import{Database as m}from"bun:sqlite";import{existsSync as q,mkdirSync as TJ,unlinkSync as p}from"fs";import*as c from"sqlite-vec";class T{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let J=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let Z of J)try{if(q(Z))return m.setCustomSQLite(Z),!0}catch{return!1}return!1}constructor(J){this.dbPath=J,this.db=this.open(J),this.configure()}open(J){let Z=J.lastIndexOf("/");if(Z>0){let $=J.substring(0,Z);TJ($,{recursive:!0})}return new m(J,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch(J){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",J.message);try{this.db.close()}catch{}this.deleteSidecarFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after removing WAL/SHM files");return}catch(Z){console.warn("[open-mem] WAL/SHM cleanup insufficient, recreating database from scratch:",Z.message);try{this.db.close()}catch{}this.deleteDatabaseFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after full database recreation");return}catch($){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",$.message),J}}}}applyPragmas(){this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA busy_timeout = 5000")}loadExtensions(){try{c.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let J of["-wal","-shm"]){let Z=this.dbPath+J;try{if(q(Z))p(Z)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(q(this.dbPath))p(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
3
+ import{rmSync as f}from"fs";import{parseArgs as aJ}from"util";import{existsSync as CJ,readFileSync as IJ}from"fs";import{existsSync as SJ,readdirSync as AJ,readFileSync as TJ}from"fs";import{join as c}from"path";var q=c(import.meta.dir,"."),_=null;function FJ(){if(_)return _;if(_=new Map,!SJ(q))return _;for(let J of AJ(q)){if(!J.endsWith(".json"))continue;try{let Z=TJ(c(q,J),"utf-8"),$=JSON.parse(Z);if($.id&&$.observationTypes&&$.conceptVocabulary)_.set($.id,$)}catch{}}return _}function l(){return[...FJ().keys()].sort()}var DJ={dbPath:".open-mem/memory.db",provider:"google",apiKey:void 0,model:"gemini-2.5-flash-lite",maxTokensPerCompression:1024,compressionEnabled:!0,contextInjectionEnabled:!0,maxContextTokens:4000,batchSize:5,batchIntervalMs:30000,ignoredTools:[],minOutputLength:50,maxIndexEntries:20,sensitivePatterns:[],retentionDays:90,maxDatabaseSizeMb:500,logLevel:"warn",contextShowTokenCosts:!0,contextObservationTypes:"all",contextFullObservationCount:3,maxObservations:50,contextShowLastSummary:!0,rateLimitingEnabled:!0,folderContextEnabled:!0,folderContextMaxDepth:5,folderContextMode:"dispersed",folderContextFilename:"AGENTS.md",daemonEnabled:!1,dashboardEnabled:!1,dashboardPort:3737,platformOpenCodeEnabled:!0,platformClaudeCodeEnabled:!1,platformCursorEnabled:!1,mcpCompatibilityMode:"strict",mcpProtocolVersion:"2024-11-05",mcpSupportedProtocolVersions:["2024-11-05"],embeddingDimension:void 0,conflictResolutionEnabled:!1,conflictSimilarityBandLow:0.7,conflictSimilarityBandHigh:0.92,userMemoryEnabled:!1,userMemoryDbPath:"~/.config/open-mem/user-memory.db",userMemoryMaxContextTokens:1000,rerankingEnabled:!1,rerankingMaxCandidates:20,entityExtractionEnabled:!1,fallbackProviders:void 0,mode:"code"};function xJ(){let J={};if(process.env.OPEN_MEM_DB_PATH)J.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)J.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)J.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)J.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")J.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")J.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)J.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((Z)=>Z.trim());if(process.env.OPEN_MEM_BATCH_SIZE)J.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)J.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)J.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")J.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)J.contextObservationTypes=process.env.OPEN_MEM_CONTEXT_TYPES==="all"?"all":process.env.OPEN_MEM_CONTEXT_TYPES.split(",").map((Z)=>Z.trim());if(process.env.OPEN_MEM_CONTEXT_FULL_COUNT)J.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)J.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")J.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")J.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")J.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)J.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="single")J.folderContextMode="single";if(process.env.OPEN_MEM_FOLDER_CONTEXT_MODE==="dispersed")J.folderContextMode="dispersed";if(process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME)J.folderContextFilename=process.env.OPEN_MEM_FOLDER_CONTEXT_FILENAME;if(process.env.OPEN_MEM_DAEMON==="true")J.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")J.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)J.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_PLATFORM_OPENCODE==="false")J.platformOpenCodeEnabled=!1;if(process.env.OPEN_MEM_PLATFORM_CLAUDE_CODE==="true")J.platformClaudeCodeEnabled=!0;if(process.env.OPEN_MEM_PLATFORM_CURSOR==="true")J.platformCursorEnabled=!0;if(process.env.OPEN_MEM_MCP_COMPAT_MODE)J.mcpCompatibilityMode=process.env.OPEN_MEM_MCP_COMPAT_MODE;if(process.env.OPEN_MEM_MCP_PROTOCOL_VERSION)J.mcpProtocolVersion=process.env.OPEN_MEM_MCP_PROTOCOL_VERSION;if(process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS)J.mcpSupportedProtocolVersions=process.env.OPEN_MEM_MCP_SUPPORTED_PROTOCOLS.split(",").map((Z)=>Z.trim()).filter(Boolean);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)J.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);if(process.env.OPEN_MEM_CONFLICT_RESOLUTION==="true")J.conflictResolutionEnabled=!0;if(process.env.OPEN_MEM_CONFLICT_BAND_LOW){let Z=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_LOW);if(!Number.isNaN(Z))J.conflictSimilarityBandLow=Z}if(process.env.OPEN_MEM_CONFLICT_BAND_HIGH){let Z=Number.parseFloat(process.env.OPEN_MEM_CONFLICT_BAND_HIGH);if(!Number.isNaN(Z))J.conflictSimilarityBandHigh=Z}if(process.env.OPEN_MEM_USER_MEMORY==="true")J.userMemoryEnabled=!0;if(process.env.OPEN_MEM_USER_MEMORY_DB_PATH)J.userMemoryDbPath=process.env.OPEN_MEM_USER_MEMORY_DB_PATH;if(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS)J.userMemoryMaxContextTokens=Number.parseInt(process.env.OPEN_MEM_USER_MEMORY_MAX_TOKENS,10);if(process.env.OPEN_MEM_RERANKING==="true")J.rerankingEnabled=!0;if(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES)J.rerankingMaxCandidates=Number.parseInt(process.env.OPEN_MEM_RERANKING_MAX_CANDIDATES,10);if(process.env.OPEN_MEM_ENTITY_EXTRACTION==="true")J.entityExtractionEnabled=!0;if(process.env.OPEN_MEM_FALLBACK_PROVIDERS)J.fallbackProviders=process.env.OPEN_MEM_FALLBACK_PROVIDERS.split(",").map((Z)=>Z.trim()).filter(Boolean);if(process.env.OPEN_MEM_MODE)J.mode=process.env.OPEN_MEM_MODE;return J}function qJ(J){let Z=`${J}/.open-mem/config.json`;if(!CJ(Z))return{};try{let $=IJ(Z,"utf-8"),K=JSON.parse($);if(!K||typeof K!=="object"||Array.isArray(K))return{};return K}catch{return{}}}function wJ(J){switch(J){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;case"openrouter":return 0;default:return 768}}function w(J,Z){let $=qJ(J),K=xJ(),W={...DJ,...$,...K,...Z};if(!W.dbPath.startsWith("/"))W.dbPath=`${J}/${W.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!Z?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)W.provider="google";else if(process.env.ANTHROPIC_API_KEY)W.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)W.provider="bedrock";else if(process.env.OPENROUTER_API_KEY)W.provider="openrouter"}if(!W.apiKey)switch(W.provider){case"google":W.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":W.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":W.apiKey=process.env.OPENAI_API_KEY;break;case"openrouter":W.apiKey=process.env.OPENROUTER_API_KEY;break;case"bedrock":break}if(W.provider==="openrouter"&&W.model==="gemini-2.5-flash-lite")W.model="google/gemini-2.5-flash-lite";if(W.embeddingDimension===void 0)W.embeddingDimension=wJ(W.provider);if(W.mode&&!l().includes(W.mode))W.mode="code";return W}import{Database as d}from"bun:sqlite";import{existsSync as j,mkdirSync as jJ,unlinkSync as n}from"fs";import*as i from"sqlite-vec";class F{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let J=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let Z of J)try{if(j(Z))return d.setCustomSQLite(Z),!0}catch{return!1}return!1}constructor(J){this.dbPath=J,this.db=this.open(J),this.configure()}open(J){let Z=J.lastIndexOf("/");if(Z>0){let $=J.substring(0,Z);jJ($,{recursive:!0})}return new d(J,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch(J){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",J.message);try{this.db.close()}catch{}this.deleteSidecarFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after removing WAL/SHM files");return}catch(Z){console.warn("[open-mem] WAL/SHM cleanup insufficient, recreating database from scratch:",Z.message);try{this.db.close()}catch{}this.deleteDatabaseFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after full database recreation");return}catch($){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",$.message),J}}}}applyPragmas(){this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA busy_timeout = 5000")}loadExtensions(){try{i.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let J of["-wal","-shm"]){let Z=this.dbPath+J;try{if(j(Z))n(Z)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(j(this.dbPath))n(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
4
4
  CREATE TABLE IF NOT EXISTS _migrations (
5
5
  version INTEGER PRIMARY KEY,
6
6
  name TEXT NOT NULL,
7
7
  applied_at TEXT NOT NULL DEFAULT (datetime('now'))
8
8
  )
9
- `)}migrate(J){this.ensureMigrationTable();let Z=this.db.query("SELECT version FROM _migrations ORDER BY version").all(),$=new Set(Z.map((X)=>X.version)),K=J.filter((X)=>!$.has(X.version)).sort((X,W)=>X.version-W.version);for(let X of K)this.db.transaction(()=>{this.db.exec(X.up),this.db.query("INSERT INTO _migrations (version, name) VALUES ($version, $name)").run({$version:X.version,$name:X.name})})()}run(J,Z){let $=this.db.query(J);if(Z)$.run(...Z);else $.run()}get(J,Z){let $=this.db.query(J);return Z?$.get(...Z):$.get()}all(J,Z){let $=this.db.query(J);return Z?$.all(...Z):$.all()}exec(J){this.db.exec(J)}transaction(J){return this.db.transaction(J)()}close(){this.db.close()}get isOpen(){try{return this.db.query("SELECT 1").get(),!0}catch{return!1}}get raw(){return this.db}}function l(J){return new T(J)}import{randomUUID as CJ}from"crypto";import{embed as oJ}from"ai";function d(J,Z){if(J.length!==Z.length||J.length===0)return 0;let $=0,K=0,X=0;for(let V=0;V<J.length;V++)$+=J[V]*Z[V],K+=J[V]*J[V],X+=Z[V]*Z[V];let W=Math.sqrt(K)*Math.sqrt(X);if(W===0)return 0;return $/W}function FJ(J){return J.replace(/[%_\\]/g,"\\$&")}class w{db;constructor(J){this.db=J}create(J){let Z=CJ(),$=new Date().toISOString(),K=J.discoveryTokens??0,X=J.importance??3,W=J.scope??"project";return this.db.run(`INSERT INTO observations
9
+ `)}migrate(J){this.ensureMigrationTable();let Z=this.db.query("SELECT version FROM _migrations ORDER BY version").all(),$=new Set(Z.map((W)=>W.version)),K=J.filter((W)=>!$.has(W.version)).sort((W,X)=>W.version-X.version);for(let W of K)this.db.transaction(()=>{this.db.exec(W.up),this.db.query("INSERT INTO _migrations (version, name) VALUES ($version, $name)").run({$version:W.version,$name:W.name})})()}run(J,Z){let $=this.db.query(J);if(Z)$.run(...Z);else $.run()}get(J,Z){let $=this.db.query(J);return Z?$.get(...Z):$.get()}all(J,Z){let $=this.db.query(J);return Z?$.all(...Z):$.all()}exec(J){this.db.exec(J)}transaction(J){return this.db.transaction(J)()}close(){this.db.close()}get isOpen(){try{return this.db.query("SELECT 1").get(),!0}catch{return!1}}get raw(){return this.db}}function s(J){return new F(J)}import{randomUUID as yJ}from"crypto";import{embed as QZ}from"ai";function r(J,Z){if(J.length!==Z.length||J.length===0)return 0;let $=0,K=0,W=0;for(let V=0;V<J.length;V++)$+=J[V]*Z[V],K+=J[V]*J[V],W+=Z[V]*Z[V];let X=Math.sqrt(K)*Math.sqrt(W);if(X===0)return 0;return $/X}function vJ(J){return J.replace(/[%_\\]/g,"\\$&")}class y{db;constructor(J){this.db=J}create(J){let Z=yJ(),$=new Date().toISOString(),K=J.discoveryTokens??0,W=J.importance??3,X=J.scope??"project";return this.db.run(`INSERT INTO observations
10
10
  (id, session_id, scope, type, title, subtitle, facts, narrative,
11
11
  concepts, files_read, files_modified, raw_tool_output,
12
12
  tool_name, created_at, token_count, discovery_tokens, importance, revision_of, deleted_at)
13
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[Z,J.sessionId,W,J.type,J.title,J.subtitle,JSON.stringify(J.facts),J.narrative,JSON.stringify(J.concepts),JSON.stringify(J.filesRead),JSON.stringify(J.filesModified),J.rawToolOutput,J.toolName,$,J.tokenCount,K,X,null,null]),{...J,id:Z,scope:W,createdAt:$,discoveryTokens:K,importance:X,revisionOf:null,deletedAt:null,supersededBy:null,supersededAt:null}}importObservation(J){this.db.run(`INSERT INTO observations
13
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[Z,J.sessionId,X,J.type,J.title,J.subtitle,JSON.stringify(J.facts),J.narrative,JSON.stringify(J.concepts),JSON.stringify(J.filesRead),JSON.stringify(J.filesModified),J.rawToolOutput,J.toolName,$,J.tokenCount,K,W,null,null]),{...J,id:Z,scope:X,createdAt:$,discoveryTokens:K,importance:W,revisionOf:null,deletedAt:null,supersededBy:null,supersededAt:null}}importObservation(J){this.db.run(`INSERT INTO observations
14
14
  (id, session_id, scope, type, title, subtitle, facts, narrative,
15
15
  concepts, files_read, files_modified, raw_tool_output,
16
16
  tool_name, created_at, token_count, discovery_tokens, importance, revision_of, deleted_at)
@@ -19,29 +19,29 @@ import{rmSync as b}from"fs";import{parseArgs as pJ}from"util";import{existsSync
19
19
  JOIN sessions s ON o.session_id = s.id
20
20
  WHERE s.project_path = ? AND o.superseded_by IS NULL AND o.deleted_at IS NULL
21
21
  ORDER BY o.created_at DESC
22
- LIMIT ?`,[J,Z]).map(($)=>({id:$.id,sessionId:$.session_id,type:$.type,title:$.title,tokenCount:$.token_count,discoveryTokens:$.discovery_tokens??0,createdAt:$.created_at,importance:$.importance??3}))}getAroundTimestamp(J,Z,$,K){let X=Z>0?this.db.all(`SELECT o.*
22
+ LIMIT ?`,[J,Z]).map(($)=>({id:$.id,sessionId:$.session_id,type:$.type,title:$.title,tokenCount:$.token_count,discoveryTokens:$.discovery_tokens??0,createdAt:$.created_at,importance:$.importance??3}))}getAroundTimestamp(J,Z,$,K){let W=Z>0?this.db.all(`SELECT o.*
23
23
  FROM observations o
24
24
  JOIN sessions s ON o.session_id = s.id
25
25
  WHERE s.project_path = ? AND o.created_at < ?
26
26
  AND o.superseded_by IS NULL AND o.deleted_at IS NULL
27
27
  ORDER BY o.created_at DESC
28
- LIMIT ?`,[K,J,Z]).reverse():[],W=$>0?this.db.all(`SELECT o.*
28
+ LIMIT ?`,[K,J,Z]).reverse():[],X=$>0?this.db.all(`SELECT o.*
29
29
  FROM observations o
30
30
  JOIN sessions s ON o.session_id = s.id
31
31
  WHERE s.project_path = ? AND o.created_at > ?
32
32
  AND o.superseded_by IS NULL AND o.deleted_at IS NULL
33
33
  ORDER BY o.created_at ASC
34
- LIMIT ?`,[K,J,$]):[];return[...X,...W].map((V)=>this.mapRow(V))}listByProject(J,Z={}){let{limit:$=50,offset:K=0,type:X,state:W,sessionId:V}=Z,Y=`SELECT o.*
34
+ LIMIT ?`,[K,J,$]):[];return[...W,...X].map((V)=>this.mapRow(V))}listByProject(J,Z={}){let{limit:$=50,offset:K=0,type:W,state:X,sessionId:V}=Z,Y=`SELECT o.*
35
35
  FROM observations o
36
36
  JOIN sessions s ON o.session_id = s.id
37
- WHERE s.project_path = ?`,Q=[J];if(V)Y+=" AND o.session_id = ?",Q.push(V);if(X)Y+=" AND o.type = ?",Q.push(X);if(W==="current")Y+=" AND o.superseded_by IS NULL AND o.deleted_at IS NULL";else if(W==="superseded")Y+=" AND o.superseded_by IS NOT NULL AND o.deleted_at IS NULL";else if(W==="tombstoned")Y+=" AND o.deleted_at IS NOT NULL";else Y+=" AND o.superseded_by IS NULL AND o.deleted_at IS NULL";return Y+=" ORDER BY o.created_at DESC LIMIT ? OFFSET ?",Q.push($,K),this.db.all(Y,Q).map((H)=>this.mapRow(H))}search(J){let Z=!!J.projectPath,$=`
37
+ WHERE s.project_path = ?`,Q=[J];if(V)Y+=" AND o.session_id = ?",Q.push(V);if(W)Y+=" AND o.type = ?",Q.push(W);if(X==="current")Y+=" AND o.superseded_by IS NULL AND o.deleted_at IS NULL";else if(X==="superseded")Y+=" AND o.superseded_by IS NOT NULL AND o.deleted_at IS NULL";else if(X==="tombstoned")Y+=" AND o.deleted_at IS NOT NULL";else Y+=" AND o.superseded_by IS NULL AND o.deleted_at IS NULL";return Y+=" ORDER BY o.created_at DESC LIMIT ? OFFSET ?",Q.push($,K),this.db.all(Y,Q).map((H)=>this.mapRow(H))}search(J){let Z=!!J.projectPath,$=`
38
38
  SELECT o.*, rank
39
39
  FROM observations o
40
40
  JOIN observations_fts fts ON o._rowid = fts.rowid
41
41
  ${Z?"JOIN sessions s ON o.session_id = s.id":""}
42
42
  WHERE observations_fts MATCH ? AND o.superseded_by IS NULL AND o.deleted_at IS NULL
43
- `,K=[J.query];if(Z&&J.projectPath)$+=" AND s.project_path = ?",K.push(J.projectPath);if(J.sessionId)$+=" AND o.session_id = ?",K.push(J.sessionId);if(J.type)$+=" AND o.type = ?",K.push(J.type);if(J.importanceMin!==void 0)$+=" AND o.importance >= ?",K.push(J.importanceMin);if(J.importanceMax!==void 0)$+=" AND o.importance <= ?",K.push(J.importanceMax);if(J.createdAfter)$+=" AND o.created_at >= ?",K.push(J.createdAfter);if(J.createdBefore)$+=" AND o.created_at <= ?",K.push(J.createdBefore);if(J.concepts&&J.concepts.length>0){let X=J.concepts.map(()=>"EXISTS (SELECT 1 FROM json_each(o.concepts) WHERE LOWER(value) = LOWER(?))");$+=` AND (${X.join(" OR ")})`;for(let W of J.concepts)K.push(W)}if(J.files&&J.files.length>0){let X=J.files.map(()=>`(EXISTS (SELECT 1 FROM json_each(o.files_read) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\')
44
- OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\'))`);$+=` AND (${X.join(" OR ")})`;for(let W of J.files){let V=`%${FJ(W)}%`;K.push(V,V)}}return $+=" ORDER BY rank LIMIT ? OFFSET ?",K.push(J.limit??10),K.push(J.offset??0),this.db.all($,K).map((X)=>({observation:this.mapRow(X),rank:X.rank,snippet:X.title}))}searchByConcept(J,Z=10,$){let K=!!$,X=`SELECT o.*
43
+ `,K=[J.query];if(Z&&J.projectPath)$+=" AND s.project_path = ?",K.push(J.projectPath);if(J.sessionId)$+=" AND o.session_id = ?",K.push(J.sessionId);if(J.type)$+=" AND o.type = ?",K.push(J.type);if(J.importanceMin!==void 0)$+=" AND o.importance >= ?",K.push(J.importanceMin);if(J.importanceMax!==void 0)$+=" AND o.importance <= ?",K.push(J.importanceMax);if(J.createdAfter)$+=" AND o.created_at >= ?",K.push(J.createdAfter);if(J.createdBefore)$+=" AND o.created_at <= ?",K.push(J.createdBefore);if(J.concepts&&J.concepts.length>0){let W=J.concepts.map(()=>"EXISTS (SELECT 1 FROM json_each(o.concepts) WHERE LOWER(value) = LOWER(?))");$+=` AND (${W.join(" OR ")})`;for(let X of J.concepts)K.push(X)}if(J.files&&J.files.length>0){let W=J.files.map(()=>`(EXISTS (SELECT 1 FROM json_each(o.files_read) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\')
44
+ OR EXISTS (SELECT 1 FROM json_each(o.files_modified) WHERE LOWER(value) LIKE LOWER(?) ESCAPE '\\'))`);$+=` AND (${W.join(" OR ")})`;for(let X of J.files){let V=`%${vJ(X)}%`;K.push(V,V)}}return $+=" ORDER BY rank LIMIT ? OFFSET ?",K.push(J.limit??10),K.push(J.offset??0),this.db.all($,K).map((W)=>({observation:this.mapRow(W),rank:W.rank,snippet:W.title}))}searchByConcept(J,Z=10,$){let K=!!$,W=`SELECT o.*
45
45
  FROM observations o
46
46
  JOIN observations_fts fts ON o._rowid = fts.rowid
47
47
  ${K?"JOIN sessions s ON o.session_id = s.id":""}
@@ -49,7 +49,7 @@ import{rmSync as b}from"fs";import{parseArgs as pJ}from"util";import{existsSync
49
49
  AND o.superseded_by IS NULL AND o.deleted_at IS NULL
50
50
  ${K?"AND s.project_path = ?":""}
51
51
  ORDER BY rank
52
- LIMIT ?`,W=[`concepts:${J}`];if(K&&$)W.push($);return W.push(Z),this.db.all(X,W).map((V)=>this.mapRow(V))}searchByFile(J,Z=10,$){let K=!!$,X=`SELECT o.*
52
+ LIMIT ?`,X=[`concepts:${J}`];if(K&&$)X.push($);return X.push(Z),this.db.all(W,X).map((V)=>this.mapRow(V))}searchByFile(J,Z=10,$){let K=!!$,W=`SELECT o.*
53
53
  FROM observations o
54
54
  JOIN observations_fts fts ON o._rowid = fts.rowid
55
55
  ${K?"JOIN sessions s ON o.session_id = s.id":""}
@@ -57,22 +57,22 @@ import{rmSync as b}from"fs";import{parseArgs as pJ}from"util";import{existsSync
57
57
  AND o.superseded_by IS NULL AND o.deleted_at IS NULL
58
58
  ${K?"AND s.project_path = ?":""}
59
59
  ORDER BY rank
60
- LIMIT ?`,W=[`files_read:"${J.replace(/"/g,'""')}" OR files_modified:"${J.replace(/"/g,'""')}"`];if(K&&$)W.push($);return W.push(Z),this.db.all(X,W).map((V)=>this.mapRow(V))}setEmbedding(J,Z){this.db.run("UPDATE observations SET embedding = ? WHERE id = ?",[JSON.stringify(Z),J])}getWithEmbeddings(J,Z){return this.db.all(`SELECT o.id, o.embedding, o.title
60
+ LIMIT ?`,X=[`files_read:"${J.replace(/"/g,'""')}" OR files_modified:"${J.replace(/"/g,'""')}"`];if(K&&$)X.push($);return X.push(Z),this.db.all(W,X).map((V)=>this.mapRow(V))}setEmbedding(J,Z){this.db.run("UPDATE observations SET embedding = ? WHERE id = ?",[JSON.stringify(Z),J])}getWithEmbeddings(J,Z){return this.db.all(`SELECT o.id, o.embedding, o.title
61
61
  FROM observations o
62
62
  JOIN sessions s ON o.session_id = s.id
63
63
  WHERE s.project_path = ? AND o.embedding IS NOT NULL AND o.superseded_by IS NULL AND o.deleted_at IS NULL
64
64
  ORDER BY o.created_at DESC
65
- LIMIT ?`,[J,Z]).map(($)=>{try{return{id:$.id,embedding:JSON.parse($.embedding),title:$.title}}catch{return null}}).filter(($)=>$!==null)}findSimilar(J,Z,$,K){let X=this.db.all(`SELECT id, embedding FROM observations
65
+ LIMIT ?`,[J,Z]).map(($)=>{try{return{id:$.id,embedding:JSON.parse($.embedding),title:$.title}}catch{return null}}).filter(($)=>$!==null)}findSimilar(J,Z,$,K){let W=this.db.all(`SELECT id, embedding FROM observations
66
66
  WHERE embedding IS NOT NULL AND type = ? AND superseded_by IS NULL AND deleted_at IS NULL
67
67
  ORDER BY created_at DESC
68
- LIMIT 200`,[Z]),W=[];for(let V of X)try{let Y=JSON.parse(V.embedding);if(!Array.isArray(Y)||Y.length!==J.length)continue;let Q=d(J,Y);if(Q>=$)W.push({id:V.id,similarity:Q})}catch{}return W.sort((V,Y)=>Y.similarity-V.similarity).slice(0,K)}insertVecEmbedding(J,Z){let $=new Float32Array(Z);this.db.run("BEGIN");try{this.db.run("DELETE FROM observation_embeddings WHERE observation_id = ?",[J]),this.db.run("INSERT INTO observation_embeddings (observation_id, embedding) VALUES (?, ?)",[J,$]),this.db.run("COMMIT")}catch(K){throw this.db.run("ROLLBACK"),K}}migrateExistingEmbeddings(J){let Z=this.db.all("SELECT id, embedding FROM observations WHERE embedding IS NOT NULL"),$=0,K=0;for(let X of Z)try{let W=JSON.parse(X.embedding);if(!Array.isArray(W)||W.length!==J){K++;continue}this.insertVecEmbedding(X.id,W),$++}catch{K++}return{migrated:$,skipped:K}}getVecEmbeddingMatches(J,Z){try{let $=new Float32Array(J);return this.db.all(`SELECT observation_id, distance
68
+ LIMIT 200`,[Z]),X=[];for(let V of W)try{let Y=JSON.parse(V.embedding);if(!Array.isArray(Y)||Y.length!==J.length)continue;let Q=r(J,Y);if(Q>=$)X.push({id:V.id,similarity:Q})}catch{}return X.sort((V,Y)=>Y.similarity-V.similarity).slice(0,K)}insertVecEmbedding(J,Z){let $=new Float32Array(Z);this.db.run("BEGIN");try{this.db.run("DELETE FROM observation_embeddings WHERE observation_id = ?",[J]),this.db.run("INSERT INTO observation_embeddings (observation_id, embedding) VALUES (?, ?)",[J,$]),this.db.run("COMMIT")}catch(K){throw this.db.run("ROLLBACK"),K}}migrateExistingEmbeddings(J){let Z=this.db.all("SELECT id, embedding FROM observations WHERE embedding IS NOT NULL"),$=0,K=0;for(let W of Z)try{let X=JSON.parse(W.embedding);if(!Array.isArray(X)||X.length!==J){K++;continue}this.insertVecEmbedding(W.id,X),$++}catch{K++}return{migrated:$,skipped:K}}getVecEmbeddingMatches(J,Z){try{let $=new Float32Array(J);return this.db.all(`SELECT observation_id, distance
69
69
  FROM observation_embeddings
70
- WHERE embedding MATCH ? AND k = ?`,[$,Z]).map((K)=>({observationId:K.observation_id,distance:K.distance}))}catch{return[]}}searchVecSubset(J,Z,$){if(Z.length===0)return[];try{let K=new Float32Array(J),X=Math.max($*5,Z.length),W=this.db.all(`SELECT observation_id, distance
70
+ WHERE embedding MATCH ? AND k = ?`,[$,Z]).map((K)=>({observationId:K.observation_id,distance:K.distance}))}catch{return[]}}searchVecSubset(J,Z,$){if(Z.length===0)return[];try{let K=new Float32Array(J),W=Math.max($*5,Z.length),X=this.db.all(`SELECT observation_id, distance
71
71
  FROM observation_embeddings
72
- WHERE embedding MATCH ? AND k = ?`,[K,X]),V=new Set(Z);return W.filter((Y)=>V.has(Y.observation_id)).slice(0,$).map((Y)=>({observationId:Y.observation_id,distance:Y.distance}))}catch{return[]}}update(J,Z){let $=this.getById(J);if(!$)return null;if(Object.keys(Z).length===0)return $;let K=this.create({sessionId:$.sessionId,scope:$.scope??"project",type:Z.type??$.type,title:Z.title??$.title,subtitle:Z.subtitle??$.subtitle,facts:Z.facts??$.facts,narrative:Z.narrative??$.narrative,concepts:Z.concepts??$.concepts,filesRead:Z.filesRead??$.filesRead,filesModified:Z.filesModified??$.filesModified,rawToolOutput:$.rawToolOutput,toolName:"mem-revise",tokenCount:$.tokenCount,discoveryTokens:$.discoveryTokens,importance:Z.importance??$.importance});return this.db.run("UPDATE observations SET revision_of = ? WHERE id = ?",[J,K.id]),this.supersede(J,K.id),this.getById(K.id)}supersede(J,Z){let $=new Date().toISOString();this.db.run("UPDATE observations SET superseded_by = ?, superseded_at = ? WHERE id = ?",[Z,$,J])}delete(J){if(this.db.all("SELECT id FROM observations WHERE id = ?",[J]).length===0)return!1;let $=new Date().toISOString();return this.db.run("UPDATE observations SET deleted_at = ? WHERE id = ?",[$,J]),this.deleteEmbeddingsForObservations([J]),!0}getLineage(J){let Z=this.getByIdIncludingArchived(J);if(!Z)return[];let $=new Set([Z.id]),K=[Z];while(K[0].revisionOf){let X=this.getByIdIncludingArchived(K[0].revisionOf);if(!X||$.has(X.id))break;K.unshift(X),$.add(X.id)}while(K[K.length-1].supersededBy){let X=K[K.length-1].supersededBy;if(!X)break;let W=this.getByIdIncludingArchived(X);if(!W||$.has(W.id))break;K.push(W),$.add(W.id)}return K}deleteOlderThan(J){return this.db.all(`DELETE FROM observations
72
+ WHERE embedding MATCH ? AND k = ?`,[K,W]),V=new Set(Z);return X.filter((Y)=>V.has(Y.observation_id)).slice(0,$).map((Y)=>({observationId:Y.observation_id,distance:Y.distance}))}catch{return[]}}update(J,Z){let $=this.getById(J);if(!$)return null;if(Object.keys(Z).length===0)return $;let K=this.create({sessionId:$.sessionId,scope:$.scope??"project",type:Z.type??$.type,title:Z.title??$.title,subtitle:Z.subtitle??$.subtitle,facts:Z.facts??$.facts,narrative:Z.narrative??$.narrative,concepts:Z.concepts??$.concepts,filesRead:Z.filesRead??$.filesRead,filesModified:Z.filesModified??$.filesModified,rawToolOutput:$.rawToolOutput,toolName:"mem-revise",tokenCount:$.tokenCount,discoveryTokens:$.discoveryTokens,importance:Z.importance??$.importance});return this.db.run("UPDATE observations SET revision_of = ? WHERE id = ?",[J,K.id]),this.supersede(J,K.id),this.getById(K.id)}supersede(J,Z){let $=new Date().toISOString();this.db.run("UPDATE observations SET superseded_by = ?, superseded_at = ? WHERE id = ?",[Z,$,J])}delete(J){if(this.db.all("SELECT id FROM observations WHERE id = ?",[J]).length===0)return!1;let $=new Date().toISOString();return this.db.run("UPDATE observations SET deleted_at = ? WHERE id = ?",[$,J]),this.deleteEmbeddingsForObservations([J]),!0}getLineage(J){let Z=this.getByIdIncludingArchived(J);if(!Z)return[];let $=new Set([Z.id]),K=[Z];while(K[0].revisionOf){let W=this.getByIdIncludingArchived(K[0].revisionOf);if(!W||$.has(W.id))break;K.unshift(W),$.add(W.id)}while(K[K.length-1].supersededBy){let W=K[K.length-1].supersededBy;if(!W)break;let X=this.getByIdIncludingArchived(W);if(!X||$.has(X.id))break;K.push(X),$.add(X.id)}return K}deleteOlderThan(J){return this.db.all(`DELETE FROM observations
73
73
  WHERE (created_at < datetime('now', '-' || ? || ' days') OR deleted_at IS NOT NULL)
74
74
  AND session_id NOT IN (SELECT id FROM sessions WHERE status != 'completed')
75
- RETURNING id`,[J]).length}deleteEmbeddingsForObservations(J){if(J.length===0)return;let Z=J.map(()=>"?").join(",");try{this.db.run(`DELETE FROM observation_embeddings WHERE observation_id IN (${Z})`,J)}catch{}this.db.run(`UPDATE observations SET embedding = NULL WHERE id IN (${Z})`,J)}mapRow(J){return{id:J.id,sessionId:J.session_id,scope:J.scope??"project",type:J.type,title:J.title,subtitle:J.subtitle,facts:JSON.parse(J.facts),narrative:J.narrative,concepts:JSON.parse(J.concepts),filesRead:JSON.parse(J.files_read),filesModified:JSON.parse(J.files_modified),rawToolOutput:J.raw_tool_output,toolName:J.tool_name,createdAt:J.created_at,tokenCount:J.token_count,discoveryTokens:J.discovery_tokens??0,importance:J.importance??3,revisionOf:J.revision_of??null,deletedAt:J.deleted_at??null,supersededBy:J.superseded_by??null,supersededAt:J.superseded_at??null}}}var IJ=[{version:1,name:"create-schema",up:`
75
+ RETURNING id`,[J]).length}deleteEmbeddingsForObservations(J){if(J.length===0)return;let Z=J.map(()=>"?").join(",");try{this.db.run(`DELETE FROM observation_embeddings WHERE observation_id IN (${Z})`,J)}catch{}this.db.run(`UPDATE observations SET embedding = NULL WHERE id IN (${Z})`,J)}mapRow(J){return{id:J.id,sessionId:J.session_id,scope:J.scope??"project",type:J.type,title:J.title,subtitle:J.subtitle,facts:JSON.parse(J.facts),narrative:J.narrative,concepts:JSON.parse(J.concepts),filesRead:JSON.parse(J.files_read),filesModified:JSON.parse(J.files_modified),rawToolOutput:J.raw_tool_output,toolName:J.tool_name,createdAt:J.created_at,tokenCount:J.token_count,discoveryTokens:J.discovery_tokens??0,importance:J.importance??3,revisionOf:J.revision_of??null,deletedAt:J.deleted_at??null,supersededBy:J.superseded_by??null,supersededAt:J.superseded_at??null}}}var gJ=[{version:1,name:"create-schema",up:`
76
76
  -- Sessions table
77
77
  CREATE TABLE IF NOT EXISTS sessions (
78
78
  _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -366,31 +366,31 @@ import{rmSync as b}from"fs";import{parseArgs as pJ}from"util";import{existsSync
366
366
  INSERT INTO entities_fts(rowid, name, entity_type)
367
367
  VALUES (new._rowid, new.name, new.entity_type);
368
368
  END;
369
- `}];function n(J,Z){if(J.migrate(IJ),Z?.hasVectorExtension&&Z?.embeddingDimension&&Z.embeddingDimension>0)DJ(J,Z.embeddingDimension)}function DJ(J,Z){if(J.get("SELECT name FROM sqlite_master WHERE type='table' AND name='observation_embeddings'")){let K=J.get("SELECT value FROM _embedding_meta WHERE key = 'dimension'");if(K&&Number(K.value)!==Z){console.warn(`[open-mem] vec0 table exists with dimension ${K.value}, but config specifies ${Z}. Drop observation_embeddings to re-create with new dimension.`);return}}else J.exec(`CREATE VIRTUAL TABLE observation_embeddings USING vec0(
369
+ `}];function a(J,Z){if(J.migrate(gJ),Z?.hasVectorExtension&&Z?.embeddingDimension&&Z.embeddingDimension>0)uJ(J,Z.embeddingDimension)}function uJ(J,Z){if(J.get("SELECT name FROM sqlite_master WHERE type='table' AND name='observation_embeddings'")){let K=J.get("SELECT value FROM _embedding_meta WHERE key = 'dimension'");if(K&&Number(K.value)!==Z){console.warn(`[open-mem] vec0 table exists with dimension ${K.value}, but config specifies ${Z}. Drop observation_embeddings to re-create with new dimension.`);return}}else J.exec(`CREATE VIRTUAL TABLE observation_embeddings USING vec0(
370
370
  observation_id TEXT PRIMARY KEY,
371
371
  embedding float[${Z}] distance_metric=cosine
372
- )`);J.run("INSERT OR REPLACE INTO _embedding_meta (key, value) VALUES (?, ?)",["dimension",String(Z)])}class j{db;constructor(J){this.db=J}create(J,Z){let $=new Date().toISOString();return this.db.run(`INSERT INTO sessions (id, project_path, started_at, status)
373
- VALUES (?, ?, ?, 'active')`,[J,Z,$]),this.getById(J)}getOrCreate(J,Z){let $=this.getById(J);if($)return $;return this.create(J,Z)}getById(J){let Z=this.db.get("SELECT * FROM sessions WHERE id = ?",[J]);return Z?this.mapRow(Z):null}getRecent(J,Z=10){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC LIMIT ?",[J,Z]).map(($)=>this.mapRow($))}getAll(J){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC",[J]).map((Z)=>this.mapRow(Z))}getActive(){return this.db.all("SELECT * FROM sessions WHERE status = 'active' ORDER BY started_at DESC").map((J)=>this.mapRow(J))}updateStatus(J,Z){this.db.run("UPDATE sessions SET status = ? WHERE id = ?",[Z,J])}markCompleted(J){this.db.run("UPDATE sessions SET status = 'completed', ended_at = datetime('now') WHERE id = ?",[J])}incrementObservationCount(J){this.db.run("UPDATE sessions SET observation_count = observation_count + 1 WHERE id = ?",[J])}setSummary(J,Z){this.db.run("UPDATE sessions SET summary_id = ? WHERE id = ?",[Z,J])}mapRow(J){return{id:J.id,projectPath:J.project_path,startedAt:J.started_at,endedAt:J.ended_at??null,status:J.status,observationCount:J.observation_count,summaryId:J.summary_id??null}}}import{existsSync as WJ}from"fs";import{readdir as hJ,readFile as JJ,unlink as ZJ,writeFile as $J}from"fs/promises";import{join as XJ,resolve as VJ}from"path";import{existsSync as i}from"fs";import{mkdir as xJ,readFile as qJ,rename as wJ,unlink as jJ,writeFile as yJ}from"fs/promises";import{dirname as C,isAbsolute as v,join as R,normalize as gJ,relative as u,resolve as E,sep as y}from"path";var _="<!-- open-mem-context -->",N="<!-- /open-mem-context -->",r={bugfix:"\uD83D\uDD34",feature:"\uD83D\uDFE3",refactor:"\uD83D\uDD04",change:"\u2705",discovery:"\uD83D\uDD35",decision:"\u2696\uFE0F"},s=new Map,vJ=new Set(["node_modules",".git","dist","coverage",".open-mem","build","__pycache__",".next",".nuxt"]);async function a(J,Z,$){if(Z.length===0)return;if($.mode==="single")return uJ(J,Z,$);let{maxDepth:K,filename:X}=$,W=[];for(let Q of Z){for(let H of Q.filesModified)W.push(H);for(let H of Q.filesRead)W.push(H)}let V=t(W,J,K);if(V.size===0)return;let Y=e(Z,V,J);for(let[Q,H]of Y)try{let U=PJ(Q,H,J);await o(Q,U,X)}catch(U){console.error(`[open-mem] Failed to update AGENTS.md in ${Q}:`,U)}}async function uJ(J,Z,$){let{maxDepth:K,filename:X}=$,W=Z.filter(g);if(W.length===0)return;let V=[];for(let B of W){for(let M of B.filesModified)V.push(M);for(let M of B.filesRead)V.push(M)}let Y=t(V,J,K),Q=e(W,Y,J),H=W.filter((B)=>{return[...B.filesModified,...B.filesRead].some((z)=>{if(!z)return!1;let O=v(z)?z:R(J,z);return E(C(O))===E(J)})});if(H.length>0)Q.set(E(J),H);if(Q.size===0)return;let U=[];U.push("## Project Activity (auto-generated by open-mem)"),U.push("");let G=[...Q.entries()].map(([B,M])=>({relPath:u(J,B)||".",observations:M})).sort((B,M)=>B.relPath.localeCompare(M.relPath));for(let{relPath:B,observations:M}of G){let z=M.filter(g).sort((L,S)=>S.createdAt.localeCompare(L.createdAt)).slice(0,10);if(z.length===0)continue;U.push(`### ${B}/`),U.push("| ID | Type | Title | Date |"),U.push("|----|------|-------|------|");for(let L of z){let S=r[L.type]||"\uD83D\uDCDD",GJ=L.createdAt.split("T")[0],_J=L.title.replace(/\|/g,"\\|");U.push(`| ${L.id} | ${S} ${L.type} | ${_J} | ${GJ} |`)}let O=new Set;for(let L of z)for(let S of L.concepts)O.add(S);if(O.size>0){let L=[...O].slice(0,10).join(", ");U.push(""),U.push(`**Key concepts:** ${L}`)}let D=z.filter((L)=>L.type==="decision").map((L)=>L.title);if(D.length>0)U.push(""),U.push(`**Recent decisions:** ${D.slice(0,5).join("; ")}`);U.push("")}U.push("\uD83D\uDCA1 *Use `mem-find` to search full details. Use `mem-create` to save important decisions.*");let k=U.join(`
374
- `);await o(J,k,X)}function g(J){return!/^\w[\w-]*\s+execution$/i.test(J.title)}function PJ(J,Z,$){let K=[...Z].filter(g).sort((H,U)=>U.createdAt.localeCompare(H.createdAt)).slice(0,10),X=u($,J)||".",W=[];W.push(`## Recent Activity in \`${X}/\` (auto-generated by open-mem)`),W.push(""),W.push("| ID | Type | Title | Date |"),W.push("|----|------|-------|------|");for(let H of K){let U=r[H.type]||"\uD83D\uDCDD",G=H.createdAt.split("T")[0],k=H.title.replace(/\|/g,"\\|");W.push(`| ${H.id} | ${U} ${H.type} | ${k} | ${G} |`)}let V=new Set;for(let H of K)for(let U of H.concepts)V.add(U);if(V.size>0){let H=[...V].slice(0,10).join(", ");W.push(""),W.push(`**Key concepts:** ${H}`)}let Y=K.filter((H)=>H.type==="decision").map((H)=>H.title);if(Y.length>0)W.push(""),W.push(`**Recent decisions:** ${Y.slice(0,5).join("; ")}`);let Q=K.filter((H)=>H.type==="decision"&&H.narrative).slice(0,3);if(Q.length>0){W.push(""),W.push("**Decision details:**");for(let H of Q){let U=H.narrative.split(/[.!?]\s/)[0],G=U.length>120?`${U.slice(0,117)}...`:U;W.push(`- \u2696\uFE0F ${H.title}: ${G}`)}}return W.push(""),W.push("\uD83D\uDCA1 *Use `mem-find` to search full details across all sessions. Use `mem-create` to save important decisions.*"),W.join(`
375
- `)}async function o(J,Z,$){if(!i(J))return;let X=(s.get(J)??Promise.resolve()).then(async()=>{let W=R(J,$),V=R(J,`.${$}.tmp`),Y="";try{Y=await qJ(W,"utf-8")}catch{}let Q=bJ(Y,Z);try{await xJ(C(V),{recursive:!0}),await yJ(V,Q,"utf-8"),await wJ(V,W)}catch(H){try{await jJ(V)}catch{}throw H}});return s.set(J,X.catch(()=>{})),X}function bJ(J,Z){if(!J)return`${_}
372
+ )`);J.run("INSERT OR REPLACE INTO _embedding_meta (key, value) VALUES (?, ?)",["dimension",String(Z)])}class v{db;constructor(J){this.db=J}create(J,Z){let $=new Date().toISOString();return this.db.run(`INSERT INTO sessions (id, project_path, started_at, status)
373
+ VALUES (?, ?, ?, 'active')`,[J,Z,$]),this.getById(J)}getOrCreate(J,Z){let $=this.getById(J);if($)return $;return this.create(J,Z)}getById(J){let Z=this.db.get("SELECT * FROM sessions WHERE id = ?",[J]);return Z?this.mapRow(Z):null}getRecent(J,Z=10){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC LIMIT ?",[J,Z]).map(($)=>this.mapRow($))}getAll(J){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC",[J]).map((Z)=>this.mapRow(Z))}getActive(){return this.db.all("SELECT * FROM sessions WHERE status = 'active' ORDER BY started_at DESC").map((J)=>this.mapRow(J))}updateStatus(J,Z){this.db.run("UPDATE sessions SET status = ? WHERE id = ?",[Z,J])}markCompleted(J){this.db.run("UPDATE sessions SET status = 'completed', ended_at = datetime('now') WHERE id = ?",[J])}incrementObservationCount(J){this.db.run("UPDATE sessions SET observation_count = observation_count + 1 WHERE id = ?",[J])}setSummary(J,Z){this.db.run("UPDATE sessions SET summary_id = ? WHERE id = ?",[Z,J])}mapRow(J){return{id:J.id,projectPath:J.project_path,startedAt:J.started_at,endedAt:J.ended_at??null,status:J.status,observationCount:J.observation_count,summaryId:J.summary_id??null}}}import{existsSync as HJ}from"fs";import{readdir as iJ,readFile as WJ,unlink as XJ,writeFile as VJ}from"fs/promises";import{join as QJ,resolve as UJ}from"path";import{existsSync as t}from"fs";import{mkdir as PJ,readFile as bJ,rename as hJ,unlink as fJ,writeFile as mJ}from"fs/promises";import{dirname as C,isAbsolute as P,join as A,normalize as pJ,relative as b,resolve as E,sep as g}from"path";var k="<!-- open-mem-context -->",M="<!-- /open-mem-context -->",e={bugfix:"\uD83D\uDD34",feature:"\uD83D\uDFE3",refactor:"\uD83D\uDD04",change:"\u2705",discovery:"\uD83D\uDD35",decision:"\u2696\uFE0F"},o=new Map,cJ=new Set(["node_modules",".git","dist","coverage",".open-mem","build","__pycache__",".next",".nuxt"]);async function JJ(J,Z,$){if(Z.length===0)return;if($.mode==="single")return lJ(J,Z,$);let{maxDepth:K,filename:W}=$,X=[];for(let Q of Z){for(let H of Q.filesModified)X.push(H);for(let H of Q.filesRead)X.push(H)}let V=$J(X,J,K);if(V.size===0)return;let Y=KJ(Z,V,J);for(let[Q,H]of Y)try{let U=dJ(Q,H,J);await ZJ(Q,U,W)}catch(U){console.error(`[open-mem] Failed to update AGENTS.md in ${Q}:`,U)}}async function lJ(J,Z,$){let{maxDepth:K,filename:W}=$,X=Z.filter(u);if(X.length===0)return;let V=[];for(let B of X){for(let z of B.filesModified)V.push(z);for(let z of B.filesRead)V.push(z)}let Y=$J(V,J,K),Q=KJ(X,Y,J),H=X.filter((B)=>{return[...B.filesModified,...B.filesRead].some((N)=>{if(!N)return!1;let R=P(N)?N:A(J,N);return E(C(R))===E(J)})});if(H.length>0)Q.set(E(J),H);if(Q.size===0)return;let U=[];U.push("## Project Activity (auto-generated by open-mem)"),U.push("");let G=[...Q.entries()].map(([B,z])=>({relPath:b(J,B)||".",observations:z})).sort((B,z)=>B.relPath.localeCompare(z.relPath));for(let{relPath:B,observations:z}of G){let N=z.filter(u).sort((L,S)=>S.createdAt.localeCompare(L.createdAt)).slice(0,10);if(N.length===0)continue;U.push(`### ${B}/`),U.push("| ID | Type | Title | Date |"),U.push("|----|------|-------|------|");for(let L of N){let S=e[L.type]||"\uD83D\uDCDD",OJ=L.createdAt.split("T")[0],RJ=L.title.replace(/\|/g,"\\|");U.push(`| ${L.id} | ${S} ${L.type} | ${RJ} | ${OJ} |`)}let R=new Set;for(let L of N)for(let S of L.concepts)R.add(S);if(R.size>0){let L=[...R].slice(0,10).join(", ");U.push(""),U.push(`**Key concepts:** ${L}`)}let x=N.filter((L)=>L.type==="decision").map((L)=>L.title);if(x.length>0)U.push(""),U.push(`**Recent decisions:** ${x.slice(0,5).join("; ")}`);U.push("")}U.push("\uD83D\uDCA1 *Use `mem-find` to search full details. Use `mem-create` to save important decisions.*");let O=U.join(`
374
+ `);await ZJ(J,O,W)}function u(J){return!/^\w[\w-]*\s+execution$/i.test(J.title)}function dJ(J,Z,$){let K=[...Z].filter(u).sort((H,U)=>U.createdAt.localeCompare(H.createdAt)).slice(0,10),W=b($,J)||".",X=[];X.push(`## Recent Activity in \`${W}/\` (auto-generated by open-mem)`),X.push(""),X.push("| ID | Type | Title | Date |"),X.push("|----|------|-------|------|");for(let H of K){let U=e[H.type]||"\uD83D\uDCDD",G=H.createdAt.split("T")[0],O=H.title.replace(/\|/g,"\\|");X.push(`| ${H.id} | ${U} ${H.type} | ${O} | ${G} |`)}let V=new Set;for(let H of K)for(let U of H.concepts)V.add(U);if(V.size>0){let H=[...V].slice(0,10).join(", ");X.push(""),X.push(`**Key concepts:** ${H}`)}let Y=K.filter((H)=>H.type==="decision").map((H)=>H.title);if(Y.length>0)X.push(""),X.push(`**Recent decisions:** ${Y.slice(0,5).join("; ")}`);let Q=K.filter((H)=>H.type==="decision"&&H.narrative).slice(0,3);if(Q.length>0){X.push(""),X.push("**Decision details:**");for(let H of Q){let U=H.narrative.split(/[.!?]\s/)[0],G=U.length>120?`${U.slice(0,117)}...`:U;X.push(`- \u2696\uFE0F ${H.title}: ${G}`)}}return X.push(""),X.push("\uD83D\uDCA1 *Use `mem-find` to search full details across all sessions. Use `mem-create` to save important decisions.*"),X.join(`
375
+ `)}async function ZJ(J,Z,$){if(!t(J))return;let W=(o.get(J)??Promise.resolve()).then(async()=>{let X=A(J,$),V=A(J,`.${$}.tmp`),Y="";try{Y=await bJ(X,"utf-8")}catch{}let Q=nJ(Y,Z);try{await PJ(C(V),{recursive:!0}),await mJ(V,Q,"utf-8"),await hJ(V,X)}catch(H){try{await fJ(V)}catch{}throw H}});return o.set(J,W.catch(()=>{})),W}function nJ(J,Z){if(!J)return`${k}
376
376
  ${Z}
377
- ${N}
378
- `;let $=J.indexOf(_),K=J.indexOf(N);if($!==-1&&K!==-1&&K>$){let W=J.substring(0,$),V=J.substring(K+N.length);return`${W}${_}
377
+ ${M}
378
+ `;let $=J.indexOf(k),K=J.indexOf(M);if($!==-1&&K!==-1&&K>$){let X=J.substring(0,$),V=J.substring(K+M.length);return`${X}${k}
379
379
  ${Z}
380
- ${N}${V}`}let X=J;if($!==-1&&K===-1)X=X.replace(_,"").trim();else if($===-1&&K!==-1)X=X.replace(N,"").trim();else if($!==-1&&K!==-1&&K<=$)X=X.replace(N,"").replace(_,"").trim();return`${X}
380
+ ${M}${V}`}let W=J;if($!==-1&&K===-1)W=W.replace(k,"").trim();else if($===-1&&K!==-1)W=W.replace(M,"").trim();else if($!==-1&&K!==-1&&K<=$)W=W.replace(M,"").replace(k,"").trim();return`${W}
381
381
 
382
- ${_}
382
+ ${k}
383
383
  ${Z}
384
- ${N}
385
- `}function t(J,Z,$){let K=new Set,X=E(Z);for(let W of J){if(!W||!W.trim())continue;if(W.startsWith("~")||W.startsWith("http"))continue;let V=v(W)?W:R(Z,W),Y=C(V),Q=E(Y);if(!Q.startsWith(X+y)&&Q!==X)continue;if(Q===X)continue;let H=u(X,Q);if(H.split(y).length>$)continue;if(gJ(H).split(y).some((k)=>vJ.has(k)))continue;if(!i(Q))continue;K.add(Q)}return K}function e(J,Z,$){let K=new Map;for(let X of J){let W=[...X.filesModified,...X.filesRead],V=new Set;for(let Y of W){if(!Y)continue;let Q=v(Y)?Y:R($,Y),H=E(C(Q));if(Z.has(H))V.add(H)}for(let Y of V){let Q=K.get(Y)??[];Q.push(X),K.set(Y,Q)}}return K}var P="<!-- open-mem-context -->",F="<!-- /open-mem-context -->";async function YJ(J,Z,$){let K;try{K=await hJ(J,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let X of K){let W=String(X.name);if(W===".git"||W==="node_modules"||W===".open-mem"||W==="dist")continue;let V=XJ(J,W);if(X.isDirectory())await YJ(V,Z,$);else if(X.isFile()&&W===Z)$.push(V)}}async function HJ(J,Z){let $=VJ(J),K=[];return await YJ($,Z,K),K}function KJ(J){let Z=J.indexOf(P),$=J.indexOf(F);if(Z===-1&&$===-1)return J;if(Z!==-1&&$===-1){let W=J.replace(P,"").trim();return W?`${W}
386
- `:""}if(Z===-1&&$!==-1){let W=J.replace(F,"").trim();return W?`${W}
387
- `:""}if($<=Z){let W=J.replace(P,"").replace(F,"").trim();return W?`${W}
388
- `:""}let K=J.slice(0,Z).trimEnd(),X=J.slice($+F.length).trimStart();if(!K&&!X)return"";if(!K)return`${X}
389
- `;if(!X)return`${K}
384
+ ${M}
385
+ `}function $J(J,Z,$){let K=new Set,W=E(Z);for(let X of J){if(!X||!X.trim())continue;if(X.startsWith("~")||X.startsWith("http"))continue;let V=P(X)?X:A(Z,X),Y=C(V),Q=E(Y);if(!Q.startsWith(W+g)&&Q!==W)continue;if(Q===W)continue;let H=b(W,Q);if(H.split(g).length>$)continue;if(pJ(H).split(g).some((O)=>cJ.has(O)))continue;if(!t(Q))continue;K.add(Q)}return K}function KJ(J,Z,$){let K=new Map;for(let W of J){let X=[...W.filesModified,...W.filesRead],V=new Set;for(let Y of X){if(!Y)continue;let Q=P(Y)?Y:A($,Y),H=E(C(Q));if(Z.has(H))V.add(H)}for(let Y of V){let Q=K.get(Y)??[];Q.push(W),K.set(Y,Q)}}return K}var h="<!-- open-mem-context -->",I="<!-- /open-mem-context -->";async function LJ(J,Z,$){let K;try{K=await iJ(J,{withFileTypes:!0,encoding:"utf8"})}catch{return}for(let W of K){let X=String(W.name);if(X===".git"||X==="node_modules"||X===".open-mem"||X==="dist")continue;let V=QJ(J,X);if(W.isDirectory())await LJ(V,Z,$);else if(W.isFile()&&X===Z)$.push(V)}}async function BJ(J,Z){let $=UJ(J),K=[];return await LJ($,Z,K),K}function YJ(J){let Z=J.indexOf(h),$=J.indexOf(I);if(Z===-1&&$===-1)return J;if(Z!==-1&&$===-1){let X=J.replace(h,"").trim();return X?`${X}
386
+ `:""}if(Z===-1&&$!==-1){let X=J.replace(I,"").trim();return X?`${X}
387
+ `:""}if($<=Z){let X=J.replace(h,"").replace(I,"").trim();return X?`${X}
388
+ `:""}let K=J.slice(0,Z).trimEnd(),W=J.slice($+I.length).trimStart();if(!K&&!W)return"";if(!K)return`${W}
389
+ `;if(!W)return`${K}
390
390
  `;return`${K}
391
391
 
392
- ${X}
393
- `}async function QJ(J,Z,$=!1){let K=await HJ(J,Z),X=0;for(let W of K){let V=await JJ(W,"utf-8"),Y=KJ(V);if(Y!==V){if(X+=1,!$)if(Y==="")await ZJ(W);else await $J(W,Y,"utf-8")}}if(Z){let W=XJ(VJ(J),Z);if(WJ(W))try{let V=await JJ(W,"utf-8"),Y=KJ(V);if(Y!==V){if(X+=1,!$)if(Y==="")await ZJ(W);else await $J(W,Y,"utf-8")}if(!K.includes(W))K.push(W)}catch{}}return{files:K,changed:X}}async function UJ(J,Z,$,K,X=!1){let V=Z.getAll(J).flatMap((Q)=>$.getBySession(Q.id));if(X){let Q=new Set;for(let H of V)for(let U of[...H.filesRead,...H.filesModified])Q.add(U);return{observations:V.length,filesTouched:Q.size}}if(!WJ(J))return{observations:0,filesTouched:0};await a(J,V,{maxDepth:K.maxDepth,mode:K.mode,filename:K.filename});let Y=await HJ(J,K.filename);return{observations:V.length,filesTouched:Y.length}}import{spawnSync as LJ}from"child_process";import{dirname as fJ,resolve as BJ}from"path";function mJ(J){try{let Z=LJ("git",["rev-parse","--git-common-dir"],{cwd:J,encoding:"utf-8",timeout:5000});if(Z.status!==0||!Z.stdout)return null;let $=Z.stdout.trim();if($===".git")return null;let K=LJ("git",["rev-parse","--git-dir"],{cwd:J,encoding:"utf-8",timeout:5000});if(K.status!==0||!K.stdout)return null;let X=K.stdout.trim(),W=BJ(J,$),V=BJ(J,X);if(W===V)return null;let Y=fJ(W);if(Y===W||Y==="/")return null;return Y}catch{return null}}function MJ(J){return mJ(J)??J}var{positionals:NJ,values:f}=pJ({args:Bun.argv.slice(2),options:{project:{type:"string",short:"p"},"dry-run":{type:"boolean",default:!1}},allowPositionals:!0,strict:!1}),A=NJ[0]??"help",h=NJ[1]??"",cJ=typeof f.project==="string"?f.project:process.cwd(),I=MJ(cJ);function zJ(){console.log(`Usage:
392
+ ${W}
393
+ `}async function zJ(J,Z,$=!1){let K=await BJ(J,Z),W=0;for(let X of K){let V=await WJ(X,"utf-8"),Y=YJ(V);if(Y!==V){if(W+=1,!$)if(Y==="")await XJ(X);else await VJ(X,Y,"utf-8")}}if(Z){let X=QJ(UJ(J),Z);if(HJ(X))try{let V=await WJ(X,"utf-8"),Y=YJ(V);if(Y!==V){if(W+=1,!$)if(Y==="")await XJ(X);else await VJ(X,Y,"utf-8")}if(!K.includes(X))K.push(X)}catch{}}return{files:K,changed:W}}async function NJ(J,Z,$,K,W=!1){let V=Z.getAll(J).flatMap((Q)=>$.getBySession(Q.id));if(W){let Q=new Set;for(let H of V)for(let U of[...H.filesRead,...H.filesModified])Q.add(U);return{observations:V.length,filesTouched:Q.size}}if(!HJ(J))return{observations:0,filesTouched:0};await JJ(J,V,{maxDepth:K.maxDepth,mode:K.mode,filename:K.filename});let Y=await BJ(J,K.filename);return{observations:V.length,filesTouched:Y.length}}import{spawnSync as MJ}from"child_process";import{dirname as sJ,resolve as GJ}from"path";function rJ(J){try{let Z=MJ("git",["rev-parse","--git-common-dir"],{cwd:J,encoding:"utf-8",timeout:5000});if(Z.status!==0||!Z.stdout)return null;let $=Z.stdout.trim();if($===".git")return null;let K=MJ("git",["rev-parse","--git-dir"],{cwd:J,encoding:"utf-8",timeout:5000});if(K.status!==0||!K.stdout)return null;let W=K.stdout.trim(),X=GJ(J,$),V=GJ(J,W);if(X===V)return null;let Y=sJ(X);if(Y===X||Y==="/")return null;return Y}catch{return null}}function _J(J){return rJ(J)??J}var{positionals:EJ,values:p}=aJ({args:Bun.argv.slice(2),options:{project:{type:"string",short:"p"},"dry-run":{type:"boolean",default:!1}},allowPositionals:!0,strict:!1}),T=EJ[0]??"help",m=EJ[1]??"",oJ=typeof p.project==="string"?p.project:process.cwd(),D=_J(oJ);function kJ(){console.log(`Usage:
394
394
  open-mem-maintenance reset-db --project <path>
395
395
  open-mem-maintenance folder-context clean --project <path> [--dry-run]
396
- open-mem-maintenance folder-context rebuild --project <path> [--dry-run]`)}async function lJ(){if(A==="help"||A==="--help"||A==="-h"){zJ();return}if(A==="reset-db"){let J=x(I);b(J.dbPath,{force:!0}),b(`${J.dbPath}-wal`,{force:!0}),b(`${J.dbPath}-shm`,{force:!0}),console.log(`Removed database files for ${J.dbPath}`);return}if(A==="folder-context"&&(h==="clean"||h==="rebuild")){let J=f["dry-run"]===!0,Z=x(I);if(h==="clean"){let V=await QJ(I,Z.folderContextFilename,J);console.log(`${J?"[dry-run] ":""}Scanned ${V.files.length} AGENTS.md files, changed ${V.changed}.`);return}T.enableExtensionSupport();let $=l(Z.dbPath);n($,{hasVectorExtension:$.hasVectorExtension,embeddingDimension:Z.embeddingDimension});let K=new j($),X=new w($),W=await UJ(I,K,X,{maxDepth:Z.folderContextMaxDepth,mode:Z.folderContextMode,filename:Z.folderContextFilename},J);$.close(),console.log(`${J?"[dry-run] ":""}Rebuilt context from ${W.observations} observations, touched ${W.filesTouched} files.`);return}zJ(),process.exitCode=1}lJ();
396
+ open-mem-maintenance folder-context rebuild --project <path> [--dry-run]`)}async function tJ(){if(T==="help"||T==="--help"||T==="-h"){kJ();return}if(T==="reset-db"){let J=w(D);f(J.dbPath,{force:!0}),f(`${J.dbPath}-wal`,{force:!0}),f(`${J.dbPath}-shm`,{force:!0}),console.log(`Removed database files for ${J.dbPath}`);return}if(T==="folder-context"&&(m==="clean"||m==="rebuild")){let J=p["dry-run"]===!0,Z=w(D);if(m==="clean"){let V=await zJ(D,Z.folderContextFilename,J);console.log(`${J?"[dry-run] ":""}Scanned ${V.files.length} AGENTS.md files, changed ${V.changed}.`);return}F.enableExtensionSupport();let $=s(Z.dbPath);a($,{hasVectorExtension:$.hasVectorExtension,embeddingDimension:Z.embeddingDimension});let K=new v($),W=new y($),X=await NJ(D,K,W,{maxDepth:Z.folderContextMaxDepth,mode:Z.folderContextMode,filename:Z.folderContextFilename},J);$.close(),console.log(`${J?"[dry-run] ":""}Rebuilt context from ${X.observations} observations, touched ${X.filesTouched} files.`);return}kJ(),process.exitCode=1}tJ();