homegraph 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +243 -243
  3. package/dist/bin/homegraph.js +371 -9
  4. package/dist/bin/homegraph.js.map +1 -1
  5. package/dist/db/migrations.js +18 -18
  6. package/dist/db/queries.js +140 -140
  7. package/dist/db/schema.sql +152 -152
  8. package/dist/directory.js +5 -5
  9. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  10. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  11. package/dist/installer/instructions-template.js +9 -9
  12. package/dist/installer/targets/shared.d.ts +5 -6
  13. package/dist/installer/targets/shared.d.ts.map +1 -1
  14. package/dist/installer/targets/shared.js +5 -6
  15. package/dist/installer/targets/shared.js.map +1 -1
  16. package/dist/mcp/liveness-watchdog.js +16 -16
  17. package/dist/mcp/server-instructions.js +69 -69
  18. package/dist/mcp/tools.d.ts +17 -4
  19. package/dist/mcp/tools.d.ts.map +1 -1
  20. package/dist/mcp/tools.js +192 -22
  21. package/dist/mcp/tools.js.map +1 -1
  22. package/dist/reasoning/reasoner.js +32 -32
  23. package/dist/spec/config.d.ts +43 -0
  24. package/dist/spec/config.d.ts.map +1 -0
  25. package/dist/spec/config.js +275 -0
  26. package/dist/spec/config.js.map +1 -0
  27. package/dist/spec/db/commit-node.d.ts +23 -0
  28. package/dist/spec/db/commit-node.d.ts.map +1 -0
  29. package/dist/spec/db/commit-node.js +62 -0
  30. package/dist/spec/db/commit-node.js.map +1 -0
  31. package/dist/spec/db/fragment-node.d.ts +23 -0
  32. package/dist/spec/db/fragment-node.d.ts.map +1 -0
  33. package/dist/spec/db/fragment-node.js +120 -0
  34. package/dist/spec/db/fragment-node.js.map +1 -0
  35. package/dist/spec/db/fts.d.ts +60 -0
  36. package/dist/spec/db/fts.d.ts.map +1 -0
  37. package/dist/spec/db/fts.js +285 -0
  38. package/dist/spec/db/fts.js.map +1 -0
  39. package/dist/spec/db/index.d.ts +13 -0
  40. package/dist/spec/db/index.d.ts.map +1 -0
  41. package/dist/spec/db/index.js +50 -0
  42. package/dist/spec/db/index.js.map +1 -0
  43. package/dist/spec/db/relations.d.ts +55 -0
  44. package/dist/spec/db/relations.d.ts.map +1 -0
  45. package/dist/spec/db/relations.js +158 -0
  46. package/dist/spec/db/relations.js.map +1 -0
  47. package/dist/spec/db/schema.d.ts +30 -0
  48. package/dist/spec/db/schema.d.ts.map +1 -0
  49. package/dist/spec/db/schema.js +87 -0
  50. package/dist/spec/db/schema.js.map +1 -0
  51. package/dist/spec/db/schema.sql +107 -0
  52. package/dist/spec/db/spec-node.d.ts +41 -0
  53. package/dist/spec/db/spec-node.d.ts.map +1 -0
  54. package/dist/spec/db/spec-node.js +114 -0
  55. package/dist/spec/db/spec-node.js.map +1 -0
  56. package/dist/spec/evolve/impact-locator.d.ts +13 -0
  57. package/dist/spec/evolve/impact-locator.d.ts.map +1 -0
  58. package/dist/spec/evolve/impact-locator.js +25 -0
  59. package/dist/spec/evolve/impact-locator.js.map +1 -0
  60. package/dist/spec/evolve/llm-client.d.ts +50 -0
  61. package/dist/spec/evolve/llm-client.d.ts.map +1 -0
  62. package/dist/spec/evolve/llm-client.js +176 -0
  63. package/dist/spec/evolve/llm-client.js.map +1 -0
  64. package/dist/spec/evolve/logic-checker.d.ts +12 -0
  65. package/dist/spec/evolve/logic-checker.d.ts.map +1 -0
  66. package/dist/spec/evolve/logic-checker.js +48 -0
  67. package/dist/spec/evolve/logic-checker.js.map +1 -0
  68. package/dist/spec/evolve/pipeline.d.ts +40 -0
  69. package/dist/spec/evolve/pipeline.d.ts.map +1 -0
  70. package/dist/spec/evolve/pipeline.js +314 -0
  71. package/dist/spec/evolve/pipeline.js.map +1 -0
  72. package/dist/spec/evolve/spec-rewriter.d.ts +42 -0
  73. package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -0
  74. package/dist/spec/evolve/spec-rewriter.js +254 -0
  75. package/dist/spec/evolve/spec-rewriter.js.map +1 -0
  76. package/dist/spec/graph/queries.d.ts +58 -0
  77. package/dist/spec/graph/queries.d.ts.map +1 -0
  78. package/dist/spec/graph/queries.js +215 -0
  79. package/dist/spec/graph/queries.js.map +1 -0
  80. package/dist/spec/mining/diff-parser.d.ts +33 -0
  81. package/dist/spec/mining/diff-parser.d.ts.map +1 -0
  82. package/dist/spec/mining/diff-parser.js +166 -0
  83. package/dist/spec/mining/diff-parser.js.map +1 -0
  84. package/dist/spec/mining/git-scanner.d.ts +91 -0
  85. package/dist/spec/mining/git-scanner.d.ts.map +1 -0
  86. package/dist/spec/mining/git-scanner.js +266 -0
  87. package/dist/spec/mining/git-scanner.js.map +1 -0
  88. package/dist/spec/mining/pipeline.d.ts +53 -0
  89. package/dist/spec/mining/pipeline.d.ts.map +1 -0
  90. package/dist/spec/mining/pipeline.js +165 -0
  91. package/dist/spec/mining/pipeline.js.map +1 -0
  92. package/dist/spec/mining/scope-resolver.d.ts +45 -0
  93. package/dist/spec/mining/scope-resolver.d.ts.map +1 -0
  94. package/dist/spec/mining/scope-resolver.js +103 -0
  95. package/dist/spec/mining/scope-resolver.js.map +1 -0
  96. package/dist/spec/mining/spec-extractor.d.ts +69 -0
  97. package/dist/spec/mining/spec-extractor.d.ts.map +1 -0
  98. package/dist/spec/mining/spec-extractor.js +369 -0
  99. package/dist/spec/mining/spec-extractor.js.map +1 -0
  100. package/dist/spec/types.d.ts +149 -0
  101. package/dist/spec/types.d.ts.map +1 -0
  102. package/dist/spec/types.js +15 -0
  103. package/dist/spec/types.js.map +1 -0
  104. package/dist/spec/utils.d.ts +166 -0
  105. package/dist/spec/utils.d.ts.map +1 -0
  106. package/dist/spec/utils.js +461 -0
  107. package/dist/spec/utils.js.map +1 -0
  108. package/package.json +58 -57
  109. package/scripts/add-lang/bench.sh +60 -60
  110. package/scripts/add-lang/check-grammar.mjs +75 -75
  111. package/scripts/add-lang/dump-ast.mjs +103 -103
  112. package/scripts/add-lang/verify-extraction.mjs +70 -70
  113. package/scripts/agent-eval/ab-adoption.sh +91 -91
  114. package/scripts/agent-eval/ab-hook.sh +86 -86
  115. package/scripts/agent-eval/ab-impl.sh +78 -78
  116. package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -102
  117. package/scripts/agent-eval/ab-sufficiency.sh +78 -78
  118. package/scripts/agent-eval/arms-F.sh +21 -21
  119. package/scripts/agent-eval/arms-matrix.sh +37 -37
  120. package/scripts/agent-eval/audit.sh +68 -68
  121. package/scripts/agent-eval/bench-readme.sh +28 -28
  122. package/scripts/agent-eval/bench-why-repo.sh +22 -22
  123. package/scripts/agent-eval/block-read-hook.sh +19 -19
  124. package/scripts/agent-eval/hook-settings.json +15 -15
  125. package/scripts/agent-eval/itrun.sh +120 -120
  126. package/scripts/agent-eval/offload-eval-3arm.sh +72 -72
  127. package/scripts/agent-eval/offload-eval-cost.mjs +133 -133
  128. package/scripts/agent-eval/offload-eval-effort.mjs +108 -108
  129. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -25
  130. package/scripts/agent-eval/offload-eval-frontload.sh +47 -47
  131. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -18
  132. package/scripts/agent-eval/offload-eval-hook.mjs +84 -84
  133. package/scripts/agent-eval/offload-eval-judge.mjs +103 -103
  134. package/scripts/agent-eval/offload-eval-matrix.sh +20 -20
  135. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -94
  136. package/scripts/agent-eval/offload-eval-refs1.sh +50 -50
  137. package/scripts/agent-eval/offload-eval-setup.sh +24 -24
  138. package/scripts/agent-eval/offload-eval-styles.sh +71 -71
  139. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -68
  140. package/scripts/agent-eval/offload-eval.md +76 -76
  141. package/scripts/agent-eval/parse-arms.mjs +116 -116
  142. package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
  143. package/scripts/agent-eval/parse-run.mjs +45 -45
  144. package/scripts/agent-eval/parse-session.mjs +93 -93
  145. package/scripts/agent-eval/probe-context.mjs +21 -21
  146. package/scripts/agent-eval/probe-explore.mjs +40 -40
  147. package/scripts/agent-eval/probe-node.mjs +20 -20
  148. package/scripts/agent-eval/probe-sweep.mjs +119 -119
  149. package/scripts/agent-eval/probe-trace.mjs +20 -20
  150. package/scripts/agent-eval/redirect-read-hook.sh +38 -38
  151. package/scripts/agent-eval/run-agent.sh +34 -34
  152. package/scripts/agent-eval/run-all.sh +69 -69
  153. package/scripts/agent-eval/run-arms.sh +56 -56
  154. package/scripts/agent-eval/seq-matrix.mjs +137 -137
  155. package/scripts/build-bundle.sh +118 -118
  156. package/scripts/extract-release-notes.mjs +130 -130
  157. package/scripts/local-install.sh +41 -41
  158. package/scripts/npm-sdk.js +75 -75
  159. package/scripts/npm-shim.js +246 -246
  160. package/scripts/pack-npm.sh +119 -119
  161. package/scripts/prepare-release.mjs +270 -270
  162. package/scripts/qa_eval/README.md +407 -404
  163. package/scripts/qa_eval/_test_deveco_probe.py +41 -41
  164. package/scripts/qa_eval/agent_runner.py +526 -526
  165. package/scripts/qa_eval/data/.gitignore +4 -4
  166. package/scripts/qa_eval/data/test-set.jsonl +2 -22
  167. package/scripts/qa_eval/eval_metrics.py +274 -233
  168. package/scripts/qa_eval/external_agent.py +976 -671
  169. package/scripts/qa_eval/llm_config.py +92 -92
  170. package/scripts/qa_eval/memory_monitor.py +132 -132
  171. package/scripts/qa_eval/my_answer_accuracy.py +187 -187
  172. package/scripts/qa_eval/requirements.txt +2 -2
  173. package/scripts/qa_eval/run_pipeline.py +804 -711
  174. package/scripts/qa_eval/stats_efficiency.py +279 -279
  175. package/scripts/qa_eval/stats_scores.py +207 -207
@@ -125,20 +125,20 @@ class QueryBuilder {
125
125
  */
126
126
  insertNode(node) {
127
127
  if (!this.stmts.insertNode) {
128
- this.stmts.insertNode = this.db.prepare(`
129
- INSERT OR REPLACE INTO nodes (
130
- id, kind, name, qualified_name, file_path, language,
131
- start_line, end_line, start_column, end_column,
132
- docstring, signature, visibility,
133
- is_exported, is_async, is_static, is_abstract,
134
- decorators, type_parameters, return_type, updated_at
135
- ) VALUES (
136
- @id, @kind, @name, @qualifiedName, @filePath, @language,
137
- @startLine, @endLine, @startColumn, @endColumn,
138
- @docstring, @signature, @visibility,
139
- @isExported, @isAsync, @isStatic, @isAbstract,
140
- @decorators, @typeParameters, @returnType, @updatedAt
141
- )
128
+ this.stmts.insertNode = this.db.prepare(`
129
+ INSERT OR REPLACE INTO nodes (
130
+ id, kind, name, qualified_name, file_path, language,
131
+ start_line, end_line, start_column, end_column,
132
+ docstring, signature, visibility,
133
+ is_exported, is_async, is_static, is_abstract,
134
+ decorators, type_parameters, return_type, updated_at
135
+ ) VALUES (
136
+ @id, @kind, @name, @qualifiedName, @filePath, @language,
137
+ @startLine, @endLine, @startColumn, @endColumn,
138
+ @docstring, @signature, @visibility,
139
+ @isExported, @isAsync, @isStatic, @isAbstract,
140
+ @decorators, @typeParameters, @returnType, @updatedAt
141
+ )
142
142
  `);
143
143
  }
144
144
  // Validate required fields to prevent SQLite bind errors
@@ -196,29 +196,29 @@ class QueryBuilder {
196
196
  */
197
197
  updateNode(node) {
198
198
  if (!this.stmts.updateNode) {
199
- this.stmts.updateNode = this.db.prepare(`
200
- UPDATE nodes SET
201
- kind = @kind,
202
- name = @name,
203
- qualified_name = @qualifiedName,
204
- file_path = @filePath,
205
- language = @language,
206
- start_line = @startLine,
207
- end_line = @endLine,
208
- start_column = @startColumn,
209
- end_column = @endColumn,
210
- docstring = @docstring,
211
- signature = @signature,
212
- visibility = @visibility,
213
- is_exported = @isExported,
214
- is_async = @isAsync,
215
- is_static = @isStatic,
216
- is_abstract = @isAbstract,
217
- decorators = @decorators,
218
- type_parameters = @typeParameters,
219
- return_type = @returnType,
220
- updated_at = @updatedAt
221
- WHERE id = @id
199
+ this.stmts.updateNode = this.db.prepare(`
200
+ UPDATE nodes SET
201
+ kind = @kind,
202
+ name = @name,
203
+ qualified_name = @qualifiedName,
204
+ file_path = @filePath,
205
+ language = @language,
206
+ start_line = @startLine,
207
+ end_line = @endLine,
208
+ start_column = @startColumn,
209
+ end_column = @endColumn,
210
+ docstring = @docstring,
211
+ signature = @signature,
212
+ visibility = @visibility,
213
+ is_exported = @isExported,
214
+ is_async = @isAsync,
215
+ is_static = @isStatic,
216
+ is_abstract = @isAbstract,
217
+ decorators = @decorators,
218
+ type_parameters = @typeParameters,
219
+ return_type = @returnType,
220
+ updated_at = @updatedAt
221
+ WHERE id = @id
222
222
  `);
223
223
  }
224
224
  // Invalidate cache before update
@@ -426,15 +426,15 @@ class QueryBuilder {
426
426
  // protobuf stub) outranks the real `server/etcdserver/server.go`
427
427
  // (470 edges) by 4×, and the boost would push the agent toward
428
428
  // generated code.
429
- this.stmts.getDominantFile = this.db.prepare(`
430
- SELECT n.file_path AS file_path, COUNT(*) AS edge_count
431
- FROM edges e
432
- JOIN nodes n ON e.source = n.id
433
- JOIN nodes m ON e.target = m.id
434
- WHERE n.file_path = m.file_path
435
- GROUP BY n.file_path
436
- ORDER BY edge_count DESC
437
- LIMIT 20
429
+ this.stmts.getDominantFile = this.db.prepare(`
430
+ SELECT n.file_path AS file_path, COUNT(*) AS edge_count
431
+ FROM edges e
432
+ JOIN nodes n ON e.source = n.id
433
+ JOIN nodes m ON e.target = m.id
434
+ WHERE n.file_path = m.file_path
435
+ GROUP BY n.file_path
436
+ ORDER BY edge_count DESC
437
+ LIMIT 20
438
438
  `);
439
439
  }
440
440
  const rows = this.stmts.getDominantFile.all();
@@ -461,13 +461,13 @@ class QueryBuilder {
461
461
  */
462
462
  getTopRouteFile() {
463
463
  if (!this.stmts.getTopRouteFile) {
464
- this.stmts.getTopRouteFile = this.db.prepare(`
465
- SELECT file_path, COUNT(*) AS cnt
466
- FROM nodes
467
- WHERE kind = 'route'
468
- GROUP BY file_path
469
- ORDER BY cnt DESC
470
- LIMIT 20
464
+ this.stmts.getTopRouteFile = this.db.prepare(`
465
+ SELECT file_path, COUNT(*) AS cnt
466
+ FROM nodes
467
+ WHERE kind = 'route'
468
+ GROUP BY file_path
469
+ ORDER BY cnt DESC
470
+ LIMIT 20
471
471
  `);
472
472
  }
473
473
  const rows = this.stmts.getTopRouteFile.all();
@@ -498,21 +498,21 @@ class QueryBuilder {
498
498
  // Edge kind varies across framework resolvers: Spring/Rails/
499
499
  // Laravel/Drupal emit `references`, Express emits `calls`. Accept
500
500
  // both — the semantic is the same (route → its handler).
501
- this.stmts.getRoutingManifest = this.db.prepare(`
502
- SELECT
503
- r.name AS url,
504
- h.name AS handler,
505
- h.file_path AS handler_file,
506
- h.start_line AS handler_line,
507
- h.kind AS handler_kind
508
- FROM nodes r
509
- JOIN edges e ON e.source = r.id
510
- JOIN nodes h ON e.target = h.id
511
- WHERE r.kind = 'route'
512
- AND e.kind IN ('references', 'calls')
513
- AND h.kind IN ('function', 'method', 'class')
514
- ORDER BY r.file_path, r.start_line
515
- LIMIT ?
501
+ this.stmts.getRoutingManifest = this.db.prepare(`
502
+ SELECT
503
+ r.name AS url,
504
+ h.name AS handler,
505
+ h.file_path AS handler_file,
506
+ h.start_line AS handler_line,
507
+ h.kind AS handler_kind
508
+ FROM nodes r
509
+ JOIN edges e ON e.source = r.id
510
+ JOIN nodes h ON e.target = h.id
511
+ WHERE r.kind = 'route'
512
+ AND e.kind IN ('references', 'calls')
513
+ AND h.kind IN ('function', 'method', 'class')
514
+ ORDER BY r.file_path, r.start_line
515
+ LIMIT ?
516
516
  `);
517
517
  }
518
518
  const rows = this.stmts.getRoutingManifest.all(limit);
@@ -838,11 +838,11 @@ class QueryBuilder {
838
838
  // Fetch 5x requested limit so post-hoc rescoring (kindBonus, pathRelevance,
839
839
  // nameMatchBonus) can promote results that BM25 alone undervalues.
840
840
  const ftsLimit = Math.max(limit * 5, 100);
841
- let sql = `
842
- SELECT nodes.*, bm25(nodes_fts, 0, 20, 5, 1, 2) as score
843
- FROM nodes_fts
844
- JOIN nodes ON nodes_fts.id = nodes.id
845
- WHERE nodes_fts MATCH ?
841
+ let sql = `
842
+ SELECT nodes.*, bm25(nodes_fts, 0, 20, 5, 1, 2) as score
843
+ FROM nodes_fts
844
+ JOIN nodes ON nodes_fts.id = nodes.id
845
+ WHERE nodes_fts MATCH ?
846
846
  `;
847
847
  const params = [ftsQuery];
848
848
  if (kinds && kinds.length > 0) {
@@ -873,21 +873,21 @@ class QueryBuilder {
873
873
  */
874
874
  searchNodesLike(query, options) {
875
875
  const { kinds, languages, limit = 100, offset = 0 } = options;
876
- let sql = `
877
- SELECT nodes.*,
878
- CASE
879
- WHEN name = ? THEN 1.0
880
- WHEN name LIKE ? THEN 0.9
881
- WHEN name LIKE ? THEN 0.8
882
- WHEN qualified_name LIKE ? THEN 0.7
883
- ELSE 0.5
884
- END as score
885
- FROM nodes
886
- WHERE (
887
- name LIKE ? OR
888
- qualified_name LIKE ? OR
889
- name LIKE ?
890
- )
876
+ let sql = `
877
+ SELECT nodes.*,
878
+ CASE
879
+ WHEN name = ? THEN 1.0
880
+ WHEN name LIKE ? THEN 0.9
881
+ WHEN name LIKE ? THEN 0.8
882
+ WHEN qualified_name LIKE ? THEN 0.7
883
+ ELSE 0.5
884
+ END as score
885
+ FROM nodes
886
+ WHERE (
887
+ name LIKE ? OR
888
+ qualified_name LIKE ? OR
889
+ name LIKE ?
890
+ )
891
891
  `;
892
892
  // Pattern variants for better matching
893
893
  const exactMatch = query;
@@ -961,10 +961,10 @@ class QueryBuilder {
961
961
  const allResults = [];
962
962
  const seenIds = new Set();
963
963
  for (const name of names) {
964
- let sql = `
965
- SELECT nodes.*, 1.0 as score
966
- FROM nodes
967
- WHERE name COLLATE NOCASE = ?
964
+ let sql = `
965
+ SELECT nodes.*, 1.0 as score
966
+ FROM nodes
967
+ WHERE name COLLATE NOCASE = ?
968
968
  `;
969
969
  const params = [name];
970
970
  if (kinds && kinds.length > 0) {
@@ -1008,10 +1008,10 @@ class QueryBuilder {
1008
1008
  */
1009
1009
  findNodesByNameSubstring(substring, options = {}) {
1010
1010
  const { kinds, languages, limit = 30, excludePrefix } = options;
1011
- let sql = `
1012
- SELECT nodes.*, 1.0 as score
1013
- FROM nodes
1014
- WHERE name LIKE ?
1011
+ let sql = `
1012
+ SELECT nodes.*, 1.0 as score
1013
+ FROM nodes
1014
+ WHERE name LIKE ?
1015
1015
  `;
1016
1016
  const params = [`%${substring}%`];
1017
1017
  // Exclude prefix matches (handled by FTS-based prefix search in Step 2b)
@@ -1043,9 +1043,9 @@ class QueryBuilder {
1043
1043
  */
1044
1044
  insertEdge(edge) {
1045
1045
  if (!this.stmts.insertEdge) {
1046
- this.stmts.insertEdge = this.db.prepare(`
1047
- INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance)
1048
- VALUES (@source, @target, @kind, @metadata, @line, @col, @provenance)
1046
+ this.stmts.insertEdge = this.db.prepare(`
1047
+ INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance)
1048
+ VALUES (@source, @target, @kind, @metadata, @line, @col, @provenance)
1049
1049
  `);
1050
1050
  }
1051
1051
  this.stmts.insertEdge.run({
@@ -1161,12 +1161,12 @@ class QueryBuilder {
1161
1161
  * it. One indexed query (idx_nodes_file_path + idx_edges_target_kind).
1162
1162
  */
1163
1163
  getDependentFilePaths(filePath) {
1164
- const sql = `SELECT DISTINCT src.file_path AS fp
1165
- FROM edges e
1166
- JOIN nodes tgt ON tgt.id = e.target
1167
- JOIN nodes src ON src.id = e.source
1168
- WHERE tgt.file_path = ?
1169
- AND e.kind != 'contains'
1164
+ const sql = `SELECT DISTINCT src.file_path AS fp
1165
+ FROM edges e
1166
+ JOIN nodes tgt ON tgt.id = e.target
1167
+ JOIN nodes src ON src.id = e.source
1168
+ WHERE tgt.file_path = ?
1169
+ AND e.kind != 'contains'
1170
1170
  AND src.file_path != ?`;
1171
1171
  const rows = this.db.prepare(sql).all(filePath, filePath);
1172
1172
  return rows.map((r) => r.fp);
@@ -1178,12 +1178,12 @@ class QueryBuilder {
1178
1178
  * (all kinds except `contains`); same reason imports-only is insufficient.
1179
1179
  */
1180
1180
  getDependencyFilePaths(filePath) {
1181
- const sql = `SELECT DISTINCT tgt.file_path AS fp
1182
- FROM edges e
1183
- JOIN nodes src ON src.id = e.source
1184
- JOIN nodes tgt ON tgt.id = e.target
1185
- WHERE src.file_path = ?
1186
- AND e.kind != 'contains'
1181
+ const sql = `SELECT DISTINCT tgt.file_path AS fp
1182
+ FROM edges e
1183
+ JOIN nodes src ON src.id = e.source
1184
+ JOIN nodes tgt ON tgt.id = e.target
1185
+ WHERE src.file_path = ?
1186
+ AND e.kind != 'contains'
1187
1187
  AND tgt.file_path != ?`;
1188
1188
  const rows = this.db.prepare(sql).all(filePath, filePath);
1189
1189
  return rows.map((r) => r.fp);
@@ -1199,12 +1199,12 @@ class QueryBuilder {
1199
1199
  * {@link getDependentFilePaths}: all kinds except `contains`.
1200
1200
  */
1201
1201
  getCrossFileIncomingEdgesWithTarget(filePath) {
1202
- const sql = `SELECT e.*, tgt.name AS target_name, tgt.kind AS target_kind
1203
- FROM edges e
1204
- JOIN nodes tgt ON tgt.id = e.target
1205
- JOIN nodes src ON src.id = e.source
1206
- WHERE tgt.file_path = ?
1207
- AND e.kind != 'contains'
1202
+ const sql = `SELECT e.*, tgt.name AS target_name, tgt.kind AS target_kind
1203
+ FROM edges e
1204
+ JOIN nodes tgt ON tgt.id = e.target
1205
+ JOIN nodes src ON src.id = e.source
1206
+ WHERE tgt.file_path = ?
1207
+ AND e.kind != 'contains'
1208
1208
  AND src.file_path != ?`;
1209
1209
  const rows = this.db.prepare(sql).all(filePath, filePath);
1210
1210
  return rows.map(row => ({
@@ -1219,10 +1219,10 @@ class QueryBuilder {
1219
1219
  */
1220
1220
  deleteArkTSCrossFileCallEdges() {
1221
1221
  const result = this.db
1222
- .prepare(`DELETE FROM edges
1223
- WHERE kind = 'calls'
1224
- AND provenance = 'heuristic'
1225
- AND metadata LIKE '%"synthesizedBy":"arkanalyzer"%'
1222
+ .prepare(`DELETE FROM edges
1223
+ WHERE kind = 'calls'
1224
+ AND provenance = 'heuristic'
1225
+ AND metadata LIKE '%"synthesizedBy":"arkanalyzer"%'
1226
1226
  AND metadata LIKE '%"sourceFile"%'`)
1227
1227
  .run();
1228
1228
  return result.changes;
@@ -1235,17 +1235,17 @@ class QueryBuilder {
1235
1235
  */
1236
1236
  upsertFile(file) {
1237
1237
  if (!this.stmts.upsertFile) {
1238
- this.stmts.upsertFile = this.db.prepare(`
1239
- INSERT INTO files (path, content_hash, language, size, modified_at, indexed_at, node_count, errors)
1240
- VALUES (@path, @contentHash, @language, @size, @modifiedAt, @indexedAt, @nodeCount, @errors)
1241
- ON CONFLICT(path) DO UPDATE SET
1242
- content_hash = @contentHash,
1243
- language = @language,
1244
- size = @size,
1245
- modified_at = @modifiedAt,
1246
- indexed_at = @indexedAt,
1247
- node_count = @nodeCount,
1248
- errors = @errors
1238
+ this.stmts.upsertFile = this.db.prepare(`
1239
+ INSERT INTO files (path, content_hash, language, size, modified_at, indexed_at, node_count, errors)
1240
+ VALUES (@path, @contentHash, @language, @size, @modifiedAt, @indexedAt, @nodeCount, @errors)
1241
+ ON CONFLICT(path) DO UPDATE SET
1242
+ content_hash = @contentHash,
1243
+ language = @language,
1244
+ size = @size,
1245
+ modified_at = @modifiedAt,
1246
+ indexed_at = @indexedAt,
1247
+ node_count = @nodeCount,
1248
+ errors = @errors
1249
1249
  `);
1250
1250
  }
1251
1251
  this.stmts.upsertFile.run({
@@ -1319,9 +1319,9 @@ class QueryBuilder {
1319
1319
  */
1320
1320
  insertUnresolvedRef(ref) {
1321
1321
  if (!this.stmts.insertUnresolved) {
1322
- this.stmts.insertUnresolved = this.db.prepare(`
1323
- INSERT INTO unresolved_refs (from_node_id, reference_name, reference_kind, line, col, candidates, file_path, language)
1324
- VALUES (@fromNodeId, @referenceName, @referenceKind, @line, @col, @candidates, @filePath, @language)
1322
+ this.stmts.insertUnresolved = this.db.prepare(`
1323
+ INSERT INTO unresolved_refs (from_node_id, reference_name, reference_kind, line, col, candidates, file_path, language)
1324
+ VALUES (@fromNodeId, @referenceName, @referenceKind, @line, @col, @candidates, @filePath, @language)
1325
1325
  `);
1326
1326
  }
1327
1327
  this.stmts.insertUnresolved.run({
@@ -1523,11 +1523,11 @@ class QueryBuilder {
1523
1523
  */
1524
1524
  getStats() {
1525
1525
  // Single query for all three aggregate counts
1526
- const counts = this.db.prepare(`
1527
- SELECT
1528
- (SELECT COUNT(*) FROM nodes) AS node_count,
1529
- (SELECT COUNT(*) FROM edges) AS edge_count,
1530
- (SELECT COUNT(*) FROM files) AS file_count
1526
+ const counts = this.db.prepare(`
1527
+ SELECT
1528
+ (SELECT COUNT(*) FROM nodes) AS node_count,
1529
+ (SELECT COUNT(*) FROM edges) AS edge_count,
1530
+ (SELECT COUNT(*) FROM files) AS file_count
1531
1531
  `).get();
1532
1532
  const nodesByKind = {};
1533
1533
  const nodeKindRows = this.db