@easbot/note 0.2.1 → 0.2.3

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.
@@ -0,0 +1 @@
1
+ 'use strict';var chunkU3YLMQXK_cjs=require('./chunk-U3YLMQXK.cjs');Object.defineProperty(exports,"Log",{enumerable:true,get:function(){return chunkU3YLMQXK_cjs.c}});
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';var chunkGR7YLLW4_cjs=require('./chunks/chunk-GR7YLLW4.cjs'),le=require('better-sqlite3'),utils=require('@easbot/utils'),types=require('@easbot/types'),z=require('fs/promises'),_=require('path'),x=require('jieba-wasm'),ai=require('ai'),crypto=require('crypto'),xdgBasedir=require('xdg-basedir');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var le__default=/*#__PURE__*/_interopDefault(le);var z__default=/*#__PURE__*/_interopDefault(z);var ___namespace=/*#__PURE__*/_interopNamespace(_);var x__namespace=/*#__PURE__*/_interopNamespace(x);var H=(l=>(l.DATABASE_INIT_FAILED="DATABASE_INIT_FAILED",l.DATABASE_NOT_INITIALIZED="DATABASE_NOT_INITIALIZED",l.DATABASE_QUERY_FAILED="DATABASE_QUERY_FAILED",l.DOCUMENT_PARSE_FAILED="DOCUMENT_PARSE_FAILED",l.EMBEDDING_FAILED="EMBEDDING_FAILED",l.ENTITY_EXTRACTION_FAILED="ENTITY_EXTRACTION_FAILED",l.SEARCH_FAILED="SEARCH_FAILED",l.NODE_NOT_FOUND="NODE_NOT_FOUND",l.EDGE_NOT_FOUND="EDGE_NOT_FOUND",l.INVALID_CONFIG="INVALID_CONFIG",l.MODEL_INJECTION_FAILED="MODEL_INJECTION_FAILED",l))(H||{}),R=class extends Error{constructor(t,r,n){super(t,{cause:n});this.code=r;this.cause=n;this.name="KnowledgeBaseError";}toString(){return `${this.name}: ${this.message} (${this.code})`}};var G=class{constructor(e){chunkGR7YLLW4_cjs.a(this,"db",null);chunkGR7YLLW4_cjs.a(this,"storagePath");chunkGR7YLLW4_cjs.a(this,"initialized",false);chunkGR7YLLW4_cjs.a(this,"initPromise",null);this.storagePath=utils.Filesystem.toUnixPath(e);}async initialize(){if(!this.initialized){if(this.initPromise){await this.initPromise;return}this.initPromise=this.doInitialize(),await this.initPromise,this.initialized=true;}}async doInitialize(){try{this.db=await this.openDatabaseAsync(),this.createTables();}catch(e){throw new R(`Database initialization failed: ${e.message}`,"DATABASE_INIT_FAILED",e)}}async openDatabaseAsync(){return new Promise((e,t)=>{setImmediate(()=>{try{let r=new le__default.default(this.storagePath);r.pragma("journal_mode = WAL"),r.pragma("synchronous = NORMAL"),r.pragma("cache_size = -64000"),r.pragma("temp_store = MEMORY"),e(r);}catch(r){t(r);}});})}ensureInitialized(){if(!this.initialized||!this.db)throw new R("Database not initialized. Call initialize() first.","DATABASE_NOT_INITIALIZED")}createTables(){if(!this.db)throw new R("Database not initialized. Call initialize() first.","DATABASE_NOT_INITIALIZED");let e=this.db;e.exec(`
1
+ 'use strict';var chunkU3YLMQXK_cjs=require('./chunks/chunk-U3YLMQXK.cjs'),ue=require('better-sqlite3'),utils=require('@easbot/utils'),types=require('@easbot/types'),U=require('fs/promises'),B=require('path'),crypto=require('crypto'),v=require('jieba-wasm'),ai=require('ai'),xdgBasedir=require('xdg-basedir');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var ue__default=/*#__PURE__*/_interopDefault(ue);var U__default=/*#__PURE__*/_interopDefault(U);var B__namespace=/*#__PURE__*/_interopNamespace(B);var v__namespace=/*#__PURE__*/_interopNamespace(v);var H=(d=>(d.DATABASE_INIT_FAILED="DATABASE_INIT_FAILED",d.DATABASE_NOT_INITIALIZED="DATABASE_NOT_INITIALIZED",d.DATABASE_QUERY_FAILED="DATABASE_QUERY_FAILED",d.DOCUMENT_PARSE_FAILED="DOCUMENT_PARSE_FAILED",d.EMBEDDING_FAILED="EMBEDDING_FAILED",d.ENTITY_EXTRACTION_FAILED="ENTITY_EXTRACTION_FAILED",d.SEARCH_FAILED="SEARCH_FAILED",d.NODE_NOT_FOUND="NODE_NOT_FOUND",d.EDGE_NOT_FOUND="EDGE_NOT_FOUND",d.INVALID_CONFIG="INVALID_CONFIG",d.MODEL_INJECTION_FAILED="MODEL_INJECTION_FAILED",d))(H||{}),R=class extends Error{constructor(t,r,n){super(t,{cause:n});chunkU3YLMQXK_cjs.a(this,"code",r);chunkU3YLMQXK_cjs.a(this,"cause",n);this.name="KnowledgeBaseError";}toString(){return `${this.name}: ${this.message} (${this.code})`}};var X=class{constructor(e){chunkU3YLMQXK_cjs.a(this,"db",null);chunkU3YLMQXK_cjs.a(this,"storagePath");chunkU3YLMQXK_cjs.a(this,"initialized",false);chunkU3YLMQXK_cjs.a(this,"initPromise",null);this.storagePath=utils.Filesystem.normalize(e);}async initialize(){if(!this.initialized){if(this.initPromise){await this.initPromise;return}this.initPromise=this.doInitialize(),await this.initPromise,this.initialized=true;}}async doInitialize(){try{this.db=await this.openDatabaseAsync(),this.createTables();}catch(e){throw new R(`Database initialization failed: ${e.message}`,"DATABASE_INIT_FAILED",e)}}async openDatabaseAsync(){return new Promise((e,t)=>{setImmediate(()=>{try{let r=new ue__default.default(this.storagePath);r.pragma("journal_mode = WAL"),r.pragma("synchronous = NORMAL"),r.pragma("cache_size = -64000"),r.pragma("temp_store = MEMORY"),e(r);}catch(r){t(r);}});})}ensureInitialized(){if(!this.initialized||!this.db)throw new R("Database not initialized. Call initialize() first.","DATABASE_NOT_INITIALIZED")}createTables(){if(!this.db)throw new R("Database not initialized. Call initialize() first.","DATABASE_NOT_INITIALIZED");let e=this.db;e.exec(`
2
2
  CREATE TABLE IF NOT EXISTS nodes (
3
3
  id INTEGER PRIMARY KEY AUTOINCREMENT,
4
4
  name TEXT NOT NULL,
@@ -81,22 +81,23 @@
81
81
  `),e.pragma("foreign_keys = ON");}query(e,t){if(!this.db)throw new Error("Database not initialized");try{let r=this.db.prepare(e);return t?r.all(...t):r.all()}catch(r){throw new R(`Query failed: ${r.message}`,"DATABASE_QUERY_FAILED",r)}}run(e,t){if(!this.db)throw new Error("Database not initialized");try{let r=this.db.prepare(e),n=t?r.run(...t):r.run();return {lastID:Number(n.lastInsertRowid),changes:n.changes}}catch(r){throw new R(`Execution failed: ${r.message}`,"DATABASE_QUERY_FAILED",r)}}transaction(e){if(!this.db)throw new Error("Database not initialized");return this.db.transaction(e)()}async close(){this.db&&(this.db.close(),this.db=null);}getPath(){return this.storagePath}getDb(){if(!this.db)throw new Error("Database not initialized");return this.db}async getDocumentsCount(){return (await this.query("SELECT COUNT(*) as count FROM documents"))[0]?.count??0}async getChunksCount(){return (await this.query("SELECT COUNT(*) as count FROM chunks"))[0]?.count??0}async getNodesCount(){return (await this.query("SELECT COUNT(*) as count FROM nodes"))[0]?.count??0}async getEdgesCount(){return (await this.query("SELECT COUNT(*) as count FROM edges"))[0]?.count??0}async isVectorSearchAvailable(){try{return ((await this.query("SELECT COUNT(*) as count FROM vectors"))[0]?.count??0)>0}catch{return false}}async healthCheck(){try{return this.db?(await this.query("SELECT 1"),!0):!1}catch{return false}}getMeta(e){if(!this.db)throw new Error("Database not initialized");return this.db.prepare("SELECT value FROM meta WHERE key = ?").get(e)?.value??null}setMeta(e,t){if(!this.db)throw new Error("Database not initialized");this.db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run(e,t);}getAllDocumentPaths(){if(!this.db)throw new Error("Database not initialized");return this.db.prepare("SELECT path FROM documents").all().map(t=>t.path)}getDocumentIdByPath(e){if(!this.db)throw new Error("Database not initialized");return this.db.prepare("SELECT id FROM documents WHERE path = ?").get(e)?.id??null}getChunkIdsByDocumentId(e){if(!this.db)throw new Error("Database not initialized");return this.db.prepare("SELECT id FROM chunks WHERE documentId = ?").all(e).map(r=>r.id)}cleanupDocumentData(e){if(!this.db)throw new Error("Database not initialized");this.transaction(()=>{let t=this.db.prepare("SELECT id, nodeIds, contentHash FROM chunks WHERE documentId = ?").all(e);if(t.length===0){this.run("DELETE FROM documents WHERE id = ?",[e]);return}let r=t.map(s=>s.id),n=t.map(s=>s.contentHash),o=new Set;for(let s of t)if(s.nodeIds)try{let i=JSON.parse(s.nodeIds);for(let c of i)o.add(c);}catch{}if(r.length>0){let s=r.map(()=>"?").join(",");try{this.run(`DELETE FROM chunks_fts WHERE chunkId IN (${s})`,r);}catch{for(let i of r)try{this.run("DELETE FROM chunks_fts WHERE chunkId = ?",[i]);}catch{}}}if(o.size>0){let s=Array.from(o),i=this.db.prepare(`
82
82
  SELECT nodeIds FROM chunks
83
83
  WHERE documentId != ?
84
- `).all(e),c=new Set;for(let a of i)if(a.nodeIds)try{let d=JSON.parse(a.nodeIds);for(let l of d)c.add(l);}catch{}for(let a of s)c.has(a)||this.run("DELETE FROM nodes WHERE id = ?",[a]);}if(n.length>0)for(let s of n){let i=this.db.prepare("SELECT COUNT(*) as count FROM chunks WHERE contentHash = ? AND documentId != ?").get(s,e);(!i||i.count===0)&&this.run("DELETE FROM embedding_cache WHERE contentHash = ?",[s]);}this.run("DELETE FROM chunks WHERE documentId = ?",[e]),this.run("DELETE FROM documents WHERE id = ?",[e]);});}deleteDocumentByPath(e){let t=this.getDocumentIdByPath(e);return t===null?false:(this.cleanupDocumentData(t),true)}};var U=class{async parse(e){try{let t=await z.readFile(e,"utf-8"),r=_.extname(e).toLowerCase(),n=this.parseMarkdown(t);return {content:n.content,metadata:n.metadata}}catch(t){throw new R(`\u6587\u6863\u89E3\u6790\u5931\u8D25: ${t.message}`,"DOCUMENT_PARSE_FAILED",t)}}parseMarkdown(e){let{frontmatter:t,content:r}=utils.Markdown.extractFrontmatter(e),n={};t.title!==void 0&&(n.title=String(t.title)),t.author!==void 0&&(n.author=String(t.author)),t.date!==void 0&&(n.date=String(t.date));for(let[s,i]of Object.entries(t))["title","author","date"].includes(s)||(n[s]=i);return {content:utils.Markdown.format(r),metadata:n}}static computeHash(e){let t=0;for(let r=0;r<e.length;r++){let n=e.charCodeAt(r);t=(t<<5)-t+n,t=t&t;}return Math.abs(t).toString(16)}};var v=chunkGR7YLLW4_cjs.c.create({service:"note.tokenizer"}),F=false,fe=utils.loadTextFile("./assets/jieba_dict.txt",chunkGR7YLLW4_cjs.b);async function rt(E){if(!F)try{v.info("Initializing jieba tokenizer");let e=fe();if(x__namespace.with_dict(e),v.info("Built-in dictionary loaded"),E?.dictPath&&E.dictPath.length>0)for(let t of E.dictPath)await ye(t);F=!0,v.info("Jieba tokenizer initialized");}catch(e){throw v.error("Failed to initialize jieba tokenizer",{error:String(e)}),e}}async function ye(E){if(!F)throw new Error("Tokenizer not initialized");try{let e=await utils.Filesystem.readText(E);x__namespace.with_dict(e),v.info("Custom dictionary loaded",{dictPath:E});}catch(e){v.warn("Failed to load custom dictionary",{dictPath:E,error:String(e)});}}function be(E){if(!F)return E.split(/\s+/).filter(Boolean);try{return x__namespace.cut(E)}catch(e){return v.warn("Tokenization failed, using fallback",{error:String(e)}),E.split(/\s+/).filter(Boolean)}}function Ie(E){if(!F)return E.split(/\s+/).filter(Boolean);try{return x__namespace.cut_for_search(E)}catch(e){return v.warn("Tokenization for search failed, using fallback",{error:String(e)}),E.split(/\s+/).filter(Boolean)}}function nt(E,e,t){if(F)try{x__namespace.add_word(E,e,t);}catch(r){v.warn("Failed to add word",{word:E,error:String(r)});}}function st(){return F}async function it(){F=false,v.info("Tokenizer closed");}function se(E){return be(E).join(" ")}function ie(E){return Ie(E).join(" ")}exports.Llm=void 0;(u=>{let E=chunkGR7YLLW4_cjs.c.create({service:"note-llm"}),e=null,t=()=>{if(!e)throw new Error("Llm is not initialized. Please call Llm.init() first.");return e};function r(m){n()||(e={models:m.models,options:{graph:m.options?.graph,rerankTopN:m.options?.rerankTopN}},E.debug("Llm initialized"));}u.init=r;function n(){return e!==null}u.isInitialized=n;function o(){return e?{embedding:!!e.models.embeddingLlm,graphLlm:!!e.models.graphLlm,rerankLlm:!!e.models.rerankLlm}:{embedding:false,graphLlm:false,rerankLlm:false}}u.capabilities=o;async function s(m){let f=t().models.embeddingLlm;if(!f)throw new Error("embeddingLlm model is not configured.");let y=await ai.embed({model:f,value:m});return new Float32Array(y.embedding)}u.embedText=s;async function i(m){let f=t().models.embeddingLlm;if(!f)throw new Error("embeddingLlm model is not configured.");return (await ai.embedMany({model:f,values:m})).embeddings.map(b=>new Float32Array(b))}u.embedTexts=i;async function c(m,h){let f=t(),y=f.models.graphLlm;if(!y)return "";let b=d(m);return (await ai.streamText({model:y,prompt:b,maxOutputTokens:h?.maxOutputTokens??f.options.graph?.maxOutputTokens,temperature:h?.temperature??f.options.graph?.temperature})).text}u.generateGraph=c;async function a(m,h,f){let y=t();return y.models.rerankLlm?(await ai.rerank({model:y.models.rerankLlm,query:m,documents:h,topN:f??y.options.rerankTopN??h.length})).ranking.map(S=>({index:S.originalIndex,score:S.score??0})):[]}u.rerank=a;function d(m){let h=types.GRAPH_ENTITY_TYPE_DEFINITIONS.map(S=>`- ${S.type}: ${S.rule}`).join(`
85
- `),f=types.GRAPH_RELATION_TYPE_DEFINITIONS.map(S=>`- ${S.type}: ${S.rule}`).join(`
86
- `),b=m.slice(0,5).join(`
84
+ `).all(e),c=new Set;for(let a of i)if(a.nodeIds)try{let l=JSON.parse(a.nodeIds);for(let d of l)c.add(d);}catch{}for(let a of s)c.has(a)||this.run("DELETE FROM nodes WHERE id = ?",[a]);}if(n.length>0)for(let s of n){let i=this.db.prepare("SELECT COUNT(*) as count FROM chunks WHERE contentHash = ? AND documentId != ?").get(s,e);(!i||i.count===0)&&this.run("DELETE FROM embedding_cache WHERE contentHash = ?",[s]);}this.run("DELETE FROM chunks WHERE documentId = ?",[e]),this.run("DELETE FROM documents WHERE id = ?",[e]);});}deleteDocumentByPath(e){let t=this.getDocumentIdByPath(e);return t===null?false:(this.cleanupDocumentData(t),true)}};var P=class{async parse(e){try{let t=await U.readFile(e,"utf-8"),r=B.extname(e).toLowerCase(),n=this.parseMarkdown(t);return {content:n.content,metadata:n.metadata}}catch(t){throw new R(`\u6587\u6863\u89E3\u6790\u5931\u8D25: ${t.message}`,"DOCUMENT_PARSE_FAILED",t)}}parseMarkdown(e){let{frontmatter:t,content:r}=utils.Markdown.extractFrontmatter(e),n={};t.title!==void 0&&(n.title=String(t.title)),t.author!==void 0&&(n.author=String(t.author)),t.date!==void 0&&(n.date=String(t.date));for(let[s,i]of Object.entries(t))["title","author","date"].includes(s)||(n[s]=i);return {content:utils.Markdown.format(r),metadata:n}}static computeHash(e){return crypto.createHash("sha256").update(e,"utf-8").digest("hex")}};var M=chunkU3YLMQXK_cjs.c.create({service:"note.tokenizer"}),x=false,fe=utils.loadTextFile("./assets/jieba_dict.txt",chunkU3YLMQXK_cjs.b);async function it(E){if(!x)try{M.info("Initializing jieba tokenizer");let e=fe();if(v__namespace.with_dict(e),M.info("Built-in dictionary loaded"),E?.dictPath&&E.dictPath.length>0)for(let t of E.dictPath)await ye(t);x=!0,M.info("Jieba tokenizer initialized");}catch(e){throw M.error("Failed to initialize jieba tokenizer",{error:String(e)}),e}}async function ye(E){if(!x)throw new Error("Tokenizer not initialized");try{let e=await utils.Filesystem.readText(E);v__namespace.with_dict(e),M.info("Custom dictionary loaded",{dictPath:E});}catch(e){M.warn("Failed to load custom dictionary",{dictPath:E,error:String(e)});}}function be(E){if(!x)return E.split(/\s+/).filter(Boolean);try{return v__namespace.cut(E)}catch(e){return M.warn("Tokenization failed, using fallback",{error:String(e)}),E.split(/\s+/).filter(Boolean)}}function Ie(E){if(!x)return E.split(/\s+/).filter(Boolean);try{return v__namespace.cut_for_search(E)}catch(e){return M.warn("Tokenization for search failed, using fallback",{error:String(e)}),E.split(/\s+/).filter(Boolean)}}function ot(E,e,t){if(x)try{v__namespace.add_word(E,e,t);}catch(r){M.warn("Failed to add word",{word:E,error:String(r)});}}function at(){return x}async function ct(){x=false,M.info("Tokenizer closed");}function ne(E){return be(E).join(" ")}function se(E){return Ie(E).join(" ")}exports.Llm=void 0;(u=>{let E=chunkU3YLMQXK_cjs.c.create({service:"note-llm"}),e=null,t=()=>{if(!e)throw new Error("Llm is not initialized. Please call Llm.init() first.");return e};function r(h){n()||(e={models:h.models,options:{graph:h.options?.graph,rerankTopN:h.options?.rerankTopN}},E.debug("Llm initialized"));}u.init=r;function n(){return e!==null}u.isInitialized=n;function o(){return e?{embedding:!!e.models.embeddingLlm,graphLlm:!!e.models.graphLlm,rerankLlm:!!e.models.rerankLlm}:{embedding:false,graphLlm:false,rerankLlm:false}}u.capabilities=o;async function s(h){let f=t().models.embeddingLlm;if(!f)throw new Error("embeddingLlm model is not configured.");let b=await ai.embed({model:f,value:h});return new Float32Array(b.embedding)}u.embedText=s;async function i(h){let f=t().models.embeddingLlm;if(!f)throw new Error("embeddingLlm model is not configured.");return (await ai.embedMany({model:f,values:h})).embeddings.map(N=>new Float32Array(N))}u.embedTexts=i;async function c(h,g){let f=t(),b=f.models.graphLlm;if(!b)return "";let N=l(h);return (await ai.streamText({model:b,prompt:N,maxOutputTokens:g?.maxOutputTokens??f.options.graph?.maxOutputTokens,temperature:g?.temperature??f.options.graph?.temperature})).text}u.generateGraph=c;async function a(h,g,f){let b=t();return b.models.rerankLlm?(await ai.rerank({model:b.models.rerankLlm,query:h,documents:g,topN:f??b.options.rerankTopN??g.length})).ranking.map(T=>({index:T.originalIndex,score:T.score??0})):[]}u.rerank=a;function l(h){let g=types.GRAPH_ENTITY_TYPE_DEFINITIONS.map(T=>`- ${T.type}: ${T.rule}`).join(`
85
+ `),f=types.GRAPH_RELATION_TYPE_DEFINITIONS.map(T=>`- ${T.type}: ${T.rule}`).join(`
86
+ `),N=h.slice(0,5).join(`
87
87
 
88
88
  `).slice(0,2e3);return `You are an information extraction engine for a general-purpose memory graph.
89
89
 
90
- Extract entities and directed relations from the text.
90
+ Extract entities and directed relations from the text, and generate a concise summary.
91
91
 
92
92
  Entity type taxonomy:
93
- ${h}
93
+ ${g}
94
94
 
95
95
  Relation type taxonomy:
96
96
  ${f}
97
97
 
98
98
  Extraction rules:
99
99
  - Output valid JSON only. Do not include markdown, prose, or code fences.
100
+ - summary: A concise summary (max 250 characters) describing the main topic and key points.
100
101
  - Use canonical, concise entity names (deduplicated, case-insensitive).
101
102
  - Prefer specific entity types over "keyword".
102
103
  - Include relation only if both source and target entities are present in the entities list.
@@ -106,6 +107,7 @@ Extraction rules:
106
107
 
107
108
  Return this exact JSON shape:
108
109
  {
110
+ "summary": "A concise summary of the text content (max 250 characters)",
109
111
  "entities": [
110
112
  { "name": "string", "type": "one_of_entity_types", "properties": {} }
111
113
  ],
@@ -115,12 +117,12 @@ Return this exact JSON shape:
115
117
  }
116
118
 
117
119
  Input text:
118
- ${b}`}u.embed=s,u.embedMany=i;})(exports.Llm||(exports.Llm={}));var Z=chunkGR7YLLW4_cjs.c.create({service:"note-ingestion"}),ke=new Set(types.GRAPH_ENTITY_TYPE_DEFINITIONS.map(E=>E.type)),De=new Set(types.GRAPH_RELATION_TYPE_DEFINITIONS.map(E=>E.type)),X=class{constructor(e,t){chunkGR7YLLW4_cjs.a(this,"db");chunkGR7YLLW4_cjs.a(this,"config");chunkGR7YLLW4_cjs.a(this,"parser");this.db=e,this.config={...types.DEFAULT_NOTE_CHUNK_CONFIG,...t,embeddingLlm:t.embeddingLlm},this.parser=new U,t.embeddingLlm&&exports.Llm.init({models:{embeddingLlm:t.embeddingLlm,graphLlm:t.graphLlm,rerankLlm:t.rerankLlm}});}async process(e){let t=utils.Filesystem.toUnixPath(e),{content:r,metadata:n}=await this.parser.parse(e),o=U.computeHash(r),s=this.db.query("SELECT id, contentHash FROM documents WHERE path = ?",[t]);if(s.length>0&&s[0]?.contentHash===o){let m=this.db.query("SELECT id FROM chunks WHERE documentId = ?",[s[0].id]).flatMap(y=>{let b=this.db.query("SELECT nodeIds FROM chunks WHERE id = ?",[y.id]);return b[0]?.nodeIds?JSON.parse(b[0].nodeIds):[]}),h=new Set(m).size,f=this.db.query(`SELECT id FROM edges WHERE source IN (${Array.from({length:h},()=>"?").join(",")})`,[...new Set(m)]).length;return {documentId:s[0].id,chunksCreated:0,vectorsCreated:0,entitiesExtracted:h,relationsExtracted:f}}let i=this.chunk(r),c=await this.embedWithCache(i),a=new Map,d,l,g=this.extractEntitiesSync(i);if(d=g.entities.length,l=g.relations.length,this.mapChunksToNodes(i,g.entities,a),this.storeEntities(g.entities,g.relations),this.config.graphLlm){let u=t;this.extractEntities(i).then(m=>{(m.entities.length>g.entities.length||m.relations.length>g.relations.length)&&(this.mergeEntitiesAndRelations(u,m.entities,m.relations),Z.debug("LLM entity extraction completed in background",{path:u,entities:m.entities.length,relations:m.relations.length}));}).catch(m=>{Z.warn("Background graph extraction failed",{path:u,error:String(m)});});}return this.db.transaction(()=>{s.length>0&&this.db.cleanupDocumentData(s[0].id);let m=this.db.run(`INSERT INTO documents (path, title, contentHash, summary, metadata, lastModified, createdAt, updatedAt)
119
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[t,n.title||___namespace.basename(e)||"Untitled",o,null,n.title?JSON.stringify(n):null,new Date().toISOString(),new Date().toISOString(),new Date().toISOString()]).lastID,h=0,f=0;r.split(`
120
- `);let b=0,S=0,$=[];for(let O=0;O<i.length;O++){let k=i[O],p=k.split(`
121
- `).length-1;$.push({startLine:S,endLine:S+p,startChar:b,endChar:b+k.length});let I=this.config.chunkOverlap;b=b+Math.max(1,k.length-I);let T=Math.floor(I/20);S=S+Math.max(1,p-T);}for(let O=0;O<i.length;O++){let k=i[O],p=U.computeHash(k),I=a.get(O)||[],T=$[O],P=this.db.run(`INSERT INTO chunks (documentId, startLine, endLine, startChar, endChar, content, contentHash, nodeIds, createdAt)
122
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[m,T.startLine,T.endLine,T.startChar,T.endChar,k,p,JSON.stringify(I),new Date().toISOString()]).lastID,q=c[O];q&&(this.db.run("INSERT INTO vectors (chunkId, embedding) VALUES (?, ?)",[P,this.float32ToBuffer(q)]),f++);let B=se(k);this.db.run("INSERT INTO chunks_fts (chunkId, documentId, content) VALUES (?, ?, ?)",[P,m,B]),h++;}return {documentId:m,chunksCreated:h,vectorsCreated:f,entitiesExtracted:d,relationsExtracted:l}})}async processBatch(e,t){let r=[];for(let n=0;n<e.length;n++){let o=await this.process(e[n]);r.push(o),t?.(n+1,e.length,o);}return r}chunk(e){let{chunkSize:t,minChunkLength:r=100}=this.config;return utils.Markdown.chunk(e,t,{minLength:r})}async embedWithCache(e){if(!this.config.embeddingLlm)return e.map(()=>new Float32Array(this.config.vectorDims));let t=[],r=[];for(let n=0;n<e.length;n++){let o=e[n],s=U.computeHash(o),i=this.db.query("SELECT embedding FROM embedding_cache WHERE contentHash = ?",[s]);i.length>0&&i[0]?.embedding?t[n]=new Float32Array(i[0].embedding.buffer,i[0].embedding.byteOffset,i[0].embedding.length/4):r.push({index:n,content:o,hash:s});}if(r.length>0)try{let n=r.map(s=>s.content),o=await exports.Llm.embedMany(n);for(let s=0;s<r.length;s++){let{index:i,hash:c}=r[s],a=o[s];if(a){let d=new Float32Array(a);t[i]=d,this.ensureVectorDims(d.length),this.db.run("INSERT OR REPLACE INTO embedding_cache (contentHash, embedding, createdAt) VALUES (?, ?, ?)",[c,this.float32ToBuffer(d),new Date().toISOString()]);}}}catch(n){throw new R(`\u5D4C\u5165\u751F\u6210\u5931\u8D25: ${n.message}`,"EMBEDDING_FAILED",n)}return t}async embed(e){if(!this.config.embeddingLlm)return e.map(()=>new Float32Array(this.config.vectorDims));try{return await exports.Llm.embedMany(e)}catch(t){throw new R(`\u5D4C\u5165\u751F\u6210\u5931\u8D25: ${t.message}`,"EMBEDDING_FAILED",t)}}async extractEntities(e){let t=e.slice(0,5).join(`
120
+ ${N}`}u.embed=s,u.embedMany=i;})(exports.Llm||(exports.Llm={}));var Y=chunkU3YLMQXK_cjs.c.create({service:"note-ingestion"}),ke=new Set(types.GRAPH_ENTITY_TYPE_DEFINITIONS.map(E=>E.type)),De=new Set(types.GRAPH_RELATION_TYPE_DEFINITIONS.map(E=>E.type)),Q=class{constructor(e,t){chunkU3YLMQXK_cjs.a(this,"db");chunkU3YLMQXK_cjs.a(this,"config");chunkU3YLMQXK_cjs.a(this,"parser");this.db=e,this.config={...types.DEFAULT_NOTE_CHUNK_CONFIG,...t,embeddingLlm:t.embeddingLlm},this.parser=new P,t.embeddingLlm&&exports.Llm.init({models:{embeddingLlm:t.embeddingLlm,graphLlm:t.graphLlm,rerankLlm:t.rerankLlm}});}async process(e){let t=utils.Filesystem.normalize(e),{content:r,metadata:n}=await this.parser.parse(e),o=P.computeHash(r),s=this.db.query("SELECT id, contentHash FROM documents WHERE path = ?",[t]);if(s.length>0&&s[0]?.contentHash===o){let g=this.db.query("SELECT id FROM chunks WHERE documentId = ?",[s[0].id]).flatMap(N=>{let T=this.db.query("SELECT nodeIds FROM chunks WHERE id = ?",[N.id]);return T[0]?.nodeIds?JSON.parse(T[0].nodeIds):[]}),f=new Set(g).size,b=this.db.query(`SELECT id FROM edges WHERE source IN (${Array.from({length:f},()=>"?").join(",")})`,[...new Set(g)]).length;return {documentId:s[0].id,chunksCreated:0,vectorsCreated:0,entitiesExtracted:f,relationsExtracted:b}}let i=this.chunk(r),c=await this.embedWithCache(i),a=new Map,l,d,m="",u=this.extractEntitiesSync(i);if(l=u.entities.length,d=u.relations.length,this.mapChunksToNodes(i,u.entities,a),this.storeEntities(u.entities,u.relations),this.config.graphLlm){let h=t;this.extractEntities(i).then(g=>{m=g.summary,this.mergeEntitiesAndRelations(h,g.entities,g.relations,g.summary),Y.debug("LLM entity extraction completed in background",{path:h,entities:g.entities.length,relations:g.relations.length,summary:g.summary});}).catch(g=>{Y.warn("Background graph extraction failed",{path:h,error:String(g)});});}return this.db.transaction(()=>{s.length>0&&this.db.cleanupDocumentData(s[0].id);let g=this.db.run(`INSERT INTO documents (path, title, contentHash, summary, metadata, lastModified, createdAt, updatedAt)
121
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[t,n.title||B__namespace.basename(e)||"Untitled",o,typeof m=="string"&&m.length>0?m:typeof u.summary=="string"?u.summary:"",JSON.stringify(n||{}),new Date().toISOString(),new Date().toISOString(),new Date().toISOString()]).lastID,f=0,b=0;r.split(`
122
+ `);let T=0,_=0,$=[];for(let L=0;L<i.length;L++){let p=i[L],I=p.split(`
123
+ `).length-1;$.push({startLine:_,endLine:_+I,startChar:T,endChar:T+p.length});let S=this.config.chunkOverlap;T=T+Math.max(1,p.length-S);let w=Math.floor(S/20);_=_+Math.max(1,I-w);}for(let L=0;L<i.length;L++){let p=i[L],I=P.computeHash(p),S=a.get(L)||[],w=$[L],q=this.db.run(`INSERT INTO chunks (documentId, startLine, endLine, startChar, endChar, content, contentHash, nodeIds, createdAt)
124
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[g,w.startLine,w.endLine,w.startChar,w.endChar,p,I,JSON.stringify(S),new Date().toISOString()]).lastID,z=c[L];z&&(this.db.run("INSERT INTO vectors (chunkId, embedding) VALUES (?, ?)",[q,this.float32ToBuffer(z)]),b++);let K=ne(p);this.db.run("INSERT INTO chunks_fts (chunkId, documentId, content) VALUES (?, ?, ?)",[q,g,K]),f++;}return {documentId:g,chunksCreated:f,vectorsCreated:b,entitiesExtracted:l,relationsExtracted:d}})}async processBatch(e,t){let r=[];for(let n=0;n<e.length;n++){let o=await this.process(e[n]);r.push(o),t?.(n+1,e.length,o);}return r}chunk(e){let{chunkSize:t,minChunkLength:r=100}=this.config;return utils.Markdown.chunk(e,t,{minLength:r})}async embedWithCache(e){if(!this.config.embeddingLlm)return e.map(()=>new Float32Array(this.config.vectorDims));let t=[],r=[];for(let n=0;n<e.length;n++){let o=e[n],s=P.computeHash(o),i=this.db.query("SELECT embedding FROM embedding_cache WHERE contentHash = ?",[s]);i.length>0&&i[0]?.embedding?t[n]=new Float32Array(i[0].embedding.buffer,i[0].embedding.byteOffset,i[0].embedding.length/4):r.push({index:n,content:o,hash:s});}if(r.length>0)try{let n=r.map(s=>s.content),o=await exports.Llm.embedMany(n);for(let s=0;s<r.length;s++){let{index:i,hash:c}=r[s],a=o[s];if(a){let l=new Float32Array(a);t[i]=l,this.ensureVectorDims(l.length),this.db.run("INSERT OR REPLACE INTO embedding_cache (contentHash, embedding, createdAt) VALUES (?, ?, ?)",[c,this.float32ToBuffer(l),new Date().toISOString()]);}}}catch(n){throw new R(`\u5D4C\u5165\u751F\u6210\u5931\u8D25: ${n.message}`,"EMBEDDING_FAILED",n)}return t}async embed(e){if(!this.config.embeddingLlm)return e.map(()=>new Float32Array(this.config.vectorDims));try{return await exports.Llm.embedMany(e)}catch(t){throw new R(`\u5D4C\u5165\u751F\u6210\u5931\u8D25: ${t.message}`,"EMBEDDING_FAILED",t)}}async extractEntities(e){let t=e.slice(0,5).join(`
123
125
 
124
126
  `);if(!this.config.graphLlm)return this.extractEntitiesByRules(t);try{let r=await exports.Llm.generateGraph(e,{maxOutputTokens:2e3}),n=this.parseEntityExtractionResult(r);return n.entities.length===0&&n.relations.length===0?this.extractEntitiesByRules(t):n}catch(r){if(r instanceof Error)return this.extractEntitiesByRules(t);throw new R(`\u5B9E\u4F53\u63D0\u53D6\u5931\u8D25: ${String(r)}`,"ENTITY_EXTRACTION_FAILED")}}extractEntitiesSync(e){let t=e.slice(0,5).join(`
125
127
 
126
- `);return this.extractEntitiesByRules(t)}parseEntityExtractionResult(e){try{let t=e.match(/\{[\s\S]*\}/);if(t){let r=JSON.parse(t[0]);return this.normalizeExtractionResult(r)}}catch(t){Z.debug("Failed to parse entity extraction result",{error:String(t)});}return {entities:[],relations:[]}}normalizeExtractionResult(e){let t=e,r=Array.isArray(t.entities)?t.entities:[],n=Array.isArray(t.relations)?t.relations:[],o=[],s=new Set,i=new Map;for(let d of r){let l=typeof d?.name=="string"?d.name.trim():"";if(!l)continue;let g=l.toLowerCase();if(s.has(g))continue;s.add(g),i.set(g,l);let u=typeof d?.type=="string"?d.type.trim():"",m=ke.has(u)?u:"keyword",h=d?.properties&&typeof d.properties=="object"&&!Array.isArray(d.properties)?d.properties:{};o.push({name:l,type:m,properties:h});}let c=[],a=new Set;for(let d of n){let l=typeof d?.source=="string"?d.source.trim():"",g=typeof d?.target=="string"?d.target.trim():"";if(!l||!g)continue;let u=i.get(l.toLowerCase()),m=i.get(g.toLowerCase());if(!u||!m||u===m)continue;let h=typeof d?.relation=="string"?d.relation.trim():"",f=De.has(h)?h:"related_to",y=`${u.toLowerCase()}|${m.toLowerCase()}|${f}`;a.has(y)||(a.add(y),c.push({source:u,target:m,relation:f}));}return {entities:o,relations:c}}extractEntitiesByRules(e){let t=[],r=[],n=new Set,o=new Set,s=new Map,i=/([A-Za-z][\w.-]{1,80})\s+(is_a|part_of|has_attribute|located_in|occurs_in|causes|influences|owned_by|member_of|uses|depends_on|related_to)\s+([A-Za-z][\w.-]{1,80})/g;for(let d of e.matchAll(i)){let l=this.sanitizeEntityToken(d[1]??""),g=(d[2]??"related_to").trim(),u=this.sanitizeEntityToken(d[3]??"");if(!l||!u||l===u)continue;let m=l.toLowerCase(),h=u.toLowerCase();n.has(m)||(n.add(m),s.set(m,l),t.push({name:l,type:this.inferEntityType(l),properties:{source:"rule_extracted"}})),n.has(h)||(n.add(h),s.set(h,u),t.push({name:u,type:this.inferEntityType(u),properties:{source:"rule_extracted"}}));let f=`${m}|${h}|${g}`;o.has(f)||(o.add(f),r.push({source:l,target:u,relation:g}));}let c=e.match(/[\p{L}\p{N}][\p{L}\p{N}_.-]{1,80}/gu)??[],a=e.split(/\n\s*\n/);for(let d of c){let l=this.sanitizeEntityToken(d);if(!l)continue;let g=l.toLowerCase();n.has(g)||(n.add(g),s.set(g,l),t.push({name:l,type:this.inferEntityType(l),properties:{source:"keyword_extracted"}}));}for(let d of a){if(d.trim().length<20)continue;let l=[];for(let g of d.match(/[\p{L}\p{N}][\p{L}\p{N}_.-]{2,80}/gu)??[]){let u=this.sanitizeEntityToken(g);if(!u)continue;let m=u.toLowerCase();n.has(m)&&!l.some(h=>h.key===m)&&l.push({key:m,name:u});}for(let g=0;g<l.length;g++)for(let u=g+1;u<l.length;u++){let m=l[g],h=l[u];if(m.key===h.key)continue;let f="related_to",y=this.inferEntityType(m.name),b=this.inferEntityType(h.name);y==="document"&&b==="object"?f="defines":y==="object"&&b==="document"?f="referenced_in":y==="process"&&b==="object"?f="uses":y==="object"&&b==="process"?f="used_by":y==="concept"&&(f="relates_to");let S=`${m.key}|${h.key}|${f}`;o.has(S)||(o.add(S),r.push({source:m.name,target:h.name,relation:f}));}}return {entities:t,relations:r}}sanitizeEntityToken(e){return e.trim().replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"").replace(/\s+/g," ").slice(0,120)}inferEntityType(e){return /(\.md|\.ts|\.json|readme|doc|spec|guideline)/i.test(e)?"document":/(api|service|system|engine|pipeline|server|db|database|memorysystem|contextengine)/i.test(e)?"process":/(team|group|org|company|inc|ltd|corp)/i.test(e)?"organization":/(deadline|date|day|week|month|year|q[1-4]|sprint)/i.test(e)?"time":/(score|rate|ratio|latency|accuracy|recall|precision|throughput|kpi)/i.test(e)?"metric":/(task|issue|ticket|todo|action)/i.test(e)?"task":/(event|incident|release|meeting|migration|launch)/i.test(e)?"event":/(process|workflow|procedure|flow|lifecycle)/i.test(e)?"process":/(file|model|dataset|artifact|resource|tool|sdk|ollama|sqlite|embedding|vector|fts)/i.test(e)?"object":/(concept|principle|policy|method|pattern|strategy)/i.test(e)?"concept":/[A-Z]/.test(e)?"object":"keyword"}storeEntities(e,t){if(e.length===0)return;let r=new Map,n=new Date().toISOString();for(let o of e){let s=this.db.query("SELECT id FROM nodes WHERE name = ? AND type = ?",[o.name,o.type]);s.length>0&&s[0]&&r.set(o.name,s[0].id);}this.db.transaction(()=>{for(let o of e){if(r.has(o.name))continue;let s=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[o.name,o.type,JSON.stringify(o.properties),n,n]);s.lastID>0&&r.set(o.name,s.lastID);}for(let o of t){let s=r.get(o.source),i=r.get(o.target);if(s&&i){let c=this.db.query("SELECT id FROM nodes WHERE id = ?",[s]),a=this.db.query("SELECT id FROM nodes WHERE id = ?",[i]);c.length>0&&a.length>0&&this.db.run("INSERT OR REPLACE INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[s,i,o.relation,"{}",n]);}}});}mergeEntitiesAndRelations(e,t,r){if(t.length===0&&r.length===0)return;let n=new Map,o=new Date().toISOString(),s=t.map(()=>"?").join(","),i=this.db.query(`SELECT id, name, type FROM nodes WHERE name IN (${s})`,t.map(c=>c.name));for(let c of i)n.set(c.name,c.id);this.db.transaction(()=>{for(let c of t)if(n.get(c.name)===void 0){let d=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[c.name,c.type,JSON.stringify(c.properties),o,o]);d.lastID>0&&n.set(c.name,d.lastID);}for(let c of r){let a=n.get(c.source),d=n.get(c.target);if(a&&d){let l=this.db.query("SELECT id FROM nodes WHERE id = ?",[a]),g=this.db.query("SELECT id FROM nodes WHERE id = ?",[d]);l.length>0&&g.length>0&&this.db.run("INSERT OR REPLACE INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[a,d,c.relation,"{}",o]);}}});}float32ToBuffer(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}ensureVectorDims(e){this.db.query("SELECT value FROM meta WHERE key = ?",["vectorDims"]).length===0&&this.db.run("INSERT OR IGNORE INTO meta (key, value) VALUES (?, ?)",["vectorDims",String(e)]);}mapChunksToNodes(e,t,r){let n=new Map,o=new Date().toISOString();this.db.transaction(()=>{for(let s of t){let i=this.db.query("SELECT id FROM nodes WHERE name = ? AND type = ?",[s.name,s.type]);if(i.length>0&&i[0])n.set(s.name,i[0].id);else {let c=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[s.name,s.type,JSON.stringify(s.properties),o,o]);c.lastID>0&&n.set(s.name,c.lastID);}}for(let s=0;s<e.length;s++){let i=e[s],c=[];for(let a of t)if(i.includes(a.name)){let d=n.get(a.name);d&&c.push(d);}r.set(s,c);}});}};chunkGR7YLLW4_cjs.c.create({service:"note-search"});var Y=class{constructor(e,t){chunkGR7YLLW4_cjs.a(this,"db");chunkGR7YLLW4_cjs.a(this,"config");this.db=e,this.config={...types.DEFAULT_NOTE_CHUNK_CONFIG,...t,embeddingLlm:t.embeddingLlm},t.embeddingLlm&&exports.Llm.init({models:{embeddingLlm:t.embeddingLlm,graphLlm:t.graphLlm,rerankLlm:t.rerankLlm}});}async search(e,t){if(!e.trim())return [];let r=t?.maxResults||3,n=t?.minScore??this.config.search.minScore,o=await this.hybridSearch(e,{...t,maxResults:r*2});return o.length===0?[]:this.config.rerankLlm?(await this.rerank(e,o,r)).filter(i=>i.score>=n):o.filter(s=>s.score>=n).slice(0,r)}async hybridSearch(e,t){let{maxResults:r=this.config.search.maxResults,minScore:n=this.config.search.minScore,vectorWeight:o=this.config.search.hybrid.vectorWeight,textWeight:s=this.config.search.hybrid.textWeight,enableEmbedding:i=true,enableFts:c=true}=t??{},a=i?await this.embed(e):new Float32Array(0),[d,l]=await Promise.all([i&&this.config.embeddingLlm?this.vectorSearch(a,r,n,t):Promise.resolve([]),c===false?Promise.resolve([]):this.ftsSearch(e,r,n,t)]);return this.mergeResults(d,l,o,s,n)}async vectorSearch(e,t,r,n){if(!this.config.embeddingLlm)return [];try{let o;if(n?.candidateChunkIds&&n.candidateChunkIds.length>0){let c=n.candidateChunkIds.map(()=>"?").join(",");o=this.db.query(`SELECT chunkId, embedding FROM vectors WHERE chunkId IN (${c})`,n.candidateChunkIds);}else o=this.db.query("SELECT chunkId, embedding FROM vectors LIMIT ?",[Math.max(t*100,1e3)]);let s=[];for(let c of o){let a=new Float32Array(c.embedding.buffer,c.embedding.byteOffset,c.embedding.length/4),d=this.cosineSimilarity(e,a);s.push({chunkId:c.chunkId,score:d});}s.sort((c,a)=>a.score-c.score);let i=s.slice(0,t);return this.buildSearchResults(i,"vector",n)}catch(o){throw new R(`\u5411\u91CF\u641C\u7D22\u5931\u8D25: ${o.message}`,"SEARCH_FAILED",o)}}async ftsSearch(e,t,r,n){let o=async()=>[];try{let s=ie(e),i=this.db.query("SELECT chunkId, rank FROM chunks_fts WHERE chunks_fts MATCH ? ORDER BY rank LIMIT ?",[s,t]);if(i.length===0)return o();let c=i.map(a=>({chunkId:a.chunkId,score:1/(1+a.rank)}));return this.buildSearchResults(c,"fts",n)}catch{return o()}}mergeResults(e,t,r,n,o){let s=r+n,i=r/s,c=n/s,a=new Map;for(let g of e){let u=`${g.chunk.id}`,m=g.score*i;a.set(u,{...g,score:m,source:"hybrid"});}for(let g of t){let u=`${g.chunk.id}`,m=a.get(u);if(m)m.score+=g.score*c;else {let h=g.score*c;a.set(u,{...g,score:h,source:"hybrid"});}}return Array.from(a.values()).map(g=>{let u=g.score,m=new Date(g.document.updatedAt),h=(Date.now()-m.getTime())/864e5,f=Math.exp(-0.01*h),y=.6*u+.4*f;return {...g,score:y}}).sort((g,u)=>u.score-g.score)}async rerank(e,t,r){if(!this.config.rerankLlm)return t.slice(0,r);try{let n=t.map(a=>{let d=a.nodes&&a.nodes.length>0?a.nodes.map(l=>{let g=(l.edges??[]).map(u=>{let m=u.source===l.id?"\u2192":"\u2190",h=u.targetNode?`${u.targetNode.type}:${u.targetNode.name}`:`id=${u.target}`;return `${m} [${u.relation}] ${h}`}).join(" | ");return `node: id=${l.id} name=${l.name} type=${l.type}${g?` edges: ${g}`:""}`}).join(" | "):"";return `<doc filePath="${a.document.path}" lineStart="${a.chunk.startLine}" lineEnd="${a.chunk.endLine}"><snippet>${a.snippet}</snippet>${d?`<nodes>${d}</nodes>`:""}</doc>`}),o=await exports.Llm.rerank(e,n,t.length);if(o.length===0)return t.slice(0,r);let s=new Map;for(let a of o)a.index>=0&&a.index<t.length&&s.set(a.index,a.score);let i=.5,c=t.map((a,d)=>{let l=s.get(d)??a.score,g=i*a.score+(1-i)*l;return {...a,originalScore:a.score,score:g,source:"reranked"}});return c.sort((a,d)=>d.score-a.score),c.slice(0,r)}catch{return t.slice(0,r)}}async embed(e){try{return await exports.Llm.embed(e)}catch{return new Float32Array(this.config.vectorDims)}}cosineSimilarity(e,t){let r=0,n=0,o=0;for(let s=0;s<e.length;s++){let i=e[s],c=t[s];r+=i*c,n+=i*i,o+=c*c;}return n===0||o===0?0:r/(Math.sqrt(n)*Math.sqrt(o))}async buildSearchResults(e,t,r){let n=[],o=e.map(p=>p.chunkId);if(o.length===0)return n;let s=r?.includeEdges??true,i=Math.max(1,r?.edgesLimit??100),c=this.db.query("SELECT * FROM chunks WHERE id IN ("+o.map(()=>"?").join(", ")+")",o),a=new Map(c.map(p=>[p.id,p])),d=Array.from(new Set(c.map(p=>p.documentId))),l=d.length>0?this.db.query("SELECT * FROM documents WHERE id IN ("+d.map(()=>"?").join(", ")+")",d):[],g=new Map(l.map(p=>[p.id,p])),u=new Map,m=[];for(let p of c){let I=[];try{let T=p.nodeIds?JSON.parse(p.nodeIds):[];I=Array.isArray(T)?T.filter(M=>typeof M=="number"):[];}catch{I=[];}u.set(p.id,I),m.push(...I);}let h=Array.from(new Set(m)),f=h.length>0?this.db.query("SELECT * FROM nodes WHERE id IN ("+h.map(()=>"?").join(", ")+")",h):[],y=new Map(f.map(p=>[p.id,{id:p.id,name:p.name,type:p.type,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt,updatedAt:p.updatedAt}])),b=s&&h.length>0?this.db.query("SELECT * FROM edges WHERE source IN ("+h.map(()=>"?").join(", ")+") OR target IN ("+h.map(()=>"?").join(", ")+") ORDER BY id LIMIT ?",[...h,...h,h.length*i]):[],S=[...new Set([...h,...b.map(p=>p.target)])],$=S.length>0?this.db.query("SELECT * FROM nodes WHERE id IN ("+S.map(()=>"?").join(", ")+")",S):[],O=new Map($.map(p=>[p.id,{id:p.id,name:p.name,type:p.type,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt,updatedAt:p.updatedAt}])),k=new Map;for(let p of b){let I={id:p.id,source:p.source,target:p.target,relation:p.relation,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt},T=O.get(p.target);T&&(I.targetNode=T);let M=k.get(I.source)??[];M.length<i&&(M.push(I),k.set(I.source,M));let P=k.get(I.target)??[];P.length<i&&(P.push(I),k.set(I.target,P));}for(let p of e){let I=a.get(p.chunkId);if(!I)continue;let T=g.get(I.documentId);if(!T)continue;let M=u.get(I.id)??[],P=M.map(w=>y.get(w)).filter(w=>w!==void 0),q=s&&M.length>0?Array.from(new Map(M.flatMap(w=>k.get(w)??[]).map(w=>[w.id,w])).values()):[],B=new Map;for(let w of q){let re=B.get(w.source)??[];re.push(w),B.set(w.source,re);}let te=P.length>0?P.map(w=>({...w,edges:s?B.get(w.id)??[]:void 0})):[];n.push({chunk:{id:I.id,documentId:I.documentId,startLine:I.startLine,endLine:I.endLine,startChar:I.startChar,endChar:I.endChar,content:I.content,contentHash:I.contentHash,nodeIds:M,path:T.path,createdAt:I.createdAt},document:{id:T.id,path:T.path,title:T.title,contentHash:T.contentHash,summary:T.summary,lastModified:T.lastModified,createdAt:T.createdAt,updatedAt:T.updatedAt},nodes:te.length>0?te:void 0,score:p.score,snippet:I.content.slice(0,200),source:t});}return n}};var Q=class{constructor(e){chunkGR7YLLW4_cjs.a(this,"db");this.db=e;}async queryNodes(e,t){try{if(typeof e=="string")return this.db.query(e,t).map(c=>this.mapNode(c));let r=[],n=[];e.ids&&e.ids.length>0&&(r.push(`id IN (${e.ids.map(()=>"?").join(",")})`),n.push(...e.ids)),e.name&&(r.push("name LIKE ?"),n.push(`%${e.name}%`)),e.type&&(r.push("type = ?"),n.push(e.type));let o="SELECT * FROM nodes";return r.length>0&&(o+=` WHERE ${r.join(" AND ")}`),o+=" ORDER BY id",e.limit&&e.limit>0&&(o+=" LIMIT ?",n.push(e.limit)),this.db.query(o,n).map(i=>this.mapNode(i))}catch(r){throw new R(`\u67E5\u8BE2\u8282\u70B9\u5931\u8D25: ${r.message}`,"SEARCH_FAILED",r)}}async queryEdges(e,t){try{if(typeof e=="string")return this.db.query(e,t).map(c=>this.mapEdge(c));let r=[],n=[];e.ids&&e.ids.length>0&&(r.push(`id IN (${e.ids.map(()=>"?").join(",")})`),n.push(...e.ids)),typeof e.source=="number"&&(r.push("source = ?"),n.push(e.source)),typeof e.target=="number"&&(r.push("target = ?"),n.push(e.target)),e.sourceOrTarget&&e.sourceOrTarget.length>0&&(r.push(`(source IN (${e.sourceOrTarget.map(()=>"?").join(", ")}) OR target IN (${e.sourceOrTarget.map(()=>"?").join(", ")}))`),n.push(...e.sourceOrTarget,...e.sourceOrTarget)),e.relation&&(r.push("relation = ?"),n.push(e.relation));let o="SELECT * FROM edges";return r.length>0&&(o+=` WHERE ${r.join(" AND ")}`),o+=" ORDER BY id",e.limit&&e.limit>0&&(o+=" LIMIT ?",n.push(e.limit)),this.db.query(o,n).map(i=>this.mapEdge(i))}catch(r){throw new R(`\u67E5\u8BE2\u8FB9\u5931\u8D25: ${r.message}`,"SEARCH_FAILED",r)}}async queryNeighbors(e,t){let r=t?.direction??"both",n=t?.relationTypes,o=t?.limit&&t.limit>0?t.limit:100,s=[],i=[];r==="incoming"?(s.push("target = ?"),i.push(e)):r==="outgoing"?(s.push("source = ?"),i.push(e)):(s.push("(source = ? OR target = ?)"),i.push(e,e)),n&&n.length>0&&(s.push(`relation IN (${n.map(()=>"?").join(",")})`),i.push(...n));let c=await this.queryEdges(`SELECT * FROM edges WHERE ${s.join(" AND ")} ORDER BY id LIMIT ?`,[...i,o]),a=Array.from(new Set(c.map(u=>u.source===e?u.target:u.source)));if(a.length===0)return {nodes:await this.queryNodes({ids:[e],limit:1}),edges:c};let d=[...new Set([e,...a])],l=await this.queryNodes({ids:d,limit:d.length}),g=new Map(l.map(u=>[u.id,u]));for(let u of c){let m=g.get(u.target);m&&(u.targetNode=m);}return {nodes:l,edges:c}}async queryCallGraph(e,t=2){let r=Math.max(1,t),n=new Map,o=[{id:e,level:0}],s=new Set;for(;o.length>0;){let i=o.shift();if(s.has(i.id)||i.level>r)continue;s.add(i.id);let c=await this.queryEdges({source:i.id,relation:"CALLS",limit:100}),a=await this.queryEdges({target:i.id,relation:"CALLS",limit:100}),d=Array.from(new Set(c.map(g=>g.target))),l=Array.from(new Set(a.map(g=>g.source)));n.set(i.id,{callers:l,callees:d});for(let g of [...l,...d])s.has(g)||o.push({id:g,level:i.level+1});}return n}async queryInheritance(e){let t=["EXTENDS","INHERITS_FROM","IMPLEMENTS"],r=await this.collectInheritance(e,"ancestor",t),n=await this.collectInheritance(e,"descendant",t);return {ancestors:r,descendants:n}}async findPath(e,t,r=3){let n=[],o=new Set,s=this.db.query("SELECT * FROM nodes WHERE name = ?",[e]);if(s.length===0)return [];let i=s.map(c=>({nodeId:c.id,path:[c.id]}));for(;i.length>0;){let{nodeId:c,path:a}=i.shift();if(a.length>r)continue;let d=a.join(",");if(o.has(d))continue;if(o.add(d),a.length>1){let g=this.db.query("SELECT id, name FROM nodes WHERE id = ?",[c]);if(g.length>0&&g[0]?.name===t){let u=a.map(()=>"?").join(","),m=this.db.query(`SELECT * FROM nodes WHERE id IN (${u})`,a),h=new Map(m.map(y=>[y.id,y])),f=[];for(let y of a){let b=h.get(y);b&&f.push({id:b.id,name:b.name,type:b.type,properties:b.properties?JSON.parse(b.properties):void 0,createdAt:b.createdAt,updatedAt:b.updatedAt});}n.push(f);continue}}let l=this.db.query("SELECT source, target FROM edges WHERE source = ? OR target = ?",[c,c]);for(let g of l){let u=g.source===c?g.target:g.source;a.includes(u)||i.push({nodeId:u,path:[...a,u]});}}return n}async searchNodesByName(e){return this.queryNodes("SELECT * FROM nodes WHERE name LIKE ?",[e])}async searchNodesByType(e){return this.queryNodes("SELECT * FROM nodes WHERE type = ?",[e])}async searchRelations(e){return this.queryEdges("SELECT * FROM edges WHERE relation = ?",[e])}async createNode(e,t,r){let n=new Date().toISOString(),o=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[e,t,r?JSON.stringify(r):null,n,n]),i=this.db.query("SELECT * FROM nodes WHERE id = ?",[o.lastID])[0];return {id:i.id,name:i.name,type:i.type,properties:i.properties?JSON.parse(i.properties):void 0,createdAt:i.createdAt,updatedAt:i.updatedAt}}async updateNode(e,t){let r=new Date().toISOString();this.db.run("UPDATE nodes SET properties = ?, updatedAt = ? WHERE id = ?",[JSON.stringify(t),r,e]);let n=this.db.query("SELECT * FROM nodes WHERE id = ?",[e]);if(n.length===0)throw new R(`\u8282\u70B9\u4E0D\u5B58\u5728: ${e}`,"NODE_NOT_FOUND");let o=n[0];return {id:o.id,name:o.name,type:o.type,properties:o.properties?JSON.parse(o.properties):void 0,createdAt:o.createdAt,updatedAt:o.updatedAt}}async deleteNode(e){this.db.run("DELETE FROM nodes WHERE id = ?",[e]);}async createEdge(e,t,r,n){let o=this.db.query("SELECT id FROM nodes WHERE id = ?",[e]),s=this.db.query("SELECT id FROM nodes WHERE id = ?",[t]);if(o.length===0||s.length===0)throw new R("\u8282\u70B9\u4E0D\u5B58\u5728","NODE_NOT_FOUND");let i=new Date().toISOString(),c=this.db.run("INSERT INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[e,t,r,n?JSON.stringify(n):null,i]),d=this.db.query("SELECT * FROM edges WHERE id = ?",[c.lastID])[0];return {id:d.id,source:d.source,target:d.target,relation:d.relation,properties:d.properties?JSON.parse(d.properties):void 0,createdAt:d.createdAt}}async deleteEdge(e){this.db.run("DELETE FROM edges WHERE id = ?",[e]);}mapNode(e){return {id:e.id,name:e.name,type:e.type,properties:e.properties?JSON.parse(e.properties):void 0,createdAt:e.createdAt,updatedAt:e.updatedAt}}mapEdge(e){return {id:e.id,source:e.source,target:e.target,relation:e.relation,properties:e.properties?JSON.parse(e.properties):void 0,createdAt:e.createdAt}}async collectInheritance(e,t,r){let n=[e],o=new Set([e]),s=new Set;for(;n.length>0;){let i=n.shift(),c=t==="ancestor"?await this.queryEdges(`SELECT * FROM edges WHERE source = ? AND relation IN (${r.map(()=>"?").join(",")})`,[i,...r]):await this.queryEdges(`SELECT * FROM edges WHERE target = ? AND relation IN (${r.map(()=>"?").join(",")})`,[i,...r]);for(let a of c){let d=t==="ancestor"?a.target:a.source;o.has(d)||(o.add(d),s.add(d),n.push(d));}}return s.size===0?[]:this.queryNodes({ids:Array.from(s),limit:s.size})}};var V=chunkGR7YLLW4_cjs.c.create({service:"note-scanner"}),Ce=["node_modules/**",".git/**","dist/**","build/**","__pycache__/**","*.min.md"],W=class{constructor(e){chunkGR7YLLW4_cjs.a(this,"workspaceDir");chunkGR7YLLW4_cjs.a(this,"extraPaths");chunkGR7YLLW4_cjs.a(this,"sources");chunkGR7YLLW4_cjs.a(this,"ignorePatterns");this.workspaceDir=e.workspaceDir,this.extraPaths=e.extraPaths??[],this.sources=new Set(e.sources??["docs"]),this.ignorePatterns=[...Ce,...e.ignorePatterns??[]];}async scanAll(e){let t=[],r=[];for(let s of this.sources){let i=___namespace.default.join(this.workspaceDir,s);r.push({source:s,dir:i});}for(let s of this.extraPaths){let i=___namespace.default.isAbsolute(s)?s:___namespace.default.join(this.workspaceDir,s);r.push({source:"local",dir:i});}let n=0,o=r.length;for(let s of r){let i=await this.scanDirectory(s.dir,s.source);t.push(...i),n++,e?.(n,o,i[0]||{absolutePath:s.dir,relativePath:s.dir,source:s.source,contentHash:"",lastModified:0,size:0});}return t}async scanDirectory(e,t){let r=[];try{await z__default.default.access(e);}catch{return V.debug("Directory not found, skipping",{dir:e}),r}let n=async o=>{try{let s=await z__default.default.readdir(o,{withFileTypes:!0});for(let i of s){let c=___namespace.default.join(o,i.name);if(!this.shouldIgnore(i.name)){if(i.isDirectory())await n(c);else if(i.isFile()&&this.isMarkdownFile(i.name)){let a=await this.getFileInfo(c,t);a&&r.push(a);}}}}catch(s){V.warn("Failed to scan directory",{dir:o,error:String(s)});}};return await n(e),r}async scanFile(e,t="upload"){try{let r=await z__default.default.stat(e);if(!r.isFile())return null;let n=await z__default.default.readFile(e,"utf-8"),o=crypto.createHash("sha256").update(n).digest("hex"),s=___namespace.default.isAbsolute(e)?utils.Filesystem.toUnixPath(___namespace.default.relative(this.workspaceDir,e)):e;return {absolutePath:e,relativePath:s||___namespace.default.basename(e),source:t,contentHash:o,lastModified:r.mtimeMs,size:r.size}}catch(r){return V.error("Failed to scan file",{filePath:e,error:String(r)}),null}}async getFileInfo(e,t){try{let r=await z__default.default.readFile(e,"utf-8"),n=await z__default.default.stat(e),o=crypto.createHash("sha256").update(r).digest("hex"),s=utils.Filesystem.toUnixPath(___namespace.default.relative(this.workspaceDir,e));return {absolutePath:e,relativePath:s,source:t,contentHash:o,lastModified:n.mtimeMs,size:n.size}}catch(r){return V.error("Failed to get file info",{filePath:e,error:String(r)}),null}}shouldIgnore(e){if(e.startsWith("."))return true;for(let t of this.ignorePatterns)if(new RegExp("^"+t.replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$").test(e))return true;return false}isMarkdownFile(e){return e.endsWith(".md")||e.endsWith(".markdown")}};var A=chunkGR7YLLW4_cjs.c.create({service:"note"}),J=class{constructor(e){chunkGR7YLLW4_cjs.a(this,"config");chunkGR7YLLW4_cjs.a(this,"db");chunkGR7YLLW4_cjs.a(this,"pipeline");chunkGR7YLLW4_cjs.a(this,"searchEngine");chunkGR7YLLW4_cjs.a(this,"graphInterface");chunkGR7YLLW4_cjs.a(this,"fileScanner");chunkGR7YLLW4_cjs.a(this,"initialized",false);chunkGR7YLLW4_cjs.a(this,"dirty",false);chunkGR7YLLW4_cjs.a(this,"syncTimer");chunkGR7YLLW4_cjs.a(this,"syncConfig");chunkGR7YLLW4_cjs.a(this,"syncingInProgress",false);let t=e.workspaceDir||process.cwd(),r=e.embeddingLlm;if(!r)throw new Error("embeddingLlm is required");let n=e.database?.path||types.getDefaultDatabasePath(xdgBasedir.xdgData,"note.db");this.config={workspaceDir:t,database:{path:n,walMode:e.database?.walMode??true},vectorDims:e.vectorDims??768,...types.DEFAULT_NOTE_CHUNK_CONFIG,extraPaths:e.extraPaths,sources:e.sources,search:{...types.DEFAULT_SEARCH_CONFIG,...e.search},indexer:{...types.DEFAULT_INDEXER_CONFIG,...e.indexer},sync:{...types.DEFAULT_SYNC_CONFIG,...e.sync},logDir:e.logDir,embeddingLlm:r,graphLlm:e.graphLlm,rerankLlm:e.rerankLlm},this.syncConfig=this.config.sync,this.db=new G(this.config.database.path),this.pipeline=new X(this.db,this.config),this.searchEngine=new Y(this.db,this.config),this.graphInterface=new Q(this.db),this.fileScanner=new W({workspaceDir:this.config.workspaceDir,extraPaths:this.config.extraPaths,sources:this.config.sources,ignorePatterns:this.config?.indexer?.ignorePatterns});}async initialize(){if(this.initialized)return;await chunkGR7YLLW4_cjs.c.init({logDir:this.config.logDir||___namespace.default.join(this.config.workspaceDir,"logs"),print:process.argv.includes("--print-logs"),dev:false,level:"INFO"}),exports.Llm.init({models:{embeddingLlm:this.config.embeddingLlm,graphLlm:this.config.graphLlm,rerankLlm:this.config.rerankLlm},options:{graph:{maxOutputTokens:2e3,temperature:.1}}}),await this.db.initialize();let e=[["version","1.0.0"],["chunkSize",String(this.config.chunkSize)],["chunkOverlap",String(this.config.chunkOverlap)],["createdAt",new Date().toISOString()]];for(let[t,r]of e)this.db.run("INSERT OR IGNORE INTO meta (key, value) VALUES (?, ?)",[t,r]);this.initialized=true,this.syncConfig.onBoot&&(this.syncAll().catch(t=>A.warn("onBoot sync failed",{error:String(t)})),this.startSyncTimer());}startSyncTimer(){this.syncTimer&&clearInterval(this.syncTimer),this.syncConfig.intervalMs>0&&(this.syncTimer=setInterval(async()=>{try{await this.syncAll();}catch(e){A.error("Interval sync failed",{error:String(e)});}},this.syncConfig.intervalMs));}ensureSynced(){this.dirty&&!this.syncingInProgress&&this.syncConfig.onSearch&&this.syncAll().catch(e=>{A.warn("Background sync failed",{error:String(e)});});}stopSyncTimer(){this.syncTimer&&(clearInterval(this.syncTimer),this.syncTimer=void 0);}async syncAll(){if(this.syncingInProgress){A.debug("Sync already in progress, skipping...");return}this.syncingInProgress=true,A.debug("Starting sync...");try{let e=await this.sync((t,r,n)=>{A.debug("Syncing file",{current:t,total:r,path:n.relativePath||___namespace.default.basename(n.absolutePath)});});this.dirty=!1,A.debug("Sync completed",{totalFiles:e.filesAdded+e.filesUpdated+e.filesSkipped,added:e.filesAdded,updated:e.filesUpdated,deleted:e.filesDeleted,skipped:e.filesSkipped,errors:e.errors.length});}finally{this.syncingInProgress=false;}}async ingestDocument(e){return await this.ensureInitialized(),this.pipeline.process(e)}async ingestDocuments(e,t){await this.ensureInitialized();let r=[];for(let n=0;n<e.length;n++){let o=await this.pipeline.process(e[n]);r.push(o),t?.((n+1)/e.length);}return r}async scanAndIngest(e){for(await this.ensureInitialized();this.syncingInProgress;)await new Promise(n=>setTimeout(n,100));let t=await this.fileScanner.scanAll(e);if(t.length===0)return [];let r=t.map(n=>n.absolutePath);return this.ingestDocuments(r,n=>{e?.(Math.round(n*t.length),t.length,t[0]||{absolutePath:"ingesting...",relativePath:"ingesting...",source:"docs",contentHash:"",lastModified:0,size:0});})}async ingestUploadedFile(e){await this.ensureInitialized();let t=await this.fileScanner.scanFile(e,"upload");if(!t)throw new Error(`\u65E0\u6CD5\u626B\u63CF\u6587\u4EF6: ${e}`);return this.pipeline.process(t.absolutePath)}async removeDocument(e){await this.ensureInitialized();let t=utils.Filesystem.toUnixPath(e);try{this.db.deleteDocumentByPath(t)&&A.debug("Removed document",{path:t});}catch(r){throw A.error("Failed to remove document",{path:t,error:String(r)}),r}}markDirty(){this.dirty=true,A.debug("Marked as dirty, will sync before next search");}async sync(e){if(await this.ensureInitialized(),this.syncingInProgress)return A.debug("Sync already in progress, skipping..."),{success:true,filesAdded:0,filesUpdated:0,filesDeleted:0,filesSkipped:0,chunksCreated:0,vectorsCreated:0,entitiesExtracted:0,relationsExtracted:0,errors:[],duration:0};this.syncingInProgress=true;try{let t=Date.now(),r={success:!0,filesAdded:0,filesUpdated:0,filesDeleted:0,filesSkipped:0,chunksCreated:0,vectorsCreated:0,entitiesExtracted:0,relationsExtracted:0,errors:[],duration:0},n=await this.fileScanner.scanAll(e),o=new Set(n.map(a=>utils.Filesystem.toUnixPath(a.relativePath))),s=this.db.query("SELECT path, contentHash FROM documents"),i=new Map;for(let a of s)i.set(a.path,a.contentHash);for(let[a]of i)if(!o.has(a))try{this.db.deleteDocumentByPath(a)&&(r.filesDeleted++,A.debug("Deleted document from index",{path:a}));}catch(d){let l=d instanceof Error?d.message:String(d);r.errors.push({filePath:a,error:`Failed to delete document: ${l}`}),A.error("Failed to delete document",{path:a,error:l});}for(let a=0;a<n.length;a++){let d=n[a],l=utils.Filesystem.toUnixPath(d.relativePath);e?.(a+1,n.length,d);try{let g=i.get(l);if(g===void 0){let u=await this.pipeline.process(d.absolutePath);r.filesAdded++,r.chunksCreated+=u.chunksCreated,r.vectorsCreated+=u.vectorsCreated,r.entitiesExtracted+=u.entitiesExtracted||0,r.relationsExtracted+=u.relationsExtracted||0,A.debug("Added new document",{path:l});}else if(g!==d.contentHash){let u=await this.pipeline.process(d.absolutePath);r.filesUpdated++,r.chunksCreated+=u.chunksCreated,r.vectorsCreated+=u.vectorsCreated,r.entitiesExtracted+=u.entitiesExtracted||0,r.relationsExtracted+=u.relationsExtracted||0,A.debug("Updated document",{path:l});}else r.filesSkipped++;}catch(g){let u=g instanceof Error?g.message:String(g);r.errors.push({filePath:l,error:u}),A.error("Failed to process document",{path:l,error:u});}}r.duration=Date.now()-t,r.success=r.errors.length===0;let c={timestamp:new Date().toISOString(),success:r.success,filesAdded:r.filesAdded,filesUpdated:r.filesUpdated,filesDeleted:r.filesDeleted,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,vectorsCreated:r.vectorsCreated,entitiesExtracted:r.entitiesExtracted,relationsExtracted:r.relationsExtracted,errorCount:r.errors.length,duration:r.duration};return this.db.setMeta("lastSync",c.timestamp),this.db.setMeta("lastSyncResult",JSON.stringify(c)),A.info("Sync completed",{added:r.filesAdded,updated:r.filesUpdated,deleted:r.filesDeleted,skipped:r.filesSkipped,errors:r.errors.length,duration:r.duration}),r}finally{this.syncingInProgress=false;}}async search(e,t){return await this.ensureInitialized(),this.ensureSynced(),this.searchEngine.search(e,t)}async queryNodes(e,t){return await this.ensureInitialized(),typeof e=="string"?this.graphInterface.queryNodes(e,t):this.graphInterface.queryNodes(e)}async queryEdges(e,t){return await this.ensureInitialized(),typeof e=="string"?this.graphInterface.queryEdges(e,t):this.graphInterface.queryEdges(e)}async findPath(e,t,r){return await this.ensureInitialized(),this.graphInterface.findPath(e,t,r)}async queryNeighbors(e,t){return await this.ensureInitialized(),this.graphInterface.queryNeighbors(e,t)}async queryCallGraph(e,t){return await this.ensureInitialized(),this.graphInterface.queryCallGraph(e,t)}async queryInheritance(e){return await this.ensureInitialized(),this.graphInterface.queryInheritance(e)}async createNode(e,t,r){return await this.ensureInitialized(),this.graphInterface.createNode(e,t,r)}async updateNode(e,t){return await this.ensureInitialized(),this.graphInterface.updateNode(e,t)}async deleteNode(e){return await this.ensureInitialized(),this.graphInterface.deleteNode(e)}async createEdge(e,t,r,n){return await this.ensureInitialized(),this.graphInterface.createEdge(e,t,r,n)}async deleteEdge(e){return await this.ensureInitialized(),this.graphInterface.deleteEdge(e)}getStatus(){let e=this.db.getPath(),t=0,r=0,n=0,o=0;try{t=this.db.getDb().prepare("SELECT COUNT(*) as count FROM documents").get()?.count||0,r=this.db.getDb().prepare("SELECT COUNT(*) as count FROM chunks").get()?.count||0,n=this.db.getDb().prepare("SELECT COUNT(*) as count FROM nodes").get()?.count||0,o=this.db.getDb().prepare("SELECT COUNT(*) as count FROM edges").get()?.count||0;}catch{}return {dbPath:e,workspaceDir:this.config.workspaceDir,documentsCount:t,chunksCount:r,nodesCount:n,edgesCount:o,embeddingLlmAvailable:!!this.config.embeddingLlm,graphLlmAvailable:!!this.config.graphLlm,rerankLlmAvailable:!!this.config.rerankLlm,healthy:this.initialized,meta:this.getMetaMap()}}getMetaMap(){let e={};try{let t=this.db.query("SELECT key, value FROM meta");for(let r of t)e[r.key]=r.value;}catch{}return e}async healthCheck(){try{return this.db.query("SELECT 1"),!0}catch{return false}}async clear(){this.db.transaction(()=>{this.db.run("DELETE FROM chunks"),this.db.run("DELETE FROM documents"),this.db.run("DELETE FROM vectors"),this.db.run("DELETE FROM nodes"),this.db.run("DELETE FROM edges"),this.db.run("DELETE FROM embedding_cache"),this.db.run("DELETE FROM sqlite_sequence WHERE name IN ('chunks', 'documents', 'nodes', 'edges')");});try{this.db.run("INSERT INTO chunks_fts(chunks_fts) VALUES('delete-all')");}catch(e){A.warn("Failed to clear FTS index",{error:String(e)});}A.info("Note knowledge base cleared");}async ensureInitialized(){this.initialized||await this.initialize();}async close(){this.initialized&&(this.stopSyncTimer(),await this.db.close(),this.initialized=false,A.info("NoteKnowledge closed"));}};async function Ue(E){let e=new J(E);return await e.initialize(),e}async function ar(E){let{Log:e}=await import('./chunks/log-RK4OYAQH.cjs'),t=false;await e.init({logDir:E.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:E.print??false,dev:E.dev??t,level:E.level??("INFO")});}Object.defineProperty(exports,"GRAPH_ENTITY_TYPE_DEFINITIONS",{enumerable:true,get:function(){return types.GRAPH_ENTITY_TYPE_DEFINITIONS}});Object.defineProperty(exports,"GRAPH_RELATION_TYPE_DEFINITIONS",{enumerable:true,get:function(){return types.GRAPH_RELATION_TYPE_DEFINITIONS}});exports.FileScanner=W;exports.KnowledgeBaseError=R;exports.KnowledgeBaseErrorCode=H;exports.NoteKnowledge=J;exports.addWord=nt;exports.closeTokenizer=it;exports.createNoteKnowledge=Ue;exports.initLog=ar;exports.initTokenizer=rt;exports.isInitialized=st;exports.loadCustomDict=ye;exports.toFtsTokens=se;exports.toFtsTokensForSearch=ie;exports.tokenize=be;exports.tokenizeForSearch=Ie;
128
+ `);return this.extractEntitiesByRules(t)}parseEntityExtractionResult(e){try{let t=e.match(/\{[\s\S]*\}/);if(t){let r=JSON.parse(t[0]);return this.normalizeExtractionResult(r)}}catch(t){Y.debug("Failed to parse entity extraction result",{error:String(t)});}return {summary:"",entities:[],relations:[]}}normalizeExtractionResult(e){let t=e,r=typeof t.summary=="string"?t.summary.trim():"",n=Array.isArray(t.entities)?t.entities:[],o=Array.isArray(t.relations)?t.relations:[],s=[],i=new Set,c=new Map;for(let d of n){let m=typeof d?.name=="string"?d.name.trim():"";if(!m)continue;let u=m.toLowerCase();if(i.has(u))continue;i.add(u),c.set(u,m);let h=typeof d?.type=="string"?d.type.trim():"",g=ke.has(h)?h:"keyword",f=d?.properties&&typeof d.properties=="object"&&!Array.isArray(d.properties)?d.properties:{};s.push({name:m,type:g,properties:f});}let a=[],l=new Set;for(let d of o){let m=typeof d?.source=="string"?d.source.trim():"",u=typeof d?.target=="string"?d.target.trim():"";if(!m||!u)continue;let h=c.get(m.toLowerCase()),g=c.get(u.toLowerCase());if(!h||!g||h===g)continue;let f=typeof d?.relation=="string"?d.relation.trim():"",b=De.has(f)?f:"related_to",N=`${h.toLowerCase()}|${g.toLowerCase()}|${b}`;l.has(N)||(l.add(N),a.push({source:h,target:g,relation:b}));}return {summary:r,entities:s,relations:a}}extractEntitiesByRules(e){let t=[],r=[],n=new Set,o=new Set,s=new Map,i=/([A-Za-z][\w.-]{1,80})\s+(is_a|part_of|has_attribute|located_in|occurs_in|causes|influences|owned_by|member_of|uses|depends_on|related_to)\s+([A-Za-z][\w.-]{1,80})/g;for(let l of e.matchAll(i)){let d=this.sanitizeEntityToken(l[1]??""),m=(l[2]??"related_to").trim(),u=this.sanitizeEntityToken(l[3]??"");if(!d||!u||d===u)continue;let h=d.toLowerCase(),g=u.toLowerCase();n.has(h)||(n.add(h),s.set(h,d),t.push({name:d,type:this.inferEntityType(d),properties:{source:"rule_extracted"}})),n.has(g)||(n.add(g),s.set(g,u),t.push({name:u,type:this.inferEntityType(u),properties:{source:"rule_extracted"}}));let f=`${h}|${g}|${m}`;o.has(f)||(o.add(f),r.push({source:d,target:u,relation:m}));}let c=e.match(/[\p{L}\p{N}][\p{L}\p{N}_.-]{1,80}/gu)??[],a=e.split(/\n\s*\n/);for(let l of c){let d=this.sanitizeEntityToken(l);if(!d)continue;let m=d.toLowerCase();n.has(m)||(n.add(m),s.set(m,d),t.push({name:d,type:this.inferEntityType(d),properties:{source:"keyword_extracted"}}));}for(let l of a){if(l.trim().length<20)continue;let d=[];for(let m of l.match(/[\p{L}\p{N}][\p{L}\p{N}_.-]{2,80}/gu)??[]){let u=this.sanitizeEntityToken(m);if(!u)continue;let h=u.toLowerCase();n.has(h)&&!d.some(g=>g.key===h)&&d.push({key:h,name:u});}for(let m=0;m<d.length;m++)for(let u=m+1;u<d.length;u++){let h=d[m],g=d[u];if(h.key===g.key)continue;let f="related_to",b=this.inferEntityType(h.name),N=this.inferEntityType(g.name);b==="document"&&N==="object"?f="defines":b==="object"&&N==="document"?f="referenced_in":b==="process"&&N==="object"?f="uses":b==="object"&&N==="process"?f="used_by":b==="concept"&&(f="relates_to");let T=`${h.key}|${g.key}|${f}`;o.has(T)||(o.add(T),r.push({source:h.name,target:g.name,relation:f}));}}return {summary:"",entities:t,relations:r}}sanitizeEntityToken(e){return e.trim().replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"").replace(/\s+/g," ").slice(0,120)}inferEntityType(e){return /(\.md|\.ts|\.json|readme|doc|spec|guideline)/i.test(e)?"document":/(api|service|system|engine|pipeline|server|db|database|memorysystem|contextengine)/i.test(e)?"process":/(team|group|org|company|inc|ltd|corp)/i.test(e)?"organization":/(deadline|date|day|week|month|year|q[1-4]|sprint)/i.test(e)?"time":/(score|rate|ratio|latency|accuracy|recall|precision|throughput|kpi)/i.test(e)?"metric":/(task|issue|ticket|todo|action)/i.test(e)?"task":/(event|incident|release|meeting|migration|launch)/i.test(e)?"event":/(process|workflow|procedure|flow|lifecycle)/i.test(e)?"process":/(file|model|dataset|artifact|resource|tool|sdk|ollama|sqlite|embedding|vector|fts)/i.test(e)?"object":/(concept|principle|policy|method|pattern|strategy)/i.test(e)?"concept":/[A-Z]/.test(e)?"object":"keyword"}storeEntities(e,t){if(e.length===0)return;let r=new Map,n=new Date().toISOString();for(let o of e){let s=this.db.query("SELECT id FROM nodes WHERE name = ? AND type = ?",[o.name,o.type]);s.length>0&&s[0]&&r.set(o.name,s[0].id);}this.db.transaction(()=>{for(let o of e){if(r.has(o.name))continue;let s=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[o.name,o.type,JSON.stringify(o.properties),n,n]);s.lastID>0&&r.set(o.name,s.lastID);}for(let o of t){let s=r.get(o.source),i=r.get(o.target);if(s&&i){let c=this.db.query("SELECT id FROM nodes WHERE id = ?",[s]),a=this.db.query("SELECT id FROM nodes WHERE id = ?",[i]);c.length>0&&a.length>0&&this.db.run("INSERT OR REPLACE INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[s,i,o.relation,"{}",n]);}}});}mergeEntitiesAndRelations(e,t,r,n){if(t.length===0&&r.length===0&&(!n||n.trim().length===0))return;let o=new Map,s=new Date().toISOString();if(t.length>0){let i=t.map(()=>"?").join(","),c=this.db.query(`SELECT id, name, type FROM nodes WHERE name IN (${i})`,t.map(a=>a.name));for(let a of c)o.set(a.name,a.id);}this.db.transaction(()=>{for(let i of t)if(o.get(i.name)===void 0){let a=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[i.name,i.type,JSON.stringify(i.properties),s,s]);a.lastID>0&&o.set(i.name,a.lastID);}for(let i of r){let c=o.get(i.source),a=o.get(i.target);if(c&&a){let l=this.db.query("SELECT id FROM nodes WHERE id = ?",[c]),d=this.db.query("SELECT id FROM nodes WHERE id = ?",[a]);l.length>0&&d.length>0&&this.db.run("INSERT OR REPLACE INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[c,a,i.relation,"{}",s]);}}n&&n.trim().length>0&&(this.db.run("UPDATE documents SET summary = ?, updatedAt = ? WHERE path = ?",[n,s,e]),Y.debug("Updated document summary",{path:e,summaryLength:n.length}));});}float32ToBuffer(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}ensureVectorDims(e){this.db.query("SELECT value FROM meta WHERE key = ?",["vectorDims"]).length===0&&this.db.run("INSERT OR IGNORE INTO meta (key, value) VALUES (?, ?)",["vectorDims",String(e)]);}mapChunksToNodes(e,t,r){let n=new Map,o=new Date().toISOString();this.db.transaction(()=>{for(let s of t){let i=this.db.query("SELECT id FROM nodes WHERE name = ? AND type = ?",[s.name,s.type]);if(i.length>0&&i[0])n.set(s.name,i[0].id);else {let c=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[s.name,s.type,JSON.stringify(s.properties),o,o]);c.lastID>0&&n.set(s.name,c.lastID);}}for(let s=0;s<e.length;s++){let i=e[s],c=[];for(let a of t)if(i.includes(a.name)){let l=n.get(a.name);l&&c.push(l);}r.set(s,c);}});}};chunkU3YLMQXK_cjs.c.create({service:"note-search"});var V=class{constructor(e,t){chunkU3YLMQXK_cjs.a(this,"db");chunkU3YLMQXK_cjs.a(this,"config");this.db=e,this.config={...types.DEFAULT_NOTE_CHUNK_CONFIG,...t,embeddingLlm:t.embeddingLlm},t.embeddingLlm&&exports.Llm.init({models:{embeddingLlm:t.embeddingLlm,graphLlm:t.graphLlm,rerankLlm:t.rerankLlm}});}async search(e,t){if(!e.trim())return [];let r=t?.maxResults||3,n=t?.minScore??this.config.search.minScore,o=await this.hybridSearch(e,{...t,maxResults:r*2});return o.length===0?[]:this.config.rerankLlm?(await this.rerank(e,o,r)).filter(i=>i.score>=n):o.filter(s=>s.score>=n).slice(0,r)}async hybridSearch(e,t){let{maxResults:r=this.config.search.maxResults,minScore:n=this.config.search.minScore,vectorWeight:o=this.config.search.hybrid.vectorWeight,textWeight:s=this.config.search.hybrid.textWeight,enableEmbedding:i=true,enableFts:c=true}=t??{},a=i?await this.embed(e):new Float32Array(0),[l,d]=await Promise.all([i&&this.config.embeddingLlm?this.vectorSearch(a,r,n,t):Promise.resolve([]),c===false?Promise.resolve([]):this.ftsSearch(e,r,n,t)]);return this.mergeResults(l,d,o,s,n)}async vectorSearch(e,t,r,n){if(!this.config.embeddingLlm)return [];try{let o;if(n?.candidateChunkIds&&n.candidateChunkIds.length>0){let c=n.candidateChunkIds.map(()=>"?").join(",");o=this.db.query(`SELECT chunkId, embedding FROM vectors WHERE chunkId IN (${c})`,n.candidateChunkIds);}else o=this.db.query("SELECT chunkId, embedding FROM vectors LIMIT ?",[Math.max(t*100,1e3)]);let s=[];for(let c of o){let a=new Float32Array(c.embedding.buffer,c.embedding.byteOffset,c.embedding.length/4),l=this.cosineSimilarity(e,a);s.push({chunkId:c.chunkId,score:l});}s.sort((c,a)=>a.score-c.score);let i=s.slice(0,t);return this.buildSearchResults(i,"vector",n)}catch(o){throw new R(`\u5411\u91CF\u641C\u7D22\u5931\u8D25: ${o.message}`,"SEARCH_FAILED",o)}}async ftsSearch(e,t,r,n){let o=async()=>[];try{let s=se(e),i=this.db.query("SELECT chunkId, bm25(chunks_fts) as score FROM chunks_fts WHERE content MATCH ? ORDER BY score DESC LIMIT ?",[s,t]);if(i.length===0)return o();let c=i.map(a=>({chunkId:a.chunkId,score:-a.score}));return this.buildSearchResults(c,"fts",n)}catch{return o()}}mergeResults(e,t,r,n,o){let s=r+n,i=r/s,c=n/s,a=new Map;for(let m of e){let u=`${m.chunk.id}`,h=m.score*i;a.set(u,{...m,score:h,source:"hybrid"});}for(let m of t){let u=`${m.chunk.id}`,h=a.get(u);if(h)h.score+=m.score*c;else {let g=m.score*c;a.set(u,{...m,score:g,source:"hybrid"});}}return Array.from(a.values()).map(m=>{let u=m.score,h=new Date(m.document.updatedAt),g=(Date.now()-h.getTime())/864e5,f=Math.exp(-0.01*g),b=.6*u+.4*f;return {...m,score:b}}).sort((m,u)=>u.score-m.score)}async rerank(e,t,r){if(!this.config.rerankLlm)return t.slice(0,r);try{let n=t.map(a=>{let l=a.nodes&&a.nodes.length>0?a.nodes.map(d=>{let m=(d.edges??[]).map(u=>{let h=u.source===d.id?"\u2192":"\u2190",g=u.targetNode?`${u.targetNode.type}:${u.targetNode.name}`:`id=${u.target}`;return `${h} [${u.relation}] ${g}`}).join(" | ");return `node: id=${d.id} name=${d.name} type=${d.type}${m?` edges: ${m}`:""}`}).join(" | "):"";return `<doc filePath="${a.document.path}" lineStart="${a.chunk.startLine}" lineEnd="${a.chunk.endLine}"><snippet>${a.snippet}</snippet>${l?`<nodes>${l}</nodes>`:""}</doc>`}),o=await exports.Llm.rerank(e,n,t.length);if(o.length===0)return t.slice(0,r);let s=new Map;for(let a of o)a.index>=0&&a.index<t.length&&s.set(a.index,a.score);let i=.5,c=t.map((a,l)=>{let d=s.get(l)??a.score,m=i*a.score+(1-i)*d;return {...a,originalScore:a.score,score:m,source:"reranked"}});return c.sort((a,l)=>l.score-a.score),c.slice(0,r)}catch{return t.slice(0,r)}}async embed(e){try{return await exports.Llm.embed(e)}catch{return new Float32Array(this.config.vectorDims)}}cosineSimilarity(e,t){let r=0,n=0,o=0;for(let s=0;s<e.length;s++){let i=e[s],c=t[s];r+=i*c,n+=i*i,o+=c*c;}return n===0||o===0?0:r/(Math.sqrt(n)*Math.sqrt(o))}async buildSearchResults(e,t,r){let n=[],o=e.map(p=>p.chunkId);if(o.length===0)return n;let s=r?.includeEdges??true,i=Math.max(1,r?.edgesLimit??100),c=this.db.query("SELECT * FROM chunks WHERE id IN ("+o.map(()=>"?").join(", ")+")",o),a=new Map(c.map(p=>[p.id,p])),l=Array.from(new Set(c.map(p=>p.documentId))),d=l.length>0?this.db.query("SELECT * FROM documents WHERE id IN ("+l.map(()=>"?").join(", ")+")",l):[],m=new Map(d.map(p=>[p.id,p])),u=new Map,h=[];for(let p of c){let I=[];try{let S=p.nodeIds?JSON.parse(p.nodeIds):[];I=Array.isArray(S)?S.filter(w=>typeof w=="number"):[];}catch{I=[];}u.set(p.id,I),h.push(...I);}let g=Array.from(new Set(h)),f=g.length>0?this.db.query("SELECT * FROM nodes WHERE id IN ("+g.map(()=>"?").join(", ")+")",g):[],b=new Map(f.map(p=>[p.id,{id:p.id,name:p.name,type:p.type,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt,updatedAt:p.updatedAt}])),N=s&&g.length>0?this.db.query("SELECT * FROM edges WHERE source IN ("+g.map(()=>"?").join(", ")+") OR target IN ("+g.map(()=>"?").join(", ")+") ORDER BY id LIMIT ?",[...g,...g,g.length*i]):[],T=[...new Set([...g,...N.map(p=>p.target)])],_=T.length>0?this.db.query("SELECT * FROM nodes WHERE id IN ("+T.map(()=>"?").join(", ")+")",T):[],$=new Map(_.map(p=>[p.id,{id:p.id,name:p.name,type:p.type,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt,updatedAt:p.updatedAt}])),L=new Map;for(let p of N){let I={id:p.id,source:p.source,target:p.target,relation:p.relation,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt},S=$.get(p.target);S&&(I.targetNode=S);let w=L.get(I.source)??[];w.length<i&&(w.push(I),L.set(I.source,w));let F=L.get(I.target)??[];F.length<i&&(F.push(I),L.set(I.target,F));}for(let p of e){let I=a.get(p.chunkId);if(!I)continue;let S=m.get(I.documentId);if(!S)continue;let w=u.get(I.id)??[],F=w.map(k=>b.get(k)).filter(k=>k!==void 0),q=s&&w.length>0?Array.from(new Map(w.flatMap(k=>L.get(k)??[]).map(k=>[k.id,k])).values()):[],z=new Map;for(let k of q){let te=z.get(k.source)??[];te.push(k),z.set(k.source,te);}let K=F.length>0?F.map(k=>({...k,edges:s?z.get(k.id)??[]:void 0})):[];n.push({chunk:{id:I.id,documentId:I.documentId,startLine:I.startLine,endLine:I.endLine,startChar:I.startChar,endChar:I.endChar,content:I.content,contentHash:I.contentHash,nodeIds:w,path:S.path,createdAt:I.createdAt},document:{id:S.id,path:S.path,title:S.title,contentHash:S.contentHash,summary:S.summary,lastModified:S.lastModified,createdAt:S.createdAt,updatedAt:S.updatedAt},nodes:K.length>0?K:void 0,score:p.score,snippet:I.content.slice(0,200),source:t});}return n}};var J=class{constructor(e){chunkU3YLMQXK_cjs.a(this,"db");this.db=e;}async queryNodes(e,t){try{if(typeof e=="string")return this.db.query(e,t).map(c=>this.mapNode(c));let r=[],n=[];e.ids&&e.ids.length>0&&(r.push(`id IN (${e.ids.map(()=>"?").join(",")})`),n.push(...e.ids)),e.name&&(r.push("name LIKE ?"),n.push(`%${e.name}%`)),e.type&&(r.push("type = ?"),n.push(e.type));let o="SELECT * FROM nodes";return r.length>0&&(o+=` WHERE ${r.join(" AND ")}`),o+=" ORDER BY id",e.limit&&e.limit>0&&(o+=" LIMIT ?",n.push(e.limit)),this.db.query(o,n).map(i=>this.mapNode(i))}catch(r){throw new R(`\u67E5\u8BE2\u8282\u70B9\u5931\u8D25: ${r.message}`,"SEARCH_FAILED",r)}}async queryEdges(e,t){try{if(typeof e=="string")return this.db.query(e,t).map(c=>this.mapEdge(c));let r=[],n=[];e.ids&&e.ids.length>0&&(r.push(`id IN (${e.ids.map(()=>"?").join(",")})`),n.push(...e.ids)),typeof e.source=="number"&&(r.push("source = ?"),n.push(e.source)),typeof e.target=="number"&&(r.push("target = ?"),n.push(e.target)),e.sourceOrTarget&&e.sourceOrTarget.length>0&&(r.push(`(source IN (${e.sourceOrTarget.map(()=>"?").join(", ")}) OR target IN (${e.sourceOrTarget.map(()=>"?").join(", ")}))`),n.push(...e.sourceOrTarget,...e.sourceOrTarget)),e.relation&&(r.push("relation = ?"),n.push(e.relation));let o="SELECT * FROM edges";return r.length>0&&(o+=` WHERE ${r.join(" AND ")}`),o+=" ORDER BY id",e.limit&&e.limit>0&&(o+=" LIMIT ?",n.push(e.limit)),this.db.query(o,n).map(i=>this.mapEdge(i))}catch(r){throw new R(`\u67E5\u8BE2\u8FB9\u5931\u8D25: ${r.message}`,"SEARCH_FAILED",r)}}async queryNeighbors(e,t){let r=t?.direction??"both",n=t?.relationTypes,o=t?.limit&&t.limit>0?t.limit:100,s=[],i=[];r==="incoming"?(s.push("target = ?"),i.push(e)):r==="outgoing"?(s.push("source = ?"),i.push(e)):(s.push("(source = ? OR target = ?)"),i.push(e,e)),n&&n.length>0&&(s.push(`relation IN (${n.map(()=>"?").join(",")})`),i.push(...n));let c=await this.queryEdges(`SELECT * FROM edges WHERE ${s.join(" AND ")} ORDER BY id LIMIT ?`,[...i,o]),a=Array.from(new Set(c.map(u=>u.source===e?u.target:u.source)));if(a.length===0)return {nodes:await this.queryNodes({ids:[e],limit:1}),edges:c};let l=[...new Set([e,...a])],d=await this.queryNodes({ids:l,limit:l.length}),m=new Map(d.map(u=>[u.id,u]));for(let u of c){let h=m.get(u.target);h&&(u.targetNode=h);}return {nodes:d,edges:c}}async queryCallGraph(e,t=2){let r=Math.max(1,t),n=new Map,o=[{id:e,level:0}],s=new Set;for(;o.length>0;){let i=o.shift();if(s.has(i.id)||i.level>r)continue;s.add(i.id);let c=await this.queryEdges({source:i.id,relation:"CALLS",limit:100}),a=await this.queryEdges({target:i.id,relation:"CALLS",limit:100}),l=Array.from(new Set(c.map(m=>m.target))),d=Array.from(new Set(a.map(m=>m.source)));n.set(i.id,{callers:d,callees:l});for(let m of [...d,...l])s.has(m)||o.push({id:m,level:i.level+1});}return n}async queryInheritance(e){let t=["EXTENDS","INHERITS_FROM","IMPLEMENTS"],r=await this.collectInheritance(e,"ancestor",t),n=await this.collectInheritance(e,"descendant",t);return {ancestors:r,descendants:n}}async findPath(e,t,r=3){let n=[],o=new Set,s=this.db.query("SELECT * FROM nodes WHERE name = ?",[e]);if(s.length===0)return [];let i=s.map(c=>({nodeId:c.id,path:[c.id]}));for(;i.length>0;){let{nodeId:c,path:a}=i.shift();if(a.length>r)continue;let l=a.join(",");if(o.has(l))continue;if(o.add(l),a.length>1){let m=this.db.query("SELECT id, name FROM nodes WHERE id = ?",[c]);if(m.length>0&&m[0]?.name===t){let u=a.map(()=>"?").join(","),h=this.db.query(`SELECT * FROM nodes WHERE id IN (${u})`,a),g=new Map(h.map(b=>[b.id,b])),f=[];for(let b of a){let N=g.get(b);N&&f.push({id:N.id,name:N.name,type:N.type,properties:N.properties?JSON.parse(N.properties):void 0,createdAt:N.createdAt,updatedAt:N.updatedAt});}n.push(f);continue}}let d=this.db.query("SELECT source, target FROM edges WHERE source = ? OR target = ?",[c,c]);for(let m of d){let u=m.source===c?m.target:m.source;a.includes(u)||i.push({nodeId:u,path:[...a,u]});}}return n}async searchNodesByName(e){return this.queryNodes("SELECT * FROM nodes WHERE name LIKE ?",[e])}async searchNodesByType(e){return this.queryNodes("SELECT * FROM nodes WHERE type = ?",[e])}async searchRelations(e){return this.queryEdges("SELECT * FROM edges WHERE relation = ?",[e])}async createNode(e,t,r){let n=new Date().toISOString(),o=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[e,t,r?JSON.stringify(r):null,n,n]),i=this.db.query("SELECT * FROM nodes WHERE id = ?",[o.lastID])[0];return {id:i.id,name:i.name,type:i.type,properties:i.properties?JSON.parse(i.properties):void 0,createdAt:i.createdAt,updatedAt:i.updatedAt}}async updateNode(e,t){let r=new Date().toISOString();this.db.run("UPDATE nodes SET properties = ?, updatedAt = ? WHERE id = ?",[JSON.stringify(t),r,e]);let n=this.db.query("SELECT * FROM nodes WHERE id = ?",[e]);if(n.length===0)throw new R(`\u8282\u70B9\u4E0D\u5B58\u5728: ${e}`,"NODE_NOT_FOUND");let o=n[0];return {id:o.id,name:o.name,type:o.type,properties:o.properties?JSON.parse(o.properties):void 0,createdAt:o.createdAt,updatedAt:o.updatedAt}}async deleteNode(e){this.db.run("DELETE FROM nodes WHERE id = ?",[e]);}async createEdge(e,t,r,n){let o=this.db.query("SELECT id FROM nodes WHERE id = ?",[e]),s=this.db.query("SELECT id FROM nodes WHERE id = ?",[t]);if(o.length===0||s.length===0)throw new R("\u8282\u70B9\u4E0D\u5B58\u5728","NODE_NOT_FOUND");let i=new Date().toISOString(),c=this.db.run("INSERT INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[e,t,r,n?JSON.stringify(n):null,i]),l=this.db.query("SELECT * FROM edges WHERE id = ?",[c.lastID])[0];return {id:l.id,source:l.source,target:l.target,relation:l.relation,properties:l.properties?JSON.parse(l.properties):void 0,createdAt:l.createdAt}}async deleteEdge(e){this.db.run("DELETE FROM edges WHERE id = ?",[e]);}mapNode(e){return {id:e.id,name:e.name,type:e.type,properties:e.properties?JSON.parse(e.properties):void 0,createdAt:e.createdAt,updatedAt:e.updatedAt}}mapEdge(e){return {id:e.id,source:e.source,target:e.target,relation:e.relation,properties:e.properties?JSON.parse(e.properties):void 0,createdAt:e.createdAt}}async collectInheritance(e,t,r){let n=[e],o=new Set([e]),s=new Set;for(;n.length>0;){let i=n.shift(),c=t==="ancestor"?await this.queryEdges(`SELECT * FROM edges WHERE source = ? AND relation IN (${r.map(()=>"?").join(",")})`,[i,...r]):await this.queryEdges(`SELECT * FROM edges WHERE target = ? AND relation IN (${r.map(()=>"?").join(",")})`,[i,...r]);for(let a of c){let l=t==="ancestor"?a.target:a.source;o.has(l)||(o.add(l),s.add(l),n.push(l));}}return s.size===0?[]:this.queryNodes({ids:Array.from(s),limit:s.size})}};var Z=chunkU3YLMQXK_cjs.c.create({service:"note-scanner"}),Ce=["node_modules/**",".git/**","dist/**","build/**","__pycache__/**","*.min.md"],W=class{constructor(e){chunkU3YLMQXK_cjs.a(this,"workspaceDir");chunkU3YLMQXK_cjs.a(this,"extraPaths");chunkU3YLMQXK_cjs.a(this,"sources");chunkU3YLMQXK_cjs.a(this,"ignorePatterns");this.workspaceDir=e.workspaceDir,this.extraPaths=e.extraPaths??[],this.sources=new Set(e.sources??["docs"]),this.ignorePatterns=[...Ce,...e.ignorePatterns??[]];}async scanAll(e){let t=[],r=[];for(let s of this.sources){let i=B__namespace.default.join(this.workspaceDir,s);r.push({source:s,dir:i});}for(let s of this.extraPaths){let i=B__namespace.default.isAbsolute(s)?s:B__namespace.default.join(this.workspaceDir,s);r.push({source:"local",dir:i});}let n=0,o=r.length;for(let s of r){let i=await this.scanDirectory(s.dir,s.source);t.push(...i),n++,e?.(n,o,i[0]||{absolutePath:s.dir,relativePath:s.dir,source:s.source,contentHash:"",lastModified:0,size:0});}return t}async scanDirectory(e,t){let r=[];try{await U__default.default.access(e);}catch{return Z.debug("Directory not found, skipping",{dir:e}),r}let n=async o=>{try{let s=await U__default.default.readdir(o,{withFileTypes:!0});for(let i of s){let c=B__namespace.default.join(o,i.name);if(!this.shouldIgnore(i.name)){if(i.isDirectory())await n(c);else if(i.isFile()&&this.isMarkdownFile(i.name)){let a=await this.getFileInfo(c,t);a&&r.push(a);}}}}catch(s){Z.warn("Failed to scan directory",{dir:o,error:String(s)});}};return await n(e),r}async scanFile(e,t="upload"){try{let r=await U__default.default.stat(e);if(!r.isFile())return null;let n=await U__default.default.readFile(e,"utf-8"),o=crypto.createHash("sha256").update(n).digest("hex"),s=utils.Filesystem.normalize(e);return {absolutePath:e,relativePath:s||B__namespace.default.basename(e),source:t,contentHash:o,lastModified:r.mtimeMs,size:r.size}}catch(r){return Z.error("Failed to scan file",{filePath:e,error:String(r)}),null}}async getFileInfo(e,t){try{let r=await U__default.default.readFile(e,"utf-8"),n=await U__default.default.stat(e),o=crypto.createHash("sha256").update(r).digest("hex"),s=utils.Filesystem.normalize(e);return {absolutePath:e,relativePath:s,source:t,contentHash:o,lastModified:n.mtimeMs,size:n.size}}catch(r){return Z.error("Failed to get file info",{filePath:e,error:String(r)}),null}}shouldIgnore(e){if(e.startsWith("."))return true;for(let t of this.ignorePatterns)if(new RegExp("^"+t.replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$").test(e))return true;return false}isMarkdownFile(e){return e.endsWith(".md")||e.endsWith(".markdown")}};var A=chunkU3YLMQXK_cjs.c.create({service:"note"}),ee=class{constructor(e){chunkU3YLMQXK_cjs.a(this,"config");chunkU3YLMQXK_cjs.a(this,"db");chunkU3YLMQXK_cjs.a(this,"pipeline");chunkU3YLMQXK_cjs.a(this,"searchEngine");chunkU3YLMQXK_cjs.a(this,"graphInterface");chunkU3YLMQXK_cjs.a(this,"fileScanner");chunkU3YLMQXK_cjs.a(this,"initialized",false);chunkU3YLMQXK_cjs.a(this,"dirty",false);chunkU3YLMQXK_cjs.a(this,"syncTimer");chunkU3YLMQXK_cjs.a(this,"syncConfig");chunkU3YLMQXK_cjs.a(this,"syncingInProgress",false);let t=e.workspaceDir||process.cwd(),r=e.embeddingLlm;if(!r)throw new Error("embeddingLlm is required");let n=e.database?.path||types.getDefaultDatabasePath(xdgBasedir.xdgData,"note.db");this.config={workspaceDir:t,database:{path:n,walMode:e.database?.walMode??true},vectorDims:e.vectorDims??768,...types.DEFAULT_NOTE_CHUNK_CONFIG,extraPaths:e.extraPaths,sources:e.sources,search:{...types.DEFAULT_SEARCH_CONFIG,...e.search},indexer:{...types.DEFAULT_INDEXER_CONFIG,...e.indexer},sync:{...types.DEFAULT_SYNC_CONFIG,...e.sync},logDir:e.logDir,embeddingLlm:r,graphLlm:e.graphLlm,rerankLlm:e.rerankLlm},this.syncConfig=this.config.sync,this.db=new X(this.config.database.path),this.pipeline=new Q(this.db,this.config),this.searchEngine=new V(this.db,this.config),this.graphInterface=new J(this.db),this.fileScanner=new W({workspaceDir:this.config.workspaceDir,extraPaths:this.config.extraPaths,sources:this.config.sources,ignorePatterns:this.config?.indexer?.ignorePatterns});}async initialize(){if(this.initialized)return;await chunkU3YLMQXK_cjs.c.init({logDir:this.config.logDir||B__namespace.default.join(this.config.workspaceDir,"logs"),print:process.argv.includes("--print-logs"),dev:false,level:"INFO"}),exports.Llm.init({models:{embeddingLlm:this.config.embeddingLlm,graphLlm:this.config.graphLlm,rerankLlm:this.config.rerankLlm},options:{graph:{maxOutputTokens:2e3,temperature:.1}}}),await this.db.initialize();let e=[["version","1.0.0"],["chunkSize",String(this.config.chunkSize)],["chunkOverlap",String(this.config.chunkOverlap)],["createdAt",new Date().toISOString()]];for(let[t,r]of e)this.db.run("INSERT OR IGNORE INTO meta (key, value) VALUES (?, ?)",[t,r]);this.initialized=true,this.syncConfig.onBoot&&(this.syncAll().catch(t=>A.warn("onBoot sync failed",{error:String(t)})),this.startSyncTimer()),A.debug("NoteKnowledge initialized",{workspaceDir:this.config.workspaceDir,dbPath:this.config.database.path,embeddingEnabled:!!this.config.embeddingLlm,graphLlmEnabled:!!this.config.graphLlm,rerankLlmEnabled:!!this.config.rerankLlm,chunkSize:this.config.chunkSize,chunkOverlap:this.config.chunkOverlap,sources:this.config.sources,syncOnBoot:this.syncConfig.onBoot,syncIntervalMs:this.syncConfig.intervalMs,hybridSearch:this.config.search?.hybrid?.enabled,vectorWeight:this.config.search?.hybrid?.vectorWeight,textWeight:this.config.search?.hybrid?.textWeight});}startSyncTimer(){this.syncTimer&&clearInterval(this.syncTimer),this.syncConfig.intervalMs>0&&(this.syncTimer=setInterval(async()=>{try{await this.syncAll();}catch(e){A.error("Interval sync failed",{error:String(e)});}},this.syncConfig.intervalMs));}ensureSynced(){this.dirty&&!this.syncingInProgress&&this.syncConfig.onSearch&&this.syncAll().catch(e=>{A.warn("Background sync failed",{error:String(e)});});}stopSyncTimer(){this.syncTimer&&(clearInterval(this.syncTimer),this.syncTimer=void 0);}async syncAll(){if(this.syncingInProgress){A.debug("Sync already in progress, skipping...");return}this.syncingInProgress=true,A.debug("Starting sync...");try{let e=await this.sync((t,r,n)=>{A.debug("Syncing file",{current:t,total:r,path:n.relativePath||B__namespace.default.basename(n.absolutePath)});});this.dirty=!1,A.debug("Sync completed",{totalFiles:e.filesAdded+e.filesUpdated+e.filesSkipped,added:e.filesAdded,updated:e.filesUpdated,deleted:e.filesDeleted,skipped:e.filesSkipped,errors:e.errors.length});}finally{this.syncingInProgress=false;}}async ingestDocument(e){return await this.ensureInitialized(),this.pipeline.process(e)}async ingestDocuments(e,t){await this.ensureInitialized();let r=[];for(let n=0;n<e.length;n++){let o=await this.pipeline.process(e[n]);r.push(o),t?.((n+1)/e.length);}return r}async scanAndIngest(e){for(await this.ensureInitialized();this.syncingInProgress;)await new Promise(n=>setTimeout(n,100));let t=await this.fileScanner.scanAll(e);if(t.length===0)return [];let r=t.map(n=>n.absolutePath);return this.ingestDocuments(r,n=>{e?.(Math.round(n*t.length),t.length,t[0]||{absolutePath:"ingesting...",relativePath:"ingesting...",source:"docs",contentHash:"",lastModified:0,size:0});})}async ingestUploadedFile(e){await this.ensureInitialized();let t=await this.fileScanner.scanFile(e,"upload");if(!t)throw new Error(`\u65E0\u6CD5\u626B\u63CF\u6587\u4EF6: ${e}`);return this.pipeline.process(t.absolutePath)}async removeDocument(e){await this.ensureInitialized();let t=utils.Filesystem.normalize(e);try{this.db.deleteDocumentByPath(t)&&A.debug("Removed document",{path:t});}catch(r){throw A.error("Failed to remove document",{path:t,error:String(r)}),r}}markDirty(){this.dirty=true,A.debug("Marked as dirty, will sync before next search");}async sync(e){if(await this.ensureInitialized(),this.syncingInProgress)return A.debug("Sync already in progress, skipping..."),{success:true,filesAdded:0,filesUpdated:0,filesDeleted:0,filesSkipped:0,chunksCreated:0,vectorsCreated:0,entitiesExtracted:0,relationsExtracted:0,errors:[],duration:0};this.syncingInProgress=true;try{let t=Date.now(),r={success:!0,filesAdded:0,filesUpdated:0,filesDeleted:0,filesSkipped:0,chunksCreated:0,vectorsCreated:0,entitiesExtracted:0,relationsExtracted:0,errors:[],duration:0},n=await this.fileScanner.scanAll(e),o=new Set(n.map(a=>a.relativePath)),s=this.db.query("SELECT path, contentHash FROM documents"),i=new Map;for(let a of s)i.set(a.path,a.contentHash);for(let[a]of i)if(!o.has(a))try{this.db.deleteDocumentByPath(a)&&(r.filesDeleted++,A.debug("Deleted document from index",{path:a}));}catch(l){let d=l instanceof Error?l.message:String(l);r.errors.push({filePath:a,error:`Failed to delete document: ${d}`}),A.error("Failed to delete document",{path:a,error:d});}for(let a=0;a<n.length;a++){let l=n[a],d=l.relativePath;e?.(a+1,n.length,l);try{let m=i.get(d);if(m===void 0){let u=await this.pipeline.process(l.absolutePath);r.filesAdded++,r.chunksCreated+=u.chunksCreated,r.vectorsCreated+=u.vectorsCreated,r.entitiesExtracted+=u.entitiesExtracted||0,r.relationsExtracted+=u.relationsExtracted||0,A.debug("Added new document",{path:d});}else if(m!==l.contentHash){let u=await this.pipeline.process(l.absolutePath);r.filesUpdated++,r.chunksCreated+=u.chunksCreated,r.vectorsCreated+=u.vectorsCreated,r.entitiesExtracted+=u.entitiesExtracted||0,r.relationsExtracted+=u.relationsExtracted||0,A.debug("Updated document",{path:d});}else r.filesSkipped++;}catch(m){let u=m instanceof Error?m.message:String(m);r.errors.push({filePath:d,error:u}),A.error("Failed to process document",{path:d,error:u});}}r.duration=Date.now()-t,r.success=r.errors.length===0;let c={timestamp:new Date().toISOString(),success:r.success,filesAdded:r.filesAdded,filesUpdated:r.filesUpdated,filesDeleted:r.filesDeleted,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,vectorsCreated:r.vectorsCreated,entitiesExtracted:r.entitiesExtracted,relationsExtracted:r.relationsExtracted,errorCount:r.errors.length,duration:r.duration};return this.db.setMeta("lastSync",c.timestamp),this.db.setMeta("lastSyncResult",JSON.stringify(c)),A.info("Sync completed",{added:r.filesAdded,updated:r.filesUpdated,deleted:r.filesDeleted,skipped:r.filesSkipped,errors:r.errors.length,duration:r.duration}),r}finally{this.syncingInProgress=false;}}async search(e,t){return await this.ensureInitialized(),this.ensureSynced(),this.searchEngine.search(e,t)}async queryNodes(e,t){return await this.ensureInitialized(),typeof e=="string"?this.graphInterface.queryNodes(e,t):this.graphInterface.queryNodes(e)}async queryEdges(e,t){return await this.ensureInitialized(),typeof e=="string"?this.graphInterface.queryEdges(e,t):this.graphInterface.queryEdges(e)}async findPath(e,t,r){return await this.ensureInitialized(),this.graphInterface.findPath(e,t,r)}async queryNeighbors(e,t){return await this.ensureInitialized(),this.graphInterface.queryNeighbors(e,t)}async queryCallGraph(e,t){return await this.ensureInitialized(),this.graphInterface.queryCallGraph(e,t)}async queryInheritance(e){return await this.ensureInitialized(),this.graphInterface.queryInheritance(e)}async createNode(e,t,r){return await this.ensureInitialized(),this.graphInterface.createNode(e,t,r)}async updateNode(e,t){return await this.ensureInitialized(),this.graphInterface.updateNode(e,t)}async deleteNode(e){return await this.ensureInitialized(),this.graphInterface.deleteNode(e)}async createEdge(e,t,r,n){return await this.ensureInitialized(),this.graphInterface.createEdge(e,t,r,n)}async deleteEdge(e){return await this.ensureInitialized(),this.graphInterface.deleteEdge(e)}getStatus(){let e=this.db.getPath(),t=0,r=0,n=0,o=0;try{t=this.db.getDb().prepare("SELECT COUNT(*) as count FROM documents").get()?.count||0,r=this.db.getDb().prepare("SELECT COUNT(*) as count FROM chunks").get()?.count||0,n=this.db.getDb().prepare("SELECT COUNT(*) as count FROM nodes").get()?.count||0,o=this.db.getDb().prepare("SELECT COUNT(*) as count FROM edges").get()?.count||0;}catch{}return {dbPath:e,workspaceDir:this.config.workspaceDir,documentsCount:t,chunksCount:r,nodesCount:n,edgesCount:o,embeddingLlmAvailable:!!this.config.embeddingLlm,graphLlmAvailable:!!this.config.graphLlm,rerankLlmAvailable:!!this.config.rerankLlm,healthy:this.initialized,meta:this.getMetaMap()}}getMetaMap(){let e={};try{let t=this.db.query("SELECT key, value FROM meta");for(let r of t)e[r.key]=r.value;}catch{}return e}async healthCheck(){try{return this.db.query("SELECT 1"),!0}catch{return false}}async clear(){this.db.transaction(()=>{this.db.run("DELETE FROM chunks"),this.db.run("DELETE FROM documents"),this.db.run("DELETE FROM vectors"),this.db.run("DELETE FROM nodes"),this.db.run("DELETE FROM edges"),this.db.run("DELETE FROM embedding_cache"),this.db.run("DELETE FROM sqlite_sequence WHERE name IN ('chunks', 'documents', 'nodes', 'edges')");});try{this.db.run("INSERT INTO chunks_fts(chunks_fts) VALUES('delete-all')");}catch(e){A.warn("Failed to clear FTS index",{error:String(e)});}A.info("Note knowledge base cleared");}async ensureInitialized(){this.initialized||await this.initialize();}async close(){this.initialized&&(this.stopSyncTimer(),await this.db.close(),this.initialized=false,A.info("NoteKnowledge closed"));}};async function He(E){let e=new ee(E);return await e.initialize(),e}async function ur(E){let{Log:e}=await import('./chunks/log-WNH7UHDM.cjs'),t=false;await e.init({logDir:E.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:E.print??false,dev:E.dev??t,level:E.level??("INFO")});}Object.defineProperty(exports,"GRAPH_ENTITY_TYPE_DEFINITIONS",{enumerable:true,get:function(){return types.GRAPH_ENTITY_TYPE_DEFINITIONS}});Object.defineProperty(exports,"GRAPH_RELATION_TYPE_DEFINITIONS",{enumerable:true,get:function(){return types.GRAPH_RELATION_TYPE_DEFINITIONS}});exports.FileScanner=W;exports.KnowledgeBaseError=R;exports.KnowledgeBaseErrorCode=H;exports.NoteKnowledge=ee;exports.addWord=ot;exports.closeTokenizer=ct;exports.createNoteKnowledge=He;exports.initLog=ur;exports.initTokenizer=it;exports.isInitialized=at;exports.loadCustomDict=ye;exports.toFtsTokens=ne;exports.toFtsTokensForSearch=se;exports.tokenize=be;exports.tokenizeForSearch=Ie;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import {b,a}from'./chunks/chunk-WT6IECLQ.mjs';import ge from'better-sqlite3';import {loadTextFile,Filesystem,Markdown}from'@easbot/utils';import {GRAPH_ENTITY_TYPE_DEFINITIONS,GRAPH_RELATION_TYPE_DEFINITIONS,getDefaultDatabasePath,DEFAULT_SYNC_CONFIG,DEFAULT_INDEXER_CONFIG,DEFAULT_SEARCH_CONFIG,DEFAULT_NOTE_CHUNK_CONFIG}from'@easbot/types';export{GRAPH_ENTITY_TYPE_DEFINITIONS,GRAPH_RELATION_TYPE_DEFINITIONS}from'@easbot/types';import B,{readFile}from'fs/promises';import*as U from'path';import U__default,{extname}from'path';import*as F from'jieba-wasm';import {embed,embedMany,streamText,rerank}from'ai';import {createHash}from'crypto';import {xdgData}from'xdg-basedir';var z=(l=>(l.DATABASE_INIT_FAILED="DATABASE_INIT_FAILED",l.DATABASE_NOT_INITIALIZED="DATABASE_NOT_INITIALIZED",l.DATABASE_QUERY_FAILED="DATABASE_QUERY_FAILED",l.DOCUMENT_PARSE_FAILED="DOCUMENT_PARSE_FAILED",l.EMBEDDING_FAILED="EMBEDDING_FAILED",l.ENTITY_EXTRACTION_FAILED="ENTITY_EXTRACTION_FAILED",l.SEARCH_FAILED="SEARCH_FAILED",l.NODE_NOT_FOUND="NODE_NOT_FOUND",l.EDGE_NOT_FOUND="EDGE_NOT_FOUND",l.INVALID_CONFIG="INVALID_CONFIG",l.MODEL_INJECTION_FAILED="MODEL_INJECTION_FAILED",l))(z||{}),R=class extends Error{constructor(t,r,n){super(t,{cause:n});this.code=r;this.cause=n;this.name="KnowledgeBaseError";}toString(){return `${this.name}: ${this.message} (${this.code})`}};var X=class{constructor(e){a(this,"db",null);a(this,"storagePath");a(this,"initialized",false);a(this,"initPromise",null);this.storagePath=Filesystem.toUnixPath(e);}async initialize(){if(!this.initialized){if(this.initPromise){await this.initPromise;return}this.initPromise=this.doInitialize(),await this.initPromise,this.initialized=true;}}async doInitialize(){try{this.db=await this.openDatabaseAsync(),this.createTables();}catch(e){throw new R(`Database initialization failed: ${e.message}`,"DATABASE_INIT_FAILED",e)}}async openDatabaseAsync(){return new Promise((e,t)=>{setImmediate(()=>{try{let r=new ge(this.storagePath);r.pragma("journal_mode = WAL"),r.pragma("synchronous = NORMAL"),r.pragma("cache_size = -64000"),r.pragma("temp_store = MEMORY"),e(r);}catch(r){t(r);}});})}ensureInitialized(){if(!this.initialized||!this.db)throw new R("Database not initialized. Call initialize() first.","DATABASE_NOT_INITIALIZED")}createTables(){if(!this.db)throw new R("Database not initialized. Call initialize() first.","DATABASE_NOT_INITIALIZED");let e=this.db;e.exec(`
1
+ import {b,a}from'./chunks/chunk-WT6IECLQ.mjs';import le from'better-sqlite3';import {loadTextFile,Filesystem,Markdown}from'@easbot/utils';import {GRAPH_ENTITY_TYPE_DEFINITIONS,GRAPH_RELATION_TYPE_DEFINITIONS,getDefaultDatabasePath,DEFAULT_SYNC_CONFIG,DEFAULT_INDEXER_CONFIG,DEFAULT_SEARCH_CONFIG,DEFAULT_NOTE_CHUNK_CONFIG}from'@easbot/types';export{GRAPH_ENTITY_TYPE_DEFINITIONS,GRAPH_RELATION_TYPE_DEFINITIONS}from'@easbot/types';import B,{readFile}from'fs/promises';import*as W from'path';import W__default,{extname}from'path';import {createHash}from'crypto';import*as x from'jieba-wasm';import {embed,embedMany,streamText,rerank}from'ai';import {xdgData}from'xdg-basedir';var U=(d=>(d.DATABASE_INIT_FAILED="DATABASE_INIT_FAILED",d.DATABASE_NOT_INITIALIZED="DATABASE_NOT_INITIALIZED",d.DATABASE_QUERY_FAILED="DATABASE_QUERY_FAILED",d.DOCUMENT_PARSE_FAILED="DOCUMENT_PARSE_FAILED",d.EMBEDDING_FAILED="EMBEDDING_FAILED",d.ENTITY_EXTRACTION_FAILED="ENTITY_EXTRACTION_FAILED",d.SEARCH_FAILED="SEARCH_FAILED",d.NODE_NOT_FOUND="NODE_NOT_FOUND",d.EDGE_NOT_FOUND="EDGE_NOT_FOUND",d.INVALID_CONFIG="INVALID_CONFIG",d.MODEL_INJECTION_FAILED="MODEL_INJECTION_FAILED",d))(U||{}),R=class extends Error{constructor(t,r,n){super(t,{cause:n});a(this,"code",r);a(this,"cause",n);this.name="KnowledgeBaseError";}toString(){return `${this.name}: ${this.message} (${this.code})`}};var Y=class{constructor(e){a(this,"db",null);a(this,"storagePath");a(this,"initialized",false);a(this,"initPromise",null);this.storagePath=Filesystem.normalize(e);}async initialize(){if(!this.initialized){if(this.initPromise){await this.initPromise;return}this.initPromise=this.doInitialize(),await this.initPromise,this.initialized=true;}}async doInitialize(){try{this.db=await this.openDatabaseAsync(),this.createTables();}catch(e){throw new R(`Database initialization failed: ${e.message}`,"DATABASE_INIT_FAILED",e)}}async openDatabaseAsync(){return new Promise((e,t)=>{setImmediate(()=>{try{let r=new le(this.storagePath);r.pragma("journal_mode = WAL"),r.pragma("synchronous = NORMAL"),r.pragma("cache_size = -64000"),r.pragma("temp_store = MEMORY"),e(r);}catch(r){t(r);}});})}ensureInitialized(){if(!this.initialized||!this.db)throw new R("Database not initialized. Call initialize() first.","DATABASE_NOT_INITIALIZED")}createTables(){if(!this.db)throw new R("Database not initialized. Call initialize() first.","DATABASE_NOT_INITIALIZED");let e=this.db;e.exec(`
2
2
  CREATE TABLE IF NOT EXISTS nodes (
3
3
  id INTEGER PRIMARY KEY AUTOINCREMENT,
4
4
  name TEXT NOT NULL,
@@ -81,22 +81,23 @@ import {b,a}from'./chunks/chunk-WT6IECLQ.mjs';import ge from'better-sqlite3';imp
81
81
  `),e.pragma("foreign_keys = ON");}query(e,t){if(!this.db)throw new Error("Database not initialized");try{let r=this.db.prepare(e);return t?r.all(...t):r.all()}catch(r){throw new R(`Query failed: ${r.message}`,"DATABASE_QUERY_FAILED",r)}}run(e,t){if(!this.db)throw new Error("Database not initialized");try{let r=this.db.prepare(e),n=t?r.run(...t):r.run();return {lastID:Number(n.lastInsertRowid),changes:n.changes}}catch(r){throw new R(`Execution failed: ${r.message}`,"DATABASE_QUERY_FAILED",r)}}transaction(e){if(!this.db)throw new Error("Database not initialized");return this.db.transaction(e)()}async close(){this.db&&(this.db.close(),this.db=null);}getPath(){return this.storagePath}getDb(){if(!this.db)throw new Error("Database not initialized");return this.db}async getDocumentsCount(){return (await this.query("SELECT COUNT(*) as count FROM documents"))[0]?.count??0}async getChunksCount(){return (await this.query("SELECT COUNT(*) as count FROM chunks"))[0]?.count??0}async getNodesCount(){return (await this.query("SELECT COUNT(*) as count FROM nodes"))[0]?.count??0}async getEdgesCount(){return (await this.query("SELECT COUNT(*) as count FROM edges"))[0]?.count??0}async isVectorSearchAvailable(){try{return ((await this.query("SELECT COUNT(*) as count FROM vectors"))[0]?.count??0)>0}catch{return false}}async healthCheck(){try{return this.db?(await this.query("SELECT 1"),!0):!1}catch{return false}}getMeta(e){if(!this.db)throw new Error("Database not initialized");return this.db.prepare("SELECT value FROM meta WHERE key = ?").get(e)?.value??null}setMeta(e,t){if(!this.db)throw new Error("Database not initialized");this.db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)").run(e,t);}getAllDocumentPaths(){if(!this.db)throw new Error("Database not initialized");return this.db.prepare("SELECT path FROM documents").all().map(t=>t.path)}getDocumentIdByPath(e){if(!this.db)throw new Error("Database not initialized");return this.db.prepare("SELECT id FROM documents WHERE path = ?").get(e)?.id??null}getChunkIdsByDocumentId(e){if(!this.db)throw new Error("Database not initialized");return this.db.prepare("SELECT id FROM chunks WHERE documentId = ?").all(e).map(r=>r.id)}cleanupDocumentData(e){if(!this.db)throw new Error("Database not initialized");this.transaction(()=>{let t=this.db.prepare("SELECT id, nodeIds, contentHash FROM chunks WHERE documentId = ?").all(e);if(t.length===0){this.run("DELETE FROM documents WHERE id = ?",[e]);return}let r=t.map(s=>s.id),n=t.map(s=>s.contentHash),o=new Set;for(let s of t)if(s.nodeIds)try{let i=JSON.parse(s.nodeIds);for(let c of i)o.add(c);}catch{}if(r.length>0){let s=r.map(()=>"?").join(",");try{this.run(`DELETE FROM chunks_fts WHERE chunkId IN (${s})`,r);}catch{for(let i of r)try{this.run("DELETE FROM chunks_fts WHERE chunkId = ?",[i]);}catch{}}}if(o.size>0){let s=Array.from(o),i=this.db.prepare(`
82
82
  SELECT nodeIds FROM chunks
83
83
  WHERE documentId != ?
84
- `).all(e),c=new Set;for(let a of i)if(a.nodeIds)try{let d=JSON.parse(a.nodeIds);for(let l of d)c.add(l);}catch{}for(let a of s)c.has(a)||this.run("DELETE FROM nodes WHERE id = ?",[a]);}if(n.length>0)for(let s of n){let i=this.db.prepare("SELECT COUNT(*) as count FROM chunks WHERE contentHash = ? AND documentId != ?").get(s,e);(!i||i.count===0)&&this.run("DELETE FROM embedding_cache WHERE contentHash = ?",[s]);}this.run("DELETE FROM chunks WHERE documentId = ?",[e]),this.run("DELETE FROM documents WHERE id = ?",[e]);});}deleteDocumentByPath(e){let t=this.getDocumentIdByPath(e);return t===null?false:(this.cleanupDocumentData(t),true)}};var H=class{async parse(e){try{let t=await readFile(e,"utf-8"),r=extname(e).toLowerCase(),n=this.parseMarkdown(t);return {content:n.content,metadata:n.metadata}}catch(t){throw new R(`\u6587\u6863\u89E3\u6790\u5931\u8D25: ${t.message}`,"DOCUMENT_PARSE_FAILED",t)}}parseMarkdown(e){let{frontmatter:t,content:r}=Markdown.extractFrontmatter(e),n={};t.title!==void 0&&(n.title=String(t.title)),t.author!==void 0&&(n.author=String(t.author)),t.date!==void 0&&(n.date=String(t.date));for(let[s,i]of Object.entries(t))["title","author","date"].includes(s)||(n[s]=i);return {content:Markdown.format(r),metadata:n}}static computeHash(e){let t=0;for(let r=0;r<e.length;r++){let n=e.charCodeAt(r);t=(t<<5)-t+n,t=t&t;}return Math.abs(t).toString(16)}};var P=b.create({service:"note.tokenizer"}),_=false,ye=loadTextFile("./assets/jieba_dict.txt",import.meta.url);async function nt(E){if(!_)try{P.info("Initializing jieba tokenizer");let e=ye();if(F.with_dict(e),P.info("Built-in dictionary loaded"),E?.dictPath&&E.dictPath.length>0)for(let t of E.dictPath)await be(t);_=!0,P.info("Jieba tokenizer initialized");}catch(e){throw P.error("Failed to initialize jieba tokenizer",{error:String(e)}),e}}async function be(E){if(!_)throw new Error("Tokenizer not initialized");try{let e=await Filesystem.readText(E);F.with_dict(e),P.info("Custom dictionary loaded",{dictPath:E});}catch(e){P.warn("Failed to load custom dictionary",{dictPath:E,error:String(e)});}}function Ie(E){if(!_)return E.split(/\s+/).filter(Boolean);try{return F.cut(E)}catch(e){return P.warn("Tokenization failed, using fallback",{error:String(e)}),E.split(/\s+/).filter(Boolean)}}function Ne(E){if(!_)return E.split(/\s+/).filter(Boolean);try{return F.cut_for_search(E)}catch(e){return P.warn("Tokenization for search failed, using fallback",{error:String(e)}),E.split(/\s+/).filter(Boolean)}}function st(E,e,t){if(_)try{F.add_word(E,e,t);}catch(r){P.warn("Failed to add word",{word:E,error:String(r)});}}function it(){return _}async function ot(){_=false,P.info("Tokenizer closed");}function ie(E){return Ie(E).join(" ")}function oe(E){return Ne(E).join(" ")}var L;(u=>{let E=b.create({service:"note-llm"}),e=null,t=()=>{if(!e)throw new Error("Llm is not initialized. Please call Llm.init() first.");return e};function r(m){n()||(e={models:m.models,options:{graph:m.options?.graph,rerankTopN:m.options?.rerankTopN}},E.debug("Llm initialized"));}u.init=r;function n(){return e!==null}u.isInitialized=n;function o(){return e?{embedding:!!e.models.embeddingLlm,graphLlm:!!e.models.graphLlm,rerankLlm:!!e.models.rerankLlm}:{embedding:false,graphLlm:false,rerankLlm:false}}u.capabilities=o;async function s(m){let f=t().models.embeddingLlm;if(!f)throw new Error("embeddingLlm model is not configured.");let y=await embed({model:f,value:m});return new Float32Array(y.embedding)}u.embedText=s;async function i(m){let f=t().models.embeddingLlm;if(!f)throw new Error("embeddingLlm model is not configured.");return (await embedMany({model:f,values:m})).embeddings.map(b=>new Float32Array(b))}u.embedTexts=i;async function c(m,h){let f=t(),y=f.models.graphLlm;if(!y)return "";let b=d(m);return (await streamText({model:y,prompt:b,maxOutputTokens:h?.maxOutputTokens??f.options.graph?.maxOutputTokens,temperature:h?.temperature??f.options.graph?.temperature})).text}u.generateGraph=c;async function a(m,h,f){let y=t();return y.models.rerankLlm?(await rerank({model:y.models.rerankLlm,query:m,documents:h,topN:f??y.options.rerankTopN??h.length})).ranking.map(S=>({index:S.originalIndex,score:S.score??0})):[]}u.rerank=a;function d(m){let h=GRAPH_ENTITY_TYPE_DEFINITIONS.map(S=>`- ${S.type}: ${S.rule}`).join(`
85
- `),f=GRAPH_RELATION_TYPE_DEFINITIONS.map(S=>`- ${S.type}: ${S.rule}`).join(`
86
- `),b=m.slice(0,5).join(`
84
+ `).all(e),c=new Set;for(let a of i)if(a.nodeIds)try{let l=JSON.parse(a.nodeIds);for(let d of l)c.add(d);}catch{}for(let a of s)c.has(a)||this.run("DELETE FROM nodes WHERE id = ?",[a]);}if(n.length>0)for(let s of n){let i=this.db.prepare("SELECT COUNT(*) as count FROM chunks WHERE contentHash = ? AND documentId != ?").get(s,e);(!i||i.count===0)&&this.run("DELETE FROM embedding_cache WHERE contentHash = ?",[s]);}this.run("DELETE FROM chunks WHERE documentId = ?",[e]),this.run("DELETE FROM documents WHERE id = ?",[e]);});}deleteDocumentByPath(e){let t=this.getDocumentIdByPath(e);return t===null?false:(this.cleanupDocumentData(t),true)}};var _=class{async parse(e){try{let t=await readFile(e,"utf-8"),r=extname(e).toLowerCase(),n=this.parseMarkdown(t);return {content:n.content,metadata:n.metadata}}catch(t){throw new R(`\u6587\u6863\u89E3\u6790\u5931\u8D25: ${t.message}`,"DOCUMENT_PARSE_FAILED",t)}}parseMarkdown(e){let{frontmatter:t,content:r}=Markdown.extractFrontmatter(e),n={};t.title!==void 0&&(n.title=String(t.title)),t.author!==void 0&&(n.author=String(t.author)),t.date!==void 0&&(n.date=String(t.date));for(let[s,i]of Object.entries(t))["title","author","date"].includes(s)||(n[s]=i);return {content:Markdown.format(r),metadata:n}}static computeHash(e){return createHash("sha256").update(e,"utf-8").digest("hex")}};var v=b.create({service:"note.tokenizer"}),F=false,ye=loadTextFile("./assets/jieba_dict.txt",import.meta.url);async function ot(E){if(!F)try{v.info("Initializing jieba tokenizer");let e=ye();if(x.with_dict(e),v.info("Built-in dictionary loaded"),E?.dictPath&&E.dictPath.length>0)for(let t of E.dictPath)await be(t);F=!0,v.info("Jieba tokenizer initialized");}catch(e){throw v.error("Failed to initialize jieba tokenizer",{error:String(e)}),e}}async function be(E){if(!F)throw new Error("Tokenizer not initialized");try{let e=await Filesystem.readText(E);x.with_dict(e),v.info("Custom dictionary loaded",{dictPath:E});}catch(e){v.warn("Failed to load custom dictionary",{dictPath:E,error:String(e)});}}function Ie(E){if(!F)return E.split(/\s+/).filter(Boolean);try{return x.cut(E)}catch(e){return v.warn("Tokenization failed, using fallback",{error:String(e)}),E.split(/\s+/).filter(Boolean)}}function Ne(E){if(!F)return E.split(/\s+/).filter(Boolean);try{return x.cut_for_search(E)}catch(e){return v.warn("Tokenization for search failed, using fallback",{error:String(e)}),E.split(/\s+/).filter(Boolean)}}function at(E,e,t){if(F)try{x.add_word(E,e,t);}catch(r){v.warn("Failed to add word",{word:E,error:String(r)});}}function ct(){return F}async function dt(){F=false,v.info("Tokenizer closed");}function se(E){return Ie(E).join(" ")}function ie(E){return Ne(E).join(" ")}var D;(u=>{let E=b.create({service:"note-llm"}),e=null,t=()=>{if(!e)throw new Error("Llm is not initialized. Please call Llm.init() first.");return e};function r(h){n()||(e={models:h.models,options:{graph:h.options?.graph,rerankTopN:h.options?.rerankTopN}},E.debug("Llm initialized"));}u.init=r;function n(){return e!==null}u.isInitialized=n;function o(){return e?{embedding:!!e.models.embeddingLlm,graphLlm:!!e.models.graphLlm,rerankLlm:!!e.models.rerankLlm}:{embedding:false,graphLlm:false,rerankLlm:false}}u.capabilities=o;async function s(h){let f=t().models.embeddingLlm;if(!f)throw new Error("embeddingLlm model is not configured.");let b=await embed({model:f,value:h});return new Float32Array(b.embedding)}u.embedText=s;async function i(h){let f=t().models.embeddingLlm;if(!f)throw new Error("embeddingLlm model is not configured.");return (await embedMany({model:f,values:h})).embeddings.map(N=>new Float32Array(N))}u.embedTexts=i;async function c(h,g){let f=t(),b=f.models.graphLlm;if(!b)return "";let N=l(h);return (await streamText({model:b,prompt:N,maxOutputTokens:g?.maxOutputTokens??f.options.graph?.maxOutputTokens,temperature:g?.temperature??f.options.graph?.temperature})).text}u.generateGraph=c;async function a(h,g,f){let b=t();return b.models.rerankLlm?(await rerank({model:b.models.rerankLlm,query:h,documents:g,topN:f??b.options.rerankTopN??g.length})).ranking.map(T=>({index:T.originalIndex,score:T.score??0})):[]}u.rerank=a;function l(h){let g=GRAPH_ENTITY_TYPE_DEFINITIONS.map(T=>`- ${T.type}: ${T.rule}`).join(`
85
+ `),f=GRAPH_RELATION_TYPE_DEFINITIONS.map(T=>`- ${T.type}: ${T.rule}`).join(`
86
+ `),N=h.slice(0,5).join(`
87
87
 
88
88
  `).slice(0,2e3);return `You are an information extraction engine for a general-purpose memory graph.
89
89
 
90
- Extract entities and directed relations from the text.
90
+ Extract entities and directed relations from the text, and generate a concise summary.
91
91
 
92
92
  Entity type taxonomy:
93
- ${h}
93
+ ${g}
94
94
 
95
95
  Relation type taxonomy:
96
96
  ${f}
97
97
 
98
98
  Extraction rules:
99
99
  - Output valid JSON only. Do not include markdown, prose, or code fences.
100
+ - summary: A concise summary (max 250 characters) describing the main topic and key points.
100
101
  - Use canonical, concise entity names (deduplicated, case-insensitive).
101
102
  - Prefer specific entity types over "keyword".
102
103
  - Include relation only if both source and target entities are present in the entities list.
@@ -106,6 +107,7 @@ Extraction rules:
106
107
 
107
108
  Return this exact JSON shape:
108
109
  {
110
+ "summary": "A concise summary of the text content (max 250 characters)",
109
111
  "entities": [
110
112
  { "name": "string", "type": "one_of_entity_types", "properties": {} }
111
113
  ],
@@ -115,12 +117,12 @@ Return this exact JSON shape:
115
117
  }
116
118
 
117
119
  Input text:
118
- ${b}`}u.embed=s,u.embedMany=i;})(L||(L={}));var ee=b.create({service:"note-ingestion"}),De=new Set(GRAPH_ENTITY_TYPE_DEFINITIONS.map(E=>E.type)),Oe=new Set(GRAPH_RELATION_TYPE_DEFINITIONS.map(E=>E.type)),Y=class{constructor(e,t){a(this,"db");a(this,"config");a(this,"parser");this.db=e,this.config={...DEFAULT_NOTE_CHUNK_CONFIG,...t,embeddingLlm:t.embeddingLlm},this.parser=new H,t.embeddingLlm&&L.init({models:{embeddingLlm:t.embeddingLlm,graphLlm:t.graphLlm,rerankLlm:t.rerankLlm}});}async process(e){let t=Filesystem.toUnixPath(e),{content:r,metadata:n}=await this.parser.parse(e),o=H.computeHash(r),s=this.db.query("SELECT id, contentHash FROM documents WHERE path = ?",[t]);if(s.length>0&&s[0]?.contentHash===o){let m=this.db.query("SELECT id FROM chunks WHERE documentId = ?",[s[0].id]).flatMap(y=>{let b=this.db.query("SELECT nodeIds FROM chunks WHERE id = ?",[y.id]);return b[0]?.nodeIds?JSON.parse(b[0].nodeIds):[]}),h=new Set(m).size,f=this.db.query(`SELECT id FROM edges WHERE source IN (${Array.from({length:h},()=>"?").join(",")})`,[...new Set(m)]).length;return {documentId:s[0].id,chunksCreated:0,vectorsCreated:0,entitiesExtracted:h,relationsExtracted:f}}let i=this.chunk(r),c=await this.embedWithCache(i),a=new Map,d,l,g=this.extractEntitiesSync(i);if(d=g.entities.length,l=g.relations.length,this.mapChunksToNodes(i,g.entities,a),this.storeEntities(g.entities,g.relations),this.config.graphLlm){let u=t;this.extractEntities(i).then(m=>{(m.entities.length>g.entities.length||m.relations.length>g.relations.length)&&(this.mergeEntitiesAndRelations(u,m.entities,m.relations),ee.debug("LLM entity extraction completed in background",{path:u,entities:m.entities.length,relations:m.relations.length}));}).catch(m=>{ee.warn("Background graph extraction failed",{path:u,error:String(m)});});}return this.db.transaction(()=>{s.length>0&&this.db.cleanupDocumentData(s[0].id);let m=this.db.run(`INSERT INTO documents (path, title, contentHash, summary, metadata, lastModified, createdAt, updatedAt)
119
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[t,n.title||U.basename(e)||"Untitled",o,null,n.title?JSON.stringify(n):null,new Date().toISOString(),new Date().toISOString(),new Date().toISOString()]).lastID,h=0,f=0;r.split(`
120
- `);let b=0,S=0,q=[];for(let O=0;O<i.length;O++){let k=i[O],p=k.split(`
121
- `).length-1;q.push({startLine:S,endLine:S+p,startChar:b,endChar:b+k.length});let I=this.config.chunkOverlap;b=b+Math.max(1,k.length-I);let T=Math.floor(I/20);S=S+Math.max(1,p-T);}for(let O=0;O<i.length;O++){let k=i[O],p=H.computeHash(k),I=a.get(O)||[],T=q[O],x=this.db.run(`INSERT INTO chunks (documentId, startLine, endLine, startChar, endChar, content, contentHash, nodeIds, createdAt)
122
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[m,T.startLine,T.endLine,T.startChar,T.endChar,k,p,JSON.stringify(I),new Date().toISOString()]).lastID,K=c[O];K&&(this.db.run("INSERT INTO vectors (chunkId, embedding) VALUES (?, ?)",[x,this.float32ToBuffer(K)]),f++);let W=ie(k);this.db.run("INSERT INTO chunks_fts (chunkId, documentId, content) VALUES (?, ?, ?)",[x,m,W]),h++;}return {documentId:m,chunksCreated:h,vectorsCreated:f,entitiesExtracted:d,relationsExtracted:l}})}async processBatch(e,t){let r=[];for(let n=0;n<e.length;n++){let o=await this.process(e[n]);r.push(o),t?.(n+1,e.length,o);}return r}chunk(e){let{chunkSize:t,minChunkLength:r=100}=this.config;return Markdown.chunk(e,t,{minLength:r})}async embedWithCache(e){if(!this.config.embeddingLlm)return e.map(()=>new Float32Array(this.config.vectorDims));let t=[],r=[];for(let n=0;n<e.length;n++){let o=e[n],s=H.computeHash(o),i=this.db.query("SELECT embedding FROM embedding_cache WHERE contentHash = ?",[s]);i.length>0&&i[0]?.embedding?t[n]=new Float32Array(i[0].embedding.buffer,i[0].embedding.byteOffset,i[0].embedding.length/4):r.push({index:n,content:o,hash:s});}if(r.length>0)try{let n=r.map(s=>s.content),o=await L.embedMany(n);for(let s=0;s<r.length;s++){let{index:i,hash:c}=r[s],a=o[s];if(a){let d=new Float32Array(a);t[i]=d,this.ensureVectorDims(d.length),this.db.run("INSERT OR REPLACE INTO embedding_cache (contentHash, embedding, createdAt) VALUES (?, ?, ?)",[c,this.float32ToBuffer(d),new Date().toISOString()]);}}}catch(n){throw new R(`\u5D4C\u5165\u751F\u6210\u5931\u8D25: ${n.message}`,"EMBEDDING_FAILED",n)}return t}async embed(e){if(!this.config.embeddingLlm)return e.map(()=>new Float32Array(this.config.vectorDims));try{return await L.embedMany(e)}catch(t){throw new R(`\u5D4C\u5165\u751F\u6210\u5931\u8D25: ${t.message}`,"EMBEDDING_FAILED",t)}}async extractEntities(e){let t=e.slice(0,5).join(`
120
+ ${N}`}u.embed=s,u.embedMany=i;})(D||(D={}));var Q=b.create({service:"note-ingestion"}),De=new Set(GRAPH_ENTITY_TYPE_DEFINITIONS.map(E=>E.type)),Oe=new Set(GRAPH_RELATION_TYPE_DEFINITIONS.map(E=>E.type)),V=class{constructor(e,t){a(this,"db");a(this,"config");a(this,"parser");this.db=e,this.config={...DEFAULT_NOTE_CHUNK_CONFIG,...t,embeddingLlm:t.embeddingLlm},this.parser=new _,t.embeddingLlm&&D.init({models:{embeddingLlm:t.embeddingLlm,graphLlm:t.graphLlm,rerankLlm:t.rerankLlm}});}async process(e){let t=Filesystem.normalize(e),{content:r,metadata:n}=await this.parser.parse(e),o=_.computeHash(r),s=this.db.query("SELECT id, contentHash FROM documents WHERE path = ?",[t]);if(s.length>0&&s[0]?.contentHash===o){let g=this.db.query("SELECT id FROM chunks WHERE documentId = ?",[s[0].id]).flatMap(N=>{let T=this.db.query("SELECT nodeIds FROM chunks WHERE id = ?",[N.id]);return T[0]?.nodeIds?JSON.parse(T[0].nodeIds):[]}),f=new Set(g).size,b=this.db.query(`SELECT id FROM edges WHERE source IN (${Array.from({length:f},()=>"?").join(",")})`,[...new Set(g)]).length;return {documentId:s[0].id,chunksCreated:0,vectorsCreated:0,entitiesExtracted:f,relationsExtracted:b}}let i=this.chunk(r),c=await this.embedWithCache(i),a=new Map,l,d,m="",u=this.extractEntitiesSync(i);if(l=u.entities.length,d=u.relations.length,this.mapChunksToNodes(i,u.entities,a),this.storeEntities(u.entities,u.relations),this.config.graphLlm){let h=t;this.extractEntities(i).then(g=>{m=g.summary,this.mergeEntitiesAndRelations(h,g.entities,g.relations,g.summary),Q.debug("LLM entity extraction completed in background",{path:h,entities:g.entities.length,relations:g.relations.length,summary:g.summary});}).catch(g=>{Q.warn("Background graph extraction failed",{path:h,error:String(g)});});}return this.db.transaction(()=>{s.length>0&&this.db.cleanupDocumentData(s[0].id);let g=this.db.run(`INSERT INTO documents (path, title, contentHash, summary, metadata, lastModified, createdAt, updatedAt)
121
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,[t,n.title||W.basename(e)||"Untitled",o,typeof m=="string"&&m.length>0?m:typeof u.summary=="string"?u.summary:"",JSON.stringify(n||{}),new Date().toISOString(),new Date().toISOString(),new Date().toISOString()]).lastID,f=0,b=0;r.split(`
122
+ `);let T=0,z=0,q=[];for(let L=0;L<i.length;L++){let p=i[L],I=p.split(`
123
+ `).length-1;q.push({startLine:z,endLine:z+I,startChar:T,endChar:T+p.length});let S=this.config.chunkOverlap;T=T+Math.max(1,p.length-S);let w=Math.floor(S/20);z=z+Math.max(1,I-w);}for(let L=0;L<i.length;L++){let p=i[L],I=_.computeHash(p),S=a.get(L)||[],w=q[L],K=this.db.run(`INSERT INTO chunks (documentId, startLine, endLine, startChar, endChar, content, contentHash, nodeIds, createdAt)
124
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,[g,w.startLine,w.endLine,w.startChar,w.endChar,p,I,JSON.stringify(S),new Date().toISOString()]).lastID,H=c[L];H&&(this.db.run("INSERT INTO vectors (chunkId, embedding) VALUES (?, ?)",[K,this.float32ToBuffer(H)]),b++);let j=se(p);this.db.run("INSERT INTO chunks_fts (chunkId, documentId, content) VALUES (?, ?, ?)",[K,g,j]),f++;}return {documentId:g,chunksCreated:f,vectorsCreated:b,entitiesExtracted:l,relationsExtracted:d}})}async processBatch(e,t){let r=[];for(let n=0;n<e.length;n++){let o=await this.process(e[n]);r.push(o),t?.(n+1,e.length,o);}return r}chunk(e){let{chunkSize:t,minChunkLength:r=100}=this.config;return Markdown.chunk(e,t,{minLength:r})}async embedWithCache(e){if(!this.config.embeddingLlm)return e.map(()=>new Float32Array(this.config.vectorDims));let t=[],r=[];for(let n=0;n<e.length;n++){let o=e[n],s=_.computeHash(o),i=this.db.query("SELECT embedding FROM embedding_cache WHERE contentHash = ?",[s]);i.length>0&&i[0]?.embedding?t[n]=new Float32Array(i[0].embedding.buffer,i[0].embedding.byteOffset,i[0].embedding.length/4):r.push({index:n,content:o,hash:s});}if(r.length>0)try{let n=r.map(s=>s.content),o=await D.embedMany(n);for(let s=0;s<r.length;s++){let{index:i,hash:c}=r[s],a=o[s];if(a){let l=new Float32Array(a);t[i]=l,this.ensureVectorDims(l.length),this.db.run("INSERT OR REPLACE INTO embedding_cache (contentHash, embedding, createdAt) VALUES (?, ?, ?)",[c,this.float32ToBuffer(l),new Date().toISOString()]);}}}catch(n){throw new R(`\u5D4C\u5165\u751F\u6210\u5931\u8D25: ${n.message}`,"EMBEDDING_FAILED",n)}return t}async embed(e){if(!this.config.embeddingLlm)return e.map(()=>new Float32Array(this.config.vectorDims));try{return await D.embedMany(e)}catch(t){throw new R(`\u5D4C\u5165\u751F\u6210\u5931\u8D25: ${t.message}`,"EMBEDDING_FAILED",t)}}async extractEntities(e){let t=e.slice(0,5).join(`
123
125
 
124
- `);if(!this.config.graphLlm)return this.extractEntitiesByRules(t);try{let r=await L.generateGraph(e,{maxOutputTokens:2e3}),n=this.parseEntityExtractionResult(r);return n.entities.length===0&&n.relations.length===0?this.extractEntitiesByRules(t):n}catch(r){if(r instanceof Error)return this.extractEntitiesByRules(t);throw new R(`\u5B9E\u4F53\u63D0\u53D6\u5931\u8D25: ${String(r)}`,"ENTITY_EXTRACTION_FAILED")}}extractEntitiesSync(e){let t=e.slice(0,5).join(`
126
+ `);if(!this.config.graphLlm)return this.extractEntitiesByRules(t);try{let r=await D.generateGraph(e,{maxOutputTokens:2e3}),n=this.parseEntityExtractionResult(r);return n.entities.length===0&&n.relations.length===0?this.extractEntitiesByRules(t):n}catch(r){if(r instanceof Error)return this.extractEntitiesByRules(t);throw new R(`\u5B9E\u4F53\u63D0\u53D6\u5931\u8D25: ${String(r)}`,"ENTITY_EXTRACTION_FAILED")}}extractEntitiesSync(e){let t=e.slice(0,5).join(`
125
127
 
126
- `);return this.extractEntitiesByRules(t)}parseEntityExtractionResult(e){try{let t=e.match(/\{[\s\S]*\}/);if(t){let r=JSON.parse(t[0]);return this.normalizeExtractionResult(r)}}catch(t){ee.debug("Failed to parse entity extraction result",{error:String(t)});}return {entities:[],relations:[]}}normalizeExtractionResult(e){let t=e,r=Array.isArray(t.entities)?t.entities:[],n=Array.isArray(t.relations)?t.relations:[],o=[],s=new Set,i=new Map;for(let d of r){let l=typeof d?.name=="string"?d.name.trim():"";if(!l)continue;let g=l.toLowerCase();if(s.has(g))continue;s.add(g),i.set(g,l);let u=typeof d?.type=="string"?d.type.trim():"",m=De.has(u)?u:"keyword",h=d?.properties&&typeof d.properties=="object"&&!Array.isArray(d.properties)?d.properties:{};o.push({name:l,type:m,properties:h});}let c=[],a=new Set;for(let d of n){let l=typeof d?.source=="string"?d.source.trim():"",g=typeof d?.target=="string"?d.target.trim():"";if(!l||!g)continue;let u=i.get(l.toLowerCase()),m=i.get(g.toLowerCase());if(!u||!m||u===m)continue;let h=typeof d?.relation=="string"?d.relation.trim():"",f=Oe.has(h)?h:"related_to",y=`${u.toLowerCase()}|${m.toLowerCase()}|${f}`;a.has(y)||(a.add(y),c.push({source:u,target:m,relation:f}));}return {entities:o,relations:c}}extractEntitiesByRules(e){let t=[],r=[],n=new Set,o=new Set,s=new Map,i=/([A-Za-z][\w.-]{1,80})\s+(is_a|part_of|has_attribute|located_in|occurs_in|causes|influences|owned_by|member_of|uses|depends_on|related_to)\s+([A-Za-z][\w.-]{1,80})/g;for(let d of e.matchAll(i)){let l=this.sanitizeEntityToken(d[1]??""),g=(d[2]??"related_to").trim(),u=this.sanitizeEntityToken(d[3]??"");if(!l||!u||l===u)continue;let m=l.toLowerCase(),h=u.toLowerCase();n.has(m)||(n.add(m),s.set(m,l),t.push({name:l,type:this.inferEntityType(l),properties:{source:"rule_extracted"}})),n.has(h)||(n.add(h),s.set(h,u),t.push({name:u,type:this.inferEntityType(u),properties:{source:"rule_extracted"}}));let f=`${m}|${h}|${g}`;o.has(f)||(o.add(f),r.push({source:l,target:u,relation:g}));}let c=e.match(/[\p{L}\p{N}][\p{L}\p{N}_.-]{1,80}/gu)??[],a=e.split(/\n\s*\n/);for(let d of c){let l=this.sanitizeEntityToken(d);if(!l)continue;let g=l.toLowerCase();n.has(g)||(n.add(g),s.set(g,l),t.push({name:l,type:this.inferEntityType(l),properties:{source:"keyword_extracted"}}));}for(let d of a){if(d.trim().length<20)continue;let l=[];for(let g of d.match(/[\p{L}\p{N}][\p{L}\p{N}_.-]{2,80}/gu)??[]){let u=this.sanitizeEntityToken(g);if(!u)continue;let m=u.toLowerCase();n.has(m)&&!l.some(h=>h.key===m)&&l.push({key:m,name:u});}for(let g=0;g<l.length;g++)for(let u=g+1;u<l.length;u++){let m=l[g],h=l[u];if(m.key===h.key)continue;let f="related_to",y=this.inferEntityType(m.name),b=this.inferEntityType(h.name);y==="document"&&b==="object"?f="defines":y==="object"&&b==="document"?f="referenced_in":y==="process"&&b==="object"?f="uses":y==="object"&&b==="process"?f="used_by":y==="concept"&&(f="relates_to");let S=`${m.key}|${h.key}|${f}`;o.has(S)||(o.add(S),r.push({source:m.name,target:h.name,relation:f}));}}return {entities:t,relations:r}}sanitizeEntityToken(e){return e.trim().replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"").replace(/\s+/g," ").slice(0,120)}inferEntityType(e){return /(\.md|\.ts|\.json|readme|doc|spec|guideline)/i.test(e)?"document":/(api|service|system|engine|pipeline|server|db|database|memorysystem|contextengine)/i.test(e)?"process":/(team|group|org|company|inc|ltd|corp)/i.test(e)?"organization":/(deadline|date|day|week|month|year|q[1-4]|sprint)/i.test(e)?"time":/(score|rate|ratio|latency|accuracy|recall|precision|throughput|kpi)/i.test(e)?"metric":/(task|issue|ticket|todo|action)/i.test(e)?"task":/(event|incident|release|meeting|migration|launch)/i.test(e)?"event":/(process|workflow|procedure|flow|lifecycle)/i.test(e)?"process":/(file|model|dataset|artifact|resource|tool|sdk|ollama|sqlite|embedding|vector|fts)/i.test(e)?"object":/(concept|principle|policy|method|pattern|strategy)/i.test(e)?"concept":/[A-Z]/.test(e)?"object":"keyword"}storeEntities(e,t){if(e.length===0)return;let r=new Map,n=new Date().toISOString();for(let o of e){let s=this.db.query("SELECT id FROM nodes WHERE name = ? AND type = ?",[o.name,o.type]);s.length>0&&s[0]&&r.set(o.name,s[0].id);}this.db.transaction(()=>{for(let o of e){if(r.has(o.name))continue;let s=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[o.name,o.type,JSON.stringify(o.properties),n,n]);s.lastID>0&&r.set(o.name,s.lastID);}for(let o of t){let s=r.get(o.source),i=r.get(o.target);if(s&&i){let c=this.db.query("SELECT id FROM nodes WHERE id = ?",[s]),a=this.db.query("SELECT id FROM nodes WHERE id = ?",[i]);c.length>0&&a.length>0&&this.db.run("INSERT OR REPLACE INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[s,i,o.relation,"{}",n]);}}});}mergeEntitiesAndRelations(e,t,r){if(t.length===0&&r.length===0)return;let n=new Map,o=new Date().toISOString(),s=t.map(()=>"?").join(","),i=this.db.query(`SELECT id, name, type FROM nodes WHERE name IN (${s})`,t.map(c=>c.name));for(let c of i)n.set(c.name,c.id);this.db.transaction(()=>{for(let c of t)if(n.get(c.name)===void 0){let d=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[c.name,c.type,JSON.stringify(c.properties),o,o]);d.lastID>0&&n.set(c.name,d.lastID);}for(let c of r){let a=n.get(c.source),d=n.get(c.target);if(a&&d){let l=this.db.query("SELECT id FROM nodes WHERE id = ?",[a]),g=this.db.query("SELECT id FROM nodes WHERE id = ?",[d]);l.length>0&&g.length>0&&this.db.run("INSERT OR REPLACE INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[a,d,c.relation,"{}",o]);}}});}float32ToBuffer(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}ensureVectorDims(e){this.db.query("SELECT value FROM meta WHERE key = ?",["vectorDims"]).length===0&&this.db.run("INSERT OR IGNORE INTO meta (key, value) VALUES (?, ?)",["vectorDims",String(e)]);}mapChunksToNodes(e,t,r){let n=new Map,o=new Date().toISOString();this.db.transaction(()=>{for(let s of t){let i=this.db.query("SELECT id FROM nodes WHERE name = ? AND type = ?",[s.name,s.type]);if(i.length>0&&i[0])n.set(s.name,i[0].id);else {let c=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[s.name,s.type,JSON.stringify(s.properties),o,o]);c.lastID>0&&n.set(s.name,c.lastID);}}for(let s=0;s<e.length;s++){let i=e[s],c=[];for(let a of t)if(i.includes(a.name)){let d=n.get(a.name);d&&c.push(d);}r.set(s,c);}});}};b.create({service:"note-search"});var Q=class{constructor(e,t){a(this,"db");a(this,"config");this.db=e,this.config={...DEFAULT_NOTE_CHUNK_CONFIG,...t,embeddingLlm:t.embeddingLlm},t.embeddingLlm&&L.init({models:{embeddingLlm:t.embeddingLlm,graphLlm:t.graphLlm,rerankLlm:t.rerankLlm}});}async search(e,t){if(!e.trim())return [];let r=t?.maxResults||3,n=t?.minScore??this.config.search.minScore,o=await this.hybridSearch(e,{...t,maxResults:r*2});return o.length===0?[]:this.config.rerankLlm?(await this.rerank(e,o,r)).filter(i=>i.score>=n):o.filter(s=>s.score>=n).slice(0,r)}async hybridSearch(e,t){let{maxResults:r=this.config.search.maxResults,minScore:n=this.config.search.minScore,vectorWeight:o=this.config.search.hybrid.vectorWeight,textWeight:s=this.config.search.hybrid.textWeight,enableEmbedding:i=true,enableFts:c=true}=t??{},a=i?await this.embed(e):new Float32Array(0),[d,l]=await Promise.all([i&&this.config.embeddingLlm?this.vectorSearch(a,r,n,t):Promise.resolve([]),c===false?Promise.resolve([]):this.ftsSearch(e,r,n,t)]);return this.mergeResults(d,l,o,s,n)}async vectorSearch(e,t,r,n){if(!this.config.embeddingLlm)return [];try{let o;if(n?.candidateChunkIds&&n.candidateChunkIds.length>0){let c=n.candidateChunkIds.map(()=>"?").join(",");o=this.db.query(`SELECT chunkId, embedding FROM vectors WHERE chunkId IN (${c})`,n.candidateChunkIds);}else o=this.db.query("SELECT chunkId, embedding FROM vectors LIMIT ?",[Math.max(t*100,1e3)]);let s=[];for(let c of o){let a=new Float32Array(c.embedding.buffer,c.embedding.byteOffset,c.embedding.length/4),d=this.cosineSimilarity(e,a);s.push({chunkId:c.chunkId,score:d});}s.sort((c,a)=>a.score-c.score);let i=s.slice(0,t);return this.buildSearchResults(i,"vector",n)}catch(o){throw new R(`\u5411\u91CF\u641C\u7D22\u5931\u8D25: ${o.message}`,"SEARCH_FAILED",o)}}async ftsSearch(e,t,r,n){let o=async()=>[];try{let s=oe(e),i=this.db.query("SELECT chunkId, rank FROM chunks_fts WHERE chunks_fts MATCH ? ORDER BY rank LIMIT ?",[s,t]);if(i.length===0)return o();let c=i.map(a=>({chunkId:a.chunkId,score:1/(1+a.rank)}));return this.buildSearchResults(c,"fts",n)}catch{return o()}}mergeResults(e,t,r,n,o){let s=r+n,i=r/s,c=n/s,a=new Map;for(let g of e){let u=`${g.chunk.id}`,m=g.score*i;a.set(u,{...g,score:m,source:"hybrid"});}for(let g of t){let u=`${g.chunk.id}`,m=a.get(u);if(m)m.score+=g.score*c;else {let h=g.score*c;a.set(u,{...g,score:h,source:"hybrid"});}}return Array.from(a.values()).map(g=>{let u=g.score,m=new Date(g.document.updatedAt),h=(Date.now()-m.getTime())/864e5,f=Math.exp(-0.01*h),y=.6*u+.4*f;return {...g,score:y}}).sort((g,u)=>u.score-g.score)}async rerank(e,t,r){if(!this.config.rerankLlm)return t.slice(0,r);try{let n=t.map(a=>{let d=a.nodes&&a.nodes.length>0?a.nodes.map(l=>{let g=(l.edges??[]).map(u=>{let m=u.source===l.id?"\u2192":"\u2190",h=u.targetNode?`${u.targetNode.type}:${u.targetNode.name}`:`id=${u.target}`;return `${m} [${u.relation}] ${h}`}).join(" | ");return `node: id=${l.id} name=${l.name} type=${l.type}${g?` edges: ${g}`:""}`}).join(" | "):"";return `<doc filePath="${a.document.path}" lineStart="${a.chunk.startLine}" lineEnd="${a.chunk.endLine}"><snippet>${a.snippet}</snippet>${d?`<nodes>${d}</nodes>`:""}</doc>`}),o=await L.rerank(e,n,t.length);if(o.length===0)return t.slice(0,r);let s=new Map;for(let a of o)a.index>=0&&a.index<t.length&&s.set(a.index,a.score);let i=.5,c=t.map((a,d)=>{let l=s.get(d)??a.score,g=i*a.score+(1-i)*l;return {...a,originalScore:a.score,score:g,source:"reranked"}});return c.sort((a,d)=>d.score-a.score),c.slice(0,r)}catch{return t.slice(0,r)}}async embed(e){try{return await L.embed(e)}catch{return new Float32Array(this.config.vectorDims)}}cosineSimilarity(e,t){let r=0,n=0,o=0;for(let s=0;s<e.length;s++){let i=e[s],c=t[s];r+=i*c,n+=i*i,o+=c*c;}return n===0||o===0?0:r/(Math.sqrt(n)*Math.sqrt(o))}async buildSearchResults(e,t,r){let n=[],o=e.map(p=>p.chunkId);if(o.length===0)return n;let s=r?.includeEdges??true,i=Math.max(1,r?.edgesLimit??100),c=this.db.query("SELECT * FROM chunks WHERE id IN ("+o.map(()=>"?").join(", ")+")",o),a=new Map(c.map(p=>[p.id,p])),d=Array.from(new Set(c.map(p=>p.documentId))),l=d.length>0?this.db.query("SELECT * FROM documents WHERE id IN ("+d.map(()=>"?").join(", ")+")",d):[],g=new Map(l.map(p=>[p.id,p])),u=new Map,m=[];for(let p of c){let I=[];try{let T=p.nodeIds?JSON.parse(p.nodeIds):[];I=Array.isArray(T)?T.filter(C=>typeof C=="number"):[];}catch{I=[];}u.set(p.id,I),m.push(...I);}let h=Array.from(new Set(m)),f=h.length>0?this.db.query("SELECT * FROM nodes WHERE id IN ("+h.map(()=>"?").join(", ")+")",h):[],y=new Map(f.map(p=>[p.id,{id:p.id,name:p.name,type:p.type,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt,updatedAt:p.updatedAt}])),b=s&&h.length>0?this.db.query("SELECT * FROM edges WHERE source IN ("+h.map(()=>"?").join(", ")+") OR target IN ("+h.map(()=>"?").join(", ")+") ORDER BY id LIMIT ?",[...h,...h,h.length*i]):[],S=[...new Set([...h,...b.map(p=>p.target)])],q=S.length>0?this.db.query("SELECT * FROM nodes WHERE id IN ("+S.map(()=>"?").join(", ")+")",S):[],O=new Map(q.map(p=>[p.id,{id:p.id,name:p.name,type:p.type,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt,updatedAt:p.updatedAt}])),k=new Map;for(let p of b){let I={id:p.id,source:p.source,target:p.target,relation:p.relation,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt},T=O.get(p.target);T&&(I.targetNode=T);let C=k.get(I.source)??[];C.length<i&&(C.push(I),k.set(I.source,C));let x=k.get(I.target)??[];x.length<i&&(x.push(I),k.set(I.target,x));}for(let p of e){let I=a.get(p.chunkId);if(!I)continue;let T=g.get(I.documentId);if(!T)continue;let C=u.get(I.id)??[],x=C.map(w=>y.get(w)).filter(w=>w!==void 0),K=s&&C.length>0?Array.from(new Map(C.flatMap(w=>k.get(w)??[]).map(w=>[w.id,w])).values()):[],W=new Map;for(let w of K){let ne=W.get(w.source)??[];ne.push(w),W.set(w.source,ne);}let re=x.length>0?x.map(w=>({...w,edges:s?W.get(w.id)??[]:void 0})):[];n.push({chunk:{id:I.id,documentId:I.documentId,startLine:I.startLine,endLine:I.endLine,startChar:I.startChar,endChar:I.endChar,content:I.content,contentHash:I.contentHash,nodeIds:C,path:T.path,createdAt:I.createdAt},document:{id:T.id,path:T.path,title:T.title,contentHash:T.contentHash,summary:T.summary,lastModified:T.lastModified,createdAt:T.createdAt,updatedAt:T.updatedAt},nodes:re.length>0?re:void 0,score:p.score,snippet:I.content.slice(0,200),source:t});}return n}};var V=class{constructor(e){a(this,"db");this.db=e;}async queryNodes(e,t){try{if(typeof e=="string")return this.db.query(e,t).map(c=>this.mapNode(c));let r=[],n=[];e.ids&&e.ids.length>0&&(r.push(`id IN (${e.ids.map(()=>"?").join(",")})`),n.push(...e.ids)),e.name&&(r.push("name LIKE ?"),n.push(`%${e.name}%`)),e.type&&(r.push("type = ?"),n.push(e.type));let o="SELECT * FROM nodes";return r.length>0&&(o+=` WHERE ${r.join(" AND ")}`),o+=" ORDER BY id",e.limit&&e.limit>0&&(o+=" LIMIT ?",n.push(e.limit)),this.db.query(o,n).map(i=>this.mapNode(i))}catch(r){throw new R(`\u67E5\u8BE2\u8282\u70B9\u5931\u8D25: ${r.message}`,"SEARCH_FAILED",r)}}async queryEdges(e,t){try{if(typeof e=="string")return this.db.query(e,t).map(c=>this.mapEdge(c));let r=[],n=[];e.ids&&e.ids.length>0&&(r.push(`id IN (${e.ids.map(()=>"?").join(",")})`),n.push(...e.ids)),typeof e.source=="number"&&(r.push("source = ?"),n.push(e.source)),typeof e.target=="number"&&(r.push("target = ?"),n.push(e.target)),e.sourceOrTarget&&e.sourceOrTarget.length>0&&(r.push(`(source IN (${e.sourceOrTarget.map(()=>"?").join(", ")}) OR target IN (${e.sourceOrTarget.map(()=>"?").join(", ")}))`),n.push(...e.sourceOrTarget,...e.sourceOrTarget)),e.relation&&(r.push("relation = ?"),n.push(e.relation));let o="SELECT * FROM edges";return r.length>0&&(o+=` WHERE ${r.join(" AND ")}`),o+=" ORDER BY id",e.limit&&e.limit>0&&(o+=" LIMIT ?",n.push(e.limit)),this.db.query(o,n).map(i=>this.mapEdge(i))}catch(r){throw new R(`\u67E5\u8BE2\u8FB9\u5931\u8D25: ${r.message}`,"SEARCH_FAILED",r)}}async queryNeighbors(e,t){let r=t?.direction??"both",n=t?.relationTypes,o=t?.limit&&t.limit>0?t.limit:100,s=[],i=[];r==="incoming"?(s.push("target = ?"),i.push(e)):r==="outgoing"?(s.push("source = ?"),i.push(e)):(s.push("(source = ? OR target = ?)"),i.push(e,e)),n&&n.length>0&&(s.push(`relation IN (${n.map(()=>"?").join(",")})`),i.push(...n));let c=await this.queryEdges(`SELECT * FROM edges WHERE ${s.join(" AND ")} ORDER BY id LIMIT ?`,[...i,o]),a=Array.from(new Set(c.map(u=>u.source===e?u.target:u.source)));if(a.length===0)return {nodes:await this.queryNodes({ids:[e],limit:1}),edges:c};let d=[...new Set([e,...a])],l=await this.queryNodes({ids:d,limit:d.length}),g=new Map(l.map(u=>[u.id,u]));for(let u of c){let m=g.get(u.target);m&&(u.targetNode=m);}return {nodes:l,edges:c}}async queryCallGraph(e,t=2){let r=Math.max(1,t),n=new Map,o=[{id:e,level:0}],s=new Set;for(;o.length>0;){let i=o.shift();if(s.has(i.id)||i.level>r)continue;s.add(i.id);let c=await this.queryEdges({source:i.id,relation:"CALLS",limit:100}),a=await this.queryEdges({target:i.id,relation:"CALLS",limit:100}),d=Array.from(new Set(c.map(g=>g.target))),l=Array.from(new Set(a.map(g=>g.source)));n.set(i.id,{callers:l,callees:d});for(let g of [...l,...d])s.has(g)||o.push({id:g,level:i.level+1});}return n}async queryInheritance(e){let t=["EXTENDS","INHERITS_FROM","IMPLEMENTS"],r=await this.collectInheritance(e,"ancestor",t),n=await this.collectInheritance(e,"descendant",t);return {ancestors:r,descendants:n}}async findPath(e,t,r=3){let n=[],o=new Set,s=this.db.query("SELECT * FROM nodes WHERE name = ?",[e]);if(s.length===0)return [];let i=s.map(c=>({nodeId:c.id,path:[c.id]}));for(;i.length>0;){let{nodeId:c,path:a}=i.shift();if(a.length>r)continue;let d=a.join(",");if(o.has(d))continue;if(o.add(d),a.length>1){let g=this.db.query("SELECT id, name FROM nodes WHERE id = ?",[c]);if(g.length>0&&g[0]?.name===t){let u=a.map(()=>"?").join(","),m=this.db.query(`SELECT * FROM nodes WHERE id IN (${u})`,a),h=new Map(m.map(y=>[y.id,y])),f=[];for(let y of a){let b=h.get(y);b&&f.push({id:b.id,name:b.name,type:b.type,properties:b.properties?JSON.parse(b.properties):void 0,createdAt:b.createdAt,updatedAt:b.updatedAt});}n.push(f);continue}}let l=this.db.query("SELECT source, target FROM edges WHERE source = ? OR target = ?",[c,c]);for(let g of l){let u=g.source===c?g.target:g.source;a.includes(u)||i.push({nodeId:u,path:[...a,u]});}}return n}async searchNodesByName(e){return this.queryNodes("SELECT * FROM nodes WHERE name LIKE ?",[e])}async searchNodesByType(e){return this.queryNodes("SELECT * FROM nodes WHERE type = ?",[e])}async searchRelations(e){return this.queryEdges("SELECT * FROM edges WHERE relation = ?",[e])}async createNode(e,t,r){let n=new Date().toISOString(),o=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[e,t,r?JSON.stringify(r):null,n,n]),i=this.db.query("SELECT * FROM nodes WHERE id = ?",[o.lastID])[0];return {id:i.id,name:i.name,type:i.type,properties:i.properties?JSON.parse(i.properties):void 0,createdAt:i.createdAt,updatedAt:i.updatedAt}}async updateNode(e,t){let r=new Date().toISOString();this.db.run("UPDATE nodes SET properties = ?, updatedAt = ? WHERE id = ?",[JSON.stringify(t),r,e]);let n=this.db.query("SELECT * FROM nodes WHERE id = ?",[e]);if(n.length===0)throw new R(`\u8282\u70B9\u4E0D\u5B58\u5728: ${e}`,"NODE_NOT_FOUND");let o=n[0];return {id:o.id,name:o.name,type:o.type,properties:o.properties?JSON.parse(o.properties):void 0,createdAt:o.createdAt,updatedAt:o.updatedAt}}async deleteNode(e){this.db.run("DELETE FROM nodes WHERE id = ?",[e]);}async createEdge(e,t,r,n){let o=this.db.query("SELECT id FROM nodes WHERE id = ?",[e]),s=this.db.query("SELECT id FROM nodes WHERE id = ?",[t]);if(o.length===0||s.length===0)throw new R("\u8282\u70B9\u4E0D\u5B58\u5728","NODE_NOT_FOUND");let i=new Date().toISOString(),c=this.db.run("INSERT INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[e,t,r,n?JSON.stringify(n):null,i]),d=this.db.query("SELECT * FROM edges WHERE id = ?",[c.lastID])[0];return {id:d.id,source:d.source,target:d.target,relation:d.relation,properties:d.properties?JSON.parse(d.properties):void 0,createdAt:d.createdAt}}async deleteEdge(e){this.db.run("DELETE FROM edges WHERE id = ?",[e]);}mapNode(e){return {id:e.id,name:e.name,type:e.type,properties:e.properties?JSON.parse(e.properties):void 0,createdAt:e.createdAt,updatedAt:e.updatedAt}}mapEdge(e){return {id:e.id,source:e.source,target:e.target,relation:e.relation,properties:e.properties?JSON.parse(e.properties):void 0,createdAt:e.createdAt}}async collectInheritance(e,t,r){let n=[e],o=new Set([e]),s=new Set;for(;n.length>0;){let i=n.shift(),c=t==="ancestor"?await this.queryEdges(`SELECT * FROM edges WHERE source = ? AND relation IN (${r.map(()=>"?").join(",")})`,[i,...r]):await this.queryEdges(`SELECT * FROM edges WHERE target = ? AND relation IN (${r.map(()=>"?").join(",")})`,[i,...r]);for(let a of c){let d=t==="ancestor"?a.target:a.source;o.has(d)||(o.add(d),s.add(d),n.push(d));}}return s.size===0?[]:this.queryNodes({ids:Array.from(s),limit:s.size})}};var J=b.create({service:"note-scanner"}),Me=["node_modules/**",".git/**","dist/**","build/**","__pycache__/**","*.min.md"],$=class{constructor(e){a(this,"workspaceDir");a(this,"extraPaths");a(this,"sources");a(this,"ignorePatterns");this.workspaceDir=e.workspaceDir,this.extraPaths=e.extraPaths??[],this.sources=new Set(e.sources??["docs"]),this.ignorePatterns=[...Me,...e.ignorePatterns??[]];}async scanAll(e){let t=[],r=[];for(let s of this.sources){let i=U__default.join(this.workspaceDir,s);r.push({source:s,dir:i});}for(let s of this.extraPaths){let i=U__default.isAbsolute(s)?s:U__default.join(this.workspaceDir,s);r.push({source:"local",dir:i});}let n=0,o=r.length;for(let s of r){let i=await this.scanDirectory(s.dir,s.source);t.push(...i),n++,e?.(n,o,i[0]||{absolutePath:s.dir,relativePath:s.dir,source:s.source,contentHash:"",lastModified:0,size:0});}return t}async scanDirectory(e,t){let r=[];try{await B.access(e);}catch{return J.debug("Directory not found, skipping",{dir:e}),r}let n=async o=>{try{let s=await B.readdir(o,{withFileTypes:!0});for(let i of s){let c=U__default.join(o,i.name);if(!this.shouldIgnore(i.name)){if(i.isDirectory())await n(c);else if(i.isFile()&&this.isMarkdownFile(i.name)){let a=await this.getFileInfo(c,t);a&&r.push(a);}}}}catch(s){J.warn("Failed to scan directory",{dir:o,error:String(s)});}};return await n(e),r}async scanFile(e,t="upload"){try{let r=await B.stat(e);if(!r.isFile())return null;let n=await B.readFile(e,"utf-8"),o=createHash("sha256").update(n).digest("hex"),s=U__default.isAbsolute(e)?Filesystem.toUnixPath(U__default.relative(this.workspaceDir,e)):e;return {absolutePath:e,relativePath:s||U__default.basename(e),source:t,contentHash:o,lastModified:r.mtimeMs,size:r.size}}catch(r){return J.error("Failed to scan file",{filePath:e,error:String(r)}),null}}async getFileInfo(e,t){try{let r=await B.readFile(e,"utf-8"),n=await B.stat(e),o=createHash("sha256").update(r).digest("hex"),s=Filesystem.toUnixPath(U__default.relative(this.workspaceDir,e));return {absolutePath:e,relativePath:s,source:t,contentHash:o,lastModified:n.mtimeMs,size:n.size}}catch(r){return J.error("Failed to get file info",{filePath:e,error:String(r)}),null}}shouldIgnore(e){if(e.startsWith("."))return true;for(let t of this.ignorePatterns)if(new RegExp("^"+t.replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$").test(e))return true;return false}isMarkdownFile(e){return e.endsWith(".md")||e.endsWith(".markdown")}};var A=b.create({service:"note"}),Z=class{constructor(e){a(this,"config");a(this,"db");a(this,"pipeline");a(this,"searchEngine");a(this,"graphInterface");a(this,"fileScanner");a(this,"initialized",false);a(this,"dirty",false);a(this,"syncTimer");a(this,"syncConfig");a(this,"syncingInProgress",false);let t=e.workspaceDir||process.cwd(),r=e.embeddingLlm;if(!r)throw new Error("embeddingLlm is required");let n=e.database?.path||getDefaultDatabasePath(xdgData,"note.db");this.config={workspaceDir:t,database:{path:n,walMode:e.database?.walMode??true},vectorDims:e.vectorDims??768,...DEFAULT_NOTE_CHUNK_CONFIG,extraPaths:e.extraPaths,sources:e.sources,search:{...DEFAULT_SEARCH_CONFIG,...e.search},indexer:{...DEFAULT_INDEXER_CONFIG,...e.indexer},sync:{...DEFAULT_SYNC_CONFIG,...e.sync},logDir:e.logDir,embeddingLlm:r,graphLlm:e.graphLlm,rerankLlm:e.rerankLlm},this.syncConfig=this.config.sync,this.db=new X(this.config.database.path),this.pipeline=new Y(this.db,this.config),this.searchEngine=new Q(this.db,this.config),this.graphInterface=new V(this.db),this.fileScanner=new $({workspaceDir:this.config.workspaceDir,extraPaths:this.config.extraPaths,sources:this.config.sources,ignorePatterns:this.config?.indexer?.ignorePatterns});}async initialize(){if(this.initialized)return;await b.init({logDir:this.config.logDir||U__default.join(this.config.workspaceDir,"logs"),print:process.argv.includes("--print-logs"),dev:false,level:"INFO"}),L.init({models:{embeddingLlm:this.config.embeddingLlm,graphLlm:this.config.graphLlm,rerankLlm:this.config.rerankLlm},options:{graph:{maxOutputTokens:2e3,temperature:.1}}}),await this.db.initialize();let e=[["version","1.0.0"],["chunkSize",String(this.config.chunkSize)],["chunkOverlap",String(this.config.chunkOverlap)],["createdAt",new Date().toISOString()]];for(let[t,r]of e)this.db.run("INSERT OR IGNORE INTO meta (key, value) VALUES (?, ?)",[t,r]);this.initialized=true,this.syncConfig.onBoot&&(this.syncAll().catch(t=>A.warn("onBoot sync failed",{error:String(t)})),this.startSyncTimer());}startSyncTimer(){this.syncTimer&&clearInterval(this.syncTimer),this.syncConfig.intervalMs>0&&(this.syncTimer=setInterval(async()=>{try{await this.syncAll();}catch(e){A.error("Interval sync failed",{error:String(e)});}},this.syncConfig.intervalMs));}ensureSynced(){this.dirty&&!this.syncingInProgress&&this.syncConfig.onSearch&&this.syncAll().catch(e=>{A.warn("Background sync failed",{error:String(e)});});}stopSyncTimer(){this.syncTimer&&(clearInterval(this.syncTimer),this.syncTimer=void 0);}async syncAll(){if(this.syncingInProgress){A.debug("Sync already in progress, skipping...");return}this.syncingInProgress=true,A.debug("Starting sync...");try{let e=await this.sync((t,r,n)=>{A.debug("Syncing file",{current:t,total:r,path:n.relativePath||U__default.basename(n.absolutePath)});});this.dirty=!1,A.debug("Sync completed",{totalFiles:e.filesAdded+e.filesUpdated+e.filesSkipped,added:e.filesAdded,updated:e.filesUpdated,deleted:e.filesDeleted,skipped:e.filesSkipped,errors:e.errors.length});}finally{this.syncingInProgress=false;}}async ingestDocument(e){return await this.ensureInitialized(),this.pipeline.process(e)}async ingestDocuments(e,t){await this.ensureInitialized();let r=[];for(let n=0;n<e.length;n++){let o=await this.pipeline.process(e[n]);r.push(o),t?.((n+1)/e.length);}return r}async scanAndIngest(e){for(await this.ensureInitialized();this.syncingInProgress;)await new Promise(n=>setTimeout(n,100));let t=await this.fileScanner.scanAll(e);if(t.length===0)return [];let r=t.map(n=>n.absolutePath);return this.ingestDocuments(r,n=>{e?.(Math.round(n*t.length),t.length,t[0]||{absolutePath:"ingesting...",relativePath:"ingesting...",source:"docs",contentHash:"",lastModified:0,size:0});})}async ingestUploadedFile(e){await this.ensureInitialized();let t=await this.fileScanner.scanFile(e,"upload");if(!t)throw new Error(`\u65E0\u6CD5\u626B\u63CF\u6587\u4EF6: ${e}`);return this.pipeline.process(t.absolutePath)}async removeDocument(e){await this.ensureInitialized();let t=Filesystem.toUnixPath(e);try{this.db.deleteDocumentByPath(t)&&A.debug("Removed document",{path:t});}catch(r){throw A.error("Failed to remove document",{path:t,error:String(r)}),r}}markDirty(){this.dirty=true,A.debug("Marked as dirty, will sync before next search");}async sync(e){if(await this.ensureInitialized(),this.syncingInProgress)return A.debug("Sync already in progress, skipping..."),{success:true,filesAdded:0,filesUpdated:0,filesDeleted:0,filesSkipped:0,chunksCreated:0,vectorsCreated:0,entitiesExtracted:0,relationsExtracted:0,errors:[],duration:0};this.syncingInProgress=true;try{let t=Date.now(),r={success:!0,filesAdded:0,filesUpdated:0,filesDeleted:0,filesSkipped:0,chunksCreated:0,vectorsCreated:0,entitiesExtracted:0,relationsExtracted:0,errors:[],duration:0},n=await this.fileScanner.scanAll(e),o=new Set(n.map(a=>Filesystem.toUnixPath(a.relativePath))),s=this.db.query("SELECT path, contentHash FROM documents"),i=new Map;for(let a of s)i.set(a.path,a.contentHash);for(let[a]of i)if(!o.has(a))try{this.db.deleteDocumentByPath(a)&&(r.filesDeleted++,A.debug("Deleted document from index",{path:a}));}catch(d){let l=d instanceof Error?d.message:String(d);r.errors.push({filePath:a,error:`Failed to delete document: ${l}`}),A.error("Failed to delete document",{path:a,error:l});}for(let a=0;a<n.length;a++){let d=n[a],l=Filesystem.toUnixPath(d.relativePath);e?.(a+1,n.length,d);try{let g=i.get(l);if(g===void 0){let u=await this.pipeline.process(d.absolutePath);r.filesAdded++,r.chunksCreated+=u.chunksCreated,r.vectorsCreated+=u.vectorsCreated,r.entitiesExtracted+=u.entitiesExtracted||0,r.relationsExtracted+=u.relationsExtracted||0,A.debug("Added new document",{path:l});}else if(g!==d.contentHash){let u=await this.pipeline.process(d.absolutePath);r.filesUpdated++,r.chunksCreated+=u.chunksCreated,r.vectorsCreated+=u.vectorsCreated,r.entitiesExtracted+=u.entitiesExtracted||0,r.relationsExtracted+=u.relationsExtracted||0,A.debug("Updated document",{path:l});}else r.filesSkipped++;}catch(g){let u=g instanceof Error?g.message:String(g);r.errors.push({filePath:l,error:u}),A.error("Failed to process document",{path:l,error:u});}}r.duration=Date.now()-t,r.success=r.errors.length===0;let c={timestamp:new Date().toISOString(),success:r.success,filesAdded:r.filesAdded,filesUpdated:r.filesUpdated,filesDeleted:r.filesDeleted,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,vectorsCreated:r.vectorsCreated,entitiesExtracted:r.entitiesExtracted,relationsExtracted:r.relationsExtracted,errorCount:r.errors.length,duration:r.duration};return this.db.setMeta("lastSync",c.timestamp),this.db.setMeta("lastSyncResult",JSON.stringify(c)),A.info("Sync completed",{added:r.filesAdded,updated:r.filesUpdated,deleted:r.filesDeleted,skipped:r.filesSkipped,errors:r.errors.length,duration:r.duration}),r}finally{this.syncingInProgress=false;}}async search(e,t){return await this.ensureInitialized(),this.ensureSynced(),this.searchEngine.search(e,t)}async queryNodes(e,t){return await this.ensureInitialized(),typeof e=="string"?this.graphInterface.queryNodes(e,t):this.graphInterface.queryNodes(e)}async queryEdges(e,t){return await this.ensureInitialized(),typeof e=="string"?this.graphInterface.queryEdges(e,t):this.graphInterface.queryEdges(e)}async findPath(e,t,r){return await this.ensureInitialized(),this.graphInterface.findPath(e,t,r)}async queryNeighbors(e,t){return await this.ensureInitialized(),this.graphInterface.queryNeighbors(e,t)}async queryCallGraph(e,t){return await this.ensureInitialized(),this.graphInterface.queryCallGraph(e,t)}async queryInheritance(e){return await this.ensureInitialized(),this.graphInterface.queryInheritance(e)}async createNode(e,t,r){return await this.ensureInitialized(),this.graphInterface.createNode(e,t,r)}async updateNode(e,t){return await this.ensureInitialized(),this.graphInterface.updateNode(e,t)}async deleteNode(e){return await this.ensureInitialized(),this.graphInterface.deleteNode(e)}async createEdge(e,t,r,n){return await this.ensureInitialized(),this.graphInterface.createEdge(e,t,r,n)}async deleteEdge(e){return await this.ensureInitialized(),this.graphInterface.deleteEdge(e)}getStatus(){let e=this.db.getPath(),t=0,r=0,n=0,o=0;try{t=this.db.getDb().prepare("SELECT COUNT(*) as count FROM documents").get()?.count||0,r=this.db.getDb().prepare("SELECT COUNT(*) as count FROM chunks").get()?.count||0,n=this.db.getDb().prepare("SELECT COUNT(*) as count FROM nodes").get()?.count||0,o=this.db.getDb().prepare("SELECT COUNT(*) as count FROM edges").get()?.count||0;}catch{}return {dbPath:e,workspaceDir:this.config.workspaceDir,documentsCount:t,chunksCount:r,nodesCount:n,edgesCount:o,embeddingLlmAvailable:!!this.config.embeddingLlm,graphLlmAvailable:!!this.config.graphLlm,rerankLlmAvailable:!!this.config.rerankLlm,healthy:this.initialized,meta:this.getMetaMap()}}getMetaMap(){let e={};try{let t=this.db.query("SELECT key, value FROM meta");for(let r of t)e[r.key]=r.value;}catch{}return e}async healthCheck(){try{return this.db.query("SELECT 1"),!0}catch{return false}}async clear(){this.db.transaction(()=>{this.db.run("DELETE FROM chunks"),this.db.run("DELETE FROM documents"),this.db.run("DELETE FROM vectors"),this.db.run("DELETE FROM nodes"),this.db.run("DELETE FROM edges"),this.db.run("DELETE FROM embedding_cache"),this.db.run("DELETE FROM sqlite_sequence WHERE name IN ('chunks', 'documents', 'nodes', 'edges')");});try{this.db.run("INSERT INTO chunks_fts(chunks_fts) VALUES('delete-all')");}catch(e){A.warn("Failed to clear FTS index",{error:String(e)});}A.info("Note knowledge base cleared");}async ensureInitialized(){this.initialized||await this.initialize();}async close(){this.initialized&&(this.stopSyncTimer(),await this.db.close(),this.initialized=false,A.info("NoteKnowledge closed"));}};async function He(E){let e=new Z(E);return await e.initialize(),e}async function cr(E){let{Log:e}=await import('./chunks/log-I3JHCPH6.mjs'),t=false;await e.init({logDir:E.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:E.print??false,dev:E.dev??t,level:E.level??("INFO")});}export{$ as FileScanner,R as KnowledgeBaseError,z as KnowledgeBaseErrorCode,L as Llm,Z as NoteKnowledge,st as addWord,ot as closeTokenizer,He as createNoteKnowledge,cr as initLog,nt as initTokenizer,it as isInitialized,be as loadCustomDict,ie as toFtsTokens,oe as toFtsTokensForSearch,Ie as tokenize,Ne as tokenizeForSearch};
128
+ `);return this.extractEntitiesByRules(t)}parseEntityExtractionResult(e){try{let t=e.match(/\{[\s\S]*\}/);if(t){let r=JSON.parse(t[0]);return this.normalizeExtractionResult(r)}}catch(t){Q.debug("Failed to parse entity extraction result",{error:String(t)});}return {summary:"",entities:[],relations:[]}}normalizeExtractionResult(e){let t=e,r=typeof t.summary=="string"?t.summary.trim():"",n=Array.isArray(t.entities)?t.entities:[],o=Array.isArray(t.relations)?t.relations:[],s=[],i=new Set,c=new Map;for(let d of n){let m=typeof d?.name=="string"?d.name.trim():"";if(!m)continue;let u=m.toLowerCase();if(i.has(u))continue;i.add(u),c.set(u,m);let h=typeof d?.type=="string"?d.type.trim():"",g=De.has(h)?h:"keyword",f=d?.properties&&typeof d.properties=="object"&&!Array.isArray(d.properties)?d.properties:{};s.push({name:m,type:g,properties:f});}let a=[],l=new Set;for(let d of o){let m=typeof d?.source=="string"?d.source.trim():"",u=typeof d?.target=="string"?d.target.trim():"";if(!m||!u)continue;let h=c.get(m.toLowerCase()),g=c.get(u.toLowerCase());if(!h||!g||h===g)continue;let f=typeof d?.relation=="string"?d.relation.trim():"",b=Oe.has(f)?f:"related_to",N=`${h.toLowerCase()}|${g.toLowerCase()}|${b}`;l.has(N)||(l.add(N),a.push({source:h,target:g,relation:b}));}return {summary:r,entities:s,relations:a}}extractEntitiesByRules(e){let t=[],r=[],n=new Set,o=new Set,s=new Map,i=/([A-Za-z][\w.-]{1,80})\s+(is_a|part_of|has_attribute|located_in|occurs_in|causes|influences|owned_by|member_of|uses|depends_on|related_to)\s+([A-Za-z][\w.-]{1,80})/g;for(let l of e.matchAll(i)){let d=this.sanitizeEntityToken(l[1]??""),m=(l[2]??"related_to").trim(),u=this.sanitizeEntityToken(l[3]??"");if(!d||!u||d===u)continue;let h=d.toLowerCase(),g=u.toLowerCase();n.has(h)||(n.add(h),s.set(h,d),t.push({name:d,type:this.inferEntityType(d),properties:{source:"rule_extracted"}})),n.has(g)||(n.add(g),s.set(g,u),t.push({name:u,type:this.inferEntityType(u),properties:{source:"rule_extracted"}}));let f=`${h}|${g}|${m}`;o.has(f)||(o.add(f),r.push({source:d,target:u,relation:m}));}let c=e.match(/[\p{L}\p{N}][\p{L}\p{N}_.-]{1,80}/gu)??[],a=e.split(/\n\s*\n/);for(let l of c){let d=this.sanitizeEntityToken(l);if(!d)continue;let m=d.toLowerCase();n.has(m)||(n.add(m),s.set(m,d),t.push({name:d,type:this.inferEntityType(d),properties:{source:"keyword_extracted"}}));}for(let l of a){if(l.trim().length<20)continue;let d=[];for(let m of l.match(/[\p{L}\p{N}][\p{L}\p{N}_.-]{2,80}/gu)??[]){let u=this.sanitizeEntityToken(m);if(!u)continue;let h=u.toLowerCase();n.has(h)&&!d.some(g=>g.key===h)&&d.push({key:h,name:u});}for(let m=0;m<d.length;m++)for(let u=m+1;u<d.length;u++){let h=d[m],g=d[u];if(h.key===g.key)continue;let f="related_to",b=this.inferEntityType(h.name),N=this.inferEntityType(g.name);b==="document"&&N==="object"?f="defines":b==="object"&&N==="document"?f="referenced_in":b==="process"&&N==="object"?f="uses":b==="object"&&N==="process"?f="used_by":b==="concept"&&(f="relates_to");let T=`${h.key}|${g.key}|${f}`;o.has(T)||(o.add(T),r.push({source:h.name,target:g.name,relation:f}));}}return {summary:"",entities:t,relations:r}}sanitizeEntityToken(e){return e.trim().replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,"").replace(/\s+/g," ").slice(0,120)}inferEntityType(e){return /(\.md|\.ts|\.json|readme|doc|spec|guideline)/i.test(e)?"document":/(api|service|system|engine|pipeline|server|db|database|memorysystem|contextengine)/i.test(e)?"process":/(team|group|org|company|inc|ltd|corp)/i.test(e)?"organization":/(deadline|date|day|week|month|year|q[1-4]|sprint)/i.test(e)?"time":/(score|rate|ratio|latency|accuracy|recall|precision|throughput|kpi)/i.test(e)?"metric":/(task|issue|ticket|todo|action)/i.test(e)?"task":/(event|incident|release|meeting|migration|launch)/i.test(e)?"event":/(process|workflow|procedure|flow|lifecycle)/i.test(e)?"process":/(file|model|dataset|artifact|resource|tool|sdk|ollama|sqlite|embedding|vector|fts)/i.test(e)?"object":/(concept|principle|policy|method|pattern|strategy)/i.test(e)?"concept":/[A-Z]/.test(e)?"object":"keyword"}storeEntities(e,t){if(e.length===0)return;let r=new Map,n=new Date().toISOString();for(let o of e){let s=this.db.query("SELECT id FROM nodes WHERE name = ? AND type = ?",[o.name,o.type]);s.length>0&&s[0]&&r.set(o.name,s[0].id);}this.db.transaction(()=>{for(let o of e){if(r.has(o.name))continue;let s=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[o.name,o.type,JSON.stringify(o.properties),n,n]);s.lastID>0&&r.set(o.name,s.lastID);}for(let o of t){let s=r.get(o.source),i=r.get(o.target);if(s&&i){let c=this.db.query("SELECT id FROM nodes WHERE id = ?",[s]),a=this.db.query("SELECT id FROM nodes WHERE id = ?",[i]);c.length>0&&a.length>0&&this.db.run("INSERT OR REPLACE INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[s,i,o.relation,"{}",n]);}}});}mergeEntitiesAndRelations(e,t,r,n){if(t.length===0&&r.length===0&&(!n||n.trim().length===0))return;let o=new Map,s=new Date().toISOString();if(t.length>0){let i=t.map(()=>"?").join(","),c=this.db.query(`SELECT id, name, type FROM nodes WHERE name IN (${i})`,t.map(a=>a.name));for(let a of c)o.set(a.name,a.id);}this.db.transaction(()=>{for(let i of t)if(o.get(i.name)===void 0){let a=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[i.name,i.type,JSON.stringify(i.properties),s,s]);a.lastID>0&&o.set(i.name,a.lastID);}for(let i of r){let c=o.get(i.source),a=o.get(i.target);if(c&&a){let l=this.db.query("SELECT id FROM nodes WHERE id = ?",[c]),d=this.db.query("SELECT id FROM nodes WHERE id = ?",[a]);l.length>0&&d.length>0&&this.db.run("INSERT OR REPLACE INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[c,a,i.relation,"{}",s]);}}n&&n.trim().length>0&&(this.db.run("UPDATE documents SET summary = ?, updatedAt = ? WHERE path = ?",[n,s,e]),Q.debug("Updated document summary",{path:e,summaryLength:n.length}));});}float32ToBuffer(e){return Buffer.from(e.buffer,e.byteOffset,e.byteLength)}ensureVectorDims(e){this.db.query("SELECT value FROM meta WHERE key = ?",["vectorDims"]).length===0&&this.db.run("INSERT OR IGNORE INTO meta (key, value) VALUES (?, ?)",["vectorDims",String(e)]);}mapChunksToNodes(e,t,r){let n=new Map,o=new Date().toISOString();this.db.transaction(()=>{for(let s of t){let i=this.db.query("SELECT id FROM nodes WHERE name = ? AND type = ?",[s.name,s.type]);if(i.length>0&&i[0])n.set(s.name,i[0].id);else {let c=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[s.name,s.type,JSON.stringify(s.properties),o,o]);c.lastID>0&&n.set(s.name,c.lastID);}}for(let s=0;s<e.length;s++){let i=e[s],c=[];for(let a of t)if(i.includes(a.name)){let l=n.get(a.name);l&&c.push(l);}r.set(s,c);}});}};b.create({service:"note-search"});var J=class{constructor(e,t){a(this,"db");a(this,"config");this.db=e,this.config={...DEFAULT_NOTE_CHUNK_CONFIG,...t,embeddingLlm:t.embeddingLlm},t.embeddingLlm&&D.init({models:{embeddingLlm:t.embeddingLlm,graphLlm:t.graphLlm,rerankLlm:t.rerankLlm}});}async search(e,t){if(!e.trim())return [];let r=t?.maxResults||3,n=t?.minScore??this.config.search.minScore,o=await this.hybridSearch(e,{...t,maxResults:r*2});return o.length===0?[]:this.config.rerankLlm?(await this.rerank(e,o,r)).filter(i=>i.score>=n):o.filter(s=>s.score>=n).slice(0,r)}async hybridSearch(e,t){let{maxResults:r=this.config.search.maxResults,minScore:n=this.config.search.minScore,vectorWeight:o=this.config.search.hybrid.vectorWeight,textWeight:s=this.config.search.hybrid.textWeight,enableEmbedding:i=true,enableFts:c=true}=t??{},a=i?await this.embed(e):new Float32Array(0),[l,d]=await Promise.all([i&&this.config.embeddingLlm?this.vectorSearch(a,r,n,t):Promise.resolve([]),c===false?Promise.resolve([]):this.ftsSearch(e,r,n,t)]);return this.mergeResults(l,d,o,s,n)}async vectorSearch(e,t,r,n){if(!this.config.embeddingLlm)return [];try{let o;if(n?.candidateChunkIds&&n.candidateChunkIds.length>0){let c=n.candidateChunkIds.map(()=>"?").join(",");o=this.db.query(`SELECT chunkId, embedding FROM vectors WHERE chunkId IN (${c})`,n.candidateChunkIds);}else o=this.db.query("SELECT chunkId, embedding FROM vectors LIMIT ?",[Math.max(t*100,1e3)]);let s=[];for(let c of o){let a=new Float32Array(c.embedding.buffer,c.embedding.byteOffset,c.embedding.length/4),l=this.cosineSimilarity(e,a);s.push({chunkId:c.chunkId,score:l});}s.sort((c,a)=>a.score-c.score);let i=s.slice(0,t);return this.buildSearchResults(i,"vector",n)}catch(o){throw new R(`\u5411\u91CF\u641C\u7D22\u5931\u8D25: ${o.message}`,"SEARCH_FAILED",o)}}async ftsSearch(e,t,r,n){let o=async()=>[];try{let s=ie(e),i=this.db.query("SELECT chunkId, bm25(chunks_fts) as score FROM chunks_fts WHERE content MATCH ? ORDER BY score DESC LIMIT ?",[s,t]);if(i.length===0)return o();let c=i.map(a=>({chunkId:a.chunkId,score:-a.score}));return this.buildSearchResults(c,"fts",n)}catch{return o()}}mergeResults(e,t,r,n,o){let s=r+n,i=r/s,c=n/s,a=new Map;for(let m of e){let u=`${m.chunk.id}`,h=m.score*i;a.set(u,{...m,score:h,source:"hybrid"});}for(let m of t){let u=`${m.chunk.id}`,h=a.get(u);if(h)h.score+=m.score*c;else {let g=m.score*c;a.set(u,{...m,score:g,source:"hybrid"});}}return Array.from(a.values()).map(m=>{let u=m.score,h=new Date(m.document.updatedAt),g=(Date.now()-h.getTime())/864e5,f=Math.exp(-0.01*g),b=.6*u+.4*f;return {...m,score:b}}).sort((m,u)=>u.score-m.score)}async rerank(e,t,r){if(!this.config.rerankLlm)return t.slice(0,r);try{let n=t.map(a=>{let l=a.nodes&&a.nodes.length>0?a.nodes.map(d=>{let m=(d.edges??[]).map(u=>{let h=u.source===d.id?"\u2192":"\u2190",g=u.targetNode?`${u.targetNode.type}:${u.targetNode.name}`:`id=${u.target}`;return `${h} [${u.relation}] ${g}`}).join(" | ");return `node: id=${d.id} name=${d.name} type=${d.type}${m?` edges: ${m}`:""}`}).join(" | "):"";return `<doc filePath="${a.document.path}" lineStart="${a.chunk.startLine}" lineEnd="${a.chunk.endLine}"><snippet>${a.snippet}</snippet>${l?`<nodes>${l}</nodes>`:""}</doc>`}),o=await D.rerank(e,n,t.length);if(o.length===0)return t.slice(0,r);let s=new Map;for(let a of o)a.index>=0&&a.index<t.length&&s.set(a.index,a.score);let i=.5,c=t.map((a,l)=>{let d=s.get(l)??a.score,m=i*a.score+(1-i)*d;return {...a,originalScore:a.score,score:m,source:"reranked"}});return c.sort((a,l)=>l.score-a.score),c.slice(0,r)}catch{return t.slice(0,r)}}async embed(e){try{return await D.embed(e)}catch{return new Float32Array(this.config.vectorDims)}}cosineSimilarity(e,t){let r=0,n=0,o=0;for(let s=0;s<e.length;s++){let i=e[s],c=t[s];r+=i*c,n+=i*i,o+=c*c;}return n===0||o===0?0:r/(Math.sqrt(n)*Math.sqrt(o))}async buildSearchResults(e,t,r){let n=[],o=e.map(p=>p.chunkId);if(o.length===0)return n;let s=r?.includeEdges??true,i=Math.max(1,r?.edgesLimit??100),c=this.db.query("SELECT * FROM chunks WHERE id IN ("+o.map(()=>"?").join(", ")+")",o),a=new Map(c.map(p=>[p.id,p])),l=Array.from(new Set(c.map(p=>p.documentId))),d=l.length>0?this.db.query("SELECT * FROM documents WHERE id IN ("+l.map(()=>"?").join(", ")+")",l):[],m=new Map(d.map(p=>[p.id,p])),u=new Map,h=[];for(let p of c){let I=[];try{let S=p.nodeIds?JSON.parse(p.nodeIds):[];I=Array.isArray(S)?S.filter(w=>typeof w=="number"):[];}catch{I=[];}u.set(p.id,I),h.push(...I);}let g=Array.from(new Set(h)),f=g.length>0?this.db.query("SELECT * FROM nodes WHERE id IN ("+g.map(()=>"?").join(", ")+")",g):[],b=new Map(f.map(p=>[p.id,{id:p.id,name:p.name,type:p.type,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt,updatedAt:p.updatedAt}])),N=s&&g.length>0?this.db.query("SELECT * FROM edges WHERE source IN ("+g.map(()=>"?").join(", ")+") OR target IN ("+g.map(()=>"?").join(", ")+") ORDER BY id LIMIT ?",[...g,...g,g.length*i]):[],T=[...new Set([...g,...N.map(p=>p.target)])],z=T.length>0?this.db.query("SELECT * FROM nodes WHERE id IN ("+T.map(()=>"?").join(", ")+")",T):[],q=new Map(z.map(p=>[p.id,{id:p.id,name:p.name,type:p.type,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt,updatedAt:p.updatedAt}])),L=new Map;for(let p of N){let I={id:p.id,source:p.source,target:p.target,relation:p.relation,properties:p.properties?JSON.parse(p.properties):void 0,createdAt:p.createdAt},S=q.get(p.target);S&&(I.targetNode=S);let w=L.get(I.source)??[];w.length<i&&(w.push(I),L.set(I.source,w));let P=L.get(I.target)??[];P.length<i&&(P.push(I),L.set(I.target,P));}for(let p of e){let I=a.get(p.chunkId);if(!I)continue;let S=m.get(I.documentId);if(!S)continue;let w=u.get(I.id)??[],P=w.map(k=>b.get(k)).filter(k=>k!==void 0),K=s&&w.length>0?Array.from(new Map(w.flatMap(k=>L.get(k)??[]).map(k=>[k.id,k])).values()):[],H=new Map;for(let k of K){let re=H.get(k.source)??[];re.push(k),H.set(k.source,re);}let j=P.length>0?P.map(k=>({...k,edges:s?H.get(k.id)??[]:void 0})):[];n.push({chunk:{id:I.id,documentId:I.documentId,startLine:I.startLine,endLine:I.endLine,startChar:I.startChar,endChar:I.endChar,content:I.content,contentHash:I.contentHash,nodeIds:w,path:S.path,createdAt:I.createdAt},document:{id:S.id,path:S.path,title:S.title,contentHash:S.contentHash,summary:S.summary,lastModified:S.lastModified,createdAt:S.createdAt,updatedAt:S.updatedAt},nodes:j.length>0?j:void 0,score:p.score,snippet:I.content.slice(0,200),source:t});}return n}};var Z=class{constructor(e){a(this,"db");this.db=e;}async queryNodes(e,t){try{if(typeof e=="string")return this.db.query(e,t).map(c=>this.mapNode(c));let r=[],n=[];e.ids&&e.ids.length>0&&(r.push(`id IN (${e.ids.map(()=>"?").join(",")})`),n.push(...e.ids)),e.name&&(r.push("name LIKE ?"),n.push(`%${e.name}%`)),e.type&&(r.push("type = ?"),n.push(e.type));let o="SELECT * FROM nodes";return r.length>0&&(o+=` WHERE ${r.join(" AND ")}`),o+=" ORDER BY id",e.limit&&e.limit>0&&(o+=" LIMIT ?",n.push(e.limit)),this.db.query(o,n).map(i=>this.mapNode(i))}catch(r){throw new R(`\u67E5\u8BE2\u8282\u70B9\u5931\u8D25: ${r.message}`,"SEARCH_FAILED",r)}}async queryEdges(e,t){try{if(typeof e=="string")return this.db.query(e,t).map(c=>this.mapEdge(c));let r=[],n=[];e.ids&&e.ids.length>0&&(r.push(`id IN (${e.ids.map(()=>"?").join(",")})`),n.push(...e.ids)),typeof e.source=="number"&&(r.push("source = ?"),n.push(e.source)),typeof e.target=="number"&&(r.push("target = ?"),n.push(e.target)),e.sourceOrTarget&&e.sourceOrTarget.length>0&&(r.push(`(source IN (${e.sourceOrTarget.map(()=>"?").join(", ")}) OR target IN (${e.sourceOrTarget.map(()=>"?").join(", ")}))`),n.push(...e.sourceOrTarget,...e.sourceOrTarget)),e.relation&&(r.push("relation = ?"),n.push(e.relation));let o="SELECT * FROM edges";return r.length>0&&(o+=` WHERE ${r.join(" AND ")}`),o+=" ORDER BY id",e.limit&&e.limit>0&&(o+=" LIMIT ?",n.push(e.limit)),this.db.query(o,n).map(i=>this.mapEdge(i))}catch(r){throw new R(`\u67E5\u8BE2\u8FB9\u5931\u8D25: ${r.message}`,"SEARCH_FAILED",r)}}async queryNeighbors(e,t){let r=t?.direction??"both",n=t?.relationTypes,o=t?.limit&&t.limit>0?t.limit:100,s=[],i=[];r==="incoming"?(s.push("target = ?"),i.push(e)):r==="outgoing"?(s.push("source = ?"),i.push(e)):(s.push("(source = ? OR target = ?)"),i.push(e,e)),n&&n.length>0&&(s.push(`relation IN (${n.map(()=>"?").join(",")})`),i.push(...n));let c=await this.queryEdges(`SELECT * FROM edges WHERE ${s.join(" AND ")} ORDER BY id LIMIT ?`,[...i,o]),a=Array.from(new Set(c.map(u=>u.source===e?u.target:u.source)));if(a.length===0)return {nodes:await this.queryNodes({ids:[e],limit:1}),edges:c};let l=[...new Set([e,...a])],d=await this.queryNodes({ids:l,limit:l.length}),m=new Map(d.map(u=>[u.id,u]));for(let u of c){let h=m.get(u.target);h&&(u.targetNode=h);}return {nodes:d,edges:c}}async queryCallGraph(e,t=2){let r=Math.max(1,t),n=new Map,o=[{id:e,level:0}],s=new Set;for(;o.length>0;){let i=o.shift();if(s.has(i.id)||i.level>r)continue;s.add(i.id);let c=await this.queryEdges({source:i.id,relation:"CALLS",limit:100}),a=await this.queryEdges({target:i.id,relation:"CALLS",limit:100}),l=Array.from(new Set(c.map(m=>m.target))),d=Array.from(new Set(a.map(m=>m.source)));n.set(i.id,{callers:d,callees:l});for(let m of [...d,...l])s.has(m)||o.push({id:m,level:i.level+1});}return n}async queryInheritance(e){let t=["EXTENDS","INHERITS_FROM","IMPLEMENTS"],r=await this.collectInheritance(e,"ancestor",t),n=await this.collectInheritance(e,"descendant",t);return {ancestors:r,descendants:n}}async findPath(e,t,r=3){let n=[],o=new Set,s=this.db.query("SELECT * FROM nodes WHERE name = ?",[e]);if(s.length===0)return [];let i=s.map(c=>({nodeId:c.id,path:[c.id]}));for(;i.length>0;){let{nodeId:c,path:a}=i.shift();if(a.length>r)continue;let l=a.join(",");if(o.has(l))continue;if(o.add(l),a.length>1){let m=this.db.query("SELECT id, name FROM nodes WHERE id = ?",[c]);if(m.length>0&&m[0]?.name===t){let u=a.map(()=>"?").join(","),h=this.db.query(`SELECT * FROM nodes WHERE id IN (${u})`,a),g=new Map(h.map(b=>[b.id,b])),f=[];for(let b of a){let N=g.get(b);N&&f.push({id:N.id,name:N.name,type:N.type,properties:N.properties?JSON.parse(N.properties):void 0,createdAt:N.createdAt,updatedAt:N.updatedAt});}n.push(f);continue}}let d=this.db.query("SELECT source, target FROM edges WHERE source = ? OR target = ?",[c,c]);for(let m of d){let u=m.source===c?m.target:m.source;a.includes(u)||i.push({nodeId:u,path:[...a,u]});}}return n}async searchNodesByName(e){return this.queryNodes("SELECT * FROM nodes WHERE name LIKE ?",[e])}async searchNodesByType(e){return this.queryNodes("SELECT * FROM nodes WHERE type = ?",[e])}async searchRelations(e){return this.queryEdges("SELECT * FROM edges WHERE relation = ?",[e])}async createNode(e,t,r){let n=new Date().toISOString(),o=this.db.run("INSERT INTO nodes (name, type, properties, createdAt, updatedAt) VALUES (?, ?, ?, ?, ?)",[e,t,r?JSON.stringify(r):null,n,n]),i=this.db.query("SELECT * FROM nodes WHERE id = ?",[o.lastID])[0];return {id:i.id,name:i.name,type:i.type,properties:i.properties?JSON.parse(i.properties):void 0,createdAt:i.createdAt,updatedAt:i.updatedAt}}async updateNode(e,t){let r=new Date().toISOString();this.db.run("UPDATE nodes SET properties = ?, updatedAt = ? WHERE id = ?",[JSON.stringify(t),r,e]);let n=this.db.query("SELECT * FROM nodes WHERE id = ?",[e]);if(n.length===0)throw new R(`\u8282\u70B9\u4E0D\u5B58\u5728: ${e}`,"NODE_NOT_FOUND");let o=n[0];return {id:o.id,name:o.name,type:o.type,properties:o.properties?JSON.parse(o.properties):void 0,createdAt:o.createdAt,updatedAt:o.updatedAt}}async deleteNode(e){this.db.run("DELETE FROM nodes WHERE id = ?",[e]);}async createEdge(e,t,r,n){let o=this.db.query("SELECT id FROM nodes WHERE id = ?",[e]),s=this.db.query("SELECT id FROM nodes WHERE id = ?",[t]);if(o.length===0||s.length===0)throw new R("\u8282\u70B9\u4E0D\u5B58\u5728","NODE_NOT_FOUND");let i=new Date().toISOString(),c=this.db.run("INSERT INTO edges (source, target, relation, properties, createdAt) VALUES (?, ?, ?, ?, ?)",[e,t,r,n?JSON.stringify(n):null,i]),l=this.db.query("SELECT * FROM edges WHERE id = ?",[c.lastID])[0];return {id:l.id,source:l.source,target:l.target,relation:l.relation,properties:l.properties?JSON.parse(l.properties):void 0,createdAt:l.createdAt}}async deleteEdge(e){this.db.run("DELETE FROM edges WHERE id = ?",[e]);}mapNode(e){return {id:e.id,name:e.name,type:e.type,properties:e.properties?JSON.parse(e.properties):void 0,createdAt:e.createdAt,updatedAt:e.updatedAt}}mapEdge(e){return {id:e.id,source:e.source,target:e.target,relation:e.relation,properties:e.properties?JSON.parse(e.properties):void 0,createdAt:e.createdAt}}async collectInheritance(e,t,r){let n=[e],o=new Set([e]),s=new Set;for(;n.length>0;){let i=n.shift(),c=t==="ancestor"?await this.queryEdges(`SELECT * FROM edges WHERE source = ? AND relation IN (${r.map(()=>"?").join(",")})`,[i,...r]):await this.queryEdges(`SELECT * FROM edges WHERE target = ? AND relation IN (${r.map(()=>"?").join(",")})`,[i,...r]);for(let a of c){let l=t==="ancestor"?a.target:a.source;o.has(l)||(o.add(l),s.add(l),n.push(l));}}return s.size===0?[]:this.queryNodes({ids:Array.from(s),limit:s.size})}};var ee=b.create({service:"note-scanner"}),Me=["node_modules/**",".git/**","dist/**","build/**","__pycache__/**","*.min.md"],$=class{constructor(e){a(this,"workspaceDir");a(this,"extraPaths");a(this,"sources");a(this,"ignorePatterns");this.workspaceDir=e.workspaceDir,this.extraPaths=e.extraPaths??[],this.sources=new Set(e.sources??["docs"]),this.ignorePatterns=[...Me,...e.ignorePatterns??[]];}async scanAll(e){let t=[],r=[];for(let s of this.sources){let i=W__default.join(this.workspaceDir,s);r.push({source:s,dir:i});}for(let s of this.extraPaths){let i=W__default.isAbsolute(s)?s:W__default.join(this.workspaceDir,s);r.push({source:"local",dir:i});}let n=0,o=r.length;for(let s of r){let i=await this.scanDirectory(s.dir,s.source);t.push(...i),n++,e?.(n,o,i[0]||{absolutePath:s.dir,relativePath:s.dir,source:s.source,contentHash:"",lastModified:0,size:0});}return t}async scanDirectory(e,t){let r=[];try{await B.access(e);}catch{return ee.debug("Directory not found, skipping",{dir:e}),r}let n=async o=>{try{let s=await B.readdir(o,{withFileTypes:!0});for(let i of s){let c=W__default.join(o,i.name);if(!this.shouldIgnore(i.name)){if(i.isDirectory())await n(c);else if(i.isFile()&&this.isMarkdownFile(i.name)){let a=await this.getFileInfo(c,t);a&&r.push(a);}}}}catch(s){ee.warn("Failed to scan directory",{dir:o,error:String(s)});}};return await n(e),r}async scanFile(e,t="upload"){try{let r=await B.stat(e);if(!r.isFile())return null;let n=await B.readFile(e,"utf-8"),o=createHash("sha256").update(n).digest("hex"),s=Filesystem.normalize(e);return {absolutePath:e,relativePath:s||W__default.basename(e),source:t,contentHash:o,lastModified:r.mtimeMs,size:r.size}}catch(r){return ee.error("Failed to scan file",{filePath:e,error:String(r)}),null}}async getFileInfo(e,t){try{let r=await B.readFile(e,"utf-8"),n=await B.stat(e),o=createHash("sha256").update(r).digest("hex"),s=Filesystem.normalize(e);return {absolutePath:e,relativePath:s,source:t,contentHash:o,lastModified:n.mtimeMs,size:n.size}}catch(r){return ee.error("Failed to get file info",{filePath:e,error:String(r)}),null}}shouldIgnore(e){if(e.startsWith("."))return true;for(let t of this.ignorePatterns)if(new RegExp("^"+t.replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$").test(e))return true;return false}isMarkdownFile(e){return e.endsWith(".md")||e.endsWith(".markdown")}};var A=b.create({service:"note"}),te=class{constructor(e){a(this,"config");a(this,"db");a(this,"pipeline");a(this,"searchEngine");a(this,"graphInterface");a(this,"fileScanner");a(this,"initialized",false);a(this,"dirty",false);a(this,"syncTimer");a(this,"syncConfig");a(this,"syncingInProgress",false);let t=e.workspaceDir||process.cwd(),r=e.embeddingLlm;if(!r)throw new Error("embeddingLlm is required");let n=e.database?.path||getDefaultDatabasePath(xdgData,"note.db");this.config={workspaceDir:t,database:{path:n,walMode:e.database?.walMode??true},vectorDims:e.vectorDims??768,...DEFAULT_NOTE_CHUNK_CONFIG,extraPaths:e.extraPaths,sources:e.sources,search:{...DEFAULT_SEARCH_CONFIG,...e.search},indexer:{...DEFAULT_INDEXER_CONFIG,...e.indexer},sync:{...DEFAULT_SYNC_CONFIG,...e.sync},logDir:e.logDir,embeddingLlm:r,graphLlm:e.graphLlm,rerankLlm:e.rerankLlm},this.syncConfig=this.config.sync,this.db=new Y(this.config.database.path),this.pipeline=new V(this.db,this.config),this.searchEngine=new J(this.db,this.config),this.graphInterface=new Z(this.db),this.fileScanner=new $({workspaceDir:this.config.workspaceDir,extraPaths:this.config.extraPaths,sources:this.config.sources,ignorePatterns:this.config?.indexer?.ignorePatterns});}async initialize(){if(this.initialized)return;await b.init({logDir:this.config.logDir||W__default.join(this.config.workspaceDir,"logs"),print:process.argv.includes("--print-logs"),dev:false,level:"INFO"}),D.init({models:{embeddingLlm:this.config.embeddingLlm,graphLlm:this.config.graphLlm,rerankLlm:this.config.rerankLlm},options:{graph:{maxOutputTokens:2e3,temperature:.1}}}),await this.db.initialize();let e=[["version","1.0.0"],["chunkSize",String(this.config.chunkSize)],["chunkOverlap",String(this.config.chunkOverlap)],["createdAt",new Date().toISOString()]];for(let[t,r]of e)this.db.run("INSERT OR IGNORE INTO meta (key, value) VALUES (?, ?)",[t,r]);this.initialized=true,this.syncConfig.onBoot&&(this.syncAll().catch(t=>A.warn("onBoot sync failed",{error:String(t)})),this.startSyncTimer()),A.debug("NoteKnowledge initialized",{workspaceDir:this.config.workspaceDir,dbPath:this.config.database.path,embeddingEnabled:!!this.config.embeddingLlm,graphLlmEnabled:!!this.config.graphLlm,rerankLlmEnabled:!!this.config.rerankLlm,chunkSize:this.config.chunkSize,chunkOverlap:this.config.chunkOverlap,sources:this.config.sources,syncOnBoot:this.syncConfig.onBoot,syncIntervalMs:this.syncConfig.intervalMs,hybridSearch:this.config.search?.hybrid?.enabled,vectorWeight:this.config.search?.hybrid?.vectorWeight,textWeight:this.config.search?.hybrid?.textWeight});}startSyncTimer(){this.syncTimer&&clearInterval(this.syncTimer),this.syncConfig.intervalMs>0&&(this.syncTimer=setInterval(async()=>{try{await this.syncAll();}catch(e){A.error("Interval sync failed",{error:String(e)});}},this.syncConfig.intervalMs));}ensureSynced(){this.dirty&&!this.syncingInProgress&&this.syncConfig.onSearch&&this.syncAll().catch(e=>{A.warn("Background sync failed",{error:String(e)});});}stopSyncTimer(){this.syncTimer&&(clearInterval(this.syncTimer),this.syncTimer=void 0);}async syncAll(){if(this.syncingInProgress){A.debug("Sync already in progress, skipping...");return}this.syncingInProgress=true,A.debug("Starting sync...");try{let e=await this.sync((t,r,n)=>{A.debug("Syncing file",{current:t,total:r,path:n.relativePath||W__default.basename(n.absolutePath)});});this.dirty=!1,A.debug("Sync completed",{totalFiles:e.filesAdded+e.filesUpdated+e.filesSkipped,added:e.filesAdded,updated:e.filesUpdated,deleted:e.filesDeleted,skipped:e.filesSkipped,errors:e.errors.length});}finally{this.syncingInProgress=false;}}async ingestDocument(e){return await this.ensureInitialized(),this.pipeline.process(e)}async ingestDocuments(e,t){await this.ensureInitialized();let r=[];for(let n=0;n<e.length;n++){let o=await this.pipeline.process(e[n]);r.push(o),t?.((n+1)/e.length);}return r}async scanAndIngest(e){for(await this.ensureInitialized();this.syncingInProgress;)await new Promise(n=>setTimeout(n,100));let t=await this.fileScanner.scanAll(e);if(t.length===0)return [];let r=t.map(n=>n.absolutePath);return this.ingestDocuments(r,n=>{e?.(Math.round(n*t.length),t.length,t[0]||{absolutePath:"ingesting...",relativePath:"ingesting...",source:"docs",contentHash:"",lastModified:0,size:0});})}async ingestUploadedFile(e){await this.ensureInitialized();let t=await this.fileScanner.scanFile(e,"upload");if(!t)throw new Error(`\u65E0\u6CD5\u626B\u63CF\u6587\u4EF6: ${e}`);return this.pipeline.process(t.absolutePath)}async removeDocument(e){await this.ensureInitialized();let t=Filesystem.normalize(e);try{this.db.deleteDocumentByPath(t)&&A.debug("Removed document",{path:t});}catch(r){throw A.error("Failed to remove document",{path:t,error:String(r)}),r}}markDirty(){this.dirty=true,A.debug("Marked as dirty, will sync before next search");}async sync(e){if(await this.ensureInitialized(),this.syncingInProgress)return A.debug("Sync already in progress, skipping..."),{success:true,filesAdded:0,filesUpdated:0,filesDeleted:0,filesSkipped:0,chunksCreated:0,vectorsCreated:0,entitiesExtracted:0,relationsExtracted:0,errors:[],duration:0};this.syncingInProgress=true;try{let t=Date.now(),r={success:!0,filesAdded:0,filesUpdated:0,filesDeleted:0,filesSkipped:0,chunksCreated:0,vectorsCreated:0,entitiesExtracted:0,relationsExtracted:0,errors:[],duration:0},n=await this.fileScanner.scanAll(e),o=new Set(n.map(a=>a.relativePath)),s=this.db.query("SELECT path, contentHash FROM documents"),i=new Map;for(let a of s)i.set(a.path,a.contentHash);for(let[a]of i)if(!o.has(a))try{this.db.deleteDocumentByPath(a)&&(r.filesDeleted++,A.debug("Deleted document from index",{path:a}));}catch(l){let d=l instanceof Error?l.message:String(l);r.errors.push({filePath:a,error:`Failed to delete document: ${d}`}),A.error("Failed to delete document",{path:a,error:d});}for(let a=0;a<n.length;a++){let l=n[a],d=l.relativePath;e?.(a+1,n.length,l);try{let m=i.get(d);if(m===void 0){let u=await this.pipeline.process(l.absolutePath);r.filesAdded++,r.chunksCreated+=u.chunksCreated,r.vectorsCreated+=u.vectorsCreated,r.entitiesExtracted+=u.entitiesExtracted||0,r.relationsExtracted+=u.relationsExtracted||0,A.debug("Added new document",{path:d});}else if(m!==l.contentHash){let u=await this.pipeline.process(l.absolutePath);r.filesUpdated++,r.chunksCreated+=u.chunksCreated,r.vectorsCreated+=u.vectorsCreated,r.entitiesExtracted+=u.entitiesExtracted||0,r.relationsExtracted+=u.relationsExtracted||0,A.debug("Updated document",{path:d});}else r.filesSkipped++;}catch(m){let u=m instanceof Error?m.message:String(m);r.errors.push({filePath:d,error:u}),A.error("Failed to process document",{path:d,error:u});}}r.duration=Date.now()-t,r.success=r.errors.length===0;let c={timestamp:new Date().toISOString(),success:r.success,filesAdded:r.filesAdded,filesUpdated:r.filesUpdated,filesDeleted:r.filesDeleted,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated,vectorsCreated:r.vectorsCreated,entitiesExtracted:r.entitiesExtracted,relationsExtracted:r.relationsExtracted,errorCount:r.errors.length,duration:r.duration};return this.db.setMeta("lastSync",c.timestamp),this.db.setMeta("lastSyncResult",JSON.stringify(c)),A.info("Sync completed",{added:r.filesAdded,updated:r.filesUpdated,deleted:r.filesDeleted,skipped:r.filesSkipped,errors:r.errors.length,duration:r.duration}),r}finally{this.syncingInProgress=false;}}async search(e,t){return await this.ensureInitialized(),this.ensureSynced(),this.searchEngine.search(e,t)}async queryNodes(e,t){return await this.ensureInitialized(),typeof e=="string"?this.graphInterface.queryNodes(e,t):this.graphInterface.queryNodes(e)}async queryEdges(e,t){return await this.ensureInitialized(),typeof e=="string"?this.graphInterface.queryEdges(e,t):this.graphInterface.queryEdges(e)}async findPath(e,t,r){return await this.ensureInitialized(),this.graphInterface.findPath(e,t,r)}async queryNeighbors(e,t){return await this.ensureInitialized(),this.graphInterface.queryNeighbors(e,t)}async queryCallGraph(e,t){return await this.ensureInitialized(),this.graphInterface.queryCallGraph(e,t)}async queryInheritance(e){return await this.ensureInitialized(),this.graphInterface.queryInheritance(e)}async createNode(e,t,r){return await this.ensureInitialized(),this.graphInterface.createNode(e,t,r)}async updateNode(e,t){return await this.ensureInitialized(),this.graphInterface.updateNode(e,t)}async deleteNode(e){return await this.ensureInitialized(),this.graphInterface.deleteNode(e)}async createEdge(e,t,r,n){return await this.ensureInitialized(),this.graphInterface.createEdge(e,t,r,n)}async deleteEdge(e){return await this.ensureInitialized(),this.graphInterface.deleteEdge(e)}getStatus(){let e=this.db.getPath(),t=0,r=0,n=0,o=0;try{t=this.db.getDb().prepare("SELECT COUNT(*) as count FROM documents").get()?.count||0,r=this.db.getDb().prepare("SELECT COUNT(*) as count FROM chunks").get()?.count||0,n=this.db.getDb().prepare("SELECT COUNT(*) as count FROM nodes").get()?.count||0,o=this.db.getDb().prepare("SELECT COUNT(*) as count FROM edges").get()?.count||0;}catch{}return {dbPath:e,workspaceDir:this.config.workspaceDir,documentsCount:t,chunksCount:r,nodesCount:n,edgesCount:o,embeddingLlmAvailable:!!this.config.embeddingLlm,graphLlmAvailable:!!this.config.graphLlm,rerankLlmAvailable:!!this.config.rerankLlm,healthy:this.initialized,meta:this.getMetaMap()}}getMetaMap(){let e={};try{let t=this.db.query("SELECT key, value FROM meta");for(let r of t)e[r.key]=r.value;}catch{}return e}async healthCheck(){try{return this.db.query("SELECT 1"),!0}catch{return false}}async clear(){this.db.transaction(()=>{this.db.run("DELETE FROM chunks"),this.db.run("DELETE FROM documents"),this.db.run("DELETE FROM vectors"),this.db.run("DELETE FROM nodes"),this.db.run("DELETE FROM edges"),this.db.run("DELETE FROM embedding_cache"),this.db.run("DELETE FROM sqlite_sequence WHERE name IN ('chunks', 'documents', 'nodes', 'edges')");});try{this.db.run("INSERT INTO chunks_fts(chunks_fts) VALUES('delete-all')");}catch(e){A.warn("Failed to clear FTS index",{error:String(e)});}A.info("Note knowledge base cleared");}async ensureInitialized(){this.initialized||await this.initialize();}async close(){this.initialized&&(this.stopSyncTimer(),await this.db.close(),this.initialized=false,A.info("NoteKnowledge closed"));}};async function Ue(E){let e=new te(E);return await e.initialize(),e}async function lr(E){let{Log:e}=await import('./chunks/log-I3JHCPH6.mjs'),t=false;await e.init({logDir:E.logDir??process.env.EASBOT_LOG_PATH??process.cwd(),print:E.print??false,dev:E.dev??t,level:E.level??("INFO")});}export{$ as FileScanner,R as KnowledgeBaseError,U as KnowledgeBaseErrorCode,D as Llm,te as NoteKnowledge,at as addWord,dt as closeTokenizer,Ue as createNoteKnowledge,lr as initLog,ot as initTokenizer,ct as isInitialized,be as loadCustomDict,se as toFtsTokens,ie as toFtsTokensForSearch,Ie as tokenize,Ne as tokenizeForSearch};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easbot/note",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Note Knowledge Base - 非结构化记忆和文档知识库管理系统,支持混合搜索(向量+FTS+图)和 LLM 驱动的知识摄取",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -46,28 +46,28 @@
46
46
  "LICENSE"
47
47
  ],
48
48
  "dependencies": {
49
- "@ai-sdk/provider": "^3.0.8",
50
- "@ai-sdk/provider-utils": "^4.0.21",
51
- "@ai-sdk/openai-compatible": "2.0.37",
52
- "@ai-sdk/anthropic": "3.0.63",
53
- "ai": "^6.0.136",
49
+ "@ai-sdk/provider": "^3.0.10",
50
+ "@ai-sdk/provider-utils": "^4.0.27",
51
+ "@ai-sdk/openai-compatible": "^2.0.47",
52
+ "@ai-sdk/anthropic": "^3.0.76",
53
+ "ai": "^6.0.176",
54
54
  "better-sqlite3": "^12.9.0",
55
55
  "jieba-wasm": "^2.4.0",
56
56
  "xdg-basedir": "^5.1.0",
57
- "@easbot/local-model-sdk": "0.2.1",
58
- "@easbot/ollama-sdk": "0.2.1",
59
- "@easbot/types": "0.2.1",
60
- "@easbot/utils": "0.2.1"
57
+ "@easbot/ollama-sdk": "0.2.3",
58
+ "@easbot/local-model-sdk": "0.2.3",
59
+ "@easbot/utils": "0.2.3",
60
+ "@easbot/types": "0.2.3"
61
61
  },
62
62
  "devDependencies": {
63
- "@biomejs/biome": "^2.4.8",
63
+ "@biomejs/biome": "^2.4.14",
64
64
  "@types/better-sqlite3": "^7.6.13",
65
- "@types/node": "^22.17.0",
66
- "@vitest/coverage-v8": "^4.1.1",
67
- "dotenv": "^17.3.1",
65
+ "@types/node": "^25.6.2",
66
+ "@vitest/coverage-v8": "^4.1.5",
67
+ "dotenv": "^17.4.2",
68
68
  "tsup": "^8.5.1",
69
- "typescript": "^6.0.2",
70
- "vitest": "^4.1.1"
69
+ "typescript": "^6.0.3",
70
+ "vitest": "^4.1.5"
71
71
  },
72
72
  "engines": {
73
73
  "node": ">=22.17.0"
@@ -1 +0,0 @@
1
- 'use strict';var chunkGR7YLLW4_cjs=require('./chunk-GR7YLLW4.cjs');Object.defineProperty(exports,"Log",{enumerable:true,get:function(){return chunkGR7YLLW4_cjs.c}});