@colbymchenry/codegraph-darwin-arm64 1.2.0 → 1.3.1

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 (232) hide show
  1. package/bin/codegraph +5 -0
  2. package/lib/dist/bin/codegraph.d.ts +1 -1
  3. package/lib/dist/bin/codegraph.d.ts.map +1 -1
  4. package/lib/dist/bin/codegraph.js +232 -61
  5. package/lib/dist/bin/codegraph.js.map +1 -1
  6. package/lib/dist/bin/command-supervision.d.ts.map +1 -1
  7. package/lib/dist/bin/command-supervision.js +4 -1
  8. package/lib/dist/bin/command-supervision.js.map +1 -1
  9. package/lib/dist/db/index.d.ts +17 -5
  10. package/lib/dist/db/index.d.ts.map +1 -1
  11. package/lib/dist/db/index.js +68 -12
  12. package/lib/dist/db/index.js.map +1 -1
  13. package/lib/dist/db/migrations.d.ts +1 -1
  14. package/lib/dist/db/migrations.d.ts.map +1 -1
  15. package/lib/dist/db/migrations.js +19 -1
  16. package/lib/dist/db/migrations.js.map +1 -1
  17. package/lib/dist/db/queries.d.ts +76 -1
  18. package/lib/dist/db/queries.d.ts.map +1 -1
  19. package/lib/dist/db/queries.js +180 -0
  20. package/lib/dist/db/queries.js.map +1 -1
  21. package/lib/dist/db/schema.sql +19 -0
  22. package/lib/dist/directory.d.ts +9 -5
  23. package/lib/dist/directory.d.ts.map +1 -1
  24. package/lib/dist/directory.js +210 -19
  25. package/lib/dist/directory.js.map +1 -1
  26. package/lib/dist/extraction/cfml-extractor.d.ts +107 -0
  27. package/lib/dist/extraction/cfml-extractor.d.ts.map +1 -0
  28. package/lib/dist/extraction/cfml-extractor.js +494 -0
  29. package/lib/dist/extraction/cfml-extractor.js.map +1 -0
  30. package/lib/dist/extraction/grammars.d.ts +9 -0
  31. package/lib/dist/extraction/grammars.d.ts.map +1 -1
  32. package/lib/dist/extraction/grammars.js +115 -3
  33. package/lib/dist/extraction/grammars.js.map +1 -1
  34. package/lib/dist/extraction/index.d.ts +46 -1
  35. package/lib/dist/extraction/index.d.ts.map +1 -1
  36. package/lib/dist/extraction/index.js +338 -34
  37. package/lib/dist/extraction/index.js.map +1 -1
  38. package/lib/dist/extraction/languages/arkts.d.ts +3 -0
  39. package/lib/dist/extraction/languages/arkts.d.ts.map +1 -0
  40. package/lib/dist/extraction/languages/arkts.js +127 -0
  41. package/lib/dist/extraction/languages/arkts.js.map +1 -0
  42. package/lib/dist/extraction/languages/c-cpp.d.ts +42 -0
  43. package/lib/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  44. package/lib/dist/extraction/languages/c-cpp.js +369 -4
  45. package/lib/dist/extraction/languages/c-cpp.js.map +1 -1
  46. package/lib/dist/extraction/languages/cfquery.d.ts +12 -0
  47. package/lib/dist/extraction/languages/cfquery.d.ts.map +1 -0
  48. package/lib/dist/extraction/languages/cfquery.js +28 -0
  49. package/lib/dist/extraction/languages/cfquery.js.map +1 -0
  50. package/lib/dist/extraction/languages/cfscript.d.ts +3 -0
  51. package/lib/dist/extraction/languages/cfscript.d.ts.map +1 -0
  52. package/lib/dist/extraction/languages/cfscript.js +73 -0
  53. package/lib/dist/extraction/languages/cfscript.js.map +1 -0
  54. package/lib/dist/extraction/languages/cobol.d.ts +33 -0
  55. package/lib/dist/extraction/languages/cobol.d.ts.map +1 -0
  56. package/lib/dist/extraction/languages/cobol.js +499 -0
  57. package/lib/dist/extraction/languages/cobol.js.map +1 -0
  58. package/lib/dist/extraction/languages/erlang.d.ts +3 -0
  59. package/lib/dist/extraction/languages/erlang.d.ts.map +1 -0
  60. package/lib/dist/extraction/languages/erlang.js +350 -0
  61. package/lib/dist/extraction/languages/erlang.js.map +1 -0
  62. package/lib/dist/extraction/languages/index.d.ts.map +1 -1
  63. package/lib/dist/extraction/languages/index.js +18 -0
  64. package/lib/dist/extraction/languages/index.js.map +1 -1
  65. package/lib/dist/extraction/languages/nix.d.ts +3 -0
  66. package/lib/dist/extraction/languages/nix.d.ts.map +1 -0
  67. package/lib/dist/extraction/languages/nix.js +294 -0
  68. package/lib/dist/extraction/languages/nix.js.map +1 -0
  69. package/lib/dist/extraction/languages/solidity.d.ts +3 -0
  70. package/lib/dist/extraction/languages/solidity.d.ts.map +1 -0
  71. package/lib/dist/extraction/languages/solidity.js +293 -0
  72. package/lib/dist/extraction/languages/solidity.js.map +1 -0
  73. package/lib/dist/extraction/languages/terraform.d.ts +3 -0
  74. package/lib/dist/extraction/languages/terraform.d.ts.map +1 -0
  75. package/lib/dist/extraction/languages/terraform.js +641 -0
  76. package/lib/dist/extraction/languages/terraform.js.map +1 -0
  77. package/lib/dist/extraction/languages/vbnet.d.ts +11 -0
  78. package/lib/dist/extraction/languages/vbnet.d.ts.map +1 -0
  79. package/lib/dist/extraction/languages/vbnet.js +141 -0
  80. package/lib/dist/extraction/languages/vbnet.js.map +1 -0
  81. package/lib/dist/extraction/mybatis-extractor.d.ts +30 -10
  82. package/lib/dist/extraction/mybatis-extractor.d.ts.map +1 -1
  83. package/lib/dist/extraction/mybatis-extractor.js +140 -38
  84. package/lib/dist/extraction/mybatis-extractor.js.map +1 -1
  85. package/lib/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
  86. package/lib/dist/extraction/tree-sitter-helpers.js +1 -0
  87. package/lib/dist/extraction/tree-sitter-helpers.js.map +1 -1
  88. package/lib/dist/extraction/tree-sitter-types.d.ts +3 -1
  89. package/lib/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  90. package/lib/dist/extraction/tree-sitter.d.ts +38 -0
  91. package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
  92. package/lib/dist/extraction/tree-sitter.js +753 -10
  93. package/lib/dist/extraction/tree-sitter.js.map +1 -1
  94. package/lib/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
  95. package/lib/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  96. package/lib/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  97. package/lib/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  98. package/lib/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  99. package/lib/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  100. package/lib/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  101. package/lib/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
  102. package/lib/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  103. package/lib/dist/index.d.ts +63 -1
  104. package/lib/dist/index.d.ts.map +1 -1
  105. package/lib/dist/index.js +327 -5
  106. package/lib/dist/index.js.map +1 -1
  107. package/lib/dist/installer/index.d.ts.map +1 -1
  108. package/lib/dist/installer/index.js +3 -1
  109. package/lib/dist/installer/index.js.map +1 -1
  110. package/lib/dist/mcp/daemon.d.ts +25 -3
  111. package/lib/dist/mcp/daemon.d.ts.map +1 -1
  112. package/lib/dist/mcp/daemon.js +62 -8
  113. package/lib/dist/mcp/daemon.js.map +1 -1
  114. package/lib/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
  115. package/lib/dist/mcp/dynamic-boundaries.js +2 -1
  116. package/lib/dist/mcp/dynamic-boundaries.js.map +1 -1
  117. package/lib/dist/mcp/early-ppid.d.ts +26 -0
  118. package/lib/dist/mcp/early-ppid.d.ts.map +1 -0
  119. package/lib/dist/mcp/early-ppid.js +29 -0
  120. package/lib/dist/mcp/early-ppid.js.map +1 -0
  121. package/lib/dist/mcp/index.d.ts.map +1 -1
  122. package/lib/dist/mcp/index.js +21 -4
  123. package/lib/dist/mcp/index.js.map +1 -1
  124. package/lib/dist/mcp/proxy.d.ts.map +1 -1
  125. package/lib/dist/mcp/proxy.js +29 -3
  126. package/lib/dist/mcp/proxy.js.map +1 -1
  127. package/lib/dist/mcp/query-pool.d.ts +14 -0
  128. package/lib/dist/mcp/query-pool.d.ts.map +1 -1
  129. package/lib/dist/mcp/query-pool.js +18 -0
  130. package/lib/dist/mcp/query-pool.js.map +1 -1
  131. package/lib/dist/mcp/session.d.ts.map +1 -1
  132. package/lib/dist/mcp/session.js +6 -0
  133. package/lib/dist/mcp/session.js.map +1 -1
  134. package/lib/dist/mcp/startup-handshake.d.ts +44 -0
  135. package/lib/dist/mcp/startup-handshake.d.ts.map +1 -0
  136. package/lib/dist/mcp/startup-handshake.js +73 -0
  137. package/lib/dist/mcp/startup-handshake.js.map +1 -0
  138. package/lib/dist/mcp/tools.d.ts +22 -0
  139. package/lib/dist/mcp/tools.d.ts.map +1 -1
  140. package/lib/dist/mcp/tools.js +88 -18
  141. package/lib/dist/mcp/tools.js.map +1 -1
  142. package/lib/dist/mcp/transport.d.ts.map +1 -1
  143. package/lib/dist/mcp/transport.js +18 -0
  144. package/lib/dist/mcp/transport.js.map +1 -1
  145. package/lib/dist/project-config.d.ts +38 -0
  146. package/lib/dist/project-config.d.ts.map +1 -1
  147. package/lib/dist/project-config.js +101 -2
  148. package/lib/dist/project-config.js.map +1 -1
  149. package/lib/dist/resolution/c-fnptr-synthesizer.d.ts +2 -1
  150. package/lib/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
  151. package/lib/dist/resolution/c-fnptr-synthesizer.js +170 -146
  152. package/lib/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
  153. package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  154. package/lib/dist/resolution/callback-synthesizer.js +982 -81
  155. package/lib/dist/resolution/callback-synthesizer.js.map +1 -1
  156. package/lib/dist/resolution/frameworks/cics.d.ts +20 -0
  157. package/lib/dist/resolution/frameworks/cics.d.ts.map +1 -0
  158. package/lib/dist/resolution/frameworks/cics.js +90 -0
  159. package/lib/dist/resolution/frameworks/cics.js.map +1 -0
  160. package/lib/dist/resolution/frameworks/index.d.ts.map +1 -1
  161. package/lib/dist/resolution/frameworks/index.js +6 -0
  162. package/lib/dist/resolution/frameworks/index.js.map +1 -1
  163. package/lib/dist/resolution/frameworks/java.d.ts.map +1 -1
  164. package/lib/dist/resolution/frameworks/java.js +14 -6
  165. package/lib/dist/resolution/frameworks/java.js.map +1 -1
  166. package/lib/dist/resolution/frameworks/terraform.d.ts +38 -0
  167. package/lib/dist/resolution/frameworks/terraform.d.ts.map +1 -0
  168. package/lib/dist/resolution/frameworks/terraform.js +277 -0
  169. package/lib/dist/resolution/frameworks/terraform.js.map +1 -0
  170. package/lib/dist/resolution/goframe-synthesizer.d.ts +2 -1
  171. package/lib/dist/resolution/goframe-synthesizer.d.ts.map +1 -1
  172. package/lib/dist/resolution/goframe-synthesizer.js +8 -3
  173. package/lib/dist/resolution/goframe-synthesizer.js.map +1 -1
  174. package/lib/dist/resolution/import-resolver.d.ts +7 -0
  175. package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
  176. package/lib/dist/resolution/import-resolver.js +129 -4
  177. package/lib/dist/resolution/import-resolver.js.map +1 -1
  178. package/lib/dist/resolution/index.d.ts +49 -6
  179. package/lib/dist/resolution/index.d.ts.map +1 -1
  180. package/lib/dist/resolution/index.js +342 -65
  181. package/lib/dist/resolution/index.js.map +1 -1
  182. package/lib/dist/resolution/name-matcher.d.ts +0 -3
  183. package/lib/dist/resolution/name-matcher.d.ts.map +1 -1
  184. package/lib/dist/resolution/name-matcher.js +225 -33
  185. package/lib/dist/resolution/name-matcher.js.map +1 -1
  186. package/lib/dist/resolution/strip-comments.d.ts +1 -1
  187. package/lib/dist/resolution/strip-comments.d.ts.map +1 -1
  188. package/lib/dist/resolution/strip-comments.js +49 -0
  189. package/lib/dist/resolution/strip-comments.js.map +1 -1
  190. package/lib/dist/resolution/types.d.ts +29 -0
  191. package/lib/dist/resolution/types.d.ts.map +1 -1
  192. package/lib/dist/resolution/workspace-packages.d.ts +10 -0
  193. package/lib/dist/resolution/workspace-packages.d.ts.map +1 -1
  194. package/lib/dist/resolution/workspace-packages.js +142 -4
  195. package/lib/dist/resolution/workspace-packages.js.map +1 -1
  196. package/lib/dist/search/identifier-segments.d.ts +60 -0
  197. package/lib/dist/search/identifier-segments.d.ts.map +1 -0
  198. package/lib/dist/search/identifier-segments.js +176 -0
  199. package/lib/dist/search/identifier-segments.js.map +1 -0
  200. package/lib/dist/sync/git-hooks.d.ts.map +1 -1
  201. package/lib/dist/sync/git-hooks.js +2 -0
  202. package/lib/dist/sync/git-hooks.js.map +1 -1
  203. package/lib/dist/sync/watcher.d.ts +10 -5
  204. package/lib/dist/sync/watcher.d.ts.map +1 -1
  205. package/lib/dist/sync/watcher.js +51 -14
  206. package/lib/dist/sync/watcher.js.map +1 -1
  207. package/lib/dist/sync/worktree.d.ts.map +1 -1
  208. package/lib/dist/sync/worktree.js +5 -0
  209. package/lib/dist/sync/worktree.js.map +1 -1
  210. package/lib/dist/types.d.ts +19 -1
  211. package/lib/dist/types.d.ts.map +1 -1
  212. package/lib/dist/types.js +10 -0
  213. package/lib/dist/types.js.map +1 -1
  214. package/lib/node_modules/.package-lock.json +1 -1
  215. package/lib/package.json +1 -1
  216. package/package.json +1 -1
  217. package/lib/dist/reasoning/config.d.ts +0 -45
  218. package/lib/dist/reasoning/config.d.ts.map +0 -1
  219. package/lib/dist/reasoning/config.js +0 -171
  220. package/lib/dist/reasoning/config.js.map +0 -1
  221. package/lib/dist/reasoning/credentials.d.ts +0 -5
  222. package/lib/dist/reasoning/credentials.d.ts.map +0 -1
  223. package/lib/dist/reasoning/credentials.js +0 -83
  224. package/lib/dist/reasoning/credentials.js.map +0 -1
  225. package/lib/dist/reasoning/login.d.ts +0 -21
  226. package/lib/dist/reasoning/login.d.ts.map +0 -1
  227. package/lib/dist/reasoning/login.js +0 -85
  228. package/lib/dist/reasoning/login.js.map +0 -1
  229. package/lib/dist/reasoning/reasoner.d.ts +0 -43
  230. package/lib/dist/reasoning/reasoner.d.ts.map +0 -1
  231. package/lib/dist/reasoning/reasoner.js +0 -308
  232. package/lib/dist/reasoning/reasoner.js.map +0 -1
@@ -240,6 +240,17 @@ class ReferenceResolver {
240
240
  nameCache; // name → nodes cache
241
241
  lowerNameCache; // lower(name) → nodes cache
242
242
  qualifiedNameCache; // qualified_name → nodes cache
243
+ fileLinesCache; // file → split lines cache
244
+ methodMatchCache; // lang\0Type::method → matching method nodes
245
+ // Node kinds are a small fixed set (~24), so this is a plain Map, not an LRU.
246
+ // getNodesByKind returns the FULL node list for a kind; it was previously
247
+ // uncached — a per-ref `SELECT * FROM nodes WHERE kind=?` + row-mapping. Called
248
+ // for every dotted call ref by the Spring resolver (constants) and every
249
+ // `hook_` ref by the Drupal resolver (functions), that scan dominated
250
+ // resolution on large repos (#1180). The node set is stable within a
251
+ // resolution pass (same lifetime assumption as nameCache); clearCaches() resets
252
+ // it between passes. Callers must treat the returned array as read-only.
253
+ nodesByKindCache = new Map();
243
254
  knownNames = null; // all known symbol names for fast pre-filtering
244
255
  knownFiles = null;
245
256
  cachesWarmed = false;
@@ -265,6 +276,10 @@ class ReferenceResolver {
265
276
  this.nameCache = new lru_cache_1.LRUCache(limit);
266
277
  this.lowerNameCache = new lru_cache_1.LRUCache(limit);
267
278
  this.qualifiedNameCache = new lru_cache_1.LRUCache(limit);
279
+ // Split-lines arrays are heavier than content strings; refs arrive
280
+ // file-ordered, so a small cache still hits nearly always.
281
+ this.fileLinesCache = new lru_cache_1.LRUCache(contentLimit);
282
+ this.methodMatchCache = new lru_cache_1.LRUCache(limit);
268
283
  this.context = this.createContext();
269
284
  }
270
285
  /**
@@ -320,6 +335,28 @@ class ReferenceResolver {
320
335
  this.knownNames = new Set(this.queries.getAllNodeNames());
321
336
  this.cachesWarmed = true;
322
337
  }
338
+ /**
339
+ * warmCaches for the async resolution entry points: streams the distinct
340
+ * name set with periodic yields instead of one synchronous `.all()`. On a
341
+ * multi-million-node index the DISTINCT scan is a solid multi-second block
342
+ * (measured up to 28s inside `codegraph sync` on the Linux kernel index),
343
+ * long enough to matter to the #850 watchdog on slower hardware. Same
344
+ * result, same memory — only the event loop keeps turning.
345
+ */
346
+ async warmCachesYielding(onYield) {
347
+ if (this.cachesWarmed)
348
+ return;
349
+ this.knownFiles = new Set(this.queries.getAllFilePaths());
350
+ const names = new Set();
351
+ let scanned = 0;
352
+ for (const name of this.queries.iterateNodeNames()) {
353
+ names.add(name);
354
+ if ((++scanned & 8191) === 0)
355
+ await onYield();
356
+ }
357
+ this.knownNames = names;
358
+ this.cachesWarmed = true;
359
+ }
323
360
  /**
324
361
  * Clear internal caches
325
362
  */
@@ -331,10 +368,30 @@ class ReferenceResolver {
331
368
  this.nameCache.clear();
332
369
  this.lowerNameCache.clear();
333
370
  this.qualifiedNameCache.clear();
371
+ this.fileLinesCache.clear();
372
+ this.methodMatchCache.clear();
373
+ this.nodesByKindCache.clear();
334
374
  this.knownNames = null;
335
375
  this.knownFiles = null;
336
376
  this.cachesWarmed = false;
337
377
  }
378
+ /** `readFile` through the LRU content cache (null = read failed, also cached). */
379
+ readFileCached(filePath) {
380
+ if (this.fileCache.has(filePath)) {
381
+ return this.fileCache.get(filePath);
382
+ }
383
+ const fullPath = path.join(this.projectRoot, filePath);
384
+ try {
385
+ const content = fs.readFileSync(fullPath, 'utf-8');
386
+ this.fileCache.set(filePath, content);
387
+ return content;
388
+ }
389
+ catch (error) {
390
+ (0, errors_1.logDebug)('Failed to read file for resolution', { filePath, error: String(error) });
391
+ this.fileCache.set(filePath, null);
392
+ return null;
393
+ }
394
+ }
338
395
  /**
339
396
  * Create the resolution context
340
397
  */
@@ -354,6 +411,30 @@ class ReferenceResolver {
354
411
  this.nameCache.set(name, result);
355
412
  return result;
356
413
  },
414
+ getMethodMatches: (typeName, methodName, language) => {
415
+ const key = `${language} ${typeName}::${methodName}`;
416
+ const cached = this.methodMatchCache.get(key);
417
+ if (cached !== undefined)
418
+ return cached;
419
+ let candidates = this.nameCache.get(methodName);
420
+ if (candidates === undefined) {
421
+ candidates = this.queries.getNodesByName(methodName);
422
+ this.nameCache.set(methodName, candidates);
423
+ }
424
+ const want = `${typeName}::${methodName}`;
425
+ const matches = [];
426
+ for (const m of candidates) {
427
+ if (m.kind !== 'method')
428
+ continue;
429
+ if (m.language !== language)
430
+ continue;
431
+ const qn = m.qualifiedName;
432
+ if (qn === want || qn.endsWith(`::${want}`))
433
+ matches.push(m);
434
+ }
435
+ this.methodMatchCache.set(key, matches);
436
+ return matches;
437
+ },
357
438
  getNodesByQualifiedName: (qualifiedName) => {
358
439
  const cached = this.qualifiedNameCache.get(qualifiedName);
359
440
  if (cached !== undefined)
@@ -363,8 +444,18 @@ class ReferenceResolver {
363
444
  return result;
364
445
  },
365
446
  getNodesByKind: (kind) => {
366
- return this.queries.getNodesByKind(kind);
447
+ const cached = this.nodesByKindCache.get(kind);
448
+ if (cached !== undefined)
449
+ return cached;
450
+ const result = this.queries.getNodesByKind(kind);
451
+ this.nodesByKindCache.set(kind, result);
452
+ return result;
367
453
  },
454
+ // Streamed, uncached — synthesizers scan-and-filter whole kinds, and
455
+ // both the materialized array AND the per-kind cache retention are
456
+ // O(nodes) memory (#1212). Per-ref resolvers keep the cached array
457
+ // variant above.
458
+ iterateNodesByKind: (kind) => this.queries.iterateNodesByKind(kind),
368
459
  fileExists: (filePath) => {
369
460
  // Check pre-built known files set first (O(1))
370
461
  if (this.knownFiles) {
@@ -383,21 +474,15 @@ class ReferenceResolver {
383
474
  return false;
384
475
  }
385
476
  },
386
- readFile: (filePath) => {
387
- if (this.fileCache.has(filePath)) {
388
- return this.fileCache.get(filePath);
389
- }
390
- const fullPath = path.join(this.projectRoot, filePath);
391
- try {
392
- const content = fs.readFileSync(fullPath, 'utf-8');
393
- this.fileCache.set(filePath, content);
394
- return content;
395
- }
396
- catch (error) {
397
- (0, errors_1.logDebug)('Failed to read file for resolution', { filePath, error: String(error) });
398
- this.fileCache.set(filePath, null);
399
- return null;
400
- }
477
+ readFile: (filePath) => this.readFileCached(filePath),
478
+ getFileLines: (filePath) => {
479
+ const cached = this.fileLinesCache.get(filePath);
480
+ if (cached !== undefined)
481
+ return cached;
482
+ const source = this.readFileCached(filePath);
483
+ const lines = source === null ? null : source.split(/\r?\n/);
484
+ this.fileLinesCache.set(filePath, lines);
485
+ return lines;
401
486
  },
402
487
  getProjectRoot: () => this.projectRoot,
403
488
  getAllFiles: () => {
@@ -500,7 +585,7 @@ class ReferenceResolver {
500
585
  // `.ts` index barrel and silently break the chain (#629). Re-key
501
586
  // the parse on the barrel's extension so the chase works no matter
502
587
  // what kind of file imports through it.
503
- const isJsFamily = /\.(?:d\.ts|[cm]?tsx?|[cm]?jsx?)$/i.test(filePath);
588
+ const isJsFamily = /\.(?:d\.ts|[cm]?tsx?|[cm]?jsx?|ets)$/i.test(filePath);
504
589
  const reExports = (0, import_resolver_1.extractReExports)(content, isJsFamily ? 'typescript' : language);
505
590
  this.reExportCache.set(filePath, reExports);
506
591
  return reExports;
@@ -667,13 +752,36 @@ class ReferenceResolver {
667
752
  if (this.isBuiltInOrExternal(ref)) {
668
753
  return null;
669
754
  }
755
+ // CFML component paths in inheritance (#1152): `extends="coldbox.system.web.
756
+ // Controller"` names the supertype by its dot-separated path (or `extends=
757
+ // "../base"` by relative file path) — the graph indexes the class under its
758
+ // final segment only, so these die at the fast pre-filter below and never
759
+ // resolved. Handled by a dedicated path-corroborated matcher, gated to
760
+ // inheritance refs only (a dotted `calls` ref is a member-access chain, not
761
+ // a component path). No fallthrough on miss: the full path string can only
762
+ // ever mis-match downstream, and an unresolvable supertype usually lives in
763
+ // an out-of-repo library (mxunit, testbox) — silent beats wrong.
764
+ if ((ref.language === 'cfml' || ref.language === 'cfscript') &&
765
+ (ref.referenceKind === 'extends' || ref.referenceKind === 'implements') &&
766
+ (ref.referenceName.includes('.') || ref.referenceName.includes('/'))) {
767
+ return this.resolveCfmlComponentPath(ref);
768
+ }
670
769
  // Fast pre-filter: skip if no symbol with this name exists anywhere
671
770
  // AND the name doesn't match a local import. The import escape is
672
771
  // necessary because re-export rename chains (`import { login }
673
772
  // from './barrel'` where the barrel has `export { signIn as login }
674
773
  // from './auth'`) intentionally call a name that has no
675
774
  // declaration anywhere — only the renamed upstream symbol does.
676
- if (!this.hasAnyPossibleMatch(ref.referenceName) &&
775
+ // ArkTS chained-attribute refs carry a leading dot (`.titleStyle`) that
776
+ // routes them to the decorator-gated matcher; the symbol itself is
777
+ // indexed under the bare name, so the existence check strips the dot.
778
+ // Nix static path imports (`import ./x.nix`) name a FILE, not a symbol —
779
+ // they bypass the symbol-existence check and resolve via resolveViaImport.
780
+ const existenceName = ref.language === 'arkts' && ref.referenceName.startsWith('.')
781
+ ? ref.referenceName.slice(1)
782
+ : ref.referenceName;
783
+ if (!(0, import_resolver_1.isNixPathImportRef)(ref) &&
784
+ !this.hasAnyPossibleMatch(existenceName) &&
677
785
  !this.matchesAnyImport(ref) &&
678
786
  !this.frameworks.some((f) => f.claimsReference?.(ref.referenceName))) {
679
787
  return null;
@@ -739,13 +847,40 @@ class ReferenceResolver {
739
847
  // If that didn't find the file, do NOT fall back to the symbol
740
848
  // name-matcher — it would mis-connect e.g. "inc/db.php" to an unrelated
741
849
  // db.php elsewhere in the tree (a wrong edge is worse than none, #660).
742
- if ((0, import_resolver_1.isPhpIncludePathRef)(ref)) {
850
+ // Terraform refs are directory-scoped by language semantics — the
851
+ // framework resolver IS the whole rulebook (`var.X` can never legally
852
+ // bind outside its module directory), so the name-matcher's
853
+ // qualified-name fallback would only ever add wrong cross-module edges.
854
+ // Nix static path imports are file references for the same reason —
855
+ // falling through would let "./x.nix" name-match an unrelated node.
856
+ if ((0, import_resolver_1.isPhpIncludePathRef)(ref) || (0, import_resolver_1.isCobolCopybookRef)(ref) || (0, import_resolver_1.isNixPathImportRef)(ref) || ref.language === 'terraform') {
743
857
  return candidates.length > 0
744
858
  ? candidates.reduce((best, curr) => curr.confidence > best.confidence ? curr : best)
745
859
  : null;
746
860
  }
747
861
  // Strategy 3: Try name matching
748
- const nameResult = this.gateLanguage((0, name_matcher_1.matchReference)(ref, this.context), ref);
862
+ let nameResult = this.gateLanguage((0, name_matcher_1.matchReference)(ref, this.context), ref);
863
+ // Nix has no ambient cross-file namespace — a callee binds lexically
864
+ // (same file) or through explicit import/callPackage wiring (the import
865
+ // path above). A cross-file name match is wrong by construction: every
866
+ // module `inherit (lib) mkOption`s the same nixpkgs helpers, so the
867
+ // matcher would link each `mkOption` call to whichever file's inherit
868
+ // binding it happened to pick. Same-file matches only.
869
+ if (nameResult) {
870
+ const target = this.queries.getNodeById(nameResult.targetNodeId);
871
+ if (ref.language === 'nix') {
872
+ if (!target || target.filePath !== ref.filePath) {
873
+ nameResult = null;
874
+ }
875
+ }
876
+ else if (target && target.language === 'nix') {
877
+ // The reverse direction is just as impossible: no other language can
878
+ // symbolically call into a .nix binding (interop is eval/CLI, never a
879
+ // linkable symbol) — without this, a Python script's `split()` lands
880
+ // on some module's `split = ...` binding as a low-confidence match.
881
+ nameResult = null;
882
+ }
883
+ }
749
884
  if (nameResult) {
750
885
  candidates.push(nameResult);
751
886
  }
@@ -832,6 +967,20 @@ class ReferenceResolver {
832
967
  referenceKind: r.original.referenceKind,
833
968
  })));
834
969
  }
970
+ // Delete unresolvable refs too — parity with resolveAndPersistBatched.
971
+ // Keeping them bought nothing: a ref is only ever retried when its file
972
+ // is re-extracted, which cascade-deletes and re-inserts its rows anyway.
973
+ // And it broke the #1187 orphan sweep's invariant — after a COMPLETED
974
+ // pass the table must hold nothing that pass processed, so that any row
975
+ // still present belongs to an interrupted run and the sweep can key off
976
+ // a bare row count.
977
+ if (result.unresolved.length > 0) {
978
+ this.queries.deleteSpecificResolvedReferences(result.unresolved.map((r) => ({
979
+ fromNodeId: r.fromNodeId,
980
+ referenceName: r.referenceName,
981
+ referenceKind: r.referenceKind,
982
+ })));
983
+ }
835
984
  return result;
836
985
  }
837
986
  /**
@@ -882,37 +1031,53 @@ class ReferenceResolver {
882
1031
  return edges.length;
883
1032
  }
884
1033
  /**
885
- * Resolve one batch in smaller sub-chunks, yielding to the event loop between
886
- * them so the #850 liveness heartbeat can fire on a slow/dense batch (#1091).
887
- * Behaviourally identical to a single `resolveAll(batch)`: `warmCaches()` is
888
- * idempotent (guarded) and `resolveOne` is independent per ref, so splitting
889
- * and re-merging changes only timing, never which edges get created. Falls
890
- * through to a plain `resolveAll` when the batch is already small.
1034
+ * Resolve one batch with a yield checkpoint between EVERY ref so the #850
1035
+ * liveness heartbeat can fire on a slow/dense batch (#1091). The checkpoint
1036
+ * granularity is per-ref not per-N-refs because per-ref cost is unbounded
1037
+ * in the worst case (a collision-heavy method name whose candidate set misses
1038
+ * the LRU re-fetches tens of thousands of rows): any fixed N multiplies that
1039
+ * worst case into the watchdog window, which is how v1.2.0 still got killed
1040
+ * at "Resolving refs" on large Java monorepos (#1122). `maybeYield()` is a
1041
+ * ~ns time check when under budget, so per-ref checkpoints cost nothing.
1042
+ * Behaviourally identical to `resolveAll(batch)`: `warmCaches()` is
1043
+ * idempotent (guarded) and `resolveOne` is independent per ref, so yielding
1044
+ * between refs changes only timing, never which edges get created.
891
1045
  */
892
- async resolveBatchYielding(batch, maybeYield, subChunkSize = 500) {
893
- if (batch.length <= subChunkSize)
894
- return this.resolveAll(batch);
1046
+ async resolveBatchYielding(batch, maybeYield) {
1047
+ this.warmCaches();
895
1048
  const resolved = [];
896
1049
  const unresolved = [];
897
1050
  const byMethod = {};
898
- let total = 0;
899
- let resolvedCount = 0;
900
- let unresolvedCount = 0;
901
- for (let i = 0; i < batch.length; i += subChunkSize) {
902
- const chunk = this.resolveAll(batch.slice(i, i + subChunkSize));
903
- for (const r of chunk.resolved)
904
- resolved.push(r);
905
- for (const u of chunk.unresolved)
906
- unresolved.push(u);
907
- total += chunk.stats.total;
908
- resolvedCount += chunk.stats.resolved;
909
- unresolvedCount += chunk.stats.unresolved;
910
- for (const [m, c] of Object.entries(chunk.stats.byMethod)) {
911
- byMethod[m] = (byMethod[m] || 0) + c;
1051
+ for (const raw of batch) {
1052
+ const ref = {
1053
+ fromNodeId: raw.fromNodeId,
1054
+ referenceName: raw.referenceName,
1055
+ referenceKind: raw.referenceKind,
1056
+ line: raw.line,
1057
+ column: raw.column,
1058
+ filePath: raw.filePath || this.getFilePathFromNodeId(raw.fromNodeId),
1059
+ language: raw.language || this.getLanguageFromNodeId(raw.fromNodeId),
1060
+ };
1061
+ const result = this.resolveOne(ref);
1062
+ if (result) {
1063
+ resolved.push(result);
1064
+ byMethod[result.resolvedBy] = (byMethod[result.resolvedBy] || 0) + 1;
1065
+ }
1066
+ else {
1067
+ unresolved.push(ref);
912
1068
  }
913
1069
  await maybeYield();
914
1070
  }
915
- return { resolved, unresolved, stats: { total, resolved: resolvedCount, unresolved: unresolvedCount, byMethod } };
1071
+ return {
1072
+ resolved,
1073
+ unresolved,
1074
+ stats: {
1075
+ total: batch.length,
1076
+ resolved: resolved.length,
1077
+ unresolved: unresolved.length,
1078
+ byMethod,
1079
+ },
1080
+ };
916
1081
  }
917
1082
  /**
918
1083
  * Resolve and persist in batches to keep memory bounded.
@@ -920,7 +1085,6 @@ class ReferenceResolver {
920
1085
  * up resolved refs after each batch to avoid accumulating large arrays.
921
1086
  */
922
1087
  async resolveAndPersistBatched(onProgress, batchSize = 5000) {
923
- this.warmCaches();
924
1088
  // Resolution runs on the indexer's MAIN thread, and the #850 liveness
925
1089
  // watchdog SIGKILLs a process whose event loop stalls past its window (60s
926
1090
  // by default). A single dense batch's resolveAll — or the synthesis pass
@@ -928,6 +1092,7 @@ class ReferenceResolver {
928
1092
  // (#1091). A shared yielder lets both give the watchdog heartbeat a regular
929
1093
  // window to fire; see ./cooperative-yield.
930
1094
  const maybeYield = (0, cooperative_yield_1.createYielder)();
1095
+ await this.warmCachesYielding(maybeYield);
931
1096
  const total = this.queries.getUnresolvedReferencesCount();
932
1097
  let processed = 0;
933
1098
  const aggregateStats = {
@@ -944,26 +1109,39 @@ class ReferenceResolver {
944
1109
  if (batch.length === 0)
945
1110
  break;
946
1111
  const result = await this.resolveBatchYielding(batch, maybeYield);
1112
+ // Persist in bounded sub-transactions with yields between: a whole
1113
+ // batch's edge insert / keyed deletes are otherwise one solid
1114
+ // synchronous span each on a multi-GB index, sitting BETWEEN the
1115
+ // per-ref yields — the last unyielded stretch of the resolution loop.
1116
+ // Crash semantics are unchanged (already several transactions): edges
1117
+ // land before their refs are deleted, so a kill mid-way re-resolves
1118
+ // the remainder idempotently on the next run/sweep (#1187).
1119
+ const PERSIST_CHUNK = 1000;
947
1120
  // Persist edges immediately
948
1121
  const edges = this.createEdges(result.resolved);
949
- if (edges.length > 0) {
950
- this.queries.insertEdges(edges);
1122
+ for (let i = 0; i < edges.length; i += PERSIST_CHUNK) {
1123
+ this.queries.insertEdges(edges.slice(i, i + PERSIST_CHUNK));
1124
+ await maybeYield();
951
1125
  }
952
1126
  // Clean up resolved refs so they don't appear in the next batch
953
- if (result.resolved.length > 0) {
954
- this.queries.deleteSpecificResolvedReferences(result.resolved.map((r) => ({
955
- fromNodeId: r.original.fromNodeId,
956
- referenceName: r.original.referenceName,
957
- referenceKind: r.original.referenceKind,
958
- })));
1127
+ const resolvedKeys = result.resolved.map((r) => ({
1128
+ fromNodeId: r.original.fromNodeId,
1129
+ referenceName: r.original.referenceName,
1130
+ referenceKind: r.original.referenceKind,
1131
+ }));
1132
+ for (let i = 0; i < resolvedKeys.length; i += PERSIST_CHUNK) {
1133
+ this.queries.deleteSpecificResolvedReferences(resolvedKeys.slice(i, i + PERSIST_CHUNK));
1134
+ await maybeYield();
959
1135
  }
960
1136
  // Delete unresolvable refs from this batch to avoid re-processing them
961
- if (result.unresolved.length > 0) {
962
- this.queries.deleteSpecificResolvedReferences(result.unresolved.map((r) => ({
963
- fromNodeId: r.fromNodeId,
964
- referenceName: r.referenceName,
965
- referenceKind: r.referenceKind,
966
- })));
1137
+ const unresolvedKeys = result.unresolved.map((r) => ({
1138
+ fromNodeId: r.fromNodeId,
1139
+ referenceName: r.referenceName,
1140
+ referenceKind: r.referenceKind,
1141
+ }));
1142
+ for (let i = 0; i < unresolvedKeys.length; i += PERSIST_CHUNK) {
1143
+ this.queries.deleteSpecificResolvedReferences(unresolvedKeys.slice(i, i + PERSIST_CHUNK));
1144
+ await maybeYield();
967
1145
  }
968
1146
  // Aggregate stats
969
1147
  aggregateStats.total += result.stats.total;
@@ -976,11 +1154,13 @@ class ReferenceResolver {
976
1154
  onProgress?.(processed, total);
977
1155
  // Yield so progress UI can render between batches
978
1156
  await new Promise(resolve => setImmediate(resolve));
979
- // If nothing was resolved or removed in this batch, we'd loop forever
980
- // on the same rows. Break to avoid infinite loop.
981
- if (result.resolved.length === 0 && result.unresolved.length === batch.length) {
982
- break;
983
- }
1157
+ // NOTE: there used to be an extra early break here when a batch resolved
1158
+ // nothing (`result.unresolved.length === batch.length`). That was wrong:
1159
+ // an all-unresolvable batch still DELETES its rows (progress), yet the
1160
+ // break abandoned every batch after it in the same run — on a repo whose
1161
+ // first 5000 refs are all external/stdlib calls, resolution stopped at
1162
+ // batch one and left the rest of the table as permanent orphans (#1187).
1163
+ // The count-based guard below catches the true no-progress case.
984
1164
  // Non-progress guard (defense-in-depth). Because we re-read from offset 0
985
1165
  // each pass, the unresolved_refs table MUST shrink every iteration — both
986
1166
  // resolved and unresolved refs are deleted above. If it didn't shrink, a
@@ -1022,11 +1202,18 @@ class ReferenceResolver {
1022
1202
  isBuiltInOrExternal(ref) {
1023
1203
  const name = ref.referenceName;
1024
1204
  const isJsTs = ref.language === 'typescript' || ref.language === 'javascript'
1025
- || ref.language === 'tsx' || ref.language === 'jsx';
1205
+ || ref.language === 'tsx' || ref.language === 'jsx' || ref.language === 'arkts';
1026
1206
  // JavaScript/TypeScript built-ins
1027
1207
  if (isJsTs && JS_BUILT_INS.has(name)) {
1028
1208
  return true;
1029
1209
  }
1210
+ // ArkTS resource-reference intrinsics — `$r('app.string.x')` /
1211
+ // `$rawfile('x.png')` are framework-provided and appear dozens of times
1212
+ // per UI file; without this they can resolve to a stray same-named
1213
+ // symbol (e.g. a checked-in hvigor wrapper's `$r`).
1214
+ if (ref.language === 'arkts' && (name === '$r' || name === '$rawfile')) {
1215
+ return true;
1216
+ }
1030
1217
  // Common JS/TS library calls (console.log, Math.floor, JSON.parse)
1031
1218
  if (isJsTs && (name.startsWith('console.') || name.startsWith('Math.') || name.startsWith('JSON.'))) {
1032
1219
  return true;
@@ -1191,6 +1378,96 @@ class ReferenceResolver {
1191
1378
  const target = found.values().next().value;
1192
1379
  return { original: ref, targetNodeId: target.id, confidence: 0.9, resolvedBy: 'import' };
1193
1380
  }
1381
+ /**
1382
+ * Resolve a CFML inheritance reference written as a component path (#1152).
1383
+ * Two forms exist in real code:
1384
+ *
1385
+ * - Dotted: `extends="coldbox.system.web.Controller"` — dots are directory
1386
+ * separators from the webroot or a CFML mapping. Mappings live in server
1387
+ * config / Application.cfc, so the leading segments may not exist in the
1388
+ * repo at all (in the coldbox repo itself the path is `system/web/
1389
+ * Controller.cfc` — the `coldbox.` root IS the repo). Matched by final
1390
+ * segment (the class), corroborated right-to-left against the candidate's
1391
+ * parent directories.
1392
+ * - Relative: `extends="../base"` / `extends="./base"` (the FW/1 style) —
1393
+ * resolved against the referencing file's own directory.
1394
+ *
1395
+ * Conservative by design: a candidate needs at least one corroborating
1396
+ * directory segment (a dotted path whose only same-named class sits in an
1397
+ * unrelated directory is almost always an out-of-repo library supertype —
1398
+ * mxunit/testbox/coldbox-as-dependency), and a corroboration tie yields no
1399
+ * edge. Directory comparison is case-insensitive (CFML path resolution is);
1400
+ * the class segment itself is matched exactly, which real code satisfies —
1401
+ * dotted paths are written to match the on-disk file name.
1402
+ */
1403
+ resolveCfmlComponentPath(ref) {
1404
+ const cfmlCandidates = (name) => this.context
1405
+ .getNodesByName(name)
1406
+ .filter((n) => (n.kind === 'class' || n.kind === 'interface') &&
1407
+ (n.language === 'cfml' || n.language === 'cfscript'));
1408
+ const norm = (p) => p.replace(/\\/g, '/').toLowerCase();
1409
+ // Relative-path form: `../base`, `./base`, `sub/thing` — resolve against
1410
+ // the referencing file's directory and require an exact (case-insensitive)
1411
+ // file match.
1412
+ if (ref.referenceName.includes('/')) {
1413
+ const rel = ref.referenceName.replace(/\.cfc$/i, '');
1414
+ const fromDir = ref.filePath.replace(/\\/g, '/').split('/').slice(0, -1);
1415
+ const parts = [...fromDir];
1416
+ for (const seg of rel.split('/')) {
1417
+ if (seg === '' || seg === '.')
1418
+ continue;
1419
+ if (seg === '..') {
1420
+ if (parts.length === 0)
1421
+ return null; // escapes the project root
1422
+ parts.pop();
1423
+ }
1424
+ else {
1425
+ parts.push(seg);
1426
+ }
1427
+ }
1428
+ const wantPath = norm(parts.join('/') + '.cfc');
1429
+ const className = parts[parts.length - 1];
1430
+ if (!className)
1431
+ return null;
1432
+ const target = cfmlCandidates(className).find((c) => norm(c.filePath) === wantPath);
1433
+ return target
1434
+ ? { original: ref, targetNodeId: target.id, confidence: 0.95, resolvedBy: 'file-path' }
1435
+ : null;
1436
+ }
1437
+ // Dotted form.
1438
+ const segments = ref.referenceName.split('.').map((s) => s.trim()).filter(Boolean);
1439
+ if (segments.length < 2)
1440
+ return null;
1441
+ const className = segments[segments.length - 1];
1442
+ const dirSegments = segments.slice(0, -1);
1443
+ let best = null;
1444
+ let bestScore = 0;
1445
+ let tie = false;
1446
+ for (const cand of cfmlCandidates(className)) {
1447
+ const dirs = cand.filePath.replace(/\\/g, '/').split('/').slice(0, -1);
1448
+ // Count matching directory segments right-to-left: for
1449
+ // `coldbox.system.web.Controller` vs `system/web/Controller.cfc`,
1450
+ // `web` and `system` match, then the repo root ends the run → score 2.
1451
+ let score = 0;
1452
+ while (score < dirSegments.length &&
1453
+ score < dirs.length &&
1454
+ dirSegments[dirSegments.length - 1 - score].toLowerCase() ===
1455
+ dirs[dirs.length - 1 - score].toLowerCase()) {
1456
+ score++;
1457
+ }
1458
+ if (score > bestScore) {
1459
+ best = cand;
1460
+ bestScore = score;
1461
+ tie = false;
1462
+ }
1463
+ else if (score === bestScore && score > 0) {
1464
+ tie = true;
1465
+ }
1466
+ }
1467
+ if (!best || bestScore === 0 || tie)
1468
+ return null;
1469
+ return { original: ref, targetNodeId: best.id, confidence: 0.9, resolvedBy: 'qualified-name' };
1470
+ }
1194
1471
  /**
1195
1472
  * Resolve a `this.<member>` function-as-value reference (#756/#808) to the
1196
1473
  * ENCLOSING CLASS's own member — never a same-named symbol elsewhere. The