@vpxa/kb 0.1.1 → 0.1.2

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.
Files changed (136) hide show
  1. package/package.json +1 -1
  2. package/packages/analyzers/dist/blast-radius-analyzer.js +13 -114
  3. package/packages/analyzers/dist/dependency-analyzer.js +11 -425
  4. package/packages/analyzers/dist/diagram-generator.js +4 -86
  5. package/packages/analyzers/dist/entry-point-analyzer.js +5 -239
  6. package/packages/analyzers/dist/index.js +1 -23
  7. package/packages/analyzers/dist/knowledge-producer.js +24 -113
  8. package/packages/analyzers/dist/pattern-analyzer.js +5 -359
  9. package/packages/analyzers/dist/regex-call-graph.js +1 -428
  10. package/packages/analyzers/dist/structure-analyzer.js +4 -258
  11. package/packages/analyzers/dist/symbol-analyzer.js +13 -442
  12. package/packages/analyzers/dist/ts-call-graph.js +1 -160
  13. package/packages/analyzers/dist/types.js +0 -1
  14. package/packages/chunker/dist/call-graph-extractor.js +1 -90
  15. package/packages/chunker/dist/chunker-factory.js +1 -36
  16. package/packages/chunker/dist/chunker.interface.js +0 -1
  17. package/packages/chunker/dist/code-chunker.js +14 -134
  18. package/packages/chunker/dist/generic-chunker.js +5 -72
  19. package/packages/chunker/dist/index.js +1 -21
  20. package/packages/chunker/dist/markdown-chunker.js +7 -119
  21. package/packages/chunker/dist/treesitter-chunker.js +8 -234
  22. package/packages/cli/dist/commands/analyze.js +3 -112
  23. package/packages/cli/dist/commands/context-cmds.js +1 -155
  24. package/packages/cli/dist/commands/environment.js +2 -204
  25. package/packages/cli/dist/commands/execution.js +1 -137
  26. package/packages/cli/dist/commands/graph.js +7 -81
  27. package/packages/cli/dist/commands/init.js +9 -87
  28. package/packages/cli/dist/commands/knowledge.js +1 -139
  29. package/packages/cli/dist/commands/search.js +8 -267
  30. package/packages/cli/dist/commands/system.js +4 -241
  31. package/packages/cli/dist/commands/workspace.js +2 -388
  32. package/packages/cli/dist/context.js +1 -14
  33. package/packages/cli/dist/helpers.js +3 -458
  34. package/packages/cli/dist/index.js +3 -69
  35. package/packages/cli/dist/kb-init.js +1 -82
  36. package/packages/cli/dist/types.js +0 -1
  37. package/packages/core/dist/constants.js +1 -43
  38. package/packages/core/dist/content-detector.js +1 -79
  39. package/packages/core/dist/errors.js +1 -40
  40. package/packages/core/dist/index.js +1 -9
  41. package/packages/core/dist/logger.js +1 -34
  42. package/packages/core/dist/types.js +0 -1
  43. package/packages/embeddings/dist/embedder.interface.js +0 -1
  44. package/packages/embeddings/dist/index.js +1 -5
  45. package/packages/embeddings/dist/onnx-embedder.js +1 -82
  46. package/packages/indexer/dist/file-hasher.js +1 -13
  47. package/packages/indexer/dist/filesystem-crawler.js +1 -125
  48. package/packages/indexer/dist/graph-extractor.js +1 -111
  49. package/packages/indexer/dist/incremental-indexer.js +1 -278
  50. package/packages/indexer/dist/index.js +1 -14
  51. package/packages/server/dist/api.js +1 -9
  52. package/packages/server/dist/config.js +1 -75
  53. package/packages/server/dist/curated-manager.js +9 -356
  54. package/packages/server/dist/index.js +1 -134
  55. package/packages/server/dist/replay-interceptor.js +1 -38
  56. package/packages/server/dist/resources/resources.js +2 -40
  57. package/packages/server/dist/server.js +1 -247
  58. package/packages/server/dist/tools/analyze.tools.js +1 -288
  59. package/packages/server/dist/tools/forge.tools.js +11 -499
  60. package/packages/server/dist/tools/forget.tool.js +3 -39
  61. package/packages/server/dist/tools/graph.tool.js +5 -110
  62. package/packages/server/dist/tools/list.tool.js +5 -53
  63. package/packages/server/dist/tools/lookup.tool.js +8 -51
  64. package/packages/server/dist/tools/onboard.tool.js +2 -112
  65. package/packages/server/dist/tools/produce.tool.js +4 -74
  66. package/packages/server/dist/tools/read.tool.js +4 -47
  67. package/packages/server/dist/tools/reindex.tool.js +2 -70
  68. package/packages/server/dist/tools/remember.tool.js +3 -42
  69. package/packages/server/dist/tools/replay.tool.js +6 -88
  70. package/packages/server/dist/tools/search.tool.js +17 -327
  71. package/packages/server/dist/tools/status.tool.js +3 -68
  72. package/packages/server/dist/tools/toolkit.tools.js +20 -1673
  73. package/packages/server/dist/tools/update.tool.js +3 -39
  74. package/packages/server/dist/tools/utility.tools.js +19 -456
  75. package/packages/store/dist/graph-store.interface.js +0 -1
  76. package/packages/store/dist/index.js +1 -9
  77. package/packages/store/dist/lance-store.js +1 -258
  78. package/packages/store/dist/sqlite-graph-store.js +8 -309
  79. package/packages/store/dist/store-factory.js +1 -14
  80. package/packages/store/dist/store.interface.js +0 -1
  81. package/packages/tools/dist/batch.js +1 -45
  82. package/packages/tools/dist/changelog.js +2 -112
  83. package/packages/tools/dist/check.js +2 -59
  84. package/packages/tools/dist/checkpoint.js +2 -43
  85. package/packages/tools/dist/codemod.js +2 -69
  86. package/packages/tools/dist/compact.js +3 -60
  87. package/packages/tools/dist/data-transform.js +1 -124
  88. package/packages/tools/dist/dead-symbols.js +2 -71
  89. package/packages/tools/dist/delegate.js +3 -128
  90. package/packages/tools/dist/diff-parse.js +3 -153
  91. package/packages/tools/dist/digest.js +7 -242
  92. package/packages/tools/dist/encode.js +1 -46
  93. package/packages/tools/dist/env-info.js +1 -58
  94. package/packages/tools/dist/eval.js +3 -79
  95. package/packages/tools/dist/evidence-map.js +3 -203
  96. package/packages/tools/dist/file-summary.js +2 -106
  97. package/packages/tools/dist/file-walk.js +1 -75
  98. package/packages/tools/dist/find-examples.js +3 -48
  99. package/packages/tools/dist/find.js +1 -120
  100. package/packages/tools/dist/forge-classify.js +2 -319
  101. package/packages/tools/dist/forge-ground.js +1 -184
  102. package/packages/tools/dist/git-context.js +3 -46
  103. package/packages/tools/dist/graph-query.js +1 -194
  104. package/packages/tools/dist/health.js +1 -118
  105. package/packages/tools/dist/http-request.js +1 -58
  106. package/packages/tools/dist/index.js +1 -273
  107. package/packages/tools/dist/lane.js +7 -227
  108. package/packages/tools/dist/measure.js +2 -119
  109. package/packages/tools/dist/onboard.js +42 -1136
  110. package/packages/tools/dist/parse-output.js +2 -158
  111. package/packages/tools/dist/process-manager.js +1 -69
  112. package/packages/tools/dist/queue.js +2 -126
  113. package/packages/tools/dist/regex-test.js +1 -39
  114. package/packages/tools/dist/rename.js +2 -70
  115. package/packages/tools/dist/replay.js +6 -108
  116. package/packages/tools/dist/schema-validate.js +1 -141
  117. package/packages/tools/dist/scope-map.js +1 -72
  118. package/packages/tools/dist/snippet.js +1 -80
  119. package/packages/tools/dist/stash.js +2 -60
  120. package/packages/tools/dist/stratum-card.js +5 -238
  121. package/packages/tools/dist/symbol.js +3 -87
  122. package/packages/tools/dist/test-run.js +2 -55
  123. package/packages/tools/dist/text-utils.js +2 -31
  124. package/packages/tools/dist/time-utils.js +1 -135
  125. package/packages/tools/dist/trace.js +2 -114
  126. package/packages/tools/dist/truncation.js +10 -41
  127. package/packages/tools/dist/watch.js +1 -61
  128. package/packages/tools/dist/web-fetch.js +9 -244
  129. package/packages/tools/dist/web-search.js +1 -46
  130. package/packages/tools/dist/workset.js +2 -77
  131. package/packages/tui/dist/App.js +260 -52468
  132. package/packages/tui/dist/index.js +286 -54551
  133. package/packages/tui/dist/panels/CuratedPanel.js +211 -34291
  134. package/packages/tui/dist/panels/LogPanel.js +259 -51703
  135. package/packages/tui/dist/panels/SearchPanel.js +212 -34824
  136. package/packages/tui/dist/panels/StatusPanel.js +211 -34304
@@ -1,258 +1 @@
1
- import { EMBEDDING_DEFAULTS, SEARCH_DEFAULTS, STORE_DEFAULTS } from "@kb/core";
2
- import { connect, Index } from "@lancedb/lancedb";
3
- const SAFE_FILTER_VALUE = /^[\w.\-/ ]+$/;
4
- function sanitizeFilterValue(value, fieldName) {
5
- if (!SAFE_FILTER_VALUE.test(value)) {
6
- throw new Error(`Invalid ${fieldName} filter value: contains disallowed characters`);
7
- }
8
- return value.replace(/'/g, "''");
9
- }
10
- class LanceStore {
11
- db = null;
12
- table = null;
13
- dbPath;
14
- tableName;
15
- constructor(options) {
16
- this.dbPath = options?.path ?? STORE_DEFAULTS.path;
17
- this.tableName = options?.tableName ?? STORE_DEFAULTS.tableName;
18
- }
19
- async initialize() {
20
- this.db = await connect(this.dbPath);
21
- const tableNames = await this.db.tableNames();
22
- if (tableNames.includes(this.tableName)) {
23
- this.table = await this.db.openTable(this.tableName);
24
- await this.createFtsIndex();
25
- }
26
- }
27
- async upsert(records, vectors) {
28
- if (records.length === 0) return;
29
- if (records.length !== vectors.length) {
30
- throw new Error(
31
- `Record count (${records.length}) does not match vector count (${vectors.length})`
32
- );
33
- }
34
- const lanceRecords = records.map(
35
- (r, i) => ({
36
- id: r.id,
37
- vector: Array.from(vectors[i]),
38
- content: r.content,
39
- sourcePath: r.sourcePath,
40
- contentType: r.contentType,
41
- headingPath: r.headingPath ?? "",
42
- chunkIndex: r.chunkIndex,
43
- totalChunks: r.totalChunks,
44
- startLine: r.startLine,
45
- endLine: r.endLine,
46
- fileHash: r.fileHash,
47
- indexedAt: r.indexedAt,
48
- origin: r.origin,
49
- tags: JSON.stringify(r.tags),
50
- category: r.category ?? "",
51
- version: r.version
52
- })
53
- );
54
- if (!this.table) {
55
- try {
56
- this.table = await this.db?.createTable(this.tableName, lanceRecords) ?? null;
57
- } catch (err) {
58
- if (String(err).includes("already exists") && this.db) {
59
- this.table = await this.db.openTable(this.tableName);
60
- await this.table.add(lanceRecords);
61
- } else {
62
- throw err;
63
- }
64
- }
65
- } else {
66
- const sourcePaths = [...new Set(records.map((r) => r.sourcePath))];
67
- for (const sp of sourcePaths) {
68
- try {
69
- await this.table.delete(`sourcePath = '${sanitizeFilterValue(sp, "sourcePath")}'`);
70
- } catch {
71
- }
72
- }
73
- await this.table.add(lanceRecords);
74
- }
75
- }
76
- async search(queryVector, options) {
77
- if (!this.table) return [];
78
- const limit = options?.limit ?? SEARCH_DEFAULTS.maxResults;
79
- const minScore = options?.minScore ?? SEARCH_DEFAULTS.minScore;
80
- let query = this.table.search(queryVector).limit(limit * 2);
81
- const filterStr = this.buildFilterString(options);
82
- if (filterStr) {
83
- query = query.where(filterStr);
84
- }
85
- const results = await query.toArray();
86
- return results.map((row) => ({
87
- record: this.fromLanceRecord(row),
88
- score: 1 - (row._distance ?? 1)
89
- // LanceDB returns L2 distance; convert to similarity
90
- })).filter((r) => r.score >= minScore).slice(0, limit);
91
- }
92
- async createFtsIndex() {
93
- if (!this.table) return;
94
- try {
95
- await this.table.createIndex("content", { config: Index.fts() });
96
- console.error("[KB] FTS index created on content column");
97
- } catch (err) {
98
- if (!String(err).includes("already exists")) {
99
- console.error("[KB] FTS index creation failed (non-fatal):", err);
100
- }
101
- }
102
- }
103
- async ftsSearch(query, options) {
104
- if (!this.table) return [];
105
- const limit = options?.limit ?? SEARCH_DEFAULTS.maxResults;
106
- try {
107
- let searchQuery = this.table.search(query).limit(limit * 2);
108
- const filterStr = this.buildFilterString(options);
109
- if (filterStr) {
110
- searchQuery = searchQuery.where(filterStr);
111
- }
112
- const results = await searchQuery.toArray();
113
- return results.map((row) => ({
114
- record: this.fromLanceRecord(row),
115
- score: row._score ?? row._relevance_score ?? 0
116
- }));
117
- } catch (err) {
118
- console.error("[KB] FTS search failed (non-fatal):", err);
119
- return [];
120
- }
121
- }
122
- async getById(id) {
123
- if (!this.table) return null;
124
- const results = await this.table.query().where(`id = '${sanitizeFilterValue(id, "id")}'`).limit(1).toArray();
125
- if (results.length === 0) return null;
126
- return this.fromLanceRecord(results[0]);
127
- }
128
- async deleteBySourcePath(sourcePath) {
129
- if (!this.table) return 0;
130
- const existing = await this.getBySourcePath(sourcePath);
131
- if (existing.length === 0) return 0;
132
- await this.table.delete(`sourcePath = '${sanitizeFilterValue(sourcePath, "sourcePath")}'`);
133
- return existing.length;
134
- }
135
- async deleteById(id) {
136
- if (!this.table) return false;
137
- const existing = await this.getById(id);
138
- if (!existing) return false;
139
- await this.table.delete(`id = '${sanitizeFilterValue(id, "id")}'`);
140
- return true;
141
- }
142
- async getBySourcePath(sourcePath) {
143
- if (!this.table) return [];
144
- const results = await this.table.query().where(`sourcePath = '${sanitizeFilterValue(sourcePath, "sourcePath")}'`).limit(1e3).toArray();
145
- return results.map((row) => this.fromLanceRecord(row));
146
- }
147
- async getStats() {
148
- if (!this.table) {
149
- return {
150
- totalRecords: 0,
151
- totalFiles: 0,
152
- contentTypeBreakdown: {},
153
- lastIndexedAt: null,
154
- storeBackend: "lancedb",
155
- embeddingModel: EMBEDDING_DEFAULTS.model
156
- };
157
- }
158
- const allRows = await this.table.countRows();
159
- const sample = await this.table.query().select(["sourcePath", "contentType", "indexedAt"]).limit(1e5).toArray();
160
- const breakdown = {};
161
- const uniquePaths = /* @__PURE__ */ new Set();
162
- let lastIndexedAt = null;
163
- for (const row of sample) {
164
- const r = row;
165
- breakdown[r.contentType] = (breakdown[r.contentType] ?? 0) + 1;
166
- uniquePaths.add(r.sourcePath);
167
- if (!lastIndexedAt || r.indexedAt > lastIndexedAt) {
168
- lastIndexedAt = r.indexedAt;
169
- }
170
- }
171
- return {
172
- totalRecords: allRows,
173
- totalFiles: uniquePaths.size,
174
- contentTypeBreakdown: breakdown,
175
- lastIndexedAt,
176
- storeBackend: "lancedb",
177
- embeddingModel: EMBEDDING_DEFAULTS.model
178
- };
179
- }
180
- async listSourcePaths() {
181
- if (!this.table) return [];
182
- const results = await this.table.query().select(["sourcePath"]).limit(1e5).toArray();
183
- return [
184
- // biome-ignore lint/suspicious/noExplicitAny: LanceDB query returns untyped results
185
- ...new Set(results.map((r) => r.sourcePath))
186
- ];
187
- }
188
- async dropTable() {
189
- if (this.db) {
190
- const tableNames = await this.db.tableNames();
191
- if (tableNames.includes(this.tableName)) {
192
- const maxRetries = 3;
193
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
194
- try {
195
- await this.db.dropTable(this.tableName);
196
- break;
197
- } catch (err) {
198
- if (attempt === maxRetries) throw err;
199
- const delay = attempt * 500;
200
- console.error(`[KB] dropTable attempt ${attempt} failed, retrying in ${delay}ms...`);
201
- await new Promise((r) => setTimeout(r, delay));
202
- }
203
- }
204
- }
205
- }
206
- this.table = null;
207
- }
208
- async close() {
209
- try {
210
- if (this.db && typeof this.db.close === "function") {
211
- await this.db.close();
212
- }
213
- } catch {
214
- }
215
- this.table = null;
216
- this.db = null;
217
- }
218
- buildFilterString(options) {
219
- const filters = [];
220
- if (options?.contentType) {
221
- filters.push(`contentType = '${sanitizeFilterValue(options.contentType, "contentType")}'`);
222
- }
223
- if (options?.origin) {
224
- filters.push(`origin = '${sanitizeFilterValue(options.origin, "origin")}'`);
225
- }
226
- if (options?.category) {
227
- filters.push(`category = '${sanitizeFilterValue(options.category, "category")}'`);
228
- }
229
- if (options?.tags && options.tags.length > 0) {
230
- const tagClauses = options.tags.map((t) => `tags LIKE '%${sanitizeFilterValue(t, "tag")}%'`);
231
- filters.push(`(${tagClauses.join(" OR ")})`);
232
- }
233
- return filters.length > 0 ? filters.join(" AND ") : null;
234
- }
235
- fromLanceRecord(row) {
236
- return {
237
- id: row.id,
238
- content: row.content,
239
- sourcePath: row.sourcePath,
240
- contentType: row.contentType,
241
- headingPath: row.headingPath || void 0,
242
- chunkIndex: row.chunkIndex,
243
- totalChunks: row.totalChunks,
244
- startLine: row.startLine,
245
- endLine: row.endLine,
246
- fileHash: row.fileHash,
247
- indexedAt: row.indexedAt,
248
- origin: row.origin,
249
- tags: JSON.parse(row.tags || "[]"),
250
- category: row.category || void 0,
251
- version: row.version
252
- };
253
- }
254
- }
255
- export {
256
- LanceStore
257
- };
258
- //# sourceMappingURL=lance-store.js.map
1
+ import{EMBEDDING_DEFAULTS as h,SEARCH_DEFAULTS as d,STORE_DEFAULTS as u}from"@kb/core";import{connect as g,Index as m}from"@lancedb/lancedb";const b=/^[\w.\-/ ]+$/;function s(l,e){if(!b.test(l))throw new Error(`Invalid ${e} filter value: contains disallowed characters`);return l.replace(/'/g,"''")}class p{db=null;table=null;dbPath;tableName;constructor(e){this.dbPath=e?.path??u.path,this.tableName=e?.tableName??u.tableName}async initialize(){this.db=await g(this.dbPath),(await this.db.tableNames()).includes(this.tableName)&&(this.table=await this.db.openTable(this.tableName),await this.createFtsIndex())}async upsert(e,n){if(e.length===0)return;if(e.length!==n.length)throw new Error(`Record count (${e.length}) does not match vector count (${n.length})`);const a=e.map((t,i)=>({id:t.id,vector:Array.from(n[i]),content:t.content,sourcePath:t.sourcePath,contentType:t.contentType,headingPath:t.headingPath??"",chunkIndex:t.chunkIndex,totalChunks:t.totalChunks,startLine:t.startLine,endLine:t.endLine,fileHash:t.fileHash,indexedAt:t.indexedAt,origin:t.origin,tags:JSON.stringify(t.tags),category:t.category??"",version:t.version}));if(this.table){const t=[...new Set(e.map(i=>i.sourcePath))];for(const i of t)try{await this.table.delete(`sourcePath = '${s(i,"sourcePath")}'`)}catch{}await this.table.add(a)}else try{this.table=await this.db?.createTable(this.tableName,a)??null}catch(t){if(String(t).includes("already exists")&&this.db)this.table=await this.db.openTable(this.tableName),await this.table.add(a);else throw t}}async search(e,n){if(!this.table)return[];const a=n?.limit??d.maxResults,t=n?.minScore??d.minScore;let i=this.table.search(e).limit(a*2);const o=this.buildFilterString(n);return o&&(i=i.where(o)),(await i.toArray()).map(c=>({record:this.fromLanceRecord(c),score:1-(c._distance??1)})).filter(c=>c.score>=t).slice(0,a)}async createFtsIndex(){if(this.table)try{await this.table.createIndex("content",{config:m.fts()}),console.error("[KB] FTS index created on content column")}catch(e){String(e).includes("already exists")||console.error("[KB] FTS index creation failed (non-fatal):",e)}}async ftsSearch(e,n){if(!this.table)return[];const a=n?.limit??d.maxResults;try{let t=this.table.search(e).limit(a*2);const i=this.buildFilterString(n);return i&&(t=t.where(i)),(await t.toArray()).map(r=>({record:this.fromLanceRecord(r),score:r._score??r._relevance_score??0}))}catch(t){return console.error("[KB] FTS search failed (non-fatal):",t),[]}}async getById(e){if(!this.table)return null;const n=await this.table.query().where(`id = '${s(e,"id")}'`).limit(1).toArray();return n.length===0?null:this.fromLanceRecord(n[0])}async deleteBySourcePath(e){if(!this.table)return 0;const n=await this.getBySourcePath(e);return n.length===0?0:(await this.table.delete(`sourcePath = '${s(e,"sourcePath")}'`),n.length)}async deleteById(e){return!this.table||!await this.getById(e)?!1:(await this.table.delete(`id = '${s(e,"id")}'`),!0)}async getBySourcePath(e){return this.table?(await this.table.query().where(`sourcePath = '${s(e,"sourcePath")}'`).limit(1e3).toArray()).map(a=>this.fromLanceRecord(a)):[]}async getStats(){if(!this.table)return{totalRecords:0,totalFiles:0,contentTypeBreakdown:{},lastIndexedAt:null,storeBackend:"lancedb",embeddingModel:h.model};const e=await this.table.countRows(),n=await this.table.query().select(["sourcePath","contentType","indexedAt"]).limit(1e5).toArray(),a={},t=new Set;let i=null;for(const o of n){const r=o;a[r.contentType]=(a[r.contentType]??0)+1,t.add(r.sourcePath),(!i||r.indexedAt>i)&&(i=r.indexedAt)}return{totalRecords:e,totalFiles:t.size,contentTypeBreakdown:a,lastIndexedAt:i,storeBackend:"lancedb",embeddingModel:h.model}}async listSourcePaths(){if(!this.table)return[];const e=await this.table.query().select(["sourcePath"]).limit(1e5).toArray();return[...new Set(e.map(n=>n.sourcePath))]}async dropTable(){if(this.db&&(await this.db.tableNames()).includes(this.tableName))for(let a=1;a<=3;a++)try{await this.db.dropTable(this.tableName);break}catch(t){if(a===3)throw t;const i=a*500;console.error(`[KB] dropTable attempt ${a} failed, retrying in ${i}ms...`),await new Promise(o=>setTimeout(o,i))}this.table=null}async close(){try{this.db&&typeof this.db.close=="function"&&await this.db.close()}catch{}this.table=null,this.db=null}buildFilterString(e){const n=[];if(e?.contentType&&n.push(`contentType = '${s(e.contentType,"contentType")}'`),e?.origin&&n.push(`origin = '${s(e.origin,"origin")}'`),e?.category&&n.push(`category = '${s(e.category,"category")}'`),e?.tags&&e.tags.length>0){const a=e.tags.map(t=>`tags LIKE '%${s(t,"tag")}%'`);n.push(`(${a.join(" OR ")})`)}return n.length>0?n.join(" AND "):null}fromLanceRecord(e){return{id:e.id,content:e.content,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath||void 0,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:e.fileHash,indexedAt:e.indexedAt,origin:e.origin,tags:JSON.parse(e.tags||"[]"),category:e.category||void 0,version:e.version}}}export{p as LanceStore};
@@ -1,22 +1,4 @@
1
- import { existsSync, mkdirSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- class SqliteGraphStore {
4
- db = null;
5
- dbPath;
6
- constructor(options) {
7
- const basePath = options?.path ?? ".kb-data";
8
- this.dbPath = join(basePath, "graph.db");
9
- }
10
- async initialize() {
11
- const dir = dirname(this.dbPath);
12
- if (!existsSync(dir)) {
13
- mkdirSync(dir, { recursive: true });
14
- }
15
- const BetterSqlite3 = (await import("better-sqlite3")).default;
16
- this.db = new BetterSqlite3(this.dbPath);
17
- this.db.pragma("journal_mode = WAL");
18
- this.db.pragma("foreign_keys = ON");
19
- this.db.exec(`
1
+ import{existsSync as l,mkdirSync as N}from"node:fs";import{dirname as y,join as S}from"node:path";class f{db=null;dbPath;constructor(e){const t=e?.path??".kb-data";this.dbPath=S(t,"graph.db")}async initialize(){const e=y(this.dbPath);l(e)||N(e,{recursive:!0});const t=(await import("better-sqlite3")).default;this.db=new t(this.dbPath),this.db.pragma("journal_mode = WAL"),this.db.pragma("foreign_keys = ON"),this.db.exec(`
20
2
  CREATE TABLE IF NOT EXISTS nodes (
21
3
  id TEXT PRIMARY KEY,
22
4
  type TEXT NOT NULL,
@@ -44,15 +26,7 @@ class SqliteGraphStore {
44
26
  CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id);
45
27
  CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id);
46
28
  CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);
47
- `);
48
- }
49
- ensureDb() {
50
- if (!this.db) throw new Error("Graph store not initialized \u2014 call initialize() first");
51
- return this.db;
52
- }
53
- async upsertNode(node) {
54
- const db = this.ensureDb();
55
- db.prepare(`
29
+ `)}ensureDb(){if(!this.db)throw new Error("Graph store not initialized \u2014 call initialize() first");return this.db}async upsertNode(e){this.ensureDb().prepare(`
56
30
  INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
57
31
  VALUES (?, ?, ?, ?, ?, ?, ?)
58
32
  ON CONFLICT(id) DO UPDATE SET
@@ -61,19 +35,7 @@ class SqliteGraphStore {
61
35
  properties = excluded.properties,
62
36
  source_record_id = excluded.source_record_id,
63
37
  source_path = excluded.source_path
64
- `).run(
65
- node.id,
66
- node.type,
67
- node.name,
68
- JSON.stringify(node.properties),
69
- node.sourceRecordId ?? null,
70
- node.sourcePath ?? null,
71
- node.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
72
- );
73
- }
74
- async upsertEdge(edge) {
75
- const db = this.ensureDb();
76
- db.prepare(`
38
+ `).run(e.id,e.type,e.name,JSON.stringify(e.properties),e.sourceRecordId??null,e.sourcePath??null,e.createdAt??new Date().toISOString())}async upsertEdge(e){this.ensureDb().prepare(`
77
39
  INSERT INTO edges (id, from_id, to_id, type, weight, properties)
78
40
  VALUES (?, ?, ?, ?, ?, ?)
79
41
  ON CONFLICT(id) DO UPDATE SET
@@ -82,19 +44,7 @@ class SqliteGraphStore {
82
44
  type = excluded.type,
83
45
  weight = excluded.weight,
84
46
  properties = excluded.properties
85
- `).run(
86
- edge.id,
87
- edge.fromId,
88
- edge.toId,
89
- edge.type,
90
- edge.weight ?? 1,
91
- JSON.stringify(edge.properties ?? {})
92
- );
93
- }
94
- async upsertNodes(nodes) {
95
- if (nodes.length === 0) return;
96
- const db = this.ensureDb();
97
- const stmt = db.prepare(`
47
+ `).run(e.id,e.fromId,e.toId,e.type,e.weight??1,JSON.stringify(e.properties??{}))}async upsertNodes(e){if(e.length===0)return;const t=this.ensureDb(),s=t.prepare(`
98
48
  INSERT INTO nodes (id, type, name, properties, source_record_id, source_path, created_at)
99
49
  VALUES (?, ?, ?, ?, ?, ?, ?)
100
50
  ON CONFLICT(id) DO UPDATE SET
@@ -103,26 +53,7 @@ class SqliteGraphStore {
103
53
  properties = excluded.properties,
104
54
  source_record_id = excluded.source_record_id,
105
55
  source_path = excluded.source_path
106
- `);
107
- const tx = db.transaction(() => {
108
- for (const node of nodes) {
109
- stmt.run(
110
- node.id,
111
- node.type,
112
- node.name,
113
- JSON.stringify(node.properties),
114
- node.sourceRecordId ?? null,
115
- node.sourcePath ?? null,
116
- node.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
117
- );
118
- }
119
- });
120
- tx();
121
- }
122
- async upsertEdges(edges) {
123
- if (edges.length === 0) return;
124
- const db = this.ensureDb();
125
- const stmt = db.prepare(`
56
+ `);t.transaction(()=>{for(const r of e)s.run(r.id,r.type,r.name,JSON.stringify(r.properties),r.sourceRecordId??null,r.sourcePath??null,r.createdAt??new Date().toISOString())})()}async upsertEdges(e){if(e.length===0)return;const t=this.ensureDb(),s=t.prepare(`
126
57
  INSERT INTO edges (id, from_id, to_id, type, weight, properties)
127
58
  VALUES (?, ?, ?, ?, ?, ?)
128
59
  ON CONFLICT(id) DO UPDATE SET
@@ -131,244 +62,12 @@ class SqliteGraphStore {
131
62
  type = excluded.type,
132
63
  weight = excluded.weight,
133
64
  properties = excluded.properties
134
- `);
135
- const tx = db.transaction(() => {
136
- for (const edge of edges) {
137
- stmt.run(
138
- edge.id,
139
- edge.fromId,
140
- edge.toId,
141
- edge.type,
142
- edge.weight ?? 1,
143
- JSON.stringify(edge.properties ?? {})
144
- );
145
- }
146
- });
147
- tx();
148
- }
149
- async getNode(id) {
150
- const db = this.ensureDb();
151
- const row = db.prepare("SELECT * FROM nodes WHERE id = ?").get(id);
152
- return row ? this.toGraphNode(row) : null;
153
- }
154
- async getNeighbors(nodeId, options) {
155
- const db = this.ensureDb();
156
- const direction = options?.direction ?? "both";
157
- const edgeType = options?.edgeType;
158
- const limit = options?.limit ?? 50;
159
- const nodes = [];
160
- const edges = [];
161
- const seenNodeIds = /* @__PURE__ */ new Set();
162
- const OUTGOING_SQL = `
65
+ `);t.transaction(()=>{for(const r of e)s.run(r.id,r.fromId,r.toId,r.type,r.weight??1,JSON.stringify(r.properties??{}))})()}async getNode(e){const s=this.ensureDb().prepare("SELECT * FROM nodes WHERE id = ?").get(e);return s?this.toGraphNode(s):null}async getNeighbors(e,t){const s=this.ensureDb(),o=t?.direction??"both",r=t?.edgeType,a=t?.limit??50,p=[],d=[],E=new Set,_=`
163
66
  SELECT e.id AS edge_id, e.from_id, e.to_id, e.type AS edge_type, e.weight, e.properties AS edge_props,
164
67
  n.id AS node_id, n.type AS node_type, n.name AS node_name, n.properties AS node_props,
165
68
  n.source_record_id AS node_src_rec, n.source_path AS node_src_path, n.created_at AS node_created
166
- FROM edges e JOIN nodes n ON e.to_id = n.id WHERE e.from_id = ?`;
167
- const INCOMING_SQL = `
69
+ FROM edges e JOIN nodes n ON e.to_id = n.id WHERE e.from_id = ?`,u=`
168
70
  SELECT e.id AS edge_id, e.from_id, e.to_id, e.type AS edge_type, e.weight, e.properties AS edge_props,
169
71
  n.id AS node_id, n.type AS node_type, n.name AS node_name, n.properties AS node_props,
170
72
  n.source_record_id AS node_src_rec, n.source_path AS node_src_path, n.created_at AS node_created
171
- FROM edges e JOIN nodes n ON e.from_id = n.id WHERE e.to_id = ?`;
172
- if (direction === "outgoing" || direction === "both") {
173
- let sql = OUTGOING_SQL;
174
- const params = [nodeId];
175
- if (edgeType) {
176
- sql += " AND e.type = ?";
177
- params.push(edgeType);
178
- }
179
- sql += " LIMIT ?";
180
- params.push(limit);
181
- const rows = db.prepare(sql).all(...params);
182
- for (const row of rows) {
183
- edges.push(joinRowToEdge(row));
184
- if (!seenNodeIds.has(row.node_id)) {
185
- seenNodeIds.add(row.node_id);
186
- nodes.push(joinRowToNode(row));
187
- }
188
- }
189
- }
190
- if (direction === "incoming" || direction === "both") {
191
- let sql = INCOMING_SQL;
192
- const params = [nodeId];
193
- if (edgeType) {
194
- sql += " AND e.type = ?";
195
- params.push(edgeType);
196
- }
197
- sql += " LIMIT ?";
198
- params.push(limit);
199
- const rows = db.prepare(sql).all(...params);
200
- for (const row of rows) {
201
- edges.push(joinRowToEdge(row));
202
- if (!seenNodeIds.has(row.node_id)) {
203
- seenNodeIds.add(row.node_id);
204
- nodes.push(joinRowToNode(row));
205
- }
206
- }
207
- }
208
- return { nodes, edges };
209
- }
210
- async traverse(startId, options) {
211
- const maxDepth = options?.maxDepth ?? 2;
212
- const direction = options?.direction ?? "both";
213
- const edgeType = options?.edgeType;
214
- const limit = options?.limit ?? 50;
215
- const allNodes = /* @__PURE__ */ new Map();
216
- const allEdges = /* @__PURE__ */ new Map();
217
- const visited = /* @__PURE__ */ new Set();
218
- const queue = [{ nodeId: startId, depth: 0 }];
219
- while (queue.length > 0 && allNodes.size < limit) {
220
- const current = queue.shift();
221
- if (!current || visited.has(current.nodeId)) continue;
222
- if (current.depth > maxDepth) continue;
223
- visited.add(current.nodeId);
224
- const neighbors = await this.getNeighbors(current.nodeId, {
225
- direction,
226
- edgeType,
227
- limit: limit - allNodes.size
228
- });
229
- for (const node of neighbors.nodes) {
230
- if (!allNodes.has(node.id)) {
231
- allNodes.set(node.id, node);
232
- if (current.depth + 1 < maxDepth) {
233
- queue.push({ nodeId: node.id, depth: current.depth + 1 });
234
- }
235
- }
236
- }
237
- for (const edge of neighbors.edges) {
238
- allEdges.set(edge.id, edge);
239
- }
240
- }
241
- return { nodes: [...allNodes.values()], edges: [...allEdges.values()] };
242
- }
243
- async findNodes(filter) {
244
- const db = this.ensureDb();
245
- const conditions = [];
246
- const params = [];
247
- if (filter.type) {
248
- conditions.push("type = ?");
249
- params.push(filter.type);
250
- }
251
- if (filter.namePattern) {
252
- conditions.push("name LIKE ?");
253
- params.push(`%${filter.namePattern}%`);
254
- }
255
- if (filter.sourcePath) {
256
- conditions.push("source_path = ?");
257
- params.push(filter.sourcePath);
258
- }
259
- const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
260
- const maxRows = filter.limit ?? 100;
261
- const rows = db.prepare(`SELECT * FROM nodes ${where} LIMIT ?`).all(...params, maxRows);
262
- return rows.map((r) => this.toGraphNode(r));
263
- }
264
- async findEdges(filter) {
265
- const db = this.ensureDb();
266
- const conditions = [];
267
- const params = [];
268
- if (filter.type) {
269
- conditions.push("type = ?");
270
- params.push(filter.type);
271
- }
272
- if (filter.fromId) {
273
- conditions.push("from_id = ?");
274
- params.push(filter.fromId);
275
- }
276
- if (filter.toId) {
277
- conditions.push("to_id = ?");
278
- params.push(filter.toId);
279
- }
280
- const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
281
- const maxRows = filter.limit ?? 100;
282
- const rows = db.prepare(`SELECT * FROM edges ${where} LIMIT ?`).all(...params, maxRows);
283
- return rows.map((r) => this.toGraphEdge(r));
284
- }
285
- async deleteNode(id) {
286
- const db = this.ensureDb();
287
- db.transaction(() => {
288
- db.prepare("DELETE FROM edges WHERE from_id = ? OR to_id = ?").run(id, id);
289
- db.prepare("DELETE FROM nodes WHERE id = ?").run(id);
290
- })();
291
- }
292
- async deleteBySourcePath(sourcePath) {
293
- const db = this.ensureDb();
294
- const nodeIds = db.prepare("SELECT id FROM nodes WHERE source_path = ?").all(sourcePath);
295
- if (nodeIds.length === 0) return 0;
296
- const tx = db.transaction(() => {
297
- for (const { id } of nodeIds) {
298
- db.prepare("DELETE FROM edges WHERE from_id = ? OR to_id = ?").run(id, id);
299
- }
300
- db.prepare("DELETE FROM nodes WHERE source_path = ?").run(sourcePath);
301
- });
302
- tx();
303
- return nodeIds.length;
304
- }
305
- async clear() {
306
- const db = this.ensureDb();
307
- db.exec("DELETE FROM edges; DELETE FROM nodes;");
308
- }
309
- async getStats() {
310
- const db = this.ensureDb();
311
- const nodeCount = db.prepare("SELECT COUNT(*) as count FROM nodes").get().count;
312
- const edgeCount = db.prepare("SELECT COUNT(*) as count FROM edges").get().count;
313
- const nodeTypeRows = db.prepare("SELECT type, COUNT(*) as count FROM nodes GROUP BY type").all();
314
- const nodeTypes = {};
315
- for (const row of nodeTypeRows) nodeTypes[row.type] = row.count;
316
- const edgeTypeRows = db.prepare("SELECT type, COUNT(*) as count FROM edges GROUP BY type").all();
317
- const edgeTypes = {};
318
- for (const row of edgeTypeRows) edgeTypes[row.type] = row.count;
319
- return { nodeCount, edgeCount, nodeTypes, edgeTypes };
320
- }
321
- async close() {
322
- if (this.db) {
323
- this.db.close();
324
- this.db = null;
325
- }
326
- }
327
- // ── Private helpers ─────────────────────────────────────────────────
328
- toGraphNode(row) {
329
- return {
330
- id: row.id,
331
- type: row.type,
332
- name: row.name,
333
- properties: JSON.parse(row.properties),
334
- sourceRecordId: row.source_record_id ?? void 0,
335
- sourcePath: row.source_path ?? void 0,
336
- createdAt: row.created_at
337
- };
338
- }
339
- toGraphEdge(row) {
340
- return {
341
- id: row.id,
342
- fromId: row.from_id,
343
- toId: row.to_id,
344
- type: row.type,
345
- weight: row.weight ?? 1,
346
- properties: JSON.parse(row.properties)
347
- };
348
- }
349
- }
350
- function joinRowToEdge(row) {
351
- return {
352
- id: row.edge_id,
353
- fromId: row.from_id,
354
- toId: row.to_id,
355
- type: row.edge_type,
356
- weight: row.weight ?? 1,
357
- properties: JSON.parse(row.edge_props ?? "{}")
358
- };
359
- }
360
- function joinRowToNode(row) {
361
- return {
362
- id: row.node_id,
363
- type: row.node_type,
364
- name: row.node_name,
365
- properties: JSON.parse(row.node_props ?? "{}"),
366
- sourceRecordId: row.node_src_rec ?? void 0,
367
- sourcePath: row.node_src_path ?? void 0,
368
- createdAt: row.node_created
369
- };
370
- }
371
- export {
372
- SqliteGraphStore
373
- };
374
- //# sourceMappingURL=sqlite-graph-store.js.map
73
+ FROM edges e JOIN nodes n ON e.from_id = n.id WHERE e.to_id = ?`;if(o==="outgoing"||o==="both"){let c=_;const i=[e];r&&(c+=" AND e.type = ?",i.push(r)),c+=" LIMIT ?",i.push(a);const g=s.prepare(c).all(...i);for(const h of g)d.push(T(h)),E.has(h.node_id)||(E.add(h.node_id),p.push(m(h)))}if(o==="incoming"||o==="both"){let c=u;const i=[e];r&&(c+=" AND e.type = ?",i.push(r)),c+=" LIMIT ?",i.push(a);const g=s.prepare(c).all(...i);for(const h of g)d.push(T(h)),E.has(h.node_id)||(E.add(h.node_id),p.push(m(h)))}return{nodes:p,edges:d}}async traverse(e,t){const s=t?.maxDepth??2,o=t?.direction??"both",r=t?.edgeType,a=t?.limit??50,p=new Map,d=new Map,E=new Set,_=[{nodeId:e,depth:0}];for(;_.length>0&&p.size<a;){const u=_.shift();if(!u||E.has(u.nodeId)||u.depth>s)continue;E.add(u.nodeId);const c=await this.getNeighbors(u.nodeId,{direction:o,edgeType:r,limit:a-p.size});for(const i of c.nodes)p.has(i.id)||(p.set(i.id,i),u.depth+1<s&&_.push({nodeId:i.id,depth:u.depth+1}));for(const i of c.edges)d.set(i.id,i)}return{nodes:[...p.values()],edges:[...d.values()]}}async findNodes(e){const t=this.ensureDb(),s=[],o=[];e.type&&(s.push("type = ?"),o.push(e.type)),e.namePattern&&(s.push("name LIKE ?"),o.push(`%${e.namePattern}%`)),e.sourcePath&&(s.push("source_path = ?"),o.push(e.sourcePath));const r=s.length>0?`WHERE ${s.join(" AND ")}`:"",a=e.limit??100;return t.prepare(`SELECT * FROM nodes ${r} LIMIT ?`).all(...o,a).map(d=>this.toGraphNode(d))}async findEdges(e){const t=this.ensureDb(),s=[],o=[];e.type&&(s.push("type = ?"),o.push(e.type)),e.fromId&&(s.push("from_id = ?"),o.push(e.fromId)),e.toId&&(s.push("to_id = ?"),o.push(e.toId));const r=s.length>0?`WHERE ${s.join(" AND ")}`:"",a=e.limit??100;return t.prepare(`SELECT * FROM edges ${r} LIMIT ?`).all(...o,a).map(d=>this.toGraphEdge(d))}async deleteNode(e){const t=this.ensureDb();t.transaction(()=>{t.prepare("DELETE FROM edges WHERE from_id = ? OR to_id = ?").run(e,e),t.prepare("DELETE FROM nodes WHERE id = ?").run(e)})()}async deleteBySourcePath(e){const t=this.ensureDb(),s=t.prepare("SELECT id FROM nodes WHERE source_path = ?").all(e);return s.length===0?0:(t.transaction(()=>{for(const{id:r}of s)t.prepare("DELETE FROM edges WHERE from_id = ? OR to_id = ?").run(r,r);t.prepare("DELETE FROM nodes WHERE source_path = ?").run(e)})(),s.length)}async clear(){this.ensureDb().exec("DELETE FROM edges; DELETE FROM nodes;")}async getStats(){const e=this.ensureDb(),t=e.prepare("SELECT COUNT(*) as count FROM nodes").get().count,s=e.prepare("SELECT COUNT(*) as count FROM edges").get().count,o=e.prepare("SELECT type, COUNT(*) as count FROM nodes GROUP BY type").all(),r={};for(const d of o)r[d.type]=d.count;const a=e.prepare("SELECT type, COUNT(*) as count FROM edges GROUP BY type").all(),p={};for(const d of a)p[d.type]=d.count;return{nodeCount:t,edgeCount:s,nodeTypes:r,edgeTypes:p}}async close(){this.db&&(this.db.close(),this.db=null)}toGraphNode(e){return{id:e.id,type:e.type,name:e.name,properties:JSON.parse(e.properties),sourceRecordId:e.source_record_id??void 0,sourcePath:e.source_path??void 0,createdAt:e.created_at}}toGraphEdge(e){return{id:e.id,fromId:e.from_id,toId:e.to_id,type:e.type,weight:e.weight??1,properties:JSON.parse(e.properties)}}}function T(n){return{id:n.edge_id,fromId:n.from_id,toId:n.to_id,type:n.edge_type,weight:n.weight??1,properties:JSON.parse(n.edge_props??"{}")}}function m(n){return{id:n.node_id,type:n.node_type,name:n.node_name,properties:JSON.parse(n.node_props??"{}"),sourceRecordId:n.node_src_rec??void 0,sourcePath:n.node_src_path??void 0,createdAt:n.node_created}}export{f as SqliteGraphStore};
@@ -1,14 +1 @@
1
- async function createStore(config) {
2
- switch (config.backend) {
3
- case "lancedb": {
4
- const { LanceStore } = await import("./lance-store.js");
5
- return new LanceStore({ path: config.path });
6
- }
7
- default:
8
- throw new Error(`Unknown store backend: "${config.backend}". Supported: lancedb`);
9
- }
10
- }
11
- export {
12
- createStore
13
- };
14
- //# sourceMappingURL=store-factory.js.map
1
+ async function n(e){if(e.backend==="lancedb"){const{LanceStore:t}=await import("./lance-store.js");return new t({path:e.path})}else throw new Error(`Unknown store backend: "${e.backend}". Supported: lancedb`)}export{n as createStore};
@@ -1 +0,0 @@
1
- //# sourceMappingURL=store.interface.js.map