@jafreck/lore 0.2.0 → 0.2.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.
- package/README.md +399 -199
- package/dist/cli.js +139 -18
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/indexer/db.d.ts +12 -11
- package/dist/indexer/db.d.ts.map +1 -1
- package/dist/indexer/db.js +118 -18
- package/dist/indexer/db.js.map +1 -1
- package/dist/indexer/docs.d.ts +42 -0
- package/dist/indexer/docs.d.ts.map +1 -0
- package/dist/indexer/docs.js +214 -0
- package/dist/indexer/docs.js.map +1 -0
- package/dist/indexer/embedder.d.ts +7 -0
- package/dist/indexer/embedder.d.ts.map +1 -1
- package/dist/indexer/embedder.js +10 -0
- package/dist/indexer/embedder.js.map +1 -1
- package/dist/indexer/ensure-python-deps.d.ts +1 -1
- package/dist/indexer/ensure-python-deps.js +1 -1
- package/dist/indexer/extractors/types.d.ts +22 -0
- package/dist/indexer/extractors/types.d.ts.map +1 -1
- package/dist/indexer/extractors/types.js +12 -0
- package/dist/indexer/extractors/types.js.map +1 -1
- package/dist/indexer/extractors/typescript.d.ts +1 -1
- package/dist/indexer/extractors/typescript.d.ts.map +1 -1
- package/dist/indexer/extractors/typescript.js +38 -8
- package/dist/indexer/extractors/typescript.js.map +1 -1
- package/dist/indexer/git-history.d.ts.map +1 -1
- package/dist/indexer/git-history.js +4 -4
- package/dist/indexer/git-history.js.map +1 -1
- package/dist/indexer/git-hooks.d.ts +1 -0
- package/dist/indexer/git-hooks.d.ts.map +1 -1
- package/dist/indexer/git-hooks.js +3 -2
- package/dist/indexer/git-hooks.js.map +1 -1
- package/dist/indexer/index.d.ts +35 -9
- package/dist/indexer/index.d.ts.map +1 -1
- package/dist/indexer/index.js +470 -30
- package/dist/indexer/index.js.map +1 -1
- package/dist/indexer/lsp/client.d.ts +61 -0
- package/dist/indexer/lsp/client.d.ts.map +1 -0
- package/dist/indexer/lsp/client.js +217 -0
- package/dist/indexer/lsp/client.js.map +1 -0
- package/dist/indexer/lsp/config.d.ts +16 -0
- package/dist/indexer/lsp/config.d.ts.map +1 -0
- package/dist/indexer/lsp/config.js +78 -0
- package/dist/indexer/lsp/config.js.map +1 -0
- package/dist/indexer/lsp/enrichment.d.ts +55 -0
- package/dist/indexer/lsp/enrichment.d.ts.map +1 -0
- package/dist/indexer/lsp/enrichment.js +211 -0
- package/dist/indexer/lsp/enrichment.js.map +1 -0
- package/dist/indexer/lsp/registry.d.ts +19 -0
- package/dist/indexer/lsp/registry.d.ts.map +1 -0
- package/dist/indexer/lsp/registry.js +118 -0
- package/dist/indexer/lsp/registry.js.map +1 -0
- package/dist/indexer/parser.d.ts +7 -0
- package/dist/indexer/parser.d.ts.map +1 -1
- package/dist/indexer/parser.js +3 -1
- package/dist/indexer/parser.js.map +1 -1
- package/dist/indexer/poller.d.ts +8 -1
- package/dist/indexer/poller.d.ts.map +1 -1
- package/dist/indexer/poller.js +7 -1
- package/dist/indexer/poller.js.map +1 -1
- package/dist/indexer/walker.d.ts +22 -0
- package/dist/indexer/walker.d.ts.map +1 -1
- package/dist/indexer/walker.js +15 -0
- package/dist/indexer/walker.js.map +1 -1
- package/dist/indexer/watcher.d.ts +8 -1
- package/dist/indexer/watcher.d.ts.map +1 -1
- package/dist/indexer/watcher.js +7 -1
- package/dist/indexer/watcher.js.map +1 -1
- package/dist/{kb-server → lore-server}/db.d.ts +158 -4
- package/dist/lore-server/db.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/db.js +457 -26
- package/dist/lore-server/db.js.map +1 -0
- package/dist/lore-server/server.d.ts +43 -0
- package/dist/lore-server/server.d.ts.map +1 -0
- package/dist/lore-server/server.js +385 -0
- package/dist/lore-server/server.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/annotations.d.ts +2 -2
- package/dist/lore-server/tools/annotations.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/annotations.js +2 -2
- package/dist/lore-server/tools/annotations.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/architecture.d.ts +9 -2
- package/dist/lore-server/tools/architecture.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/architecture.js +37 -2
- package/dist/lore-server/tools/architecture.js.map +1 -0
- package/dist/lore-server/tools/blame.d.ts +159 -0
- package/dist/lore-server/tools/blame.d.ts.map +1 -0
- package/dist/lore-server/tools/blame.js +595 -0
- package/dist/lore-server/tools/blame.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/coverage.d.ts +2 -2
- package/dist/lore-server/tools/coverage.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/coverage.js +2 -2
- package/dist/lore-server/tools/coverage.js.map +1 -0
- package/dist/lore-server/tools/docs.d.ts +86 -0
- package/dist/lore-server/tools/docs.d.ts.map +1 -0
- package/dist/lore-server/tools/docs.js +243 -0
- package/dist/lore-server/tools/docs.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/graph.d.ts +40 -3
- package/dist/lore-server/tools/graph.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/graph.js +122 -11
- package/dist/lore-server/tools/graph.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/history.d.ts +13 -6
- package/dist/lore-server/tools/history.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/history.js +43 -10
- package/dist/lore-server/tools/history.js.map +1 -0
- package/dist/lore-server/tools/lookup.d.ts +75 -0
- package/dist/lore-server/tools/lookup.d.ts.map +1 -0
- package/dist/lore-server/tools/lookup.js +148 -0
- package/dist/lore-server/tools/lookup.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/metrics.d.ts +3 -3
- package/dist/lore-server/tools/metrics.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/metrics.js +3 -3
- package/dist/lore-server/tools/metrics.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/notes.d.ts +16 -16
- package/dist/lore-server/tools/notes.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/notes.js +55 -20
- package/dist/lore-server/tools/notes.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/routes.d.ts +2 -2
- package/dist/lore-server/tools/routes.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/routes.js +2 -2
- package/dist/lore-server/tools/routes.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/search.d.ts +57 -13
- package/dist/lore-server/tools/search.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/search.js +123 -23
- package/dist/lore-server/tools/search.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/snippet.d.ts +20 -4
- package/dist/lore-server/tools/snippet.d.ts.map +1 -0
- package/dist/lore-server/tools/snippet.js +116 -0
- package/dist/lore-server/tools/snippet.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/test-map.d.ts +2 -2
- package/dist/lore-server/tools/test-map.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/test-map.js +2 -2
- package/dist/lore-server/tools/test-map.js.map +1 -0
- package/dist/{kb-server → lore-server}/tools/writeback.d.ts +2 -2
- package/dist/lore-server/tools/writeback.d.ts.map +1 -0
- package/dist/{kb-server → lore-server}/tools/writeback.js +3 -3
- package/dist/lore-server/tools/writeback.js.map +1 -0
- package/package.json +14 -14
- package/dist/kb-server/db.d.ts.map +0 -1
- package/dist/kb-server/db.js.map +0 -1
- package/dist/kb-server/server.d.ts +0 -42
- package/dist/kb-server/server.d.ts.map +0 -1
- package/dist/kb-server/server.js +0 -241
- package/dist/kb-server/server.js.map +0 -1
- package/dist/kb-server/tools/annotations.d.ts.map +0 -1
- package/dist/kb-server/tools/annotations.js.map +0 -1
- package/dist/kb-server/tools/architecture.d.ts.map +0 -1
- package/dist/kb-server/tools/architecture.js.map +0 -1
- package/dist/kb-server/tools/blame.d.ts +0 -67
- package/dist/kb-server/tools/blame.d.ts.map +0 -1
- package/dist/kb-server/tools/blame.js +0 -162
- package/dist/kb-server/tools/blame.js.map +0 -1
- package/dist/kb-server/tools/coverage.d.ts.map +0 -1
- package/dist/kb-server/tools/coverage.js.map +0 -1
- package/dist/kb-server/tools/graph.d.ts.map +0 -1
- package/dist/kb-server/tools/graph.js.map +0 -1
- package/dist/kb-server/tools/history.d.ts.map +0 -1
- package/dist/kb-server/tools/history.js.map +0 -1
- package/dist/kb-server/tools/lookup.d.ts +0 -36
- package/dist/kb-server/tools/lookup.d.ts.map +0 -1
- package/dist/kb-server/tools/lookup.js +0 -45
- package/dist/kb-server/tools/lookup.js.map +0 -1
- package/dist/kb-server/tools/metrics.d.ts.map +0 -1
- package/dist/kb-server/tools/metrics.js.map +0 -1
- package/dist/kb-server/tools/notes.d.ts.map +0 -1
- package/dist/kb-server/tools/notes.js.map +0 -1
- package/dist/kb-server/tools/routes.d.ts.map +0 -1
- package/dist/kb-server/tools/routes.js.map +0 -1
- package/dist/kb-server/tools/search.d.ts.map +0 -1
- package/dist/kb-server/tools/search.js.map +0 -1
- package/dist/kb-server/tools/snippet.d.ts.map +0 -1
- package/dist/kb-server/tools/snippet.js +0 -49
- package/dist/kb-server/tools/snippet.js.map +0 -1
- package/dist/kb-server/tools/test-map.d.ts.map +0 -1
- package/dist/kb-server/tools/test-map.js.map +0 -1
- package/dist/kb-server/tools/writeback.d.ts.map +0 -1
- package/dist/kb-server/tools/writeback.js.map +0 -1
package/dist/indexer/index.js
CHANGED
|
@@ -9,14 +9,18 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import * as fs from 'node:fs';
|
|
11
11
|
import * as crypto from 'node:crypto';
|
|
12
|
+
import * as path from 'node:path';
|
|
12
13
|
import { execFileSync } from 'node:child_process';
|
|
13
|
-
import { openDb,
|
|
14
|
+
import { openDb, setLoreMeta, getLoreMeta, createVec0Tables, LORE_META_INDEX_CHECKPOINT, LORE_META_LAST_HEAD_SHA, LORE_META_COVERAGE_LAST_SOURCE_PATH, LORE_META_COVERAGE_LAST_SOURCE_MTIME, } from './db.js';
|
|
14
15
|
import { walkFiles } from './walker.js';
|
|
15
16
|
import { detectLanguageForPath } from './walker.js';
|
|
17
|
+
import { walkDocumentationFiles } from './walker.js';
|
|
18
|
+
import { inferSeededDocNoteKey, buildDocNoteScope } from './docs.js';
|
|
16
19
|
import { ingestGitHistory } from './git-history.js';
|
|
17
20
|
import { ParserPool } from './parser.js';
|
|
18
21
|
import { ImportResolver } from './resolver.js';
|
|
19
22
|
import { buildCallGraph } from './call-graph.js';
|
|
23
|
+
import { isPublicDeclarationSurfaceSymbol, } from './extractors/types.js';
|
|
20
24
|
import { CExtractor } from './extractors/c.js';
|
|
21
25
|
import { RustExtractor } from './extractors/rust.js';
|
|
22
26
|
import { PythonExtractor } from './extractors/python.js';
|
|
@@ -41,9 +45,10 @@ import { HaskellExtractor } from './extractors/haskell.js';
|
|
|
41
45
|
import { JuliaExtractor } from './extractors/julia.js';
|
|
42
46
|
import { ElmExtractor } from './extractors/elm.js';
|
|
43
47
|
import { ObjcExtractor } from './extractors/objc.js';
|
|
44
|
-
import { DEFAULT_EMBEDDING_MODEL } from './embedder.js';
|
|
48
|
+
import { DEFAULT_EMBEDDING_MODEL, buildStructuralEmbeddingText } from './embedder.js';
|
|
45
49
|
import { ingestCoverageReport } from './coverage.js';
|
|
46
50
|
import { refreshTestMappings } from './test-mapper.js';
|
|
51
|
+
import { LspEnrichmentCoordinator } from './lsp/enrichment.js';
|
|
47
52
|
// ─── Extractor registry ───────────────────────────────────────────────────────
|
|
48
53
|
const EXTRACTORS = {
|
|
49
54
|
c: new CExtractor(),
|
|
@@ -79,7 +84,7 @@ const EMBED_BATCH_SIZE = 64;
|
|
|
79
84
|
*
|
|
80
85
|
* @example
|
|
81
86
|
* ```ts
|
|
82
|
-
* const builder = new IndexBuilder('/path/to/
|
|
87
|
+
* const builder = new IndexBuilder('/path/to/lore.db', { rootDir: '/path/to/src' });
|
|
83
88
|
* await builder.build();
|
|
84
89
|
* ```
|
|
85
90
|
*/
|
|
@@ -90,7 +95,10 @@ export class IndexBuilder {
|
|
|
90
95
|
resolver;
|
|
91
96
|
embedder;
|
|
92
97
|
history;
|
|
98
|
+
indexDependencies;
|
|
93
99
|
embeddingModel;
|
|
100
|
+
docsAutoNotes;
|
|
101
|
+
lspSettings;
|
|
94
102
|
constructor(dbPath, walkerConfig, embedder, embeddingModelOrOptions) {
|
|
95
103
|
this.dbPath = dbPath;
|
|
96
104
|
this.walkerConfig = walkerConfig;
|
|
@@ -108,6 +116,9 @@ export class IndexBuilder {
|
|
|
108
116
|
this.embedder = null;
|
|
109
117
|
}
|
|
110
118
|
this.history = opts.history ?? false;
|
|
119
|
+
this.docsAutoNotes = opts.docsAutoNotes ?? true;
|
|
120
|
+
this.indexDependencies = opts.indexDependencies ?? false;
|
|
121
|
+
this.lspSettings = opts.lsp ?? null;
|
|
111
122
|
}
|
|
112
123
|
// ─── Public API ──────────────────────────────────────────────────────────
|
|
113
124
|
/**
|
|
@@ -118,8 +129,17 @@ export class IndexBuilder {
|
|
|
118
129
|
async build() {
|
|
119
130
|
const db = openDb(this.dbPath);
|
|
120
131
|
const branch = this.resolveBranch();
|
|
132
|
+
const lspCoordinator = this.createLspEnrichmentCoordinator();
|
|
121
133
|
try {
|
|
134
|
+
this.saveDocsAutoNotesSetting(db);
|
|
122
135
|
const files = await walkFiles(this.walkerConfig);
|
|
136
|
+
const docs = await walkDocumentationFiles(this.walkerConfig);
|
|
137
|
+
if (lspCoordinator) {
|
|
138
|
+
const languages = new Set(files.map((file) => file.language));
|
|
139
|
+
if (this.indexDependencies)
|
|
140
|
+
languages.add('typescript');
|
|
141
|
+
await lspCoordinator.start(languages);
|
|
142
|
+
}
|
|
123
143
|
const resumeAt = this.loadBuildCheckpoint(db, branch, files.length);
|
|
124
144
|
db.transaction(() => {
|
|
125
145
|
for (let i = resumeAt; i < files.length; i++) {
|
|
@@ -129,22 +149,38 @@ export class IndexBuilder {
|
|
|
129
149
|
this.processFile(db, file.path, file.language, branch);
|
|
130
150
|
this.saveBuildCheckpoint(db, branch, i + 1, files.length);
|
|
131
151
|
}
|
|
152
|
+
const seenDocPaths = new Set();
|
|
153
|
+
for (const doc of docs) {
|
|
154
|
+
seenDocPaths.add(doc.path);
|
|
155
|
+
this.processDocumentationFile(db, doc, branch);
|
|
156
|
+
this.upsertSeededDocumentationNote(db, doc, branch);
|
|
157
|
+
}
|
|
158
|
+
this.removeStaleDocumentation(db, branch, seenDocPaths);
|
|
132
159
|
})();
|
|
133
160
|
this.saveBuildCheckpoint(db, branch, files.length, files.length);
|
|
134
161
|
this.resolveImports(db, branch);
|
|
162
|
+
await this.indexDependencyDeclarations(db, lspCoordinator);
|
|
163
|
+
await this.enrichProjectSymbolsAndCallRefs(db, branch, files, lspCoordinator);
|
|
135
164
|
refreshTestMappings(db, branch);
|
|
136
165
|
buildCallGraph(db);
|
|
137
166
|
this.saveLastKnownHead(db);
|
|
138
167
|
if (this.embedder) {
|
|
139
168
|
await this.embedder.init();
|
|
140
169
|
await this.embedStructural(db);
|
|
170
|
+
await this.embedDocumentation(db);
|
|
141
171
|
}
|
|
142
172
|
if (this.history) {
|
|
143
173
|
const historyOptions = typeof this.history === 'object' ? this.history : undefined;
|
|
144
174
|
await ingestGitHistory(db, this.walkerConfig.rootDir, historyOptions);
|
|
175
|
+
if (this.embedder) {
|
|
176
|
+
await this.embedCommitMessages(db);
|
|
177
|
+
}
|
|
145
178
|
}
|
|
146
179
|
}
|
|
147
180
|
finally {
|
|
181
|
+
if (lspCoordinator) {
|
|
182
|
+
await lspCoordinator.dispose();
|
|
183
|
+
}
|
|
148
184
|
db.close();
|
|
149
185
|
}
|
|
150
186
|
}
|
|
@@ -157,7 +193,25 @@ export class IndexBuilder {
|
|
|
157
193
|
async update(changedFiles) {
|
|
158
194
|
const db = openDb(this.dbPath);
|
|
159
195
|
const branch = this.resolveBranch();
|
|
196
|
+
const lspCoordinator = this.createLspEnrichmentCoordinator();
|
|
197
|
+
const enrichedFiles = [];
|
|
160
198
|
try {
|
|
199
|
+
this.saveDocsAutoNotesSetting(db);
|
|
200
|
+
const docs = await walkDocumentationFiles(this.walkerConfig);
|
|
201
|
+
const docsByPath = new Map(docs.map(doc => [doc.path, doc]));
|
|
202
|
+
if (lspCoordinator) {
|
|
203
|
+
const languages = new Set();
|
|
204
|
+
for (const filePath of changedFiles) {
|
|
205
|
+
if (!fs.existsSync(filePath))
|
|
206
|
+
continue;
|
|
207
|
+
const language = detectLanguageForPath(filePath, this.walkerConfig);
|
|
208
|
+
if (language)
|
|
209
|
+
languages.add(language);
|
|
210
|
+
}
|
|
211
|
+
if (this.indexDependencies)
|
|
212
|
+
languages.add('typescript');
|
|
213
|
+
await lspCoordinator.start(languages);
|
|
214
|
+
}
|
|
161
215
|
db.transaction(() => {
|
|
162
216
|
for (const filePath of changedFiles) {
|
|
163
217
|
// If the file no longer exists, remove it from the DB
|
|
@@ -169,23 +223,35 @@ export class IndexBuilder {
|
|
|
169
223
|
db.prepare('DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file_id = ?)').run(row.id);
|
|
170
224
|
db.prepare('DELETE FROM files WHERE id = ?').run(row.id);
|
|
171
225
|
}
|
|
226
|
+
this.deleteDocumentationByPath(db, filePath, branch);
|
|
172
227
|
continue;
|
|
173
228
|
}
|
|
174
229
|
const language = detectLanguageForPath(filePath, this.walkerConfig);
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
230
|
+
if (language) {
|
|
231
|
+
enrichedFiles.push({ path: filePath, language });
|
|
232
|
+
// Null out resolved_id references pointing to this file before deletion
|
|
233
|
+
const existingRow = db.prepare('SELECT id FROM files WHERE path = ? AND branch = ?').get(filePath, branch);
|
|
234
|
+
if (existingRow) {
|
|
235
|
+
db.prepare('UPDATE file_imports SET resolved_id = NULL WHERE resolved_id = ?').run(existingRow.id);
|
|
236
|
+
db.prepare('DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file_id = ?)').run(existingRow.id);
|
|
237
|
+
}
|
|
238
|
+
// Delete existing rows for this file (cascade handles symbols/imports)
|
|
239
|
+
db.prepare('DELETE FROM files WHERE path = ? AND branch = ?').run(filePath, branch);
|
|
240
|
+
this.processFile(db, filePath, language, branch);
|
|
241
|
+
}
|
|
242
|
+
const changedDoc = docsByPath.get(filePath);
|
|
243
|
+
if (changedDoc) {
|
|
244
|
+
this.processDocumentationFile(db, changedDoc, branch);
|
|
245
|
+
this.upsertSeededDocumentationNote(db, changedDoc, branch);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
this.deleteDocumentationByPath(db, filePath, branch);
|
|
182
249
|
}
|
|
183
|
-
// Delete existing rows for this file (cascade handles symbols/imports)
|
|
184
|
-
db.prepare('DELETE FROM files WHERE path = ? AND branch = ?').run(filePath, branch);
|
|
185
|
-
this.processFile(db, filePath, language, branch);
|
|
186
250
|
}
|
|
187
251
|
})();
|
|
188
252
|
this.resolveImports(db, branch);
|
|
253
|
+
await this.indexDependencyDeclarations(db, lspCoordinator);
|
|
254
|
+
await this.enrichProjectSymbolsAndCallRefs(db, branch, enrichedFiles, lspCoordinator);
|
|
189
255
|
refreshTestMappings(db, branch);
|
|
190
256
|
if (this.history) {
|
|
191
257
|
const historyOptions = typeof this.history === 'object' ? this.history : undefined;
|
|
@@ -194,11 +260,18 @@ export class IndexBuilder {
|
|
|
194
260
|
if (this.embedder) {
|
|
195
261
|
await this.embedder.init();
|
|
196
262
|
await this.embedStructural(db);
|
|
263
|
+
await this.embedDocumentation(db);
|
|
264
|
+
if (this.history) {
|
|
265
|
+
await this.embedCommitMessages(db);
|
|
266
|
+
}
|
|
197
267
|
}
|
|
198
268
|
buildCallGraph(db);
|
|
199
269
|
this.saveLastKnownHead(db);
|
|
200
270
|
}
|
|
201
271
|
finally {
|
|
272
|
+
if (lspCoordinator) {
|
|
273
|
+
await lspCoordinator.dispose();
|
|
274
|
+
}
|
|
202
275
|
db.close();
|
|
203
276
|
}
|
|
204
277
|
}
|
|
@@ -238,8 +311,8 @@ export class IndexBuilder {
|
|
|
238
311
|
commitSha: resolvedCommitSha,
|
|
239
312
|
sourceMtime,
|
|
240
313
|
});
|
|
241
|
-
|
|
242
|
-
|
|
314
|
+
setLoreMeta(db, LORE_META_COVERAGE_LAST_SOURCE_PATH, reportPath);
|
|
315
|
+
setLoreMeta(db, LORE_META_COVERAGE_LAST_SOURCE_MTIME, String(sourceMtime));
|
|
243
316
|
}
|
|
244
317
|
finally {
|
|
245
318
|
db.close();
|
|
@@ -264,8 +337,8 @@ export class IndexBuilder {
|
|
|
264
337
|
// Upsert the file row
|
|
265
338
|
let fileId;
|
|
266
339
|
if (existing) {
|
|
267
|
-
db.prepare(`UPDATE files SET language = ?, size_bytes = ?, last_hash = ?, indexed_at = unixepoch()
|
|
268
|
-
|
|
340
|
+
db.prepare(`UPDATE files SET language = ?, size_bytes = ?, last_hash = ?, source = ?, indexed_at = unixepoch()
|
|
341
|
+
WHERE id = ?`).run(language, sizeBytes, hash, source, existing.id);
|
|
269
342
|
fileId = existing.id;
|
|
270
343
|
// Remove stale symbols / imports / external deps (also clean up FTS5 index)
|
|
271
344
|
db.prepare(`DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file_id = ?)`).run(fileId);
|
|
@@ -276,9 +349,9 @@ export class IndexBuilder {
|
|
|
276
349
|
}
|
|
277
350
|
else {
|
|
278
351
|
const info = db
|
|
279
|
-
.prepare(`INSERT INTO files (path, branch, language, size_bytes, last_hash)
|
|
280
|
-
VALUES (?, ?, ?, ?, ?)`)
|
|
281
|
-
.run(filePath, branch, language, sizeBytes, hash);
|
|
352
|
+
.prepare(`INSERT INTO files (path, branch, language, size_bytes, last_hash, source)
|
|
353
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
354
|
+
.run(filePath, branch, language, sizeBytes, hash, source);
|
|
282
355
|
fileId = Number(info.lastInsertRowid);
|
|
283
356
|
}
|
|
284
357
|
// Parse the source
|
|
@@ -299,7 +372,10 @@ export class IndexBuilder {
|
|
|
299
372
|
const info = insertSymbol.run(fileId, sym.name, sym.kind, sym.startLine, sym.endLine, sym.signature ?? null, sym.docComment ?? null);
|
|
300
373
|
const symId = Number(info.lastInsertRowid);
|
|
301
374
|
symbolIdMap.set(sym.name, symId);
|
|
302
|
-
insertFts.run(symId, sym.name,
|
|
375
|
+
insertFts.run(symId, sym.name, buildStructuralEmbeddingText({
|
|
376
|
+
name: sym.name,
|
|
377
|
+
signature: sym.signature ?? null,
|
|
378
|
+
}), sym.kind);
|
|
303
379
|
}
|
|
304
380
|
const insertRoute = db.prepare(`INSERT INTO api_routes (file_id, method, path, handler_id, handler_name, framework, line, middleware)
|
|
305
381
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
@@ -321,6 +397,95 @@ export class IndexBuilder {
|
|
|
321
397
|
}
|
|
322
398
|
}
|
|
323
399
|
}
|
|
400
|
+
processDocumentationFile(db, doc, branch) {
|
|
401
|
+
const existing = db.prepare('SELECT id, content_hash FROM docs WHERE path = ? AND branch = ?').get(doc.path, branch);
|
|
402
|
+
if (existing?.content_hash === doc.hash) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
let docId;
|
|
406
|
+
if (existing) {
|
|
407
|
+
db.prepare(`UPDATE docs
|
|
408
|
+
SET kind = ?, title = ?, content = ?, content_hash = ?, indexed_at = unixepoch()
|
|
409
|
+
WHERE id = ?`).run(doc.kind, doc.title, doc.content, doc.hash, existing.id);
|
|
410
|
+
docId = existing.id;
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
const info = db.prepare(`INSERT INTO docs (path, branch, kind, title, content, content_hash)
|
|
414
|
+
VALUES (?, ?, ?, ?, ?, ?)`).run(doc.path, branch, doc.kind, doc.title, doc.content, doc.hash);
|
|
415
|
+
docId = Number(info.lastInsertRowid);
|
|
416
|
+
}
|
|
417
|
+
const existingSections = db.prepare('SELECT id, section_index FROM doc_sections WHERE doc_id = ?').all(docId);
|
|
418
|
+
const insertSection = db.prepare(`INSERT INTO doc_sections (
|
|
419
|
+
doc_id, section_index, title, depth, heading_path, line_start, line_end, content, content_hash
|
|
420
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
421
|
+
ON CONFLICT(doc_id, section_index) DO UPDATE SET
|
|
422
|
+
title = excluded.title,
|
|
423
|
+
depth = excluded.depth,
|
|
424
|
+
heading_path = excluded.heading_path,
|
|
425
|
+
line_start = excluded.line_start,
|
|
426
|
+
line_end = excluded.line_end,
|
|
427
|
+
content = excluded.content,
|
|
428
|
+
content_hash = excluded.content_hash`);
|
|
429
|
+
const activeSectionIndexes = new Set();
|
|
430
|
+
for (const chunk of doc.chunks) {
|
|
431
|
+
activeSectionIndexes.add(chunk.sectionIndex);
|
|
432
|
+
insertSection.run(docId, chunk.sectionIndex, chunk.title, chunk.depth, JSON.stringify(chunk.headingPath), chunk.lineStart, chunk.lineEnd, chunk.content, chunk.hash);
|
|
433
|
+
}
|
|
434
|
+
const staleSectionIds = existingSections
|
|
435
|
+
.filter(section => !activeSectionIndexes.has(section.section_index))
|
|
436
|
+
.map(section => section.id);
|
|
437
|
+
this.deleteDocSectionEmbeddings(db, staleSectionIds);
|
|
438
|
+
if (staleSectionIds.length > 0) {
|
|
439
|
+
db.prepare(`DELETE FROM doc_sections
|
|
440
|
+
WHERE id IN (${staleSectionIds.map(() => '?').join(', ')})`).run(...staleSectionIds);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
upsertSeededDocumentationNote(db, doc, branch) {
|
|
444
|
+
if (!this.docsAutoNotes)
|
|
445
|
+
return;
|
|
446
|
+
const key = inferSeededDocNoteKey(doc);
|
|
447
|
+
if (!key)
|
|
448
|
+
return;
|
|
449
|
+
const scope = buildDocNoteScope(doc.path, branch);
|
|
450
|
+
const existing = db.prepare('SELECT content, source_hash FROM notes WHERE key = ? AND scope = ?').get(key, scope);
|
|
451
|
+
if (existing?.content === doc.content && existing.source_hash === doc.hash) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
db.prepare(`INSERT INTO notes (key, scope, content, model, source_hash, created_at, updated_at)
|
|
455
|
+
VALUES (?, ?, ?, ?, ?, unixepoch(), unixepoch())
|
|
456
|
+
ON CONFLICT(key, scope) DO UPDATE SET
|
|
457
|
+
content = excluded.content,
|
|
458
|
+
model = excluded.model,
|
|
459
|
+
source_hash = excluded.source_hash,
|
|
460
|
+
updated_at = unixepoch()`).run(key, scope, doc.content, 'system:auto-doc-seed', doc.hash);
|
|
461
|
+
}
|
|
462
|
+
removeStaleDocumentation(db, branch, retainedPaths) {
|
|
463
|
+
const docs = db.prepare('SELECT id, path FROM docs WHERE branch = ?').all(branch);
|
|
464
|
+
for (const doc of docs) {
|
|
465
|
+
if (!retainedPaths.has(doc.path)) {
|
|
466
|
+
this.deleteDocumentationById(db, doc.id);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
deleteDocumentationByPath(db, docPath, branch) {
|
|
471
|
+
const row = db.prepare('SELECT id FROM docs WHERE path = ? AND branch = ?').get(docPath, branch);
|
|
472
|
+
if (!row)
|
|
473
|
+
return;
|
|
474
|
+
this.deleteDocumentationById(db, row.id);
|
|
475
|
+
}
|
|
476
|
+
deleteDocumentationById(db, docId) {
|
|
477
|
+
const sectionIds = db.prepare('SELECT id FROM doc_sections WHERE doc_id = ?').all(docId);
|
|
478
|
+
this.deleteDocSectionEmbeddings(db, sectionIds.map(row => row.id));
|
|
479
|
+
db.prepare('DELETE FROM docs WHERE id = ?').run(docId);
|
|
480
|
+
}
|
|
481
|
+
deleteDocSectionEmbeddings(db, sectionIds) {
|
|
482
|
+
if (sectionIds.length === 0)
|
|
483
|
+
return;
|
|
484
|
+
const hasEmbeddingsTable = db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type IN ('table', 'virtual table') AND name = 'doc_section_embeddings'").get();
|
|
485
|
+
if (!hasEmbeddingsTable)
|
|
486
|
+
return;
|
|
487
|
+
db.prepare(`DELETE FROM doc_section_embeddings WHERE rowid IN (${sectionIds.map(() => '?').join(', ')})`).run(...sectionIds);
|
|
488
|
+
}
|
|
324
489
|
/**
|
|
325
490
|
* Second pass: resolve raw_import strings to file IDs in the
|
|
326
491
|
* `file_imports.resolved_id` column. Also populates `external_deps` for
|
|
@@ -352,6 +517,146 @@ export class IndexBuilder {
|
|
|
352
517
|
}
|
|
353
518
|
}
|
|
354
519
|
}
|
|
520
|
+
async indexDependencyDeclarations(db, lspCoordinator) {
|
|
521
|
+
db.prepare('DELETE FROM external_symbols').run();
|
|
522
|
+
if (!this.indexDependencies)
|
|
523
|
+
return;
|
|
524
|
+
const directDependencies = this.loadDirectDependencies();
|
|
525
|
+
if (directDependencies.size === 0)
|
|
526
|
+
return;
|
|
527
|
+
const extractor = EXTRACTORS.typescript;
|
|
528
|
+
if (!extractor)
|
|
529
|
+
return;
|
|
530
|
+
const insertExternalSymbol = db.prepare(`INSERT OR IGNORE INTO external_symbols
|
|
531
|
+
(
|
|
532
|
+
package_name,
|
|
533
|
+
package_version,
|
|
534
|
+
source_ref,
|
|
535
|
+
symbol_name,
|
|
536
|
+
symbol_kind,
|
|
537
|
+
signature,
|
|
538
|
+
doc_comment,
|
|
539
|
+
resolved_type_signature,
|
|
540
|
+
resolved_return_type,
|
|
541
|
+
definition_uri,
|
|
542
|
+
definition_path
|
|
543
|
+
)
|
|
544
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
545
|
+
for (const [packageName, declaredVersion] of directDependencies) {
|
|
546
|
+
const packageDir = path.join(this.walkerConfig.rootDir, 'node_modules', packageName);
|
|
547
|
+
if (!fs.existsSync(packageDir) || !fs.statSync(packageDir).isDirectory())
|
|
548
|
+
continue;
|
|
549
|
+
const packageVersion = this.readInstalledPackageVersion(packageDir) ?? declaredVersion ?? null;
|
|
550
|
+
const declarationFiles = this.collectDeclarationFiles(packageDir);
|
|
551
|
+
for (const declarationFile of declarationFiles) {
|
|
552
|
+
const source = fs.readFileSync(declarationFile, 'utf8');
|
|
553
|
+
const tree = this.pool.parse('typescript', source);
|
|
554
|
+
if (!tree)
|
|
555
|
+
continue;
|
|
556
|
+
const result = extractor.extract(tree, source, declarationFile);
|
|
557
|
+
const declarationSymbols = result.symbols.filter((symbol) => this.shouldIndexDependencySymbol(symbol));
|
|
558
|
+
const enrichmentRows = lspCoordinator
|
|
559
|
+
? await lspCoordinator.enrich({
|
|
560
|
+
filePath: declarationFile,
|
|
561
|
+
language: 'typescript',
|
|
562
|
+
source,
|
|
563
|
+
targets: declarationSymbols.map((symbol) => ({
|
|
564
|
+
line: symbol.startLine,
|
|
565
|
+
character: symbol.startCharacter ?? 0,
|
|
566
|
+
})),
|
|
567
|
+
})
|
|
568
|
+
: declarationSymbols.map(() => null);
|
|
569
|
+
for (let i = 0; i < declarationSymbols.length; i++) {
|
|
570
|
+
const symbol = declarationSymbols[i];
|
|
571
|
+
if (!symbol)
|
|
572
|
+
continue;
|
|
573
|
+
const metadata = enrichmentRows[i];
|
|
574
|
+
insertExternalSymbol.run(packageName, packageVersion, declarationFile, symbol.name, symbol.kind, symbol.signature, symbol.docComment ?? null, metadata?.resolvedTypeSignature ?? null, metadata?.resolvedReturnType ?? null, metadata?.definitionUri ?? null, metadata?.definitionPath ?? null);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
createLspEnrichmentCoordinator() {
|
|
580
|
+
if (!this.lspSettings?.enabled) {
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
return new LspEnrichmentCoordinator(this.lspSettings, this.walkerConfig.rootDir);
|
|
584
|
+
}
|
|
585
|
+
async enrichProjectSymbolsAndCallRefs(db, branch, files, lspCoordinator) {
|
|
586
|
+
if (!lspCoordinator || files.length === 0)
|
|
587
|
+
return;
|
|
588
|
+
const selectSymbols = db.prepare(`SELECT s.id, s.name, s.signature, s.start_line
|
|
589
|
+
FROM symbols s
|
|
590
|
+
JOIN files f ON f.id = s.file_id
|
|
591
|
+
WHERE f.path = ? AND f.branch = ?
|
|
592
|
+
ORDER BY s.id`);
|
|
593
|
+
const selectCallRefs = db.prepare(`SELECT sr.id, sr.call_line
|
|
594
|
+
FROM symbol_refs sr
|
|
595
|
+
JOIN symbols s ON s.id = sr.caller_id
|
|
596
|
+
JOIN files f ON f.id = s.file_id
|
|
597
|
+
WHERE f.path = ? AND f.branch = ?
|
|
598
|
+
ORDER BY sr.id`);
|
|
599
|
+
const updateSymbol = db.prepare(`UPDATE symbols
|
|
600
|
+
SET resolved_type_signature = ?, resolved_return_type = ?, definition_uri = ?, definition_path = ?
|
|
601
|
+
WHERE id = ?`);
|
|
602
|
+
const updateSymbolFts = db.prepare('UPDATE symbols_fts SET signature = ? WHERE rowid = ?');
|
|
603
|
+
const updateCallRef = db.prepare(`UPDATE symbol_refs
|
|
604
|
+
SET resolved_type_signature = ?, resolved_return_type = ?, definition_uri = ?, definition_path = ?
|
|
605
|
+
WHERE id = ?`);
|
|
606
|
+
for (const file of files) {
|
|
607
|
+
if (!file || !fs.existsSync(file.path))
|
|
608
|
+
continue;
|
|
609
|
+
let source;
|
|
610
|
+
try {
|
|
611
|
+
source = fs.readFileSync(file.path, 'utf8');
|
|
612
|
+
}
|
|
613
|
+
catch {
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
const symbols = selectSymbols.all(file.path, branch);
|
|
617
|
+
if (symbols.length > 0) {
|
|
618
|
+
const symbolMetadata = await lspCoordinator.enrich({
|
|
619
|
+
filePath: file.path,
|
|
620
|
+
language: file.language,
|
|
621
|
+
source,
|
|
622
|
+
targets: symbols.map((symbol) => ({ line: symbol.start_line, character: 0 })),
|
|
623
|
+
});
|
|
624
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
625
|
+
const symbol = symbols[i];
|
|
626
|
+
if (!symbol)
|
|
627
|
+
continue;
|
|
628
|
+
const metadata = symbolMetadata[i];
|
|
629
|
+
if (!metadata)
|
|
630
|
+
continue;
|
|
631
|
+
updateSymbol.run(metadata.resolvedTypeSignature, metadata.resolvedReturnType, metadata.definitionUri, metadata.definitionPath, symbol.id);
|
|
632
|
+
updateSymbolFts.run(buildStructuralEmbeddingText({
|
|
633
|
+
name: symbol.name,
|
|
634
|
+
signature: symbol.signature,
|
|
635
|
+
resolvedTypeSignature: metadata.resolvedTypeSignature,
|
|
636
|
+
resolvedReturnType: metadata.resolvedReturnType,
|
|
637
|
+
}), symbol.id);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const callRefs = selectCallRefs.all(file.path, branch);
|
|
641
|
+
if (callRefs.length > 0) {
|
|
642
|
+
const callRefMetadata = await lspCoordinator.enrich({
|
|
643
|
+
filePath: file.path,
|
|
644
|
+
language: file.language,
|
|
645
|
+
source,
|
|
646
|
+
targets: callRefs.map((callRef) => ({ line: callRef.call_line, character: 0 })),
|
|
647
|
+
});
|
|
648
|
+
for (let i = 0; i < callRefs.length; i++) {
|
|
649
|
+
const callRef = callRefs[i];
|
|
650
|
+
if (!callRef)
|
|
651
|
+
continue;
|
|
652
|
+
const metadata = callRefMetadata[i];
|
|
653
|
+
if (!metadata)
|
|
654
|
+
continue;
|
|
655
|
+
updateCallRef.run(metadata.resolvedTypeSignature, metadata.resolvedReturnType, metadata.definitionUri, metadata.definitionPath, callRef.id);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
355
660
|
resolveBranch() {
|
|
356
661
|
if (this.walkerConfig.branch)
|
|
357
662
|
return this.walkerConfig.branch;
|
|
@@ -360,9 +665,12 @@ export class IndexBuilder {
|
|
|
360
665
|
saveLastKnownHead(db) {
|
|
361
666
|
const headSha = this.readGitValue(['rev-parse', 'HEAD']);
|
|
362
667
|
if (headSha) {
|
|
363
|
-
|
|
668
|
+
setLoreMeta(db, LORE_META_LAST_HEAD_SHA, headSha);
|
|
364
669
|
}
|
|
365
670
|
}
|
|
671
|
+
saveDocsAutoNotesSetting(db) {
|
|
672
|
+
setLoreMeta(db, 'docs_auto_notes', this.docsAutoNotes ? '1' : '0');
|
|
673
|
+
}
|
|
366
674
|
readGitValue(args) {
|
|
367
675
|
try {
|
|
368
676
|
const value = execFileSync('git', ['-C', this.walkerConfig.rootDir, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
@@ -372,8 +680,82 @@ export class IndexBuilder {
|
|
|
372
680
|
return undefined;
|
|
373
681
|
}
|
|
374
682
|
}
|
|
683
|
+
loadDirectDependencies() {
|
|
684
|
+
const packageJsonPath = path.join(this.walkerConfig.rootDir, 'package.json');
|
|
685
|
+
if (!fs.existsSync(packageJsonPath))
|
|
686
|
+
return new Map();
|
|
687
|
+
const raw = fs.readFileSync(packageJsonPath, 'utf8');
|
|
688
|
+
const pkg = JSON.parse(raw);
|
|
689
|
+
const deps = new Map();
|
|
690
|
+
for (const section of [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies]) {
|
|
691
|
+
if (!section)
|
|
692
|
+
continue;
|
|
693
|
+
for (const [name, version] of Object.entries(section)) {
|
|
694
|
+
if (!deps.has(name))
|
|
695
|
+
deps.set(name, version);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return deps;
|
|
699
|
+
}
|
|
700
|
+
readInstalledPackageVersion(packageDir) {
|
|
701
|
+
const packageJsonPath = path.join(packageDir, 'package.json');
|
|
702
|
+
if (!fs.existsSync(packageJsonPath))
|
|
703
|
+
return undefined;
|
|
704
|
+
const raw = fs.readFileSync(packageJsonPath, 'utf8');
|
|
705
|
+
const pkg = JSON.parse(raw);
|
|
706
|
+
return pkg.version;
|
|
707
|
+
}
|
|
708
|
+
collectDeclarationFiles(packageDir) {
|
|
709
|
+
const declarations = [];
|
|
710
|
+
const stack = [packageDir];
|
|
711
|
+
while (stack.length > 0) {
|
|
712
|
+
const currentDir = stack.pop();
|
|
713
|
+
if (!currentDir)
|
|
714
|
+
continue;
|
|
715
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
716
|
+
for (const entry of entries) {
|
|
717
|
+
if (entry.name === 'node_modules')
|
|
718
|
+
continue;
|
|
719
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
720
|
+
if (entry.isDirectory()) {
|
|
721
|
+
stack.push(fullPath);
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
if (entry.isFile() && fullPath.endsWith('.d.ts')) {
|
|
725
|
+
declarations.push(fullPath);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return declarations;
|
|
730
|
+
}
|
|
731
|
+
shouldIndexDependencySymbol(symbol) {
|
|
732
|
+
if (!isPublicDeclarationSurfaceSymbol(symbol))
|
|
733
|
+
return false;
|
|
734
|
+
if (symbol.declarationSurface)
|
|
735
|
+
return true;
|
|
736
|
+
return !this.hasImplementationBody(symbol);
|
|
737
|
+
}
|
|
738
|
+
hasImplementationBody(symbol) {
|
|
739
|
+
const node = symbol.astNode;
|
|
740
|
+
if (!node)
|
|
741
|
+
return false;
|
|
742
|
+
if (node.type === 'arrow_function' ||
|
|
743
|
+
node.type === 'function_expression' ||
|
|
744
|
+
node.type === 'generator_function') {
|
|
745
|
+
return true;
|
|
746
|
+
}
|
|
747
|
+
if (node.type === 'class_declaration' ||
|
|
748
|
+
node.type === 'interface_declaration' ||
|
|
749
|
+
node.type === 'type_alias_declaration') {
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
752
|
+
const bodyNode = node.childForFieldName('body');
|
|
753
|
+
if (!bodyNode)
|
|
754
|
+
return false;
|
|
755
|
+
return bodyNode.namedChildCount > 0 || bodyNode.text.trim() !== '';
|
|
756
|
+
}
|
|
375
757
|
loadBuildCheckpoint(db, branch, totalFiles) {
|
|
376
|
-
const raw =
|
|
758
|
+
const raw = getLoreMeta(db, LORE_META_INDEX_CHECKPOINT);
|
|
377
759
|
if (!raw)
|
|
378
760
|
return 0;
|
|
379
761
|
try {
|
|
@@ -395,28 +777,37 @@ export class IndexBuilder {
|
|
|
395
777
|
nextFileIndex,
|
|
396
778
|
updatedAt: Math.floor(Date.now() / 1000),
|
|
397
779
|
};
|
|
398
|
-
|
|
780
|
+
setLoreMeta(db, LORE_META_INDEX_CHECKPOINT, JSON.stringify(checkpoint));
|
|
399
781
|
}
|
|
400
782
|
/**
|
|
401
783
|
* Embed structural symbol signatures in batches and persist results to
|
|
402
784
|
* the `symbol_embeddings` vec0 virtual table.
|
|
403
785
|
*
|
|
404
|
-
* Also stores the embedding model name and dims in `
|
|
786
|
+
* Also stores the embedding model name and dims in `lore_meta` and
|
|
405
787
|
* creates the vec0 tables if they don't exist yet.
|
|
406
788
|
*/
|
|
407
789
|
async embedStructural(db) {
|
|
408
790
|
const embedder = this.embedder;
|
|
409
|
-
|
|
410
|
-
|
|
791
|
+
setLoreMeta(db, 'embedding_model', embedder.modelName);
|
|
792
|
+
setLoreMeta(db, 'embedding_dims', String(embedder.dims));
|
|
411
793
|
createVec0Tables(db, embedder.dims);
|
|
412
|
-
// Fetch all symbols that have
|
|
794
|
+
// Fetch all symbols that have structural text to embed.
|
|
413
795
|
const symbols = db
|
|
414
|
-
.prepare(
|
|
796
|
+
.prepare(`SELECT id, name, signature, resolved_type_signature, resolved_return_type
|
|
797
|
+
FROM symbols
|
|
798
|
+
WHERE signature IS NOT NULL
|
|
799
|
+
OR resolved_type_signature IS NOT NULL
|
|
800
|
+
OR resolved_return_type IS NOT NULL`)
|
|
415
801
|
.all();
|
|
416
802
|
const insertEmbed = db.prepare('INSERT OR REPLACE INTO symbol_embeddings(rowid, embedding) VALUES (CAST(? AS INTEGER), json(?))');
|
|
417
803
|
for (let i = 0; i < symbols.length; i += EMBED_BATCH_SIZE) {
|
|
418
804
|
const batch = symbols.slice(i, i + EMBED_BATCH_SIZE);
|
|
419
|
-
const texts = batch.map(
|
|
805
|
+
const texts = batch.map((symbol) => buildStructuralEmbeddingText({
|
|
806
|
+
name: symbol.name,
|
|
807
|
+
signature: symbol.signature,
|
|
808
|
+
resolvedTypeSignature: symbol.resolved_type_signature,
|
|
809
|
+
resolvedReturnType: symbol.resolved_return_type,
|
|
810
|
+
}));
|
|
420
811
|
const embeddings = await embedder.embed(texts);
|
|
421
812
|
db.transaction(() => {
|
|
422
813
|
for (let j = 0; j < batch.length; j++) {
|
|
@@ -427,5 +818,54 @@ export class IndexBuilder {
|
|
|
427
818
|
})();
|
|
428
819
|
}
|
|
429
820
|
}
|
|
821
|
+
async embedDocumentation(db) {
|
|
822
|
+
const embedder = this.embedder;
|
|
823
|
+
db.exec(`
|
|
824
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS doc_section_embeddings USING vec0(
|
|
825
|
+
embedding FLOAT[${embedder.dims}]
|
|
826
|
+
);
|
|
827
|
+
`);
|
|
828
|
+
const sections = db.prepare(`SELECT id, title, content
|
|
829
|
+
FROM doc_sections
|
|
830
|
+
ORDER BY id`).all();
|
|
831
|
+
if (sections.length === 0)
|
|
832
|
+
return;
|
|
833
|
+
const insertEmbed = db.prepare('INSERT OR REPLACE INTO doc_section_embeddings(rowid, embedding) VALUES (CAST(? AS INTEGER), json(?))');
|
|
834
|
+
for (let i = 0; i < sections.length; i += EMBED_BATCH_SIZE) {
|
|
835
|
+
const batch = sections.slice(i, i + EMBED_BATCH_SIZE);
|
|
836
|
+
const texts = batch.map(section => section.content || section.title);
|
|
837
|
+
const embeddings = await embedder.embed(texts);
|
|
838
|
+
db.transaction(() => {
|
|
839
|
+
for (let j = 0; j < batch.length; j++) {
|
|
840
|
+
const section = batch[j];
|
|
841
|
+
if (section) {
|
|
842
|
+
insertEmbed.run(section.id, JSON.stringify(embeddings[j]));
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
})();
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
async embedCommitMessages(db) {
|
|
849
|
+
const embedder = this.embedder;
|
|
850
|
+
const commits = db.prepare(`SELECT rowid, message
|
|
851
|
+
FROM commits
|
|
852
|
+
WHERE length(trim(message)) > 0
|
|
853
|
+
ORDER BY rowid`).all();
|
|
854
|
+
if (commits.length === 0)
|
|
855
|
+
return;
|
|
856
|
+
const insertEmbed = db.prepare('INSERT OR REPLACE INTO commit_embeddings(rowid, embedding) VALUES (CAST(? AS INTEGER), json(?))');
|
|
857
|
+
for (let i = 0; i < commits.length; i += EMBED_BATCH_SIZE) {
|
|
858
|
+
const batch = commits.slice(i, i + EMBED_BATCH_SIZE);
|
|
859
|
+
const embeddings = await embedder.embed(batch.map((commit) => commit.message));
|
|
860
|
+
db.transaction(() => {
|
|
861
|
+
for (let j = 0; j < batch.length; j++) {
|
|
862
|
+
const commit = batch[j];
|
|
863
|
+
if (commit) {
|
|
864
|
+
insertEmbed.run(commit.rowid, JSON.stringify(embeddings[j]));
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
})();
|
|
868
|
+
}
|
|
869
|
+
}
|
|
430
870
|
}
|
|
431
871
|
//# sourceMappingURL=index.js.map
|