@jafreck/lore 0.3.3 → 0.3.5
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 +23 -6
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/indexer/embedder.d.ts +67 -30
- package/dist/indexer/embedder.d.ts.map +1 -1
- package/dist/indexer/embedder.js +151 -146
- package/dist/indexer/embedder.js.map +1 -1
- package/dist/indexer/graph-analysis.d.ts +115 -0
- package/dist/indexer/graph-analysis.d.ts.map +1 -0
- package/dist/indexer/graph-analysis.js +575 -0
- package/dist/indexer/graph-analysis.js.map +1 -0
- package/dist/indexer/stages/embedding.d.ts +9 -0
- package/dist/indexer/stages/embedding.d.ts.map +1 -1
- package/dist/indexer/stages/embedding.js +127 -83
- package/dist/indexer/stages/embedding.js.map +1 -1
- package/dist/lore-server/db.d.ts +74 -0
- package/dist/lore-server/db.d.ts.map +1 -1
- package/dist/lore-server/db.js +114 -0
- package/dist/lore-server/db.js.map +1 -1
- package/dist/lore-server/server.d.ts.map +1 -1
- package/dist/lore-server/server.js +7 -17
- package/dist/lore-server/server.js.map +1 -1
- package/dist/lore-server/tool-registry.d.ts.map +1 -1
- package/dist/lore-server/tool-registry.js +6 -1
- package/dist/lore-server/tool-registry.js.map +1 -1
- package/dist/lore-server/tools/graph-analysis.d.ts +64 -0
- package/dist/lore-server/tools/graph-analysis.d.ts.map +1 -0
- package/dist/lore-server/tools/graph-analysis.js +82 -0
- package/dist/lore-server/tools/graph-analysis.js.map +1 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +4 -5
- package/dist/runtime.js.map +1 -1
- package/package.json +2 -1
- package/dist/indexer/ensure-python-deps.d.ts +0 -22
- package/dist/indexer/ensure-python-deps.d.ts.map +0 -1
- package/dist/indexer/ensure-python-deps.js +0 -47
- package/dist/indexer/ensure-python-deps.js.map +0 -1
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module indexer/graph-analysis
|
|
3
|
+
*
|
|
4
|
+
* Higher-level graph analysis primitives operating on the SQLite
|
|
5
|
+
* knowledge-base:
|
|
6
|
+
*
|
|
7
|
+
* - `detectSymbolCycles(db, opts)` — Tarjan's SCC on the symbol adjacency
|
|
8
|
+
* graph (call_refs, type_refs, or both).
|
|
9
|
+
* - `findConnectedComponents(db, opts)` — union-find connected components
|
|
10
|
+
* at file or symbol scope.
|
|
11
|
+
* - `clusterSymbols(db, opts)` — partitions the call graph into bounded-
|
|
12
|
+
* size coherent chunks via SCC contraction, same-file merge, greedy
|
|
13
|
+
* edge-weight consolidation, and affinity folding.
|
|
14
|
+
* - `buildCodebaseSummary(db, opts)` — condensed dependency summary with
|
|
15
|
+
* per-module files, symbol counts, line spans, and SCCs.
|
|
16
|
+
*/
|
|
17
|
+
import { RESOLVED_METHODS } from './resolution-method.js';
|
|
18
|
+
/**
|
|
19
|
+
* Loads resolved symbol-level edges from the database.
|
|
20
|
+
* Returns only edges where both source and target are non-NULL and the
|
|
21
|
+
* resolution_method passes the configured filter.
|
|
22
|
+
*/
|
|
23
|
+
function loadSymbolEdges(db, options = {}) {
|
|
24
|
+
const edgeKinds = options.edgeKinds ?? 'both';
|
|
25
|
+
const methods = options.methods ?? [...RESOLVED_METHODS];
|
|
26
|
+
const branch = options.branch;
|
|
27
|
+
if (methods.length === 0)
|
|
28
|
+
return [];
|
|
29
|
+
const placeholders = methods.map(() => '?').join(', ');
|
|
30
|
+
const edges = [];
|
|
31
|
+
if (edgeKinds === 'call' || edgeKinds === 'both') {
|
|
32
|
+
const where = [`sr.callee_id IS NOT NULL`, `sr.resolution_method IN (${placeholders})`];
|
|
33
|
+
const params = [...methods];
|
|
34
|
+
if (branch !== undefined) {
|
|
35
|
+
where.push('f.branch = ?');
|
|
36
|
+
params.push(branch);
|
|
37
|
+
}
|
|
38
|
+
const rows = db.prepare(`SELECT sr.caller_id AS source, sr.callee_id AS target
|
|
39
|
+
FROM symbol_refs sr
|
|
40
|
+
JOIN symbols s ON s.id = sr.caller_id
|
|
41
|
+
JOIN files f ON f.id = s.file_id
|
|
42
|
+
WHERE ${where.join(' AND ')}`).all(...params);
|
|
43
|
+
edges.push(...rows);
|
|
44
|
+
}
|
|
45
|
+
if (edgeKinds === 'type' || edgeKinds === 'both') {
|
|
46
|
+
const where = [`tr.type_id IS NOT NULL`, `tr.resolution_method IN (${placeholders})`];
|
|
47
|
+
const params = [...methods];
|
|
48
|
+
if (branch !== undefined) {
|
|
49
|
+
where.push('f.branch = ?');
|
|
50
|
+
params.push(branch);
|
|
51
|
+
}
|
|
52
|
+
const rows = db.prepare(`SELECT tr.symbol_id AS source, tr.type_id AS target
|
|
53
|
+
FROM type_refs tr
|
|
54
|
+
JOIN files f ON f.id = tr.file_id
|
|
55
|
+
WHERE tr.symbol_id IS NOT NULL AND ${where.join(' AND ')}`).all(...params);
|
|
56
|
+
edges.push(...rows);
|
|
57
|
+
}
|
|
58
|
+
return edges;
|
|
59
|
+
}
|
|
60
|
+
// ─── detectSymbolCycles ───────────────────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Detects strongly connected components (mutual recursion, circular type
|
|
63
|
+
* dependencies) in the **symbol** adjacency graph using Tarjan's algorithm.
|
|
64
|
+
*
|
|
65
|
+
* Returns arrays of symbol IDs where each SCC has 2+ members (or a single
|
|
66
|
+
* member with a self-edge).
|
|
67
|
+
*/
|
|
68
|
+
export function detectSymbolCycles(db, options = {}) {
|
|
69
|
+
const edges = loadSymbolEdges(db, options);
|
|
70
|
+
// Build directed adjacency list
|
|
71
|
+
const adjacency = new Map();
|
|
72
|
+
const allNodes = new Set();
|
|
73
|
+
for (const { source, target } of edges) {
|
|
74
|
+
allNodes.add(source);
|
|
75
|
+
allNodes.add(target);
|
|
76
|
+
let list = adjacency.get(source);
|
|
77
|
+
if (!list) {
|
|
78
|
+
list = [];
|
|
79
|
+
adjacency.set(source, list);
|
|
80
|
+
}
|
|
81
|
+
list.push(target);
|
|
82
|
+
}
|
|
83
|
+
// Tarjan's SCC
|
|
84
|
+
let index = 0;
|
|
85
|
+
const indices = new Map();
|
|
86
|
+
const lowlink = new Map();
|
|
87
|
+
const onStack = new Set();
|
|
88
|
+
const stack = [];
|
|
89
|
+
const sccs = [];
|
|
90
|
+
function strongConnect(v) {
|
|
91
|
+
indices.set(v, index);
|
|
92
|
+
lowlink.set(v, index);
|
|
93
|
+
index++;
|
|
94
|
+
stack.push(v);
|
|
95
|
+
onStack.add(v);
|
|
96
|
+
for (const w of adjacency.get(v) ?? []) {
|
|
97
|
+
if (!indices.has(w)) {
|
|
98
|
+
strongConnect(w);
|
|
99
|
+
lowlink.set(v, Math.min(lowlink.get(v), lowlink.get(w)));
|
|
100
|
+
}
|
|
101
|
+
else if (onStack.has(w)) {
|
|
102
|
+
lowlink.set(v, Math.min(lowlink.get(v), indices.get(w)));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (lowlink.get(v) === indices.get(v)) {
|
|
106
|
+
const scc = [];
|
|
107
|
+
let w;
|
|
108
|
+
do {
|
|
109
|
+
w = stack.pop();
|
|
110
|
+
onStack.delete(w);
|
|
111
|
+
scc.push(w);
|
|
112
|
+
} while (w !== v);
|
|
113
|
+
if (scc.length > 1) {
|
|
114
|
+
sccs.push(scc);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// Single-node SCC — only report if self-loop exists
|
|
118
|
+
const selfLoop = (adjacency.get(scc[0]) ?? []).includes(scc[0]);
|
|
119
|
+
if (selfLoop)
|
|
120
|
+
sccs.push(scc);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (const node of allNodes) {
|
|
125
|
+
if (!indices.has(node)) {
|
|
126
|
+
strongConnect(node);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return sccs;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Finds connected components in the **undirected** graph of files or symbols
|
|
133
|
+
* using a union-find (disjoint set) data structure.
|
|
134
|
+
*
|
|
135
|
+
* Returns arrays of IDs where each component has 2+ members.
|
|
136
|
+
*/
|
|
137
|
+
export function findConnectedComponents(db, options = {}) {
|
|
138
|
+
const scope = options.scope ?? 'symbol';
|
|
139
|
+
if (scope === 'file') {
|
|
140
|
+
return findFileComponents(db, options);
|
|
141
|
+
}
|
|
142
|
+
return findSymbolComponents(db, options);
|
|
143
|
+
}
|
|
144
|
+
function findFileComponents(db, options) {
|
|
145
|
+
const branch = options.branch;
|
|
146
|
+
const allFiles = (branch !== undefined
|
|
147
|
+
? db.prepare('SELECT id FROM files WHERE branch = ?').all(branch)
|
|
148
|
+
: db.prepare('SELECT id FROM files').all());
|
|
149
|
+
const edges = (branch !== undefined
|
|
150
|
+
? db.prepare(`SELECT fi.file_id AS source, fi.resolved_id AS target
|
|
151
|
+
FROM file_imports fi
|
|
152
|
+
JOIN files f ON f.id = fi.file_id
|
|
153
|
+
WHERE fi.resolved_id IS NOT NULL AND f.branch = ?`).all(branch)
|
|
154
|
+
: db.prepare(`SELECT fi.file_id AS source, fi.resolved_id AS target
|
|
155
|
+
FROM file_imports fi
|
|
156
|
+
WHERE fi.resolved_id IS NOT NULL`).all());
|
|
157
|
+
const uf = new UnionFind();
|
|
158
|
+
for (const f of allFiles)
|
|
159
|
+
uf.makeSet(f.id);
|
|
160
|
+
for (const { source, target } of edges)
|
|
161
|
+
uf.union(source, target);
|
|
162
|
+
return uf.components().filter(c => c.length > 1);
|
|
163
|
+
}
|
|
164
|
+
function findSymbolComponents(db, options) {
|
|
165
|
+
const edges = loadSymbolEdges(db, options);
|
|
166
|
+
const uf = new UnionFind();
|
|
167
|
+
for (const { source, target } of edges) {
|
|
168
|
+
uf.makeSet(source);
|
|
169
|
+
uf.makeSet(target);
|
|
170
|
+
uf.union(source, target);
|
|
171
|
+
}
|
|
172
|
+
return uf.components().filter(c => c.length > 1);
|
|
173
|
+
}
|
|
174
|
+
/** Simple union-find with path compression and union by rank. */
|
|
175
|
+
class UnionFind {
|
|
176
|
+
parent = new Map();
|
|
177
|
+
rank = new Map();
|
|
178
|
+
makeSet(x) {
|
|
179
|
+
if (!this.parent.has(x)) {
|
|
180
|
+
this.parent.set(x, x);
|
|
181
|
+
this.rank.set(x, 0);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
find(x) {
|
|
185
|
+
let root = x;
|
|
186
|
+
while (this.parent.get(root) !== root) {
|
|
187
|
+
root = this.parent.get(root);
|
|
188
|
+
}
|
|
189
|
+
// Path compression
|
|
190
|
+
let curr = x;
|
|
191
|
+
while (curr !== root) {
|
|
192
|
+
const next = this.parent.get(curr);
|
|
193
|
+
this.parent.set(curr, root);
|
|
194
|
+
curr = next;
|
|
195
|
+
}
|
|
196
|
+
return root;
|
|
197
|
+
}
|
|
198
|
+
union(a, b) {
|
|
199
|
+
this.makeSet(a);
|
|
200
|
+
this.makeSet(b);
|
|
201
|
+
const ra = this.find(a);
|
|
202
|
+
const rb = this.find(b);
|
|
203
|
+
if (ra === rb)
|
|
204
|
+
return;
|
|
205
|
+
const rankA = this.rank.get(ra);
|
|
206
|
+
const rankB = this.rank.get(rb);
|
|
207
|
+
if (rankA < rankB) {
|
|
208
|
+
this.parent.set(ra, rb);
|
|
209
|
+
}
|
|
210
|
+
else if (rankA > rankB) {
|
|
211
|
+
this.parent.set(rb, ra);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
this.parent.set(rb, ra);
|
|
215
|
+
this.rank.set(ra, rankA + 1);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
components() {
|
|
219
|
+
const groups = new Map();
|
|
220
|
+
for (const x of this.parent.keys()) {
|
|
221
|
+
const root = this.find(x);
|
|
222
|
+
let list = groups.get(root);
|
|
223
|
+
if (!list) {
|
|
224
|
+
list = [];
|
|
225
|
+
groups.set(root, list);
|
|
226
|
+
}
|
|
227
|
+
list.push(x);
|
|
228
|
+
}
|
|
229
|
+
return [...groups.values()];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Partition the symbol call graph into bounded-size coherent clusters.
|
|
234
|
+
*
|
|
235
|
+
* Algorithm:
|
|
236
|
+
* 1. Contract SCCs (mutually dependent symbols → same cluster)
|
|
237
|
+
* 2. Merge same-file symbols into one cluster per file
|
|
238
|
+
* 3. Greedy merge by edge weight (respecting maxLines)
|
|
239
|
+
* 4. Fold undersized clusters into their heaviest-edge neighbor
|
|
240
|
+
*/
|
|
241
|
+
export function clusterSymbols(db, options = {}) {
|
|
242
|
+
const maxLines = options.maxLinesPerCluster ?? 500;
|
|
243
|
+
const branch = options.branch;
|
|
244
|
+
// Load all symbols with line spans
|
|
245
|
+
const symbolRows = (branch !== undefined
|
|
246
|
+
? db.prepare(`SELECT s.id, s.file_id, (s.end_line - s.start_line + 1) AS lines
|
|
247
|
+
FROM symbols s JOIN files f ON f.id = s.file_id
|
|
248
|
+
WHERE f.branch = ?`).all(branch)
|
|
249
|
+
: db.prepare('SELECT id, file_id, (end_line - start_line + 1) AS lines FROM symbols').all());
|
|
250
|
+
if (symbolRows.length === 0)
|
|
251
|
+
return [];
|
|
252
|
+
const symbolById = new Map();
|
|
253
|
+
for (const s of symbolRows)
|
|
254
|
+
symbolById.set(s.id, s);
|
|
255
|
+
const edges = loadSymbolEdges(db, options);
|
|
256
|
+
// Filter edges to only include symbols we loaded
|
|
257
|
+
const validEdges = edges.filter(e => symbolById.has(e.source) && symbolById.has(e.target));
|
|
258
|
+
// Step 1: SCC contraction — assign each symbol to a cluster
|
|
259
|
+
const sccs = detectSymbolCycles(db, options);
|
|
260
|
+
const clusterOf = new Map(); // symbol → cluster representative
|
|
261
|
+
let nextCluster = 0;
|
|
262
|
+
for (const scc of sccs) {
|
|
263
|
+
const cid = nextCluster++;
|
|
264
|
+
for (const sid of scc)
|
|
265
|
+
clusterOf.set(sid, cid);
|
|
266
|
+
}
|
|
267
|
+
// Assign singletons
|
|
268
|
+
for (const s of symbolRows) {
|
|
269
|
+
if (!clusterOf.has(s.id)) {
|
|
270
|
+
clusterOf.set(s.id, nextCluster++);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Step 2: Same-file merge — merge clusters whose symbols share a file
|
|
274
|
+
const fileToClusterIds = new Map();
|
|
275
|
+
for (const s of symbolRows) {
|
|
276
|
+
const cid = clusterOf.get(s.id);
|
|
277
|
+
let set = fileToClusterIds.get(s.fileId);
|
|
278
|
+
if (!set) {
|
|
279
|
+
set = new Set();
|
|
280
|
+
fileToClusterIds.set(s.fileId, set);
|
|
281
|
+
}
|
|
282
|
+
set.add(cid);
|
|
283
|
+
}
|
|
284
|
+
// Use union-find for merging
|
|
285
|
+
const clusterUf = new UnionFind();
|
|
286
|
+
for (const cid of new Set(clusterOf.values()))
|
|
287
|
+
clusterUf.makeSet(cid);
|
|
288
|
+
for (const clusterIds of fileToClusterIds.values()) {
|
|
289
|
+
const ids = [...clusterIds];
|
|
290
|
+
for (let i = 1; i < ids.length; i++) {
|
|
291
|
+
// Only merge if combined size stays within bounds
|
|
292
|
+
const rootA = clusterUf.find(ids[0]);
|
|
293
|
+
const rootB = clusterUf.find(ids[i]);
|
|
294
|
+
if (rootA !== rootB) {
|
|
295
|
+
const sizeA = clusterLineCount(rootA, clusterOf, clusterUf, symbolById);
|
|
296
|
+
const sizeB = clusterLineCount(rootB, clusterOf, clusterUf, symbolById);
|
|
297
|
+
if (sizeA + sizeB <= maxLines) {
|
|
298
|
+
clusterUf.union(rootA, rootB);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// Step 3: Greedy merge by edge weight
|
|
304
|
+
const crossEdgeWeights = new Map();
|
|
305
|
+
for (const { source, target } of validEdges) {
|
|
306
|
+
const ca = clusterUf.find(clusterOf.get(source));
|
|
307
|
+
const cb = clusterUf.find(clusterOf.get(target));
|
|
308
|
+
if (ca === cb)
|
|
309
|
+
continue;
|
|
310
|
+
const key = ca < cb ? `${ca}:${cb}` : `${cb}:${ca}`;
|
|
311
|
+
crossEdgeWeights.set(key, (crossEdgeWeights.get(key) ?? 0) + 1);
|
|
312
|
+
}
|
|
313
|
+
// Sort by edge weight descending and greedily merge
|
|
314
|
+
const sortedPairs = [...crossEdgeWeights.entries()]
|
|
315
|
+
.sort((a, b) => b[1] - a[1]);
|
|
316
|
+
for (const [key] of sortedPairs) {
|
|
317
|
+
const [aStr, bStr] = key.split(':');
|
|
318
|
+
const ca = clusterUf.find(Number(aStr));
|
|
319
|
+
const cb = clusterUf.find(Number(bStr));
|
|
320
|
+
if (ca === cb)
|
|
321
|
+
continue;
|
|
322
|
+
const sizeA = clusterLineCount(ca, clusterOf, clusterUf, symbolById);
|
|
323
|
+
const sizeB = clusterLineCount(cb, clusterOf, clusterUf, symbolById);
|
|
324
|
+
if (sizeA + sizeB <= maxLines) {
|
|
325
|
+
clusterUf.union(ca, cb);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// Step 4: Fold undersized clusters (<30 lines) into heaviest neighbor
|
|
329
|
+
const MIN_CLUSTER_LINES = 30;
|
|
330
|
+
const finalClusters = new Map(); // root → symbol ids
|
|
331
|
+
for (const s of symbolRows) {
|
|
332
|
+
const root = clusterUf.find(clusterOf.get(s.id));
|
|
333
|
+
let list = finalClusters.get(root);
|
|
334
|
+
if (!list) {
|
|
335
|
+
list = [];
|
|
336
|
+
finalClusters.set(root, list);
|
|
337
|
+
}
|
|
338
|
+
list.push(s.id);
|
|
339
|
+
}
|
|
340
|
+
// Find undersized clusters and their best merge target
|
|
341
|
+
for (const [root, symbolIds] of finalClusters) {
|
|
342
|
+
const totalLines = symbolIds.reduce((sum, id) => sum + (symbolById.get(id)?.lines ?? 0), 0);
|
|
343
|
+
if (totalLines >= MIN_CLUSTER_LINES)
|
|
344
|
+
continue;
|
|
345
|
+
// Find the neighbor cluster with the most edges
|
|
346
|
+
let bestNeighbor;
|
|
347
|
+
let bestWeight = 0;
|
|
348
|
+
for (const { source, target } of validEdges) {
|
|
349
|
+
const cs = clusterUf.find(clusterOf.get(source));
|
|
350
|
+
const ct = clusterUf.find(clusterOf.get(target));
|
|
351
|
+
if (cs === root && ct !== root) {
|
|
352
|
+
const neighborLines = clusterLineCount(ct, clusterOf, clusterUf, symbolById);
|
|
353
|
+
if (neighborLines + totalLines <= maxLines) {
|
|
354
|
+
const key = root < ct ? `${root}:${ct}` : `${ct}:${root}`;
|
|
355
|
+
const w = crossEdgeWeights.get(key) ?? 1;
|
|
356
|
+
if (w > bestWeight) {
|
|
357
|
+
bestWeight = w;
|
|
358
|
+
bestNeighbor = ct;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
else if (ct === root && cs !== root) {
|
|
363
|
+
const neighborLines = clusterLineCount(cs, clusterOf, clusterUf, symbolById);
|
|
364
|
+
if (neighborLines + totalLines <= maxLines) {
|
|
365
|
+
const key = root < cs ? `${root}:${cs}` : `${cs}:${root}`;
|
|
366
|
+
const w = crossEdgeWeights.get(key) ?? 1;
|
|
367
|
+
if (w > bestWeight) {
|
|
368
|
+
bestWeight = w;
|
|
369
|
+
bestNeighbor = cs;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (bestNeighbor !== undefined) {
|
|
375
|
+
clusterUf.union(root, bestNeighbor);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// Build final result
|
|
379
|
+
const resultMap = new Map();
|
|
380
|
+
for (const s of symbolRows) {
|
|
381
|
+
const root = clusterUf.find(clusterOf.get(s.id));
|
|
382
|
+
let entry = resultMap.get(root);
|
|
383
|
+
if (!entry) {
|
|
384
|
+
entry = { symbolIds: [], fileIds: new Set(), totalLines: 0 };
|
|
385
|
+
resultMap.set(root, entry);
|
|
386
|
+
}
|
|
387
|
+
entry.symbolIds.push(s.id);
|
|
388
|
+
entry.fileIds.add(s.fileId);
|
|
389
|
+
entry.totalLines += s.lines;
|
|
390
|
+
}
|
|
391
|
+
// Count internal/external edges per cluster
|
|
392
|
+
const results = [];
|
|
393
|
+
let idx = 0;
|
|
394
|
+
for (const entry of resultMap.values()) {
|
|
395
|
+
const memberSet = new Set(entry.symbolIds);
|
|
396
|
+
let internalEdges = 0;
|
|
397
|
+
let externalEdges = 0;
|
|
398
|
+
for (const { source, target } of validEdges) {
|
|
399
|
+
const sIn = memberSet.has(source);
|
|
400
|
+
const tIn = memberSet.has(target);
|
|
401
|
+
if (sIn && tIn)
|
|
402
|
+
internalEdges++;
|
|
403
|
+
else if (sIn || tIn)
|
|
404
|
+
externalEdges++;
|
|
405
|
+
}
|
|
406
|
+
results.push({
|
|
407
|
+
id: idx++,
|
|
408
|
+
symbolIds: entry.symbolIds,
|
|
409
|
+
totalLines: entry.totalLines,
|
|
410
|
+
fileIds: [...entry.fileIds],
|
|
411
|
+
internalEdges,
|
|
412
|
+
externalEdges,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
return results.sort((a, b) => b.totalLines - a.totalLines);
|
|
416
|
+
}
|
|
417
|
+
function clusterLineCount(clusterRoot, clusterOf, uf, symbolById) {
|
|
418
|
+
let total = 0;
|
|
419
|
+
for (const [symId, cid] of clusterOf) {
|
|
420
|
+
if (uf.find(cid) === clusterRoot) {
|
|
421
|
+
total += symbolById.get(symId)?.lines ?? 0;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return total;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Produces a condensed dependency summary of the codebase — the "30-second
|
|
428
|
+
* architecture overview."
|
|
429
|
+
*
|
|
430
|
+
* Combines symbol clustering with inter-module edge analysis and SCC/CC
|
|
431
|
+
* detection at the module level.
|
|
432
|
+
*/
|
|
433
|
+
export function buildCodebaseSummary(db, options = {}) {
|
|
434
|
+
const branch = options.branch;
|
|
435
|
+
// Counts
|
|
436
|
+
const totalFiles = (branch !== undefined
|
|
437
|
+
? db.prepare('SELECT COUNT(*) AS cnt FROM files WHERE branch = ?').get(branch)
|
|
438
|
+
: db.prepare('SELECT COUNT(*) AS cnt FROM files').get());
|
|
439
|
+
const totalSymbols = (branch !== undefined
|
|
440
|
+
? db.prepare('SELECT COUNT(*) AS cnt FROM symbols s JOIN files f ON f.id = s.file_id WHERE f.branch = ?').get(branch)
|
|
441
|
+
: db.prepare('SELECT COUNT(*) AS cnt FROM symbols').get());
|
|
442
|
+
const totalEdges = (branch !== undefined
|
|
443
|
+
? db.prepare(`SELECT COUNT(*) AS cnt FROM symbol_refs sr
|
|
444
|
+
JOIN symbols s ON s.id = sr.caller_id
|
|
445
|
+
JOIN files f ON f.id = s.file_id
|
|
446
|
+
WHERE sr.callee_id IS NOT NULL AND f.branch = ?`).get(branch)
|
|
447
|
+
: db.prepare('SELECT COUNT(*) AS cnt FROM symbol_refs WHERE callee_id IS NOT NULL').get());
|
|
448
|
+
// Cluster symbols into modules
|
|
449
|
+
const clusters = clusterSymbols(db, {
|
|
450
|
+
...options,
|
|
451
|
+
maxLinesPerCluster: options.maxLinesPerModule ?? 500,
|
|
452
|
+
});
|
|
453
|
+
if (clusters.length === 0) {
|
|
454
|
+
return {
|
|
455
|
+
totalFiles: totalFiles.cnt,
|
|
456
|
+
totalSymbols: totalSymbols.cnt,
|
|
457
|
+
totalEdges: totalEdges.cnt,
|
|
458
|
+
modules: [],
|
|
459
|
+
connectedComponents: [],
|
|
460
|
+
cyclicGroups: [],
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
// Build symbol → cluster mapping
|
|
464
|
+
const symbolToCluster = new Map();
|
|
465
|
+
for (const c of clusters) {
|
|
466
|
+
for (const sid of c.symbolIds) {
|
|
467
|
+
symbolToCluster.set(sid, c.id);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
// Load file paths for each cluster
|
|
471
|
+
const filePathById = new Map((branch !== undefined
|
|
472
|
+
? db.prepare('SELECT id, path FROM files WHERE branch = ?').all(branch)
|
|
473
|
+
: db.prepare('SELECT id, path FROM files').all()).map((r) => [r.id, r.path]));
|
|
474
|
+
// Build module summaries
|
|
475
|
+
const edges = loadSymbolEdges(db, options);
|
|
476
|
+
const moduleAdj = new Map(); // module → set of modules it depends on
|
|
477
|
+
const moduleRevAdj = new Map(); // module → set of modules that depend on it
|
|
478
|
+
for (const c of clusters) {
|
|
479
|
+
moduleAdj.set(c.id, new Set());
|
|
480
|
+
moduleRevAdj.set(c.id, new Set());
|
|
481
|
+
}
|
|
482
|
+
for (const { source, target } of edges) {
|
|
483
|
+
const cm = symbolToCluster.get(source);
|
|
484
|
+
const cn = symbolToCluster.get(target);
|
|
485
|
+
if (cm === undefined || cn === undefined || cm === cn)
|
|
486
|
+
continue;
|
|
487
|
+
moduleAdj.get(cm).add(cn);
|
|
488
|
+
moduleRevAdj.get(cn).add(cm);
|
|
489
|
+
}
|
|
490
|
+
const modules = clusters.map(c => ({
|
|
491
|
+
id: c.id,
|
|
492
|
+
files: c.fileIds.map(fid => filePathById.get(fid) ?? `file:${fid}`).sort(),
|
|
493
|
+
symbolCount: c.symbolIds.length,
|
|
494
|
+
totalLines: c.totalLines,
|
|
495
|
+
dependsOn: [...(moduleAdj.get(c.id) ?? [])].sort((a, b) => a - b),
|
|
496
|
+
dependedOnBy: [...(moduleRevAdj.get(c.id) ?? [])].sort((a, b) => a - b),
|
|
497
|
+
}));
|
|
498
|
+
// Module-level connected components
|
|
499
|
+
const moduleUf = new UnionFind();
|
|
500
|
+
for (const c of clusters)
|
|
501
|
+
moduleUf.makeSet(c.id);
|
|
502
|
+
for (const { source, target } of edges) {
|
|
503
|
+
const cm = symbolToCluster.get(source);
|
|
504
|
+
const cn = symbolToCluster.get(target);
|
|
505
|
+
if (cm !== undefined && cn !== undefined && cm !== cn) {
|
|
506
|
+
moduleUf.union(cm, cn);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
const connectedComponents = moduleUf.components().filter(c => c.length > 1);
|
|
510
|
+
// Module-level SCCs
|
|
511
|
+
const moduleSccAdj = new Map();
|
|
512
|
+
for (const c of clusters)
|
|
513
|
+
moduleSccAdj.set(c.id, []);
|
|
514
|
+
for (const [mid, deps] of moduleAdj) {
|
|
515
|
+
moduleSccAdj.set(mid, [...deps]);
|
|
516
|
+
}
|
|
517
|
+
const cyclicGroups = tarjanScc(moduleSccAdj);
|
|
518
|
+
return {
|
|
519
|
+
totalFiles: totalFiles.cnt,
|
|
520
|
+
totalSymbols: totalSymbols.cnt,
|
|
521
|
+
totalEdges: totalEdges.cnt,
|
|
522
|
+
modules,
|
|
523
|
+
connectedComponents,
|
|
524
|
+
cyclicGroups,
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
/** Generic Tarjan's SCC for number-keyed adjacency. */
|
|
528
|
+
function tarjanScc(adjacency) {
|
|
529
|
+
let index = 0;
|
|
530
|
+
const indices = new Map();
|
|
531
|
+
const lowlink = new Map();
|
|
532
|
+
const onStack = new Set();
|
|
533
|
+
const stack = [];
|
|
534
|
+
const sccs = [];
|
|
535
|
+
function strongConnect(v) {
|
|
536
|
+
indices.set(v, index);
|
|
537
|
+
lowlink.set(v, index);
|
|
538
|
+
index++;
|
|
539
|
+
stack.push(v);
|
|
540
|
+
onStack.add(v);
|
|
541
|
+
for (const w of adjacency.get(v) ?? []) {
|
|
542
|
+
if (!indices.has(w)) {
|
|
543
|
+
strongConnect(w);
|
|
544
|
+
lowlink.set(v, Math.min(lowlink.get(v), lowlink.get(w)));
|
|
545
|
+
}
|
|
546
|
+
else if (onStack.has(w)) {
|
|
547
|
+
lowlink.set(v, Math.min(lowlink.get(v), indices.get(w)));
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (lowlink.get(v) === indices.get(v)) {
|
|
551
|
+
const scc = [];
|
|
552
|
+
let w;
|
|
553
|
+
do {
|
|
554
|
+
w = stack.pop();
|
|
555
|
+
onStack.delete(w);
|
|
556
|
+
scc.push(w);
|
|
557
|
+
} while (w !== v);
|
|
558
|
+
if (scc.length > 1) {
|
|
559
|
+
sccs.push(scc);
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
const selfLoop = (adjacency.get(scc[0]) ?? []).includes(scc[0]);
|
|
563
|
+
if (selfLoop)
|
|
564
|
+
sccs.push(scc);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
for (const node of adjacency.keys()) {
|
|
569
|
+
if (!indices.has(node)) {
|
|
570
|
+
strongConnect(node);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return sccs;
|
|
574
|
+
}
|
|
575
|
+
//# sourceMappingURL=graph-analysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-analysis.js","sourceRoot":"","sources":["../../src/indexer/graph-analysis.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Pipeline stage: embed symbol signatures, documentation sections, and
|
|
5
5
|
* commit messages into vec0 virtual tables for semantic search.
|
|
6
|
+
*
|
|
7
|
+
* Optimisations:
|
|
8
|
+
* - **Token-aware batching**: batches are sized by estimated token budget
|
|
9
|
+
* rather than a fixed item count, avoiding pathological padding waste
|
|
10
|
+
* when one long signature inflates the whole batch.
|
|
11
|
+
* - **Skip-unchanged**: in update mode, symbols whose embedding input text
|
|
12
|
+
* has not changed (by SHA-256 hash) are skipped entirely.
|
|
13
|
+
* - **Double-buffered I/O**: the next `embed()` call fires while the
|
|
14
|
+
* current batch's vectors are written to SQLite.
|
|
6
15
|
*/
|
|
7
16
|
import type { PipelineContext, PipelineStage } from '../pipeline.js';
|
|
8
17
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../../src/indexer/stages/embedding.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../../src/indexer/stages/embedding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAMrE;;;;GAIG;AACH,qBAAa,cAAe,YAAW,aAAa;IAClD,QAAQ,CAAC,IAAI,eAAe;IAEtB,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CA6BjF"}
|