@quolu/lattice 0.63.0 → 0.63.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/LICENSE +147 -147
- package/README.ja.md +378 -378
- package/README.md +303 -303
- package/bin/lattice-mcp.mjs +0 -0
- package/bin/lattice-scripted-adapter.mjs +0 -0
- package/bin/lattice-scripted-worker.mjs +0 -0
- package/bin/lattice-work-order-adapter.mjs +0 -0
- package/bin/lattice.mjs +3 -1
- package/docs/bridge-setup.md +248 -248
- package/docs/schemas/lattice.executor_packet.v1.schema.json +57 -57
- package/docs/schemas/lattice.executor_receipt.v1.schema.json +66 -66
- package/docs/schemas/lattice.phase_todo_revision.v3.schema.json +360 -360
- package/docs/schemas/lattice.plan_create_input.v1.schema.json +56 -56
- package/docs/schemas/lattice.plan_create_input.v2.schema.json +72 -72
- package/docs/schemas/lattice.plan_create_input.v3.schema.json +81 -81
- package/docs/schemas/lattice.plan_create_input.v4.schema.json +357 -85
- package/docs/schemas/lattice.plan_scope_review.v1.schema.json +55 -55
- package/docs/schemas/lattice.run_request.v1.schema.json +238 -238
- package/docs/schemas/lattice.runtime_adapter_capabilities.v2.schema.json +55 -55
- package/docs/schemas/lattice.runtime_adapter_registration_input.v1.schema.json +78 -78
- package/docs/schemas/lattice.runtime_adapter_registration_input.v2.schema.json +86 -86
- package/docs/schemas/lattice.todo_extraction.v2.schema.json +298 -298
- package/docs/schemas/lattice.todo_extraction.v3.schema.json +150 -150
- package/docs/schemas/lattice.todo_extraction.v4.schema.json +161 -161
- package/docs/schemas/lattice.todo_revision.v2.schema.json +260 -260
- package/docs/schemas/lattice.todo_revision_set.v3.schema.json +363 -363
- package/docs/schemas/lattice.todo_structure_binding.v1.schema.json +47 -47
- package/docs/schemas/lattice.todo_structure_realization.v1.schema.json +55 -55
- package/docs/schemas/lattice.todo_structure_set.v1.schema.json +264 -264
- package/package.json +109 -109
- package/sensor/LICENSE +21 -21
- package/sensor/NOTICE +19 -19
- package/sensor/dist/bin/lattice-sensor.js +9 -9
- package/sensor/dist/db/index.js +24 -24
- package/sensor/dist/db/migrations.js +41 -41
- package/sensor/dist/db/queries.js +164 -164
- package/sensor/dist/db/schema.sql +205 -205
- package/sensor/dist/directory.js +5 -5
- package/sensor/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
- package/sensor/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
- package/sensor/dist/mcp/liveness-watchdog.js +53 -53
- package/sensor/dist/mcp/server-instructions.js +95 -95
- package/sensor/package.json +56 -56
- package/src/project-cli.mjs +164 -24
- package/src/todo-authoring-input.mjs +35 -5
- package/src/todo-cli.mjs +2 -2
- package/src/todo-store.mjs +52 -21
|
@@ -265,20 +265,20 @@ class QueryBuilder {
|
|
|
265
265
|
*/
|
|
266
266
|
insertNode(node) {
|
|
267
267
|
if (!this.stmts.insertNode) {
|
|
268
|
-
this.stmts.insertNode = this.db.prepare(`
|
|
269
|
-
INSERT OR REPLACE INTO nodes (
|
|
270
|
-
id, kind, name, qualified_name, file_path, language,
|
|
271
|
-
start_line, end_line, start_column, end_column,
|
|
272
|
-
docstring, signature, visibility,
|
|
273
|
-
is_exported, is_async, is_static, is_abstract,
|
|
274
|
-
decorators, type_parameters, return_type, extent_start_line, updated_at
|
|
275
|
-
) VALUES (
|
|
276
|
-
@id, @kind, @name, @qualifiedName, @filePath, @language,
|
|
277
|
-
@startLine, @endLine, @startColumn, @endColumn,
|
|
278
|
-
@docstring, @signature, @visibility,
|
|
279
|
-
@isExported, @isAsync, @isStatic, @isAbstract,
|
|
280
|
-
@decorators, @typeParameters, @returnType, @extentStartLine, @updatedAt
|
|
281
|
-
)
|
|
268
|
+
this.stmts.insertNode = this.db.prepare(`
|
|
269
|
+
INSERT OR REPLACE INTO nodes (
|
|
270
|
+
id, kind, name, qualified_name, file_path, language,
|
|
271
|
+
start_line, end_line, start_column, end_column,
|
|
272
|
+
docstring, signature, visibility,
|
|
273
|
+
is_exported, is_async, is_static, is_abstract,
|
|
274
|
+
decorators, type_parameters, return_type, extent_start_line, updated_at
|
|
275
|
+
) VALUES (
|
|
276
|
+
@id, @kind, @name, @qualifiedName, @filePath, @language,
|
|
277
|
+
@startLine, @endLine, @startColumn, @endColumn,
|
|
278
|
+
@docstring, @signature, @visibility,
|
|
279
|
+
@isExported, @isAsync, @isStatic, @isAbstract,
|
|
280
|
+
@decorators, @typeParameters, @returnType, @extentStartLine, @updatedAt
|
|
281
|
+
)
|
|
282
282
|
`);
|
|
283
283
|
}
|
|
284
284
|
// Validate required fields to prevent SQLite bind errors
|
|
@@ -396,12 +396,12 @@ class QueryBuilder {
|
|
|
396
396
|
if (this.isSegmentableKind(node.kind))
|
|
397
397
|
this.collectNameSegmentRows(node.name, segmentRows);
|
|
398
398
|
}
|
|
399
|
-
this.runBatched('insertNodes', `INSERT OR REPLACE INTO nodes (
|
|
400
|
-
id, kind, name, qualified_name, file_path, language,
|
|
401
|
-
start_line, end_line, start_column, end_column,
|
|
402
|
-
docstring, signature, visibility,
|
|
403
|
-
is_exported, is_async, is_static, is_abstract,
|
|
404
|
-
decorators, type_parameters, return_type, extent_start_line, updated_at
|
|
399
|
+
this.runBatched('insertNodes', `INSERT OR REPLACE INTO nodes (
|
|
400
|
+
id, kind, name, qualified_name, file_path, language,
|
|
401
|
+
start_line, end_line, start_column, end_column,
|
|
402
|
+
docstring, signature, visibility,
|
|
403
|
+
is_exported, is_async, is_static, is_abstract,
|
|
404
|
+
decorators, type_parameters, return_type, extent_start_line, updated_at
|
|
405
405
|
) VALUES `, '(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', rows);
|
|
406
406
|
this.runBatched('insertNameSegments', 'INSERT OR IGNORE INTO name_segment_vocab (segment, name) VALUES ', '(?,?)', segmentRows);
|
|
407
407
|
})();
|
|
@@ -460,30 +460,30 @@ class QueryBuilder {
|
|
|
460
460
|
*/
|
|
461
461
|
updateNode(node) {
|
|
462
462
|
if (!this.stmts.updateNode) {
|
|
463
|
-
this.stmts.updateNode = this.db.prepare(`
|
|
464
|
-
UPDATE nodes SET
|
|
465
|
-
kind = @kind,
|
|
466
|
-
name = @name,
|
|
467
|
-
qualified_name = @qualifiedName,
|
|
468
|
-
file_path = @filePath,
|
|
469
|
-
language = @language,
|
|
470
|
-
start_line = @startLine,
|
|
471
|
-
end_line = @endLine,
|
|
472
|
-
start_column = @startColumn,
|
|
473
|
-
end_column = @endColumn,
|
|
474
|
-
docstring = @docstring,
|
|
475
|
-
signature = @signature,
|
|
476
|
-
visibility = @visibility,
|
|
477
|
-
is_exported = @isExported,
|
|
478
|
-
is_async = @isAsync,
|
|
479
|
-
is_static = @isStatic,
|
|
480
|
-
is_abstract = @isAbstract,
|
|
481
|
-
decorators = @decorators,
|
|
482
|
-
type_parameters = @typeParameters,
|
|
483
|
-
return_type = @returnType,
|
|
484
|
-
extent_start_line = @extentStartLine,
|
|
485
|
-
updated_at = @updatedAt
|
|
486
|
-
WHERE id = @id
|
|
463
|
+
this.stmts.updateNode = this.db.prepare(`
|
|
464
|
+
UPDATE nodes SET
|
|
465
|
+
kind = @kind,
|
|
466
|
+
name = @name,
|
|
467
|
+
qualified_name = @qualifiedName,
|
|
468
|
+
file_path = @filePath,
|
|
469
|
+
language = @language,
|
|
470
|
+
start_line = @startLine,
|
|
471
|
+
end_line = @endLine,
|
|
472
|
+
start_column = @startColumn,
|
|
473
|
+
end_column = @endColumn,
|
|
474
|
+
docstring = @docstring,
|
|
475
|
+
signature = @signature,
|
|
476
|
+
visibility = @visibility,
|
|
477
|
+
is_exported = @isExported,
|
|
478
|
+
is_async = @isAsync,
|
|
479
|
+
is_static = @isStatic,
|
|
480
|
+
is_abstract = @isAbstract,
|
|
481
|
+
decorators = @decorators,
|
|
482
|
+
type_parameters = @typeParameters,
|
|
483
|
+
return_type = @returnType,
|
|
484
|
+
extent_start_line = @extentStartLine,
|
|
485
|
+
updated_at = @updatedAt
|
|
486
|
+
WHERE id = @id
|
|
487
487
|
`);
|
|
488
488
|
}
|
|
489
489
|
// Invalidate cache before update
|
|
@@ -607,12 +607,12 @@ class QueryBuilder {
|
|
|
607
607
|
const placeholders = variants.map(() => '?').join(', ');
|
|
608
608
|
const whens = variants.map(() => 'WHEN ? THEN ?').join(' ');
|
|
609
609
|
const rows = this.db
|
|
610
|
-
.prepare(`SELECT name, COUNT(DISTINCT CASE segment ${whens} END) AS matches
|
|
611
|
-
FROM name_segment_vocab
|
|
612
|
-
WHERE segment IN (${placeholders})
|
|
613
|
-
GROUP BY name
|
|
614
|
-
HAVING matches >= ?
|
|
615
|
-
ORDER BY matches DESC, length(name) ASC
|
|
610
|
+
.prepare(`SELECT name, COUNT(DISTINCT CASE segment ${whens} END) AS matches
|
|
611
|
+
FROM name_segment_vocab
|
|
612
|
+
WHERE segment IN (${placeholders})
|
|
613
|
+
GROUP BY name
|
|
614
|
+
HAVING matches >= ?
|
|
615
|
+
ORDER BY matches DESC, length(name) ASC
|
|
616
616
|
LIMIT ?`)
|
|
617
617
|
.all(...variants.flatMap((v) => [v.segment, v.word]), ...variants.map((v) => v.segment), minWords, limit);
|
|
618
618
|
return rows;
|
|
@@ -624,7 +624,7 @@ class QueryBuilder {
|
|
|
624
624
|
return new Map();
|
|
625
625
|
const placeholders = segments.map(() => '?').join(', ');
|
|
626
626
|
const rows = this.db
|
|
627
|
-
.prepare(`SELECT segment, COUNT(*) AS n FROM name_segment_vocab
|
|
627
|
+
.prepare(`SELECT segment, COUNT(*) AS n FROM name_segment_vocab
|
|
628
628
|
WHERE segment IN (${placeholders}) GROUP BY segment`)
|
|
629
629
|
.all(...segments);
|
|
630
630
|
return new Map(rows.map((r) => [r.segment, r.n]));
|
|
@@ -784,15 +784,15 @@ class QueryBuilder {
|
|
|
784
784
|
// protobuf stub) outranks the real `server/etcdserver/server.go`
|
|
785
785
|
// (470 edges) by 4×, and the boost would push the agent toward
|
|
786
786
|
// generated code.
|
|
787
|
-
this.stmts.getDominantFile = this.db.prepare(`
|
|
788
|
-
SELECT n.file_path AS file_path, COUNT(*) AS edge_count
|
|
789
|
-
FROM edges e
|
|
790
|
-
JOIN nodes n ON e.source = n.id
|
|
791
|
-
JOIN nodes m ON e.target = m.id
|
|
792
|
-
WHERE n.file_path = m.file_path
|
|
793
|
-
GROUP BY n.file_path
|
|
794
|
-
ORDER BY edge_count DESC
|
|
795
|
-
LIMIT 20
|
|
787
|
+
this.stmts.getDominantFile = this.db.prepare(`
|
|
788
|
+
SELECT n.file_path AS file_path, COUNT(*) AS edge_count
|
|
789
|
+
FROM edges e
|
|
790
|
+
JOIN nodes n ON e.source = n.id
|
|
791
|
+
JOIN nodes m ON e.target = m.id
|
|
792
|
+
WHERE n.file_path = m.file_path
|
|
793
|
+
GROUP BY n.file_path
|
|
794
|
+
ORDER BY edge_count DESC
|
|
795
|
+
LIMIT 20
|
|
796
796
|
`);
|
|
797
797
|
}
|
|
798
798
|
const rows = this.stmts.getDominantFile.all();
|
|
@@ -819,13 +819,13 @@ class QueryBuilder {
|
|
|
819
819
|
*/
|
|
820
820
|
getTopRouteFile() {
|
|
821
821
|
if (!this.stmts.getTopRouteFile) {
|
|
822
|
-
this.stmts.getTopRouteFile = this.db.prepare(`
|
|
823
|
-
SELECT file_path, COUNT(*) AS cnt
|
|
824
|
-
FROM nodes
|
|
825
|
-
WHERE kind = 'route'
|
|
826
|
-
GROUP BY file_path
|
|
827
|
-
ORDER BY cnt DESC
|
|
828
|
-
LIMIT 20
|
|
822
|
+
this.stmts.getTopRouteFile = this.db.prepare(`
|
|
823
|
+
SELECT file_path, COUNT(*) AS cnt
|
|
824
|
+
FROM nodes
|
|
825
|
+
WHERE kind = 'route'
|
|
826
|
+
GROUP BY file_path
|
|
827
|
+
ORDER BY cnt DESC
|
|
828
|
+
LIMIT 20
|
|
829
829
|
`);
|
|
830
830
|
}
|
|
831
831
|
const rows = this.stmts.getTopRouteFile.all();
|
|
@@ -856,21 +856,21 @@ class QueryBuilder {
|
|
|
856
856
|
// Edge kind varies across framework resolvers: Spring/Rails/
|
|
857
857
|
// Laravel/Drupal emit `references`, Express emits `calls`. Accept
|
|
858
858
|
// both — the semantic is the same (route → its handler).
|
|
859
|
-
this.stmts.getRoutingManifest = this.db.prepare(`
|
|
860
|
-
SELECT
|
|
861
|
-
r.name AS url,
|
|
862
|
-
h.name AS handler,
|
|
863
|
-
h.file_path AS handler_file,
|
|
864
|
-
h.start_line AS handler_line,
|
|
865
|
-
h.kind AS handler_kind
|
|
866
|
-
FROM nodes r
|
|
867
|
-
JOIN edges e ON e.source = r.id
|
|
868
|
-
JOIN nodes h ON e.target = h.id
|
|
869
|
-
WHERE r.kind = 'route'
|
|
870
|
-
AND e.kind IN ('references', 'calls')
|
|
871
|
-
AND h.kind IN ('function', 'method', 'class')
|
|
872
|
-
ORDER BY r.file_path, r.start_line
|
|
873
|
-
LIMIT ?
|
|
859
|
+
this.stmts.getRoutingManifest = this.db.prepare(`
|
|
860
|
+
SELECT
|
|
861
|
+
r.name AS url,
|
|
862
|
+
h.name AS handler,
|
|
863
|
+
h.file_path AS handler_file,
|
|
864
|
+
h.start_line AS handler_line,
|
|
865
|
+
h.kind AS handler_kind
|
|
866
|
+
FROM nodes r
|
|
867
|
+
JOIN edges e ON e.source = r.id
|
|
868
|
+
JOIN nodes h ON e.target = h.id
|
|
869
|
+
WHERE r.kind = 'route'
|
|
870
|
+
AND e.kind IN ('references', 'calls')
|
|
871
|
+
AND h.kind IN ('function', 'method', 'class')
|
|
872
|
+
ORDER BY r.file_path, r.start_line
|
|
873
|
+
LIMIT ?
|
|
874
874
|
`);
|
|
875
875
|
}
|
|
876
876
|
const rows = this.stmts.getRoutingManifest.all(limit);
|
|
@@ -1234,11 +1234,11 @@ class QueryBuilder {
|
|
|
1234
1234
|
// Fetch 5x requested limit so post-hoc rescoring (kindBonus, pathRelevance,
|
|
1235
1235
|
// nameMatchBonus) can promote results that BM25 alone undervalues.
|
|
1236
1236
|
const ftsLimit = Math.max(limit * 5, 100);
|
|
1237
|
-
let sql = `
|
|
1238
|
-
SELECT nodes.*, bm25(nodes_fts, 0, 20, 5, 1, 2) as score
|
|
1239
|
-
FROM nodes_fts
|
|
1240
|
-
JOIN nodes ON nodes_fts.id = nodes.id
|
|
1241
|
-
WHERE nodes_fts MATCH ?
|
|
1237
|
+
let sql = `
|
|
1238
|
+
SELECT nodes.*, bm25(nodes_fts, 0, 20, 5, 1, 2) as score
|
|
1239
|
+
FROM nodes_fts
|
|
1240
|
+
JOIN nodes ON nodes_fts.id = nodes.id
|
|
1241
|
+
WHERE nodes_fts MATCH ?
|
|
1242
1242
|
`;
|
|
1243
1243
|
const params = [ftsQuery];
|
|
1244
1244
|
if (kinds && kinds.length > 0) {
|
|
@@ -1269,21 +1269,21 @@ class QueryBuilder {
|
|
|
1269
1269
|
*/
|
|
1270
1270
|
searchNodesLike(query, options) {
|
|
1271
1271
|
const { kinds, languages, limit = 100, offset = 0 } = options;
|
|
1272
|
-
let sql = `
|
|
1273
|
-
SELECT nodes.*,
|
|
1274
|
-
CASE
|
|
1275
|
-
WHEN name = ? THEN 1.0
|
|
1276
|
-
WHEN name LIKE ? THEN 0.9
|
|
1277
|
-
WHEN name LIKE ? THEN 0.8
|
|
1278
|
-
WHEN qualified_name LIKE ? THEN 0.7
|
|
1279
|
-
ELSE 0.5
|
|
1280
|
-
END as score
|
|
1281
|
-
FROM nodes
|
|
1282
|
-
WHERE (
|
|
1283
|
-
name LIKE ? OR
|
|
1284
|
-
qualified_name LIKE ? OR
|
|
1285
|
-
name LIKE ?
|
|
1286
|
-
)
|
|
1272
|
+
let sql = `
|
|
1273
|
+
SELECT nodes.*,
|
|
1274
|
+
CASE
|
|
1275
|
+
WHEN name = ? THEN 1.0
|
|
1276
|
+
WHEN name LIKE ? THEN 0.9
|
|
1277
|
+
WHEN name LIKE ? THEN 0.8
|
|
1278
|
+
WHEN qualified_name LIKE ? THEN 0.7
|
|
1279
|
+
ELSE 0.5
|
|
1280
|
+
END as score
|
|
1281
|
+
FROM nodes
|
|
1282
|
+
WHERE (
|
|
1283
|
+
name LIKE ? OR
|
|
1284
|
+
qualified_name LIKE ? OR
|
|
1285
|
+
name LIKE ?
|
|
1286
|
+
)
|
|
1287
1287
|
`;
|
|
1288
1288
|
// Pattern variants for better matching
|
|
1289
1289
|
const exactMatch = query;
|
|
@@ -1357,10 +1357,10 @@ class QueryBuilder {
|
|
|
1357
1357
|
const allResults = [];
|
|
1358
1358
|
const seenIds = new Set();
|
|
1359
1359
|
for (const name of names) {
|
|
1360
|
-
let sql = `
|
|
1361
|
-
SELECT nodes.*, 1.0 as score
|
|
1362
|
-
FROM nodes
|
|
1363
|
-
WHERE name COLLATE NOCASE = ?
|
|
1360
|
+
let sql = `
|
|
1361
|
+
SELECT nodes.*, 1.0 as score
|
|
1362
|
+
FROM nodes
|
|
1363
|
+
WHERE name COLLATE NOCASE = ?
|
|
1364
1364
|
`;
|
|
1365
1365
|
const params = [name];
|
|
1366
1366
|
if (kinds && kinds.length > 0) {
|
|
@@ -1404,10 +1404,10 @@ class QueryBuilder {
|
|
|
1404
1404
|
*/
|
|
1405
1405
|
findNodesByNameSubstring(substring, options = {}) {
|
|
1406
1406
|
const { kinds, languages, limit = 30, excludePrefix } = options;
|
|
1407
|
-
let sql = `
|
|
1408
|
-
SELECT nodes.*, 1.0 as score
|
|
1409
|
-
FROM nodes
|
|
1410
|
-
WHERE name LIKE ?
|
|
1407
|
+
let sql = `
|
|
1408
|
+
SELECT nodes.*, 1.0 as score
|
|
1409
|
+
FROM nodes
|
|
1410
|
+
WHERE name LIKE ?
|
|
1411
1411
|
`;
|
|
1412
1412
|
const params = [`%${substring}%`];
|
|
1413
1413
|
// Exclude prefix matches (handled by FTS-based prefix search in Step 2b)
|
|
@@ -1439,9 +1439,9 @@ class QueryBuilder {
|
|
|
1439
1439
|
*/
|
|
1440
1440
|
insertEdge(edge) {
|
|
1441
1441
|
if (!this.stmts.insertEdge) {
|
|
1442
|
-
this.stmts.insertEdge = this.db.prepare(`
|
|
1443
|
-
INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance, confidence, resolved_by)
|
|
1444
|
-
VALUES (@source, @target, @kind, @metadata, @line, @col, @provenance, @confidence, @resolvedBy)
|
|
1442
|
+
this.stmts.insertEdge = this.db.prepare(`
|
|
1443
|
+
INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance, confidence, resolved_by)
|
|
1444
|
+
VALUES (@source, @target, @kind, @metadata, @line, @col, @provenance, @confidence, @resolvedBy)
|
|
1445
1445
|
`);
|
|
1446
1446
|
}
|
|
1447
1447
|
this.stmts.insertEdge.run({
|
|
@@ -1571,18 +1571,18 @@ class QueryBuilder {
|
|
|
1571
1571
|
* it. One indexed query (idx_nodes_file_path + idx_edges_target_kind).
|
|
1572
1572
|
*/
|
|
1573
1573
|
getDependentFilePaths(filePath) {
|
|
1574
|
-
const sql = `SELECT DISTINCT src.file_path AS fp
|
|
1575
|
-
FROM edges e
|
|
1576
|
-
JOIN nodes tgt ON tgt.id = e.target
|
|
1577
|
-
JOIN nodes src ON src.id = e.source
|
|
1578
|
-
WHERE tgt.file_path = ?
|
|
1579
|
-
AND e.kind != 'contains'
|
|
1580
|
-
AND src.file_path != ?
|
|
1581
|
-
AND (
|
|
1582
|
-
e.kind = 'imports'
|
|
1583
|
-
OR src.language NOT IN (${UNCORROBORATED_FILTER_LANGUAGES_SQL_LIST})
|
|
1584
|
-
OR e.resolved_by IS NULL
|
|
1585
|
-
OR e.resolved_by NOT IN (${UNCORROBORATED_RESOLVED_BY_SQL_LIST})
|
|
1574
|
+
const sql = `SELECT DISTINCT src.file_path AS fp
|
|
1575
|
+
FROM edges e
|
|
1576
|
+
JOIN nodes tgt ON tgt.id = e.target
|
|
1577
|
+
JOIN nodes src ON src.id = e.source
|
|
1578
|
+
WHERE tgt.file_path = ?
|
|
1579
|
+
AND e.kind != 'contains'
|
|
1580
|
+
AND src.file_path != ?
|
|
1581
|
+
AND (
|
|
1582
|
+
e.kind = 'imports'
|
|
1583
|
+
OR src.language NOT IN (${UNCORROBORATED_FILTER_LANGUAGES_SQL_LIST})
|
|
1584
|
+
OR e.resolved_by IS NULL
|
|
1585
|
+
OR e.resolved_by NOT IN (${UNCORROBORATED_RESOLVED_BY_SQL_LIST})
|
|
1586
1586
|
)`;
|
|
1587
1587
|
const rows = this.db.prepare(sql).all(filePath, filePath);
|
|
1588
1588
|
return rows.map((r) => r.fp);
|
|
@@ -1594,18 +1594,18 @@ class QueryBuilder {
|
|
|
1594
1594
|
* (all kinds except `contains`); same reason imports-only is insufficient.
|
|
1595
1595
|
*/
|
|
1596
1596
|
getDependencyFilePaths(filePath) {
|
|
1597
|
-
const sql = `SELECT DISTINCT tgt.file_path AS fp
|
|
1598
|
-
FROM edges e
|
|
1599
|
-
JOIN nodes src ON src.id = e.source
|
|
1600
|
-
JOIN nodes tgt ON tgt.id = e.target
|
|
1601
|
-
WHERE src.file_path = ?
|
|
1602
|
-
AND e.kind != 'contains'
|
|
1603
|
-
AND tgt.file_path != ?
|
|
1604
|
-
AND (
|
|
1605
|
-
e.kind = 'imports'
|
|
1606
|
-
OR src.language NOT IN (${UNCORROBORATED_FILTER_LANGUAGES_SQL_LIST})
|
|
1607
|
-
OR e.resolved_by IS NULL
|
|
1608
|
-
OR e.resolved_by NOT IN (${UNCORROBORATED_RESOLVED_BY_SQL_LIST})
|
|
1597
|
+
const sql = `SELECT DISTINCT tgt.file_path AS fp
|
|
1598
|
+
FROM edges e
|
|
1599
|
+
JOIN nodes src ON src.id = e.source
|
|
1600
|
+
JOIN nodes tgt ON tgt.id = e.target
|
|
1601
|
+
WHERE src.file_path = ?
|
|
1602
|
+
AND e.kind != 'contains'
|
|
1603
|
+
AND tgt.file_path != ?
|
|
1604
|
+
AND (
|
|
1605
|
+
e.kind = 'imports'
|
|
1606
|
+
OR src.language NOT IN (${UNCORROBORATED_FILTER_LANGUAGES_SQL_LIST})
|
|
1607
|
+
OR e.resolved_by IS NULL
|
|
1608
|
+
OR e.resolved_by NOT IN (${UNCORROBORATED_RESOLVED_BY_SQL_LIST})
|
|
1609
1609
|
)`;
|
|
1610
1610
|
const rows = this.db.prepare(sql).all(filePath, filePath);
|
|
1611
1611
|
return rows.map((r) => r.fp);
|
|
@@ -1621,13 +1621,13 @@ class QueryBuilder {
|
|
|
1621
1621
|
* {@link getDependentFilePaths}: all kinds except `contains`.
|
|
1622
1622
|
*/
|
|
1623
1623
|
getCrossFileIncomingEdgesWithTarget(filePath) {
|
|
1624
|
-
const sql = `SELECT e.*, tgt.name AS target_name, tgt.kind AS target_kind,
|
|
1625
|
-
src.file_path AS source_file_path, src.language AS source_language
|
|
1626
|
-
FROM edges e
|
|
1627
|
-
JOIN nodes tgt ON tgt.id = e.target
|
|
1628
|
-
JOIN nodes src ON src.id = e.source
|
|
1629
|
-
WHERE tgt.file_path = ?
|
|
1630
|
-
AND e.kind != 'contains'
|
|
1624
|
+
const sql = `SELECT e.*, tgt.name AS target_name, tgt.kind AS target_kind,
|
|
1625
|
+
src.file_path AS source_file_path, src.language AS source_language
|
|
1626
|
+
FROM edges e
|
|
1627
|
+
JOIN nodes tgt ON tgt.id = e.target
|
|
1628
|
+
JOIN nodes src ON src.id = e.source
|
|
1629
|
+
WHERE tgt.file_path = ?
|
|
1630
|
+
AND e.kind != 'contains'
|
|
1631
1631
|
AND src.file_path != ?`;
|
|
1632
1632
|
const rows = this.db.prepare(sql).all(filePath, filePath);
|
|
1633
1633
|
return rows.map(row => ({
|
|
@@ -1646,18 +1646,18 @@ class QueryBuilder {
|
|
|
1646
1646
|
*/
|
|
1647
1647
|
upsertFile(file) {
|
|
1648
1648
|
if (!this.stmts.upsertFile) {
|
|
1649
|
-
this.stmts.upsertFile = this.db.prepare(`
|
|
1650
|
-
INSERT INTO files (path, content_hash, language, size, modified_at, indexed_at, node_count, extraction_version, errors)
|
|
1651
|
-
VALUES (@path, @contentHash, @language, @size, @modifiedAt, @indexedAt, @nodeCount, @extractionVersion, @errors)
|
|
1652
|
-
ON CONFLICT(path) DO UPDATE SET
|
|
1653
|
-
content_hash = @contentHash,
|
|
1654
|
-
language = @language,
|
|
1655
|
-
size = @size,
|
|
1656
|
-
modified_at = @modifiedAt,
|
|
1657
|
-
indexed_at = @indexedAt,
|
|
1658
|
-
node_count = @nodeCount,
|
|
1659
|
-
extraction_version = @extractionVersion,
|
|
1660
|
-
errors = @errors
|
|
1649
|
+
this.stmts.upsertFile = this.db.prepare(`
|
|
1650
|
+
INSERT INTO files (path, content_hash, language, size, modified_at, indexed_at, node_count, extraction_version, errors)
|
|
1651
|
+
VALUES (@path, @contentHash, @language, @size, @modifiedAt, @indexedAt, @nodeCount, @extractionVersion, @errors)
|
|
1652
|
+
ON CONFLICT(path) DO UPDATE SET
|
|
1653
|
+
content_hash = @contentHash,
|
|
1654
|
+
language = @language,
|
|
1655
|
+
size = @size,
|
|
1656
|
+
modified_at = @modifiedAt,
|
|
1657
|
+
indexed_at = @indexedAt,
|
|
1658
|
+
node_count = @nodeCount,
|
|
1659
|
+
extraction_version = @extractionVersion,
|
|
1660
|
+
errors = @errors
|
|
1661
1661
|
`);
|
|
1662
1662
|
}
|
|
1663
1663
|
this.stmts.upsertFile.run({
|
|
@@ -1771,9 +1771,9 @@ class QueryBuilder {
|
|
|
1771
1771
|
*/
|
|
1772
1772
|
insertUnresolvedRef(ref) {
|
|
1773
1773
|
if (!this.stmts.insertUnresolved) {
|
|
1774
|
-
this.stmts.insertUnresolved = this.db.prepare(`
|
|
1775
|
-
INSERT INTO unresolved_refs (from_node_id, reference_name, reference_kind, line, col, candidates, file_path, language, binding_form, imported_name)
|
|
1776
|
-
VALUES (@fromNodeId, @referenceName, @referenceKind, @line, @col, @candidates, @filePath, @language, @bindingForm, @importedName)
|
|
1774
|
+
this.stmts.insertUnresolved = this.db.prepare(`
|
|
1775
|
+
INSERT INTO unresolved_refs (from_node_id, reference_name, reference_kind, line, col, candidates, file_path, language, binding_form, imported_name)
|
|
1776
|
+
VALUES (@fromNodeId, @referenceName, @referenceKind, @line, @col, @candidates, @filePath, @language, @bindingForm, @importedName)
|
|
1777
1777
|
`);
|
|
1778
1778
|
}
|
|
1779
1779
|
this.stmts.insertUnresolved.run({
|
|
@@ -2246,11 +2246,11 @@ class QueryBuilder {
|
|
|
2246
2246
|
*/
|
|
2247
2247
|
getStats() {
|
|
2248
2248
|
// Single query for all three aggregate counts
|
|
2249
|
-
const counts = this.db.prepare(`
|
|
2250
|
-
SELECT
|
|
2251
|
-
(SELECT COUNT(*) FROM nodes) AS node_count,
|
|
2252
|
-
(SELECT COUNT(*) FROM edges) AS edge_count,
|
|
2253
|
-
(SELECT COUNT(*) FROM files) AS file_count
|
|
2249
|
+
const counts = this.db.prepare(`
|
|
2250
|
+
SELECT
|
|
2251
|
+
(SELECT COUNT(*) FROM nodes) AS node_count,
|
|
2252
|
+
(SELECT COUNT(*) FROM edges) AS edge_count,
|
|
2253
|
+
(SELECT COUNT(*) FROM files) AS file_count
|
|
2254
2254
|
`).get();
|
|
2255
2255
|
const nodesByKind = {};
|
|
2256
2256
|
const nodeKindRows = this.db
|