@vpxa/kb 0.1.4 → 0.1.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vpxa/kb",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "description": "Local-first AI developer toolkit — knowledge base, code analysis, context management, and developer tools for LLM agents",
6
6
  "license": "MIT",
@@ -41,10 +41,10 @@
41
41
  "@huggingface/transformers": "^3.x",
42
42
  "@lancedb/lancedb": "^0.x",
43
43
  "@modelcontextprotocol/sdk": "^1.x",
44
- "better-sqlite3": "^12.x",
45
44
  "express": "^5.x",
46
45
  "linkedom": "^0.x",
47
46
  "minimatch": "^10.x",
47
+ "sql.js": "^1.x",
48
48
  "turndown": "^7.x",
49
49
  "zod": "^4.x"
50
50
  },
@@ -1 +1 @@
1
- import{pipeline as m}from"@huggingface/transformers";import{EMBEDDING_DEFAULTS as l}from"../../core/dist/index.js";class h{pipe=null;dimensions;modelId;queryPrefix;constructor(e){this.modelId=e?.model??l.model,this.dimensions=e?.dimensions??l.dimensions,this.queryPrefix=e?.queryPrefix??this.detectQueryPrefix(this.modelId)}detectQueryPrefix(e){const i=e.toLowerCase();return i.includes("bge")||i.includes("mxbai-embed")?"Represent this sentence for searching relevant passages: ":i.includes("/e5-")||i.includes("multilingual-e5")?"query: ":""}async initialize(){if(!this.pipe)try{this.pipe=await m("feature-extraction",this.modelId,{dtype:"fp32"})}catch(e){throw new Error(`Failed to initialize embedding model "${this.modelId}": ${e.message}`)}}async shutdown(){this.pipe=null}async embed(e){this.pipe||await this.initialize();const i=await this.pipe?.(e,{pooling:"mean",normalize:!0});if(!i)throw new Error("Embedding pipeline returned no output");return new Float32Array(i.data)}async embedQuery(e){return this.embed(this.queryPrefix+e)}async embedBatch(e){if(e.length===0)return[];this.pipe||await this.initialize();const i=[],a=32;for(let r=0;r<e.length;r+=a){const t=e.slice(r,r+a),n=await this.pipe?.(t,{pooling:"mean",normalize:!0});if(!n)throw new Error("Embedding pipeline returned no output");if(t.length===1)i.push(new Float32Array(n.data));else for(let s=0;s<t.length;s++){const o=s*this.dimensions,d=n.data.slice(o,o+this.dimensions);i.push(new Float32Array(d))}}return i}}export{h as OnnxEmbedder};
1
+ import{homedir as m}from"node:os";import{join as u}from"node:path";import{env as p,pipeline as c}from"@huggingface/transformers";import{EMBEDDING_DEFAULTS as l}from"../../core/dist/index.js";p.cacheDir=u(m(),".cache","huggingface","transformers-js");class w{pipe=null;dimensions;modelId;queryPrefix;constructor(e){this.modelId=e?.model??l.model,this.dimensions=e?.dimensions??l.dimensions,this.queryPrefix=e?.queryPrefix??this.detectQueryPrefix(this.modelId)}detectQueryPrefix(e){const i=e.toLowerCase();return i.includes("bge")||i.includes("mxbai-embed")?"Represent this sentence for searching relevant passages: ":i.includes("/e5-")||i.includes("multilingual-e5")?"query: ":""}async initialize(){if(!this.pipe)try{this.pipe=await c("feature-extraction",this.modelId,{dtype:"fp32"})}catch(e){throw new Error(`Failed to initialize embedding model "${this.modelId}": ${e.message}`)}}async shutdown(){this.pipe=null}async embed(e){this.pipe||await this.initialize();const i=await this.pipe?.(e,{pooling:"mean",normalize:!0});if(!i)throw new Error("Embedding pipeline returned no output");return new Float32Array(i.data)}async embedQuery(e){return this.embed(this.queryPrefix+e)}async embedBatch(e){if(e.length===0)return[];this.pipe||await this.initialize();const i=[],o=32;for(let r=0;r<e.length;r+=o){const t=e.slice(r,r+o),n=await this.pipe?.(t,{pooling:"mean",normalize:!0});if(!n)throw new Error("Embedding pipeline returned no output");if(t.length===1)i.push(new Float32Array(n.data));else for(let s=0;s<t.length;s++){const a=s*this.dimensions,d=n.data.slice(a,a+this.dimensions);i.push(new Float32Array(d))}}return i}}export{w as OnnxEmbedder};
@@ -1 +1 @@
1
- import{parseArgs as m}from"node:util";import{loadConfig as f}from"./config.js";import{createMcpServer as w,createServer as x,initializeKnowledgeBase as g}from"./server.js";const{values:u}=m({options:{transport:{type:"string",default:process.env.KB_TRANSPORT??"stdio"},port:{type:"string",default:process.env.KB_PORT??"3210"}}});async function I(){console.error("[KB] Starting MCP Knowledge Base server...");const t=f();if(console.error(`[KB] Config loaded: ${t.sources.length} source(s), store at ${t.store.path}`),u.transport==="http"){const{StreamableHTTPServerTransport:d}=await import("@modelcontextprotocol/sdk/server/streamableHttp.js"),a=(await import("express")).default,i=await g(t),c=w(i,t);console.error("[KB] MCP server configured with 46 tools and 2 resources");const n=a();n.use(a.json()),n.use((s,e,o)=>{if(e.setHeader("Access-Control-Allow-Origin",process.env.KB_CORS_ORIGIN??"*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, DELETE, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),s.method==="OPTIONS"){e.status(204).end();return}o()}),n.get("/health",(s,e)=>{e.json({status:"ok"})}),n.post("/mcp",async(s,e)=>{try{const o=new d({sessionIdGenerator:void 0});await c.connect(o),await o.handleRequest(s,e,s.body),e.on("close",()=>{o.close()})}catch(o){console.error("[KB] MCP handler error:",o),e.headersSent||e.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal server error"},id:null})}}),n.get("/mcp",(s,e)=>{e.writeHead(405).end(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Method not allowed."},id:null}))}),n.delete("/mcp",(s,e)=>{e.writeHead(405).end(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Method not allowed."},id:null}))});const l=Number(u.port),h=n.listen(l,()=>{console.error(`[KB] MCP server listening on http://0.0.0.0:${l}/mcp`),(async()=>{try{const e=t.sources.map(r=>r.path).join(", ");console.error(`[KB] Running initial index for sources: ${e}`);const o=await i.indexer.index(t,r=>{r.phase==="crawling"||r.phase==="done"||r.phase==="chunking"&&r.currentFile&&console.error(`[KB] [${r.filesProcessed+1}/${r.filesTotal}] ${r.currentFile}`)});console.error(`[KB] Indexed ${o.filesProcessed} files (${o.filesSkipped} skipped, ${o.chunksCreated} chunks) in ${(o.durationMs/1e3).toFixed(1)}s`);try{const r=await i.curated.reindexAll();console.error(`[KB] Curated re-index: ${r.indexed} entries restored to vector store`)}catch(r){console.error("[KB] Curated re-index failed:",r)}}catch(e){console.error("[KB] Initial index failed (will retry on kb_reindex):",e)}})()}),p=async s=>{console.error(`[KB] ${s} received \u2014 shutting down...`),h.close(),await c.close(),await i.store.close(),await i.embedder.shutdown(),process.exit(0)};process.on("SIGINT",()=>p("SIGINT")),process.on("SIGTERM",()=>p("SIGTERM"))}else{const{server:d,runInitialIndex:a}=await x(t),{StdioServerTransport:i}=await import("@modelcontextprotocol/sdk/server/stdio.js"),c=new i;await d.connect(c),console.error("[KB] MCP server started (stdio)"),process.env.KB_AUTO_INDEX!=="false"?a():console.error("[KB] Auto-index disabled (KB_AUTO_INDEX=false). Use kb_reindex to index manually.")}}I().catch(t=>{console.error("[KB] Fatal error:",t),process.exit(1)});
1
+ import{parseArgs as w}from"node:util";import{loadConfig as h}from"./config.js";import{createMcpServer as f,createServer as x,initializeKnowledgeBase as g}from"./server.js";const{values:u}=w({options:{transport:{type:"string",default:process.env.KB_TRANSPORT??"stdio"},port:{type:"string",default:process.env.KB_PORT??"3210"}}});async function I(){console.error("[KB] Starting MCP Knowledge Base server...");const t=h();if(console.error(`[KB] Config loaded: ${t.sources.length} source(s), store at ${t.store.path}`),u.transport==="http"){const{StreamableHTTPServerTransport:d}=await import("@modelcontextprotocol/sdk/server/streamableHttp.js"),a=(await import("express")).default,i=await g(t),c=f(i,t);console.error("[KB] MCP server configured with 46 tools and 2 resources");const n=a();n.use(a.json()),n.use((s,e,o)=>{if(e.setHeader("Access-Control-Allow-Origin",process.env.KB_CORS_ORIGIN??"*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, DELETE, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type, Authorization"),s.method==="OPTIONS"){e.status(204).end();return}o()}),n.get("/health",(s,e)=>{e.json({status:"ok"})}),n.post("/mcp",async(s,e)=>{try{const o=new d({sessionIdGenerator:void 0});await c.connect(o),await o.handleRequest(s,e,s.body),e.on("close",()=>{o.close()})}catch(o){console.error("[KB] MCP handler error:",o),e.headersSent||e.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal server error"},id:null})}}),n.get("/mcp",(s,e)=>{e.writeHead(405).end(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Method not allowed."},id:null}))}),n.delete("/mcp",(s,e)=>{e.writeHead(405).end(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Method not allowed."},id:null}))});const l=Number(u.port),m=n.listen(l,()=>{console.error(`[KB] MCP server listening on http://0.0.0.0:${l}/mcp`),(async()=>{try{const e=t.sources.map(r=>r.path).join(", ");console.error(`[KB] Running initial index for sources: ${e}`);const o=await i.indexer.index(t,r=>{r.phase==="crawling"||r.phase==="done"||r.phase==="chunking"&&r.currentFile&&console.error(`[KB] [${r.filesProcessed+1}/${r.filesTotal}] ${r.currentFile}`)});console.error(`[KB] Indexed ${o.filesProcessed} files (${o.filesSkipped} skipped, ${o.chunksCreated} chunks) in ${(o.durationMs/1e3).toFixed(1)}s`);try{const r=await i.curated.reindexAll();console.error(`[KB] Curated re-index: ${r.indexed} entries restored to vector store`)}catch(r){console.error("[KB] Curated re-index failed:",r)}}catch(e){console.error("[KB] Initial index failed (will retry on kb_reindex):",e)}})()}),p=async s=>{console.error(`[KB] ${s} received \u2014 shutting down...`),m.close(),await c.close(),await i.store.close(),await i.embedder.shutdown(),process.exit(0)};process.on("SIGINT",()=>p("SIGINT")),process.on("SIGTERM",()=>p("SIGTERM"))}else{const{McpServer:d}=await import("@modelcontextprotocol/sdk/server/mcp.js"),{StdioServerTransport:a}=await import("@modelcontextprotocol/sdk/server/stdio.js"),i=new d({name:"kb",version:"0.1.0"}),c=new a;await i.connect(c),console.error("[KB] MCP server started (stdio)");const{runInitialIndex:n}=await x(t,i);console.error("[KB] MCP server configured with 64 tools and 2 resources"),process.env.KB_AUTO_INDEX!=="false"?n():console.error("[KB] Auto-index disabled (KB_AUTO_INDEX=false). Use kb_reindex to index manually.")}}I().catch(t=>{console.error("[KB] Fatal error:",t),process.exit(1)});
@@ -14,8 +14,10 @@ export interface KnowledgeBaseComponents {
14
14
  }
15
15
  export declare function initializeKnowledgeBase(config: KBConfig): Promise<KnowledgeBaseComponents>;
16
16
  export declare function createMcpServer(kb: KnowledgeBaseComponents, config: KBConfig): McpServer;
17
- export declare function createServer(config: KBConfig): Promise<{
17
+ export declare function registerMcpTools(server: McpServer, kb: KnowledgeBaseComponents, config: KBConfig): void;
18
+ export declare function createServer(config: KBConfig, existingServer?: McpServer): Promise<{
18
19
  server: McpServer;
19
20
  runInitialIndex: () => Promise<void>;
21
+ shutdown: () => Promise<void>;
20
22
  }>;
21
23
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- import{initializeTreeSitter as c}from"../../chunker/dist/index.js";import{OnnxEmbedder as m}from"../../embeddings/dist/index.js";import{IncrementalIndexer as g}from"../../indexer/dist/index.js";import{createStore as p,SqliteGraphStore as T}from"../../store/dist/index.js";import{McpServer as u}from"@modelcontextprotocol/sdk/server/mcp.js";import{CuratedKnowledgeManager as f}from"./curated-manager.js";import{installReplayInterceptor as h}from"./replay-interceptor.js";import{registerResources as S}from"./resources/resources.js";import{registerAnalyzeDependenciesTool as x,registerAnalyzeDiagramTool as w,registerAnalyzeEntryPointsTool as K,registerAnalyzePatternsTool as y,registerAnalyzeStructureTool as B,registerAnalyzeSymbolsTool as C,registerBlastRadiusTool as I}from"./tools/analyze.tools.js";import{registerDigestTool as v,registerEvidenceMapTool as P,registerForgeClassifyTool as z,registerForgeGroundTool as R,registerStratumCardTool as E}from"./tools/forge.tools.js";import{registerForgetTool as F}from"./tools/forget.tool.js";import{registerGraphTool as M}from"./tools/graph.tool.js";import{registerListTool as $}from"./tools/list.tool.js";import{registerLookupTool as G}from"./tools/lookup.tool.js";import{registerOnboardTool as A}from"./tools/onboard.tool.js";import{registerProduceKnowledgeTool as D}from"./tools/produce.tool.js";import{registerReadTool as O}from"./tools/read.tool.js";import{registerReindexTool as W}from"./tools/reindex.tool.js";import{registerRememberTool as j}from"./tools/remember.tool.js";import{registerReplayTool as L}from"./tools/replay.tool.js";import{registerSearchTool as H}from"./tools/search.tool.js";import{registerStatusTool as q}from"./tools/status.tool.js";import{registerBatchTool as N,registerCheckpointTool as Q,registerCheckTool as U,registerCodemodTool as V,registerCompactTool as _,registerDataTransformTool as J,registerDeadSymbolsTool as X,registerDelegateTool as Y,registerDiffParseTool as Z,registerEvalTool as b,registerFileSummaryTool as k,registerFindExamplesTool as ee,registerFindTool as re,registerGitContextTool as oe,registerHealthTool as te,registerLaneTool as se,registerParseOutputTool as ie,registerProcessTool as ne,registerQueueTool as ae,registerRenameTool as le,registerScopeMapTool as de,registerStashTool as ce,registerSymbolTool as me,registerTestRunTool as ge,registerTraceTool as pe,registerWatchTool as Te,registerWebFetchTool as ue,registerWorksetTool as fe}from"./tools/toolkit.tools.js";import{registerUpdateTool as he}from"./tools/update.tool.js";import{registerChangelogTool as Se,registerEncodeTool as xe,registerEnvTool as we,registerHttpTool as Ke,registerMeasureTool as ye,registerRegexTestTool as Be,registerSchemaValidateTool as Ce,registerSnippetTool as Ie,registerTimeTool as ve,registerWebSearchTool as Pe}from"./tools/utility.tools.js";async function ze(r){console.error("[KB] Initializing knowledge base components...");const t=new m({model:r.embedding.model,dimensions:r.embedding.dimensions});await t.initialize(),console.error(`[KB] Embedder loaded: ${t.modelId} (${t.dimensions}d)`);const e=await p({backend:r.store.backend,path:r.store.path});await e.initialize(),console.error("[KB] Store initialized");const a=new g(t,e),i=r.curated.path,d=new f(i,e,t),s=new T({path:r.store.path});await s.initialize(),console.error("[KB] Graph store initialized"),a.setGraphStore(s);const n=await c();return console.error(n?"[KB] Tree-sitter chunking enabled":"[KB] Tree-sitter not available \u2014 using regex-based code chunking"),{embedder:t,store:e,indexer:a,curated:d,graphStore:s}}function Re(r,t){const e=new u({name:"kb",version:"0.1.0"});return h(e),H(e,r.embedder,r.store,r.graphStore),G(e,r.store),q(e,r.store,r.graphStore),W(e,r.indexer,t,r.curated,r.store),j(e,r.curated),he(e,r.curated),F(e,r.curated),O(e,r.curated),$(e,r.curated),B(e,r.store,r.embedder),x(e,r.store,r.embedder),C(e,r.store,r.embedder),y(e,r.store,r.embedder),K(e,r.store,r.embedder),w(e,r.store,r.embedder),I(e,r.store,r.embedder),D(e),A(e,r.store,r.embedder),M(e,r.graphStore),_(e,r.embedder),de(e,r.embedder,r.store),re(e,r.embedder,r.store),ie(e),fe(e),U(e),N(e,r.embedder,r.store),me(e,r.embedder,r.store),b(e),ge(e),ce(e),oe(e),Z(e),le(e),V(e),k(e),Q(e),J(e),pe(e,r.embedder,r.store),ee(e,r.embedder,r.store),ne(e),Te(e),X(e,r.embedder,r.store),Y(e),te(e),se(e),ae(e),ue(e),P(e),v(e,r.embedder),z(e),E(e,r.embedder),R(e,r.embedder,r.store),Pe(e),Ke(e),Be(e),xe(e),ye(e),Se(e),Ce(e),Ie(e),we(e),ve(e),S(e,r.store),L(e),e}async function rr(r){const t=await ze(r),e=Re(t,r);console.error("[KB] MCP server configured with 64 tools and 2 resources");const a=async()=>{try{const n=r.sources.map(o=>o.path).join(", ");console.error(`[KB] Running initial index for sources: ${n}`);const l=await t.indexer.index(r,o=>{o.phase==="crawling"||o.phase==="done"||(o.phase==="chunking"&&o.currentFile&&console.error(`[KB] [${o.filesProcessed+1}/${o.filesTotal}] ${o.currentFile}`),o.phase==="cleanup"&&console.error(`[KB] cleanup: removing ${o.filesTotal-o.filesProcessed} stale entries`))});console.error(`[KB] Indexed ${l.filesProcessed} files (${l.filesSkipped} skipped, ${l.chunksCreated} chunks) in ${(l.durationMs/1e3).toFixed(1)}s`);try{await t.store.createFtsIndex()}catch(o){console.error("[KB] FTS index creation failed (non-fatal):",o)}try{const o=await t.curated.reindexAll();console.error(`[KB] Curated re-index: ${o.indexed} entries restored to vector store`)}catch(o){console.error("[KB] Curated re-index failed:",o)}}catch(n){console.error("[KB] Initial index failed (will retry on kb_reindex):",n)}},i=async()=>{console.error("[KB] Shutting down..."),await t.graphStore.close().catch(()=>{}),await t.store.close(),process.exit(0)};process.on("SIGINT",i),process.on("SIGTERM",i);const d=process.ppid,s=setInterval(()=>{try{process.kill(d,0)}catch{console.error("[KB] Parent process died \u2014 orphan detected, shutting down..."),clearInterval(s),i()}},5e3);return s.unref(),{server:e,runInitialIndex:a}}export{Re as createMcpServer,rr as createServer,ze as initializeKnowledgeBase};
1
+ import{initializeTreeSitter as g}from"../../chunker/dist/index.js";import{OnnxEmbedder as p}from"../../embeddings/dist/index.js";import{IncrementalIndexer as T}from"../../indexer/dist/index.js";import{createStore as u,SqliteGraphStore as f}from"../../store/dist/index.js";import{McpServer as h}from"@modelcontextprotocol/sdk/server/mcp.js";import{CuratedKnowledgeManager as S}from"./curated-manager.js";import{installReplayInterceptor as x}from"./replay-interceptor.js";import{registerResources as w}from"./resources/resources.js";import{registerAnalyzeDependenciesTool as K,registerAnalyzeDiagramTool as B,registerAnalyzeEntryPointsTool as y,registerAnalyzePatternsTool as C,registerAnalyzeStructureTool as I,registerAnalyzeSymbolsTool as P,registerBlastRadiusTool as M}from"./tools/analyze.tools.js";import{registerDigestTool as z,registerEvidenceMapTool as R,registerForgeClassifyTool as E,registerForgeGroundTool as F,registerStratumCardTool as $}from"./tools/forge.tools.js";import{registerForgetTool as G}from"./tools/forget.tool.js";import{registerGraphTool as A}from"./tools/graph.tool.js";import{registerListTool as D}from"./tools/list.tool.js";import{registerLookupTool as O}from"./tools/lookup.tool.js";import{registerOnboardTool as W}from"./tools/onboard.tool.js";import{registerProduceKnowledgeTool as j}from"./tools/produce.tool.js";import{registerReadTool as L}from"./tools/read.tool.js";import{registerReindexTool as H}from"./tools/reindex.tool.js";import{registerRememberTool as q}from"./tools/remember.tool.js";import{registerReplayTool as N}from"./tools/replay.tool.js";import{registerSearchTool as Q}from"./tools/search.tool.js";import{registerStatusTool as U}from"./tools/status.tool.js";import{registerBatchTool as V,registerCheckpointTool as _,registerCheckTool as J,registerCodemodTool as X,registerCompactTool as Y,registerDataTransformTool as Z,registerDeadSymbolsTool as b,registerDelegateTool as k,registerDiffParseTool as v,registerEvalTool as ee,registerFileSummaryTool as oe,registerFindExamplesTool as re,registerFindTool as te,registerGitContextTool as ie,registerHealthTool as ne,registerLaneTool as ae,registerParseOutputTool as se,registerProcessTool as le,registerQueueTool as de,registerRenameTool as ce,registerScopeMapTool as me,registerStashTool as ge,registerSymbolTool as pe,registerTestRunTool as Te,registerTraceTool as ue,registerWatchTool as fe,registerWebFetchTool as he,registerWorksetTool as Se}from"./tools/toolkit.tools.js";import{registerUpdateTool as xe}from"./tools/update.tool.js";import{registerChangelogTool as we,registerEncodeTool as Ke,registerEnvTool as Be,registerHttpTool as ye,registerMeasureTool as Ce,registerRegexTestTool as Ie,registerSchemaValidateTool as Pe,registerSnippetTool as Me,registerTimeTool as ze,registerWebSearchTool as Re}from"./tools/utility.tools.js";async function Ee(e){console.error("[KB] Initializing knowledge base components...");const o=new p({model:e.embedding.model,dimensions:e.embedding.dimensions});await o.initialize(),console.error(`[KB] Embedder loaded: ${o.modelId} (${o.dimensions}d)`);const t=await u({backend:e.store.backend,path:e.store.path});await t.initialize(),console.error("[KB] Store initialized");const i=new T(o,t),d=e.curated.path,n=new S(d,t,o),a=new f({path:e.store.path});await a.initialize(),console.error("[KB] Graph store initialized"),i.setGraphStore(a);const s=await g();return console.error(s?"[KB] Tree-sitter chunking enabled":"[KB] Tree-sitter not available \u2014 using regex-based code chunking"),{embedder:o,store:t,indexer:i,curated:n,graphStore:a}}function Fe(e,o){const t=new h({name:"kb",version:"0.1.0"});return m(t,e,o),t}function m(e,o,t){x(e),Q(e,o.embedder,o.store,o.graphStore),O(e,o.store),U(e,o.store,o.graphStore),H(e,o.indexer,t,o.curated,o.store),q(e,o.curated),xe(e,o.curated),G(e,o.curated),L(e,o.curated),D(e,o.curated),I(e,o.store,o.embedder),K(e,o.store,o.embedder),P(e,o.store,o.embedder),C(e,o.store,o.embedder),y(e,o.store,o.embedder),B(e,o.store,o.embedder),M(e,o.store,o.embedder),j(e),W(e,o.store,o.embedder),A(e,o.graphStore),Y(e,o.embedder),me(e,o.embedder,o.store),te(e,o.embedder,o.store),se(e),Se(e),J(e),V(e,o.embedder,o.store),pe(e,o.embedder,o.store),ee(e),Te(e),ge(e),ie(e),v(e),ce(e),X(e),oe(e),_(e),Z(e),ue(e,o.embedder,o.store),re(e,o.embedder,o.store),le(e),fe(e),b(e,o.embedder,o.store),k(e),ne(e),ae(e),de(e),he(e),R(e),z(e,o.embedder),E(e),$(e,o.embedder),F(e,o.embedder,o.store),Re(e),ye(e),Ie(e),Ke(e),Ce(e),we(e),Pe(e),Me(e),Be(e),ze(e),w(e,o.store),N(e)}async function to(e,o){const t=await Ee(e);let i;o?(m(o,t,e),i=o):i=Fe(t,e);const d=async()=>{try{const c=e.sources.map(r=>r.path).join(", ");console.error(`[KB] Running initial index for sources: ${c}`);const l=await t.indexer.index(e,r=>{r.phase==="crawling"||r.phase==="done"||(r.phase==="chunking"&&r.currentFile&&console.error(`[KB] [${r.filesProcessed+1}/${r.filesTotal}] ${r.currentFile}`),r.phase==="cleanup"&&console.error(`[KB] cleanup: removing ${r.filesTotal-r.filesProcessed} stale entries`))});console.error(`[KB] Indexed ${l.filesProcessed} files (${l.filesSkipped} skipped, ${l.chunksCreated} chunks) in ${(l.durationMs/1e3).toFixed(1)}s`);try{await t.store.createFtsIndex()}catch(r){console.error("[KB] FTS index creation failed (non-fatal):",r)}try{const r=await t.curated.reindexAll();console.error(`[KB] Curated re-index: ${r.indexed} entries restored to vector store`)}catch(r){console.error("[KB] Curated re-index failed:",r)}}catch(c){console.error("[KB] Initial index failed (will retry on kb_reindex):",c)}},n=async()=>{console.error("[KB] Shutting down..."),await t.graphStore.close().catch(()=>{}),await t.store.close(),process.exit(0)};process.on("SIGINT",n),process.on("SIGTERM",n);const a=process.ppid,s=setInterval(()=>{try{process.kill(a,0)}catch{console.error("[KB] Parent process died \u2014 orphan detected, shutting down..."),clearInterval(s),n()}},5e3);return s.unref(),{server:i,runInitialIndex:d,shutdown:n}}export{Fe as createMcpServer,to as createServer,Ee as initializeKnowledgeBase,m as registerMcpTools};
@@ -1,18 +1,25 @@
1
1
  /**
2
2
  * SQLite-backed knowledge graph store.
3
3
  *
4
- * Uses better-sqlite3 for a zero-config, embedded, single-file graph database.
4
+ * Uses sql.js (WASM) for a zero-native-dependency, embedded, single-file graph database.
5
5
  * Stores nodes and edges with JSON properties, supports multi-hop traversal.
6
+ * Persists to disk by writing the full database buffer on mutations.
6
7
  */
7
8
  import type { GraphEdge, GraphNode, GraphStats, GraphTraversalOptions, GraphTraversalResult, IGraphStore } from './graph-store.interface.js';
8
9
  export declare class SqliteGraphStore implements IGraphStore {
9
10
  private db;
10
11
  private readonly dbPath;
12
+ private dirty;
11
13
  constructor(options?: {
12
14
  path?: string;
13
15
  });
14
16
  initialize(): Promise<void>;
15
17
  private ensureDb;
18
+ private persist;
19
+ private markDirty;
20
+ private flushIfDirty;
21
+ private query;
22
+ private run;
16
23
  upsertNode(node: GraphNode): Promise<void>;
17
24
  upsertEdge(edge: GraphEdge): Promise<void>;
18
25
  upsertNodes(nodes: GraphNode[]): Promise<void>;
@@ -37,7 +44,5 @@ export declare class SqliteGraphStore implements IGraphStore {
37
44
  clear(): Promise<void>;
38
45
  getStats(): Promise<GraphStats>;
39
46
  close(): Promise<void>;
40
- private toGraphNode;
41
- private toGraphEdge;
42
47
  }
43
48
  //# sourceMappingURL=sqlite-graph-store.d.ts.map
@@ -1,4 +1,4 @@
1
- import{existsSync as l,mkdirSync as N}from"node:fs";import{dirname as y,join as S}from"node:path";class f{db=null;dbPath;constructor(e){const t=e?.path??".kb-data";this.dbPath=S(t,"graph.db")}async initialize(){const e=y(this.dbPath);l(e)||N(e,{recursive:!0});const t=(await import("better-sqlite3")).default;this.db=new t(this.dbPath),this.db.pragma("journal_mode = WAL"),this.db.pragma("foreign_keys = ON"),this.db.exec(`
1
+ import{existsSync as g,mkdirSync as l,readFileSync as N,writeFileSync as f}from"node:fs";import{dirname as S,join as I}from"node:path";class b{db=null;dbPath;dirty=!1;constructor(e){const t=e?.path??".kb-data";this.dbPath=I(t,"graph.db")}async initialize(){const e=S(this.dbPath);g(e)||l(e,{recursive:!0});const t=(await import("sql.js")).default,s=await t();if(g(this.dbPath)){const i=N(this.dbPath);this.db=new s.Database(i)}else this.db=new s.Database;this.db.run("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA foreign_keys = ON;"),this.db.run(`
2
2
  CREATE TABLE IF NOT EXISTS nodes (
3
3
  id TEXT PRIMARY KEY,
4
4
  type TEXT NOT NULL,
@@ -7,8 +7,8 @@ import{existsSync as l,mkdirSync as N}from"node:fs";import{dirname as y,join as
7
7
  source_record_id TEXT,
8
8
  source_path TEXT,
9
9
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
10
- );
11
-
10
+ )
11
+ `),this.db.run(`
12
12
  CREATE TABLE IF NOT EXISTS edges (
13
13
  id TEXT PRIMARY KEY,
14
14
  from_id TEXT NOT NULL,
@@ -18,56 +18,29 @@ import{existsSync as l,mkdirSync as N}from"node:fs";import{dirname as y,join as
18
18
  properties TEXT NOT NULL DEFAULT '{}',
19
19
  FOREIGN KEY (from_id) REFERENCES nodes(id) ON DELETE CASCADE,
20
20
  FOREIGN KEY (to_id) REFERENCES nodes(id) ON DELETE CASCADE
21
- );
22
-
23
- CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);
24
- CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name);
25
- CREATE INDEX IF NOT EXISTS idx_nodes_source_path ON nodes(source_path);
26
- CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id);
27
- CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id);
28
- CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);
29
- `)}ensureDb(){if(!this.db)throw new Error("Graph store not initialized \u2014 call initialize() first");return this.db}async upsertNode(e){this.ensureDb().prepare(`
30
- INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
31
- VALUES (?, ?, ?, ?, ?, ?, ?)
32
- ON CONFLICT(id) DO UPDATE SET
33
- type = excluded.type,
34
- name = excluded.name,
35
- properties = excluded.properties,
36
- source_record_id = excluded.source_record_id,
37
- source_path = excluded.source_path
38
- `).run(e.id,e.type,e.name,JSON.stringify(e.properties),e.sourceRecordId??null,e.sourcePath??null,e.createdAt??new Date().toISOString())}async upsertEdge(e){this.ensureDb().prepare(`
39
- INSERT INTO edges (id, from_id, to_id, type, weight, properties)
40
- VALUES (?, ?, ?, ?, ?, ?)
41
- ON CONFLICT(id) DO UPDATE SET
42
- from_id = excluded.from_id,
43
- to_id = excluded.to_id,
44
- type = excluded.type,
45
- weight = excluded.weight,
46
- properties = excluded.properties
47
- `).run(e.id,e.fromId,e.toId,e.type,e.weight??1,JSON.stringify(e.properties??{}))}async upsertNodes(e){if(e.length===0)return;const t=this.ensureDb(),s=t.prepare(`
48
- INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
49
- VALUES (?, ?, ?, ?, ?, ?, ?)
50
- ON CONFLICT(id) DO UPDATE SET
51
- type = excluded.type,
52
- name = excluded.name,
53
- properties = excluded.properties,
54
- source_record_id = excluded.source_record_id,
55
- source_path = excluded.source_path
56
- `);t.transaction(()=>{for(const r of e)s.run(r.id,r.type,r.name,JSON.stringify(r.properties),r.sourceRecordId??null,r.sourcePath??null,r.createdAt??new Date().toISOString())})()}async upsertEdges(e){if(e.length===0)return;const t=this.ensureDb(),s=t.prepare(`
57
- INSERT INTO edges (id, from_id, to_id, type, weight, properties)
58
- VALUES (?, ?, ?, ?, ?, ?)
59
- ON CONFLICT(id) DO UPDATE SET
60
- from_id = excluded.from_id,
61
- to_id = excluded.to_id,
62
- type = excluded.type,
63
- weight = excluded.weight,
64
- properties = excluded.properties
65
- `);t.transaction(()=>{for(const r of e)s.run(r.id,r.fromId,r.toId,r.type,r.weight??1,JSON.stringify(r.properties??{}))})()}async getNode(e){const s=this.ensureDb().prepare("SELECT * FROM nodes WHERE id = ?").get(e);return s?this.toGraphNode(s):null}async getNeighbors(e,t){const s=this.ensureDb(),o=t?.direction??"both",r=t?.edgeType,a=t?.limit??50,p=[],d=[],E=new Set,_=`
21
+ )
22
+ `),this.db.run("CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_nodes_source_path ON nodes(source_path)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id)"),this.db.run("CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type)"),this.persist()}ensureDb(){if(!this.db)throw new Error("Graph store not initialized \u2014 call initialize() first");return this.db}persist(){if(!this.db)return;const e=this.db.export();f(this.dbPath,Buffer.from(e)),this.db.exec("PRAGMA foreign_keys = ON;"),this.dirty=!1}markDirty(){this.dirty=!0}flushIfDirty(){this.dirty&&this.persist()}query(e,t=[]){const i=this.ensureDb().prepare(e);i.bind(t);const d=[];for(;i.step();)d.push(i.getAsObject());return i.free(),d}run(e,t=[]){this.ensureDb().run(e,t)}async upsertNode(e){this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
23
+ VALUES (?, ?, ?, ?, ?, ?, ?)
24
+ ON CONFLICT(id) DO UPDATE SET
25
+ type = excluded.type, name = excluded.name, properties = excluded.properties,
26
+ source_record_id = excluded.source_record_id, source_path = excluded.source_path`,[e.id,e.type,e.name,JSON.stringify(e.properties),e.sourceRecordId??null,e.sourcePath??null,e.createdAt??new Date().toISOString()]),this.markDirty(),this.flushIfDirty()}async upsertEdge(e){this.run(`INSERT INTO edges (id, from_id, to_id, type, weight, properties)
27
+ VALUES (?, ?, ?, ?, ?, ?)
28
+ ON CONFLICT(id) DO UPDATE SET
29
+ from_id = excluded.from_id, to_id = excluded.to_id,
30
+ type = excluded.type, weight = excluded.weight, properties = excluded.properties`,[e.id,e.fromId,e.toId,e.type,e.weight??1,JSON.stringify(e.properties??{})]),this.markDirty(),this.flushIfDirty()}async upsertNodes(e){if(e.length!==0){this.ensureDb().run("BEGIN TRANSACTION");for(const t of e)this.run(`INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
31
+ VALUES (?, ?, ?, ?, ?, ?, ?)
32
+ ON CONFLICT(id) DO UPDATE SET
33
+ type = excluded.type, name = excluded.name, properties = excluded.properties,
34
+ source_record_id = excluded.source_record_id, source_path = excluded.source_path`,[t.id,t.type,t.name,JSON.stringify(t.properties),t.sourceRecordId??null,t.sourcePath??null,t.createdAt??new Date().toISOString()]);this.ensureDb().run("COMMIT"),this.markDirty(),this.flushIfDirty()}}async upsertEdges(e){if(e.length!==0){this.ensureDb().run("BEGIN TRANSACTION");for(const t of e)this.run(`INSERT INTO edges (id, from_id, to_id, type, weight, properties)
35
+ VALUES (?, ?, ?, ?, ?, ?)
36
+ ON CONFLICT(id) DO UPDATE SET
37
+ from_id = excluded.from_id, to_id = excluded.to_id,
38
+ type = excluded.type, weight = excluded.weight, properties = excluded.properties`,[t.id,t.fromId,t.toId,t.type,t.weight??1,JSON.stringify(t.properties??{})]);this.ensureDb().run("COMMIT"),this.markDirty(),this.flushIfDirty()}}async getNode(e){const t=this.query("SELECT * FROM nodes WHERE id = ?",[e]);return t.length>0?T(t[0]):null}async getNeighbors(e,t){const s=t?.direction??"both",i=t?.edgeType,d=t?.limit??50,p=[],n=[],u=new Set,h=`
66
39
  SELECT e.id AS edge_id, e.from_id, e.to_id, e.type AS edge_type, e.weight, e.properties AS edge_props,
67
40
  n.id AS node_id, n.type AS node_type, n.name AS node_name, n.properties AS node_props,
68
41
  n.source_record_id AS node_src_rec, n.source_path AS node_src_path, n.created_at AS node_created
69
- FROM edges e JOIN nodes n ON e.to_id = n.id WHERE e.from_id = ?`,u=`
42
+ FROM edges e JOIN nodes n ON e.to_id = n.id WHERE e.from_id = ?`,_=`
70
43
  SELECT e.id AS edge_id, e.from_id, e.to_id, e.type AS edge_type, e.weight, e.properties AS edge_props,
71
44
  n.id AS node_id, n.type AS node_type, n.name AS node_name, n.properties AS node_props,
72
45
  n.source_record_id AS node_src_rec, n.source_path AS node_src_path, n.created_at AS node_created
73
- FROM edges e JOIN nodes n ON e.from_id = n.id WHERE e.to_id = ?`;if(o==="outgoing"||o==="both"){let c=_;const i=[e];r&&(c+=" AND e.type = ?",i.push(r)),c+=" LIMIT ?",i.push(a);const g=s.prepare(c).all(...i);for(const h of g)d.push(T(h)),E.has(h.node_id)||(E.add(h.node_id),p.push(m(h)))}if(o==="incoming"||o==="both"){let c=u;const i=[e];r&&(c+=" AND e.type = ?",i.push(r)),c+=" LIMIT ?",i.push(a);const g=s.prepare(c).all(...i);for(const h of g)d.push(T(h)),E.has(h.node_id)||(E.add(h.node_id),p.push(m(h)))}return{nodes:p,edges:d}}async traverse(e,t){const s=t?.maxDepth??2,o=t?.direction??"both",r=t?.edgeType,a=t?.limit??50,p=new Map,d=new Map,E=new Set,_=[{nodeId:e,depth:0}];for(;_.length>0&&p.size<a;){const u=_.shift();if(!u||E.has(u.nodeId)||u.depth>s)continue;E.add(u.nodeId);const c=await this.getNeighbors(u.nodeId,{direction:o,edgeType:r,limit:a-p.size});for(const i of c.nodes)p.has(i.id)||(p.set(i.id,i),u.depth+1<s&&_.push({nodeId:i.id,depth:u.depth+1}));for(const i of c.edges)d.set(i.id,i)}return{nodes:[...p.values()],edges:[...d.values()]}}async findNodes(e){const t=this.ensureDb(),s=[],o=[];e.type&&(s.push("type = ?"),o.push(e.type)),e.namePattern&&(s.push("name LIKE ?"),o.push(`%${e.namePattern}%`)),e.sourcePath&&(s.push("source_path = ?"),o.push(e.sourcePath));const r=s.length>0?`WHERE ${s.join(" AND ")}`:"",a=e.limit??100;return t.prepare(`SELECT * FROM nodes ${r} LIMIT ?`).all(...o,a).map(d=>this.toGraphNode(d))}async findEdges(e){const t=this.ensureDb(),s=[],o=[];e.type&&(s.push("type = ?"),o.push(e.type)),e.fromId&&(s.push("from_id = ?"),o.push(e.fromId)),e.toId&&(s.push("to_id = ?"),o.push(e.toId));const r=s.length>0?`WHERE ${s.join(" AND ")}`:"",a=e.limit??100;return t.prepare(`SELECT * FROM edges ${r} LIMIT ?`).all(...o,a).map(d=>this.toGraphEdge(d))}async deleteNode(e){const t=this.ensureDb();t.transaction(()=>{t.prepare("DELETE FROM edges WHERE from_id = ? OR to_id = ?").run(e,e),t.prepare("DELETE FROM nodes WHERE id = ?").run(e)})()}async deleteBySourcePath(e){const t=this.ensureDb(),s=t.prepare("SELECT id FROM nodes WHERE source_path = ?").all(e);return s.length===0?0:(t.transaction(()=>{for(const{id:r}of s)t.prepare("DELETE FROM edges WHERE from_id = ? OR to_id = ?").run(r,r);t.prepare("DELETE FROM nodes WHERE source_path = ?").run(e)})(),s.length)}async clear(){this.ensureDb().exec("DELETE FROM edges; DELETE FROM nodes;")}async getStats(){const e=this.ensureDb(),t=e.prepare("SELECT COUNT(*) as count FROM nodes").get().count,s=e.prepare("SELECT COUNT(*) as count FROM edges").get().count,o=e.prepare("SELECT type, COUNT(*) as count FROM nodes GROUP BY type").all(),r={};for(const d of o)r[d.type]=d.count;const a=e.prepare("SELECT type, COUNT(*) as count FROM edges GROUP BY type").all(),p={};for(const d of a)p[d.type]=d.count;return{nodeCount:t,edgeCount:s,nodeTypes:r,edgeTypes:p}}async close(){this.db&&(this.db.close(),this.db=null)}toGraphNode(e){return{id:e.id,type:e.type,name:e.name,properties:JSON.parse(e.properties),sourceRecordId:e.source_record_id??void 0,sourcePath:e.source_path??void 0,createdAt:e.created_at}}toGraphEdge(e){return{id:e.id,fromId:e.from_id,toId:e.to_id,type:e.type,weight:e.weight??1,properties:JSON.parse(e.properties)}}}function T(n){return{id:n.edge_id,fromId:n.from_id,toId:n.to_id,type:n.edge_type,weight:n.weight??1,properties:JSON.parse(n.edge_props??"{}")}}function m(n){return{id:n.node_id,type:n.node_type,name:n.node_name,properties:JSON.parse(n.node_props??"{}"),sourceRecordId:n.node_src_rec??void 0,sourcePath:n.node_src_path??void 0,createdAt:n.node_created}}export{f as SqliteGraphStore};
46
+ FROM edges e JOIN nodes n ON e.from_id = n.id WHERE e.to_id = ?`;if(s==="outgoing"||s==="both"){let o=h;const c=[e];i&&(o+=" AND e.type = ?",c.push(i)),o+=" LIMIT ?",c.push(d);const a=this.query(o,c);for(const E of a)n.push(y(E)),u.has(E.node_id)||(u.add(E.node_id),p.push(m(E)))}if(s==="incoming"||s==="both"){let o=_;const c=[e];i&&(o+=" AND e.type = ?",c.push(i)),o+=" LIMIT ?",c.push(d);const a=this.query(o,c);for(const E of a)n.push(y(E)),u.has(E.node_id)||(u.add(E.node_id),p.push(m(E)))}return{nodes:p,edges:n}}async traverse(e,t){const s=t?.maxDepth??2,i=t?.direction??"both",d=t?.edgeType,p=t?.limit??50,n=new Map,u=new Map,h=new Set,_=[{nodeId:e,depth:0}];for(;_.length>0&&n.size<p;){const o=_.shift();if(!o||h.has(o.nodeId)||o.depth>s)continue;h.add(o.nodeId);const c=await this.getNeighbors(o.nodeId,{direction:i,edgeType:d,limit:p-n.size});for(const a of c.nodes)n.has(a.id)||(n.set(a.id,a),o.depth+1<s&&_.push({nodeId:a.id,depth:o.depth+1}));for(const a of c.edges)u.set(a.id,a)}return{nodes:[...n.values()],edges:[...u.values()]}}async findNodes(e){const t=[],s=[];e.type&&(t.push("type = ?"),s.push(e.type)),e.namePattern&&(t.push("name LIKE ?"),s.push(`%${e.namePattern}%`)),e.sourcePath&&(t.push("source_path = ?"),s.push(e.sourcePath));const i=t.length>0?`WHERE ${t.join(" AND ")}`:"",d=e.limit??100;return this.query(`SELECT * FROM nodes ${i} LIMIT ?`,[...s,d]).map(n=>T(n))}async findEdges(e){const t=[],s=[];e.type&&(t.push("type = ?"),s.push(e.type)),e.fromId&&(t.push("from_id = ?"),s.push(e.fromId)),e.toId&&(t.push("to_id = ?"),s.push(e.toId));const i=t.length>0?`WHERE ${t.join(" AND ")}`:"",d=e.limit??100;return this.query(`SELECT * FROM edges ${i} LIMIT ?`,[...s,d]).map(n=>O(n))}async deleteNode(e){this.ensureDb().run("BEGIN TRANSACTION"),this.run("DELETE FROM edges WHERE from_id = ? OR to_id = ?",[e,e]),this.run("DELETE FROM nodes WHERE id = ?",[e]),this.ensureDb().run("COMMIT"),this.markDirty(),this.flushIfDirty()}async deleteBySourcePath(e){const t=this.query("SELECT id FROM nodes WHERE source_path = ?",[e]);if(t.length===0)return 0;this.ensureDb().run("BEGIN TRANSACTION");for(const s of t)this.run("DELETE FROM edges WHERE from_id = ? OR to_id = ?",[s.id,s.id]);return this.run("DELETE FROM nodes WHERE source_path = ?",[e]),this.ensureDb().run("COMMIT"),this.markDirty(),this.flushIfDirty(),t.length}async clear(){this.run("DELETE FROM edges"),this.run("DELETE FROM nodes"),this.markDirty(),this.flushIfDirty()}async getStats(){const t=this.query("SELECT COUNT(*) as count FROM nodes")[0]?.count??0,i=this.query("SELECT COUNT(*) as count FROM edges")[0]?.count??0,d=this.query("SELECT type, COUNT(*) as count FROM nodes GROUP BY type"),p={};for(const h of d)p[h.type]=h.count;const n=this.query("SELECT type, COUNT(*) as count FROM edges GROUP BY type"),u={};for(const h of n)u[h.type]=h.count;return{nodeCount:t,edgeCount:i,nodeTypes:p,edgeTypes:u}}async close(){this.db&&(this.flushIfDirty(),this.db.close(),this.db=null)}}function T(r){return{id:r.id,type:r.type,name:r.name,properties:JSON.parse(r.properties),sourceRecordId:r.source_record_id??void 0,sourcePath:r.source_path??void 0,createdAt:r.created_at}}function O(r){return{id:r.id,fromId:r.from_id,toId:r.to_id,type:r.type,weight:r.weight??1,properties:JSON.parse(r.properties)}}function y(r){return{id:r.edge_id,fromId:r.from_id,toId:r.to_id,type:r.edge_type,weight:r.weight??1,properties:JSON.parse(r.edge_props??"{}")}}function m(r){return{id:r.node_id,type:r.node_type,name:r.node_name,properties:JSON.parse(r.node_props??"{}"),sourceRecordId:r.node_src_rec??void 0,sourcePath:r.node_src_path??void 0,createdAt:r.node_created}}export{b as SqliteGraphStore};