homegraph 1.2.0 → 1.5.0

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 (560) hide show
  1. package/README.md +48 -11
  2. package/dist/bin/homegraph.js +298 -72
  3. package/dist/bin/homegraph.js.map +1 -1
  4. package/dist/context/index.d.ts.map +1 -1
  5. package/dist/context/index.js +117 -11
  6. package/dist/context/index.js.map +1 -1
  7. package/dist/db/index.d.ts +207 -6
  8. package/dist/db/index.d.ts.map +1 -1
  9. package/dist/db/index.js +461 -20
  10. package/dist/db/index.js.map +1 -1
  11. package/dist/db/migrations.d.ts +1 -1
  12. package/dist/db/migrations.d.ts.map +1 -1
  13. package/dist/db/migrations.js +19 -1
  14. package/dist/db/migrations.js.map +1 -1
  15. package/dist/db/queries.d.ts +157 -3
  16. package/dist/db/queries.d.ts.map +1 -1
  17. package/dist/db/queries.js +426 -9
  18. package/dist/db/queries.js.map +1 -1
  19. package/dist/db/schema.sql +32 -1
  20. package/dist/db/sqlite-adapter.d.ts +24 -17
  21. package/dist/db/sqlite-adapter.d.ts.map +1 -1
  22. package/dist/db/sqlite-adapter.js +292 -36
  23. package/dist/db/sqlite-adapter.js.map +1 -1
  24. package/dist/db/wal-valve.d.ts +119 -0
  25. package/dist/db/wal-valve.d.ts.map +1 -0
  26. package/dist/db/wal-valve.js +290 -0
  27. package/dist/db/wal-valve.js.map +1 -0
  28. package/dist/directory.d.ts +9 -5
  29. package/dist/directory.d.ts.map +1 -1
  30. package/dist/directory.js +210 -19
  31. package/dist/directory.js.map +1 -1
  32. package/dist/extraction/arkts-batch-worker.js +3 -2
  33. package/dist/extraction/arkts-batch-worker.js.map +1 -1
  34. package/dist/extraction/cfml-extractor.d.ts +107 -0
  35. package/dist/extraction/cfml-extractor.d.ts.map +1 -0
  36. package/dist/extraction/cfml-extractor.js +494 -0
  37. package/dist/extraction/cfml-extractor.js.map +1 -0
  38. package/dist/extraction/default-ignore.d.ts +39 -0
  39. package/dist/extraction/default-ignore.d.ts.map +1 -0
  40. package/dist/extraction/default-ignore.js +221 -0
  41. package/dist/extraction/default-ignore.js.map +1 -0
  42. package/dist/extraction/grammars.d.ts +25 -1
  43. package/dist/extraction/grammars.d.ts.map +1 -1
  44. package/dist/extraction/grammars.js +177 -24
  45. package/dist/extraction/grammars.js.map +1 -1
  46. package/dist/extraction/index.d.ts +52 -14
  47. package/dist/extraction/index.d.ts.map +1 -1
  48. package/dist/extraction/index.js +521 -314
  49. package/dist/extraction/index.js.map +1 -1
  50. package/dist/extraction/languages/arkts.d.ts +90 -6
  51. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  52. package/dist/extraction/languages/arkts.js +1579 -128
  53. package/dist/extraction/languages/arkts.js.map +1 -1
  54. package/dist/extraction/languages/c-cpp.d.ts +42 -0
  55. package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  56. package/dist/extraction/languages/c-cpp.js +369 -4
  57. package/dist/extraction/languages/c-cpp.js.map +1 -1
  58. package/dist/extraction/languages/cfquery.d.ts +12 -0
  59. package/dist/extraction/languages/cfquery.d.ts.map +1 -0
  60. package/dist/extraction/languages/cfquery.js +28 -0
  61. package/dist/extraction/languages/cfquery.js.map +1 -0
  62. package/dist/extraction/languages/cfscript.d.ts +3 -0
  63. package/dist/extraction/languages/cfscript.d.ts.map +1 -0
  64. package/dist/extraction/languages/cfscript.js +73 -0
  65. package/dist/extraction/languages/cfscript.js.map +1 -0
  66. package/dist/extraction/languages/cobol.d.ts +33 -0
  67. package/dist/extraction/languages/cobol.d.ts.map +1 -0
  68. package/dist/extraction/languages/cobol.js +499 -0
  69. package/dist/extraction/languages/cobol.js.map +1 -0
  70. package/dist/extraction/languages/erlang.d.ts +3 -0
  71. package/dist/extraction/languages/erlang.d.ts.map +1 -0
  72. package/dist/extraction/languages/erlang.js +350 -0
  73. package/dist/extraction/languages/erlang.js.map +1 -0
  74. package/dist/extraction/languages/index.d.ts.map +1 -1
  75. package/dist/extraction/languages/index.js +16 -0
  76. package/dist/extraction/languages/index.js.map +1 -1
  77. package/dist/extraction/languages/nix.d.ts +3 -0
  78. package/dist/extraction/languages/nix.d.ts.map +1 -0
  79. package/dist/extraction/languages/nix.js +294 -0
  80. package/dist/extraction/languages/nix.js.map +1 -0
  81. package/dist/extraction/languages/solidity.d.ts +3 -0
  82. package/dist/extraction/languages/solidity.d.ts.map +1 -0
  83. package/dist/extraction/languages/solidity.js +293 -0
  84. package/dist/extraction/languages/solidity.js.map +1 -0
  85. package/dist/extraction/languages/terraform.d.ts +3 -0
  86. package/dist/extraction/languages/terraform.d.ts.map +1 -0
  87. package/dist/extraction/languages/terraform.js +641 -0
  88. package/dist/extraction/languages/terraform.js.map +1 -0
  89. package/dist/extraction/languages/vbnet.d.ts +11 -0
  90. package/dist/extraction/languages/vbnet.d.ts.map +1 -0
  91. package/dist/extraction/languages/vbnet.js +141 -0
  92. package/dist/extraction/languages/vbnet.js.map +1 -0
  93. package/dist/extraction/mybatis-extractor.d.ts +30 -10
  94. package/dist/extraction/mybatis-extractor.d.ts.map +1 -1
  95. package/dist/extraction/mybatis-extractor.js +140 -38
  96. package/dist/extraction/mybatis-extractor.js.map +1 -1
  97. package/dist/extraction/parse-pool.d.ts +27 -1
  98. package/dist/extraction/parse-pool.d.ts.map +1 -1
  99. package/dist/extraction/parse-pool.js +75 -7
  100. package/dist/extraction/parse-pool.js.map +1 -1
  101. package/dist/extraction/parse-worker.js +9 -2
  102. package/dist/extraction/parse-worker.js.map +1 -1
  103. package/dist/extraction/store-worker.d.ts +20 -0
  104. package/dist/extraction/store-worker.d.ts.map +1 -0
  105. package/dist/extraction/store-worker.js +102 -0
  106. package/dist/extraction/store-worker.js.map +1 -0
  107. package/dist/extraction/store-writer.d.ts +48 -0
  108. package/dist/extraction/store-writer.d.ts.map +1 -0
  109. package/dist/extraction/store-writer.js +167 -0
  110. package/dist/extraction/store-writer.js.map +1 -0
  111. package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
  112. package/dist/extraction/tree-sitter-helpers.js +1 -0
  113. package/dist/extraction/tree-sitter-helpers.js.map +1 -1
  114. package/dist/extraction/tree-sitter-types.d.ts +3 -1
  115. package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  116. package/dist/extraction/tree-sitter.d.ts +38 -0
  117. package/dist/extraction/tree-sitter.d.ts.map +1 -1
  118. package/dist/extraction/tree-sitter.js +801 -10
  119. package/dist/extraction/tree-sitter.js.map +1 -1
  120. package/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
  121. package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  122. package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  123. package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  124. package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  125. package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  126. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  127. package/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
  128. package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  129. package/dist/extraction/wasm-runtime-flags.d.ts +14 -4
  130. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
  131. package/dist/extraction/wasm-runtime-flags.js +55 -7
  132. package/dist/extraction/wasm-runtime-flags.js.map +1 -1
  133. package/dist/graph/traversal.d.ts.map +1 -1
  134. package/dist/graph/traversal.js +1 -1
  135. package/dist/graph/traversal.js.map +1 -1
  136. package/dist/index.d.ts +74 -5
  137. package/dist/index.d.ts.map +1 -1
  138. package/dist/index.js +436 -55
  139. package/dist/index.js.map +1 -1
  140. package/dist/installer/index.d.ts +42 -0
  141. package/dist/installer/index.d.ts.map +1 -1
  142. package/dist/installer/index.js +97 -2
  143. package/dist/installer/index.js.map +1 -1
  144. package/dist/mcp/daemon.d.ts +25 -3
  145. package/dist/mcp/daemon.d.ts.map +1 -1
  146. package/dist/mcp/daemon.js +62 -8
  147. package/dist/mcp/daemon.js.map +1 -1
  148. package/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
  149. package/dist/mcp/dynamic-boundaries.js +2 -1
  150. package/dist/mcp/dynamic-boundaries.js.map +1 -1
  151. package/dist/mcp/early-ppid.d.ts +26 -0
  152. package/dist/mcp/early-ppid.d.ts.map +1 -0
  153. package/dist/mcp/early-ppid.js +29 -0
  154. package/dist/mcp/early-ppid.js.map +1 -0
  155. package/dist/mcp/engine.d.ts +4 -5
  156. package/dist/mcp/engine.d.ts.map +1 -1
  157. package/dist/mcp/engine.js +27 -1
  158. package/dist/mcp/engine.js.map +1 -1
  159. package/dist/mcp/index.d.ts.map +1 -1
  160. package/dist/mcp/index.js +41 -6
  161. package/dist/mcp/index.js.map +1 -1
  162. package/dist/mcp/liveness-watchdog.d.ts +18 -1
  163. package/dist/mcp/liveness-watchdog.d.ts.map +1 -1
  164. package/dist/mcp/liveness-watchdog.js +73 -13
  165. package/dist/mcp/liveness-watchdog.js.map +1 -1
  166. package/dist/mcp/memory-budget.d.ts +30 -0
  167. package/dist/mcp/memory-budget.d.ts.map +1 -0
  168. package/dist/mcp/memory-budget.js +123 -0
  169. package/dist/mcp/memory-budget.js.map +1 -0
  170. package/dist/mcp/proxy.d.ts.map +1 -1
  171. package/dist/mcp/proxy.js +88 -4
  172. package/dist/mcp/proxy.js.map +1 -1
  173. package/dist/mcp/query-cache.d.ts +35 -4
  174. package/dist/mcp/query-cache.d.ts.map +1 -1
  175. package/dist/mcp/query-cache.js +89 -19
  176. package/dist/mcp/query-cache.js.map +1 -1
  177. package/dist/mcp/query-pool.d.ts +46 -12
  178. package/dist/mcp/query-pool.d.ts.map +1 -1
  179. package/dist/mcp/query-pool.js +100 -23
  180. package/dist/mcp/query-pool.js.map +1 -1
  181. package/dist/mcp/query-worker.d.ts +2 -2
  182. package/dist/mcp/query-worker.js +2 -2
  183. package/dist/mcp/server-instructions.d.ts +4 -27
  184. package/dist/mcp/server-instructions.d.ts.map +1 -1
  185. package/dist/mcp/server-instructions.js +39 -84
  186. package/dist/mcp/server-instructions.js.map +1 -1
  187. package/dist/mcp/session.d.ts +14 -0
  188. package/dist/mcp/session.d.ts.map +1 -1
  189. package/dist/mcp/session.js +28 -1
  190. package/dist/mcp/session.js.map +1 -1
  191. package/dist/mcp/startup-handshake.d.ts +44 -0
  192. package/dist/mcp/startup-handshake.d.ts.map +1 -0
  193. package/dist/mcp/startup-handshake.js +73 -0
  194. package/dist/mcp/startup-handshake.js.map +1 -0
  195. package/dist/mcp/tools.d.ts +104 -4
  196. package/dist/mcp/tools.d.ts.map +1 -1
  197. package/dist/mcp/tools.js +2432 -217
  198. package/dist/mcp/tools.js.map +1 -1
  199. package/dist/mcp/transport.d.ts.map +1 -1
  200. package/dist/mcp/transport.js +18 -0
  201. package/dist/mcp/transport.js.map +1 -1
  202. package/dist/project-config.d.ts +38 -0
  203. package/dist/project-config.d.ts.map +1 -1
  204. package/dist/project-config.js +101 -2
  205. package/dist/project-config.js.map +1 -1
  206. package/dist/resolution/c-fnptr-synthesizer.d.ts +2 -1
  207. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
  208. package/dist/resolution/c-fnptr-synthesizer.js +178 -146
  209. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
  210. package/dist/resolution/callback-synthesizer.d.ts +54 -10
  211. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  212. package/dist/resolution/callback-synthesizer.js +1299 -257
  213. package/dist/resolution/callback-synthesizer.js.map +1 -1
  214. package/dist/resolution/cooperative-yield.d.ts +10 -2
  215. package/dist/resolution/cooperative-yield.d.ts.map +1 -1
  216. package/dist/resolution/cooperative-yield.js +6 -4
  217. package/dist/resolution/cooperative-yield.js.map +1 -1
  218. package/dist/resolution/frameworks/cics.d.ts +20 -0
  219. package/dist/resolution/frameworks/cics.d.ts.map +1 -0
  220. package/dist/resolution/frameworks/cics.js +90 -0
  221. package/dist/resolution/frameworks/cics.js.map +1 -0
  222. package/dist/resolution/frameworks/go.d.ts.map +1 -1
  223. package/dist/resolution/frameworks/go.js +29 -6
  224. package/dist/resolution/frameworks/go.js.map +1 -1
  225. package/dist/resolution/frameworks/index.d.ts.map +1 -1
  226. package/dist/resolution/frameworks/index.js +3 -0
  227. package/dist/resolution/frameworks/index.js.map +1 -1
  228. package/dist/resolution/frameworks/java.d.ts.map +1 -1
  229. package/dist/resolution/frameworks/java.js +14 -6
  230. package/dist/resolution/frameworks/java.js.map +1 -1
  231. package/dist/resolution/frameworks/terraform.d.ts +38 -0
  232. package/dist/resolution/frameworks/terraform.d.ts.map +1 -0
  233. package/dist/resolution/frameworks/terraform.js +277 -0
  234. package/dist/resolution/frameworks/terraform.js.map +1 -0
  235. package/dist/resolution/goframe-synthesizer.d.ts +2 -1
  236. package/dist/resolution/goframe-synthesizer.d.ts.map +1 -1
  237. package/dist/resolution/goframe-synthesizer.js +8 -3
  238. package/dist/resolution/goframe-synthesizer.js.map +1 -1
  239. package/dist/resolution/import-resolver.d.ts +9 -3
  240. package/dist/resolution/import-resolver.d.ts.map +1 -1
  241. package/dist/resolution/import-resolver.js +295 -11
  242. package/dist/resolution/import-resolver.js.map +1 -1
  243. package/dist/resolution/index.d.ts +146 -8
  244. package/dist/resolution/index.d.ts.map +1 -1
  245. package/dist/resolution/index.js +1089 -131
  246. package/dist/resolution/index.js.map +1 -1
  247. package/dist/resolution/memory-budget.d.ts +48 -0
  248. package/dist/resolution/memory-budget.d.ts.map +1 -0
  249. package/dist/resolution/memory-budget.js +162 -0
  250. package/dist/resolution/memory-budget.js.map +1 -0
  251. package/dist/resolution/name-matcher.d.ts +12 -4
  252. package/dist/resolution/name-matcher.d.ts.map +1 -1
  253. package/dist/resolution/name-matcher.js +793 -130
  254. package/dist/resolution/name-matcher.js.map +1 -1
  255. package/dist/resolution/resolver-pool.d.ts +106 -0
  256. package/dist/resolution/resolver-pool.d.ts.map +1 -0
  257. package/dist/resolution/resolver-pool.js +344 -0
  258. package/dist/resolution/resolver-pool.js.map +1 -0
  259. package/dist/resolution/resolver-worker.d.ts +17 -0
  260. package/dist/resolution/resolver-worker.d.ts.map +1 -0
  261. package/dist/resolution/resolver-worker.js +141 -0
  262. package/dist/resolution/resolver-worker.js.map +1 -0
  263. package/dist/resolution/strip-comments.d.ts +1 -1
  264. package/dist/resolution/strip-comments.d.ts.map +1 -1
  265. package/dist/resolution/strip-comments.js +49 -0
  266. package/dist/resolution/strip-comments.js.map +1 -1
  267. package/dist/resolution/types.d.ts +32 -0
  268. package/dist/resolution/types.d.ts.map +1 -1
  269. package/dist/resolution/workspace-packages.d.ts +10 -0
  270. package/dist/resolution/workspace-packages.d.ts.map +1 -1
  271. package/dist/resolution/workspace-packages.js +142 -4
  272. package/dist/resolution/workspace-packages.js.map +1 -1
  273. package/dist/search/identifier-segments.d.ts +60 -0
  274. package/dist/search/identifier-segments.d.ts.map +1 -0
  275. package/dist/search/identifier-segments.js +176 -0
  276. package/dist/search/identifier-segments.js.map +1 -0
  277. package/dist/search/query-utils.d.ts +201 -0
  278. package/dist/search/query-utils.d.ts.map +1 -1
  279. package/dist/search/query-utils.js +919 -2
  280. package/dist/search/query-utils.js.map +1 -1
  281. package/dist/spec/build/diff-parser.d.ts +55 -0
  282. package/dist/spec/build/diff-parser.d.ts.map +1 -0
  283. package/dist/spec/build/diff-parser.js +205 -0
  284. package/dist/spec/build/diff-parser.js.map +1 -0
  285. package/dist/spec/build/git-scanner.d.ts +93 -0
  286. package/dist/spec/build/git-scanner.d.ts.map +1 -0
  287. package/dist/spec/build/git-scanner.js +254 -0
  288. package/dist/spec/build/git-scanner.js.map +1 -0
  289. package/dist/spec/build/pipeline.d.ts +54 -0
  290. package/dist/spec/build/pipeline.d.ts.map +1 -0
  291. package/dist/spec/build/pipeline.js +170 -0
  292. package/dist/spec/build/pipeline.js.map +1 -0
  293. package/dist/spec/build/scan.d.ts +48 -0
  294. package/dist/spec/build/scan.d.ts.map +1 -0
  295. package/dist/spec/build/scan.js +89 -0
  296. package/dist/spec/build/scan.js.map +1 -0
  297. package/dist/spec/build/scope-resolver.d.ts +50 -0
  298. package/dist/spec/build/scope-resolver.d.ts.map +1 -0
  299. package/dist/spec/build/scope-resolver.js +105 -0
  300. package/dist/spec/build/scope-resolver.js.map +1 -0
  301. package/dist/spec/build/spec-extractor.d.ts +74 -0
  302. package/dist/spec/build/spec-extractor.d.ts.map +1 -0
  303. package/dist/spec/build/spec-extractor.js +344 -0
  304. package/dist/spec/build/spec-extractor.js.map +1 -0
  305. package/dist/spec/config.d.ts +35 -1
  306. package/dist/spec/config.d.ts.map +1 -1
  307. package/dist/spec/config.js +30 -5
  308. package/dist/spec/config.js.map +1 -1
  309. package/dist/spec/db/fts.d.ts.map +1 -1
  310. package/dist/spec/db/fts.js +19 -50
  311. package/dist/spec/db/fts.js.map +1 -1
  312. package/dist/spec/db/index.d.ts +5 -3
  313. package/dist/spec/db/index.d.ts.map +1 -1
  314. package/dist/spec/db/index.js +16 -1
  315. package/dist/spec/db/index.js.map +1 -1
  316. package/dist/spec/db/persist.d.ts +45 -0
  317. package/dist/spec/db/persist.d.ts.map +1 -0
  318. package/dist/spec/db/persist.js +66 -0
  319. package/dist/spec/db/persist.js.map +1 -0
  320. package/dist/spec/db/relations.d.ts +80 -1
  321. package/dist/spec/db/relations.d.ts.map +1 -1
  322. package/dist/spec/db/relations.js +175 -4
  323. package/dist/spec/db/relations.js.map +1 -1
  324. package/dist/spec/db/schema.d.ts +4 -0
  325. package/dist/spec/db/schema.d.ts.map +1 -1
  326. package/dist/spec/db/schema.js +4 -0
  327. package/dist/spec/db/schema.js.map +1 -1
  328. package/dist/spec/db/schema.sql +5 -1
  329. package/dist/spec/db/spec-node.d.ts +5 -0
  330. package/dist/spec/db/spec-node.d.ts.map +1 -1
  331. package/dist/spec/db/spec-node.js +11 -5
  332. package/dist/spec/db/spec-node.js.map +1 -1
  333. package/dist/spec/db/sql-utils.d.ts +11 -0
  334. package/dist/spec/db/sql-utils.d.ts.map +1 -0
  335. package/dist/spec/db/sql-utils.js +19 -0
  336. package/dist/spec/db/sql-utils.js.map +1 -0
  337. package/dist/spec/evolve/cluster-context.d.ts +30 -0
  338. package/dist/spec/evolve/cluster-context.d.ts.map +1 -0
  339. package/dist/spec/evolve/cluster-context.js +78 -0
  340. package/dist/spec/evolve/cluster-context.js.map +1 -0
  341. package/dist/spec/evolve/commit-spec-analyzer.d.ts +51 -0
  342. package/dist/spec/evolve/commit-spec-analyzer.d.ts.map +1 -0
  343. package/dist/spec/evolve/commit-spec-analyzer.js +88 -0
  344. package/dist/spec/evolve/commit-spec-analyzer.js.map +1 -0
  345. package/dist/spec/evolve/commit-spec-persister.d.ts +53 -0
  346. package/dist/spec/evolve/commit-spec-persister.d.ts.map +1 -0
  347. package/dist/spec/evolve/commit-spec-persister.js +93 -0
  348. package/dist/spec/evolve/commit-spec-persister.js.map +1 -0
  349. package/dist/spec/evolve/impact-locator.d.ts +23 -7
  350. package/dist/spec/evolve/impact-locator.d.ts.map +1 -1
  351. package/dist/spec/evolve/impact-locator.js +58 -14
  352. package/dist/spec/evolve/impact-locator.js.map +1 -1
  353. package/dist/spec/evolve/pipeline.d.ts +62 -25
  354. package/dist/spec/evolve/pipeline.d.ts.map +1 -1
  355. package/dist/spec/evolve/pipeline.js +436 -457
  356. package/dist/spec/evolve/pipeline.js.map +1 -1
  357. package/dist/spec/evolve/spec-rewriter.d.ts +13 -13
  358. package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -1
  359. package/dist/spec/evolve/spec-rewriter.js +45 -45
  360. package/dist/spec/evolve/spec-rewriter.js.map +1 -1
  361. package/dist/spec/git/commits.d.ts +85 -0
  362. package/dist/spec/git/commits.d.ts.map +1 -0
  363. package/dist/spec/git/commits.js +218 -0
  364. package/dist/spec/git/commits.js.map +1 -0
  365. package/dist/spec/git/exec.d.ts +13 -0
  366. package/dist/spec/git/exec.d.ts.map +1 -0
  367. package/dist/spec/git/exec.js +19 -0
  368. package/dist/spec/git/exec.js.map +1 -0
  369. package/dist/spec/git/index.d.ts +9 -0
  370. package/dist/spec/git/index.d.ts.map +1 -0
  371. package/dist/spec/git/index.js +22 -0
  372. package/dist/spec/git/index.js.map +1 -0
  373. package/dist/spec/git-utils.d.ts +8 -0
  374. package/dist/spec/git-utils.d.ts.map +1 -0
  375. package/dist/spec/git-utils.js +14 -0
  376. package/dist/spec/git-utils.js.map +1 -0
  377. package/dist/spec/graph/index.d.ts +8 -0
  378. package/dist/spec/graph/index.d.ts.map +1 -0
  379. package/dist/spec/graph/index.js +17 -0
  380. package/dist/spec/graph/index.js.map +1 -0
  381. package/dist/spec/graph/queries.d.ts +6 -35
  382. package/dist/spec/graph/queries.d.ts.map +1 -1
  383. package/dist/spec/graph/queries.js +71 -248
  384. package/dist/spec/graph/queries.js.map +1 -1
  385. package/dist/spec/llm/agent-client.d.ts +59 -0
  386. package/dist/spec/llm/agent-client.d.ts.map +1 -0
  387. package/dist/spec/llm/agent-client.js +213 -0
  388. package/dist/spec/llm/agent-client.js.map +1 -0
  389. package/dist/spec/llm/agents/claude-code.d.ts +32 -0
  390. package/dist/spec/llm/agents/claude-code.d.ts.map +1 -0
  391. package/dist/spec/llm/agents/claude-code.js +125 -0
  392. package/dist/spec/llm/agents/claude-code.js.map +1 -0
  393. package/dist/spec/llm/agents/codex.d.ts +32 -0
  394. package/dist/spec/llm/agents/codex.d.ts.map +1 -0
  395. package/dist/spec/llm/agents/codex.js +145 -0
  396. package/dist/spec/llm/agents/codex.js.map +1 -0
  397. package/dist/spec/llm/agents/detect-utils.d.ts +28 -0
  398. package/dist/spec/llm/agents/detect-utils.d.ts.map +1 -0
  399. package/dist/spec/llm/agents/detect-utils.js +91 -0
  400. package/dist/spec/llm/agents/detect-utils.js.map +1 -0
  401. package/dist/spec/llm/agents/deveco-code.d.ts +33 -0
  402. package/dist/spec/llm/agents/deveco-code.d.ts.map +1 -0
  403. package/dist/spec/llm/agents/deveco-code.js +165 -0
  404. package/dist/spec/llm/agents/deveco-code.js.map +1 -0
  405. package/dist/spec/llm/agents/index.d.ts +31 -0
  406. package/dist/spec/llm/agents/index.d.ts.map +1 -0
  407. package/dist/spec/llm/agents/index.js +65 -0
  408. package/dist/spec/llm/agents/index.js.map +1 -0
  409. package/dist/spec/llm/agents/types.d.ts +76 -0
  410. package/dist/spec/llm/agents/types.d.ts.map +1 -0
  411. package/dist/spec/llm/agents/types.js +15 -0
  412. package/dist/spec/llm/agents/types.js.map +1 -0
  413. package/dist/spec/llm/client.d.ts +31 -11
  414. package/dist/spec/llm/client.d.ts.map +1 -1
  415. package/dist/spec/llm/client.js +143 -81
  416. package/dist/spec/llm/client.js.map +1 -1
  417. package/dist/spec/llm/factory.d.ts +41 -0
  418. package/dist/spec/llm/factory.d.ts.map +1 -0
  419. package/dist/spec/llm/factory.js +80 -0
  420. package/dist/spec/llm/factory.js.map +1 -0
  421. package/dist/spec/llm/prompts.d.ts +24 -8
  422. package/dist/spec/llm/prompts.d.ts.map +1 -1
  423. package/dist/spec/llm/prompts.js +100 -50
  424. package/dist/spec/llm/prompts.js.map +1 -1
  425. package/dist/spec/llm/retry.d.ts +53 -0
  426. package/dist/spec/llm/retry.d.ts.map +1 -0
  427. package/dist/spec/llm/retry.js +153 -0
  428. package/dist/spec/llm/retry.js.map +1 -0
  429. package/dist/spec/mine/clusterer.d.ts +63 -0
  430. package/dist/spec/mine/clusterer.d.ts.map +1 -0
  431. package/dist/spec/mine/clusterer.js +904 -0
  432. package/dist/spec/mine/clusterer.js.map +1 -0
  433. package/dist/spec/mine/clustering/features.d.ts +38 -0
  434. package/dist/spec/mine/clustering/features.d.ts.map +1 -0
  435. package/dist/spec/mine/clustering/features.js +108 -0
  436. package/dist/spec/mine/clustering/features.js.map +1 -0
  437. package/dist/spec/mine/clustering/index.d.ts +62 -0
  438. package/dist/spec/mine/clustering/index.d.ts.map +1 -0
  439. package/dist/spec/mine/clustering/index.js +259 -0
  440. package/dist/spec/mine/clustering/index.js.map +1 -0
  441. package/dist/spec/mine/clustering/leiden.d.ts +61 -0
  442. package/dist/spec/mine/clustering/leiden.d.ts.map +1 -0
  443. package/dist/spec/mine/clustering/leiden.js +489 -0
  444. package/dist/spec/mine/clustering/leiden.js.map +1 -0
  445. package/dist/spec/mine/clustering/text-similarity.d.ts +22 -0
  446. package/dist/spec/mine/clustering/text-similarity.d.ts.map +1 -0
  447. package/dist/spec/mine/clustering/text-similarity.js +98 -0
  448. package/dist/spec/mine/clustering/text-similarity.js.map +1 -0
  449. package/dist/spec/mine/generator.d.ts +54 -0
  450. package/dist/spec/mine/generator.d.ts.map +1 -0
  451. package/dist/spec/mine/generator.js +267 -0
  452. package/dist/spec/mine/generator.js.map +1 -0
  453. package/dist/spec/mine/persist.d.ts +37 -0
  454. package/dist/spec/mine/persist.d.ts.map +1 -0
  455. package/dist/spec/mine/persist.js +170 -0
  456. package/dist/spec/mine/persist.js.map +1 -0
  457. package/dist/spec/mine/pipeline.d.ts +41 -0
  458. package/dist/spec/mine/pipeline.d.ts.map +1 -0
  459. package/dist/spec/mine/pipeline.js +236 -0
  460. package/dist/spec/mine/pipeline.js.map +1 -0
  461. package/dist/spec/mine/progress-handler.d.ts +22 -0
  462. package/dist/spec/mine/progress-handler.d.ts.map +1 -0
  463. package/dist/spec/mine/progress-handler.js +108 -0
  464. package/dist/spec/mine/progress-handler.js.map +1 -0
  465. package/dist/spec/mine/progress.d.ts +23 -0
  466. package/dist/spec/mine/progress.d.ts.map +1 -0
  467. package/dist/spec/mine/progress.js +12 -0
  468. package/dist/spec/mine/progress.js.map +1 -0
  469. package/dist/spec/mine/scanner.d.ts +59 -0
  470. package/dist/spec/mine/scanner.d.ts.map +1 -0
  471. package/dist/spec/mine/scanner.js +383 -0
  472. package/dist/spec/mine/scanner.js.map +1 -0
  473. package/dist/spec/types.d.ts +32 -0
  474. package/dist/spec/types.d.ts.map +1 -1
  475. package/dist/spec/ui/index.d.ts +9 -0
  476. package/dist/spec/ui/index.d.ts.map +1 -0
  477. package/dist/spec/ui/index.js +16 -0
  478. package/dist/spec/ui/index.js.map +1 -0
  479. package/dist/spec/ui/progress-handler.d.ts +33 -0
  480. package/dist/spec/ui/progress-handler.d.ts.map +1 -0
  481. package/dist/spec/ui/progress-handler.js +132 -0
  482. package/dist/spec/ui/progress-handler.js.map +1 -0
  483. package/dist/spec/ui/progress.d.ts +24 -0
  484. package/dist/spec/ui/progress.d.ts.map +1 -0
  485. package/dist/spec/ui/progress.js +13 -0
  486. package/dist/spec/ui/progress.js.map +1 -0
  487. package/dist/spec/utils/fs.d.ts +45 -0
  488. package/dist/spec/utils/fs.d.ts.map +1 -0
  489. package/dist/spec/utils/fs.js +163 -0
  490. package/dist/spec/utils/fs.js.map +1 -0
  491. package/dist/spec/utils/index.d.ts +12 -0
  492. package/dist/spec/utils/index.d.ts.map +1 -0
  493. package/dist/spec/utils/index.js +26 -0
  494. package/dist/spec/utils/index.js.map +1 -0
  495. package/dist/spec/utils/meta.d.ts +32 -0
  496. package/dist/spec/utils/meta.d.ts.map +1 -0
  497. package/dist/spec/utils/meta.js +122 -0
  498. package/dist/spec/utils/meta.js.map +1 -0
  499. package/dist/spec/utils/truncate.d.ts +86 -0
  500. package/dist/spec/utils/truncate.d.ts.map +1 -0
  501. package/dist/spec/utils/truncate.js +172 -0
  502. package/dist/spec/utils/truncate.js.map +1 -0
  503. package/dist/spec/utils.d.ts +4 -16
  504. package/dist/spec/utils.d.ts.map +1 -1
  505. package/dist/spec/utils.js +6 -58
  506. package/dist/spec/utils.js.map +1 -1
  507. package/dist/sync/git-hooks.d.ts.map +1 -1
  508. package/dist/sync/git-hooks.js +2 -0
  509. package/dist/sync/git-hooks.js.map +1 -1
  510. package/dist/sync/watcher.d.ts +35 -6
  511. package/dist/sync/watcher.d.ts.map +1 -1
  512. package/dist/sync/watcher.js +127 -17
  513. package/dist/sync/watcher.js.map +1 -1
  514. package/dist/sync/worktree.d.ts.map +1 -1
  515. package/dist/sync/worktree.js +5 -0
  516. package/dist/sync/worktree.js.map +1 -1
  517. package/dist/telemetry/index.js +3 -3
  518. package/dist/telemetry/index.js.map +1 -1
  519. package/dist/types.d.ts +22 -1
  520. package/dist/types.d.ts.map +1 -1
  521. package/dist/types.js +10 -0
  522. package/dist/types.js.map +1 -1
  523. package/dist/upgrade/index.d.ts +32 -0
  524. package/dist/upgrade/index.d.ts.map +1 -1
  525. package/dist/upgrade/index.js +162 -14
  526. package/dist/upgrade/index.js.map +1 -1
  527. package/dist/upgrade/remove-binary.d.ts +87 -0
  528. package/dist/upgrade/remove-binary.d.ts.map +1 -0
  529. package/dist/upgrade/remove-binary.js +289 -0
  530. package/dist/upgrade/remove-binary.js.map +1 -0
  531. package/dist/upgrade/update-check.d.ts +92 -0
  532. package/dist/upgrade/update-check.d.ts.map +1 -0
  533. package/dist/upgrade/update-check.js +258 -0
  534. package/dist/upgrade/update-check.js.map +1 -0
  535. package/package.json +6 -2
  536. package/scripts/agent-eval/run-all.sh +6 -0
  537. package/scripts/build-bundle.sh +5 -0
  538. package/scripts/npm-shim.js +8 -1
  539. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  540. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  541. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-310.pyc +0 -0
  542. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  543. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  544. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  545. package/scripts/exp_boundary_eval/data/agents.json +0 -109
  546. package/scripts/exp_boundary_eval/data/experiments.json +0 -140
  547. package/scripts/qa_eval/README.md +0 -407
  548. package/scripts/qa_eval/_test_deveco_probe.py +0 -41
  549. package/scripts/qa_eval/agent_runner.py +0 -526
  550. package/scripts/qa_eval/data/.gitignore +0 -4
  551. package/scripts/qa_eval/data/test-set.jsonl +0 -2
  552. package/scripts/qa_eval/eval_metrics.py +0 -274
  553. package/scripts/qa_eval/external_agent.py +0 -976
  554. package/scripts/qa_eval/llm_config.py +0 -92
  555. package/scripts/qa_eval/memory_monitor.py +0 -132
  556. package/scripts/qa_eval/my_answer_accuracy.py +0 -187
  557. package/scripts/qa_eval/requirements.txt +0 -2
  558. package/scripts/qa_eval/run_pipeline.py +0 -804
  559. package/scripts/qa_eval/stats_efficiency.py +0 -279
  560. package/scripts/qa_eval/stats_scores.py +0 -207
@@ -54,6 +54,7 @@ const astro_extractor_1 = require("./astro-extractor");
54
54
  const dfm_extractor_1 = require("./dfm-extractor");
55
55
  const vue_extractor_1 = require("./vue-extractor");
56
56
  const mybatis_extractor_1 = require("./mybatis-extractor");
57
+ const cfml_extractor_1 = require("./cfml-extractor");
57
58
  const arkts_1 = require("./languages/arkts");
58
59
  const frameworks_1 = require("../resolution/frameworks");
59
60
  // Re-export for backward compatibility
@@ -78,6 +79,27 @@ const VUE_STORE_FACTORY_CALLEES = new Set(['defineStore', 'createStore']);
78
79
  /** Distinct signals that a file is a Vuex/Pinia store (≥2 ⇒ treat a bare
79
80
  * `const actions = {…}` as a store collection — see looksLikeVueStoreFile). */
80
81
  const VUE_STORE_FILE_SIGNAL = /\bdefineStore\b|\bcreateStore\b|\bVuex\b|\bmutations\b|\bactions\b|\bgetters\b|\bnamespaced\b/g;
82
+ /**
83
+ * Erlang calls that take their real callee as (Module, Function, Args)
84
+ * ARGUMENTS — the spawn/apply family. Keys are the callee as the call site
85
+ * spells it: bare for auto-imported BIFs, `module:function` for remote calls.
86
+ * Used by the erlang branch of extractCall to lift a static MFA pair into a
87
+ * call edge (the spawned/applied function is otherwise invisible to the graph).
88
+ */
89
+ /** Compiler-predefined Erlang macros — no `-define` exists to link a use to. */
90
+ const ERLANG_PREDEFINED_MACROS = new Set([
91
+ 'MODULE', 'MODULE_STRING', 'FILE', 'LINE', 'MACHINE',
92
+ 'FUNCTION_NAME', 'FUNCTION_ARITY', 'OTP_RELEASE',
93
+ 'FEATURE_AVAILABLE', 'FEATURE_ENABLED',
94
+ ]);
95
+ const ERLANG_MFA_CALLS = new Set([
96
+ 'spawn', 'spawn_link', 'spawn_monitor', 'spawn_opt', 'apply',
97
+ 'erlang:spawn', 'erlang:spawn_link', 'erlang:spawn_monitor', 'erlang:spawn_opt', 'erlang:apply',
98
+ 'proc_lib:spawn', 'proc_lib:spawn_link', 'proc_lib:spawn_opt', 'proc_lib:start', 'proc_lib:start_link',
99
+ 'timer:apply_after', 'timer:apply_interval',
100
+ 'rpc:call', 'rpc:cast', 'rpc:async_call',
101
+ 'erpc:call', 'erpc:cast',
102
+ ]);
81
103
  /**
82
104
  * Extract the name from a node based on language
83
105
  */
@@ -334,6 +356,29 @@ const INSTANTIATION_KINDS = new Set([
334
356
  'struct_expression', // rust — `Widget { n: 1 }` / `m::Widget { .. }`
335
357
  'instance_expression', // scala — `new Monoid[Int] { ... }`
336
358
  ]);
359
+ /**
360
+ * tree-sitter node types (across grammars) for literal expressions in method-
361
+ * call RECEIVER position. A literal's methods are the language's builtins —
362
+ * `", ".join`, `"x".toUpperCase()`, `5.times`, `[].concat` — never project
363
+ * symbols, so a member call on one must not emit a `calls` ref that bare-name
364
+ * matching could bind to an unrelated same-named project function (#1230).
365
+ */
366
+ const LITERAL_RECEIVER_TYPES = new Set([
367
+ // strings
368
+ 'string', 'string_literal', 'interpreted_string_literal', 'raw_string_literal',
369
+ 'template_string', 'concatenated_string', 'formatted_string', 'f_string',
370
+ 'line_string_literal', 'string_content', 'heredoc_body',
371
+ // numbers
372
+ 'number', 'number_literal', 'integer', 'integer_literal', 'float',
373
+ 'float_literal', 'int_literal', 'decimal_integer_literal', 'real_literal',
374
+ // chars / runes / regex / booleans / null-likes
375
+ 'char_literal', 'character_literal', 'rune_literal', 'regex', 'regex_literal',
376
+ 'true', 'false', 'boolean_literal', 'bool_literal', 'none', 'null', 'nil',
377
+ 'null_literal', 'undefined',
378
+ // collection literals
379
+ 'list', 'list_literal', 'array', 'array_literal', 'array_creation_expression',
380
+ 'dictionary', 'dict_literal', 'object', 'tuple', 'set',
381
+ ]);
337
382
  /**
338
383
  * TreeSitterExtractor - Main extraction class
339
384
  */
@@ -348,7 +393,7 @@ class TreeSitterExtractor {
348
393
  // Value-reference edges (default ON; set HOMEGRAPH_VALUE_REFS=0 to disable; see flushValueRefs).
349
394
  // Same-file reads of file-scope const/var symbols → `references` edges so impact analysis catches
350
395
  // value consumers ("change this constant/table, affect its readers").
351
- static VALUE_REF_LANGS = new Set(['typescript', 'javascript', 'tsx', 'go', 'python', 'rust', 'ruby', 'c', 'java', 'csharp', 'php', 'scala', 'kotlin', 'swift', 'dart', 'pascal']);
396
+ static VALUE_REF_LANGS = new Set(['typescript', 'javascript', 'tsx', 'arkts', 'go', 'python', 'rust', 'ruby', 'c', 'java', 'csharp', 'php', 'scala', 'kotlin', 'swift', 'dart', 'pascal']);
352
397
  static MAX_VALUE_REF_NODES = 20_000;
353
398
  valueRefsEnabled = process.env.HOMEGRAPH_VALUE_REFS !== '0';
354
399
  fileScopeValues = new Map();
@@ -357,6 +402,20 @@ class TreeSitterExtractor {
357
402
  errors = [];
358
403
  extractor = null;
359
404
  nodeStack = []; // Stack of parent node IDs
405
+ // C/C++ enclosing `namespace ns { … }` names, prepended to every contained
406
+ // symbol's qualifiedName (see visitNode). Prefix-only by design — no
407
+ // namespace NODE is created: `namespace cutlass {` opens in thousands of
408
+ // files, and a node per block would flood search with same-named symbols
409
+ // (the #1093 crowd-out failure mode). Always empty outside C/C++.
410
+ namespacePrefix = [];
411
+ // C++ local function-pointer bindings, per enclosing symbol:
412
+ // `auto kernel = &flash_fwd_kernel<…>;` recorded as callerId → kernel →
413
+ // {flash_fwd_kernel}, so a later `kernel<<<grid, block>>>(params)` (or plain
414
+ // `kernel(args)`) in the same body emits calls refs to the real target(s)
415
+ // instead of an unresolvable local name. Branch reassignments accumulate —
416
+ // each assigned target is a genuine possible callee. Same-body locality is
417
+ // the precision guard (the #932 table-dispatch philosophy scoped to locals).
418
+ cppLocalFnPtrs = new Map();
360
419
  methodIndex = null; // lookup key → node ID for Pascal defProc lookup
361
420
  // Function-as-value capture (#756): per-language spec + candidates collected
362
421
  // during the walk, gated & flushed into unresolvedReferences at end-of-file
@@ -417,7 +476,7 @@ class TreeSitterExtractor {
417
476
  // this.source so downstream getNodeText reads the same bytes the parser
418
477
  // saw (identical outside the blanked directive lines).
419
478
  if (this.extractor?.preParse) {
420
- this.source = this.extractor.preParse(this.source);
479
+ this.source = this.extractor.preParse(this.source, this.filePath);
421
480
  }
422
481
  this.tree = parser.parse(this.source) ?? null;
423
482
  if (!this.tree) {
@@ -875,6 +934,31 @@ class TreeSitterExtractor {
875
934
  if (skipChildren)
876
935
  return;
877
936
  }
937
+ // C++ namespace blocks: carry the namespace name as a qualifiedName prefix
938
+ // while walking the body, so `namespace flash { void compute_attn(); }`
939
+ // indexes compute_attn with qualifiedName `flash::compute_attn` and a
940
+ // namespace-qualified call (`flash::compute_attn(...)`) resolves by exact
941
+ // qualified match instead of never resolving — C++ namespaces previously
942
+ // left no trace in qualifiedNames at all, so every `ns::fn()` call site
943
+ // was a permanently dead edge (surfaced by #387 flow validation on
944
+ // flash-attention/cutlass, whose kernel dispatch is namespace-qualified).
945
+ // C++17 nested forms (`namespace a::b {`) prefix as written. An anonymous
946
+ // namespace falls through to the generic walk — its contents stay bare,
947
+ // matching how call sites spell them.
948
+ if (this.language === 'cpp' && nodeType === 'namespace_definition') {
949
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
950
+ const nsName = nameNode ? (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source) : '';
951
+ if (nsName) {
952
+ this.namespacePrefix.push(nsName);
953
+ for (let i = 0; i < node.namedChildCount; i++) {
954
+ const child = node.namedChild(i);
955
+ if (child)
956
+ this.visitNode(child);
957
+ }
958
+ this.namespacePrefix.pop();
959
+ return;
960
+ }
961
+ }
878
962
  // Function-as-value capture (#756) — independent of the dispatch ladder
879
963
  // below (the captured container types have no other handler there), so it
880
964
  // can never shadow or be shadowed by an extraction branch.
@@ -1108,7 +1192,8 @@ class TreeSitterExtractor {
1108
1192
  // falls through to its normal declaration extraction).
1109
1193
  else if (nodeType === 'export_statement' &&
1110
1194
  (this.language === 'typescript' || this.language === 'tsx' ||
1111
- this.language === 'javascript' || this.language === 'jsx') &&
1195
+ this.language === 'javascript' || this.language === 'jsx' ||
1196
+ this.language === 'arkts') &&
1112
1197
  (0, tree_sitter_helpers_1.getChildByField)(node, 'source')) {
1113
1198
  const parentId = this.nodeStack[this.nodeStack.length - 1];
1114
1199
  if (parentId)
@@ -1138,7 +1223,7 @@ class TreeSitterExtractor {
1138
1223
  // produce an `instantiates` reference. Children still walked so
1139
1224
  // nested calls inside the constructor args (`new Foo(bar())`) get
1140
1225
  // their own `calls` refs.
1141
- else if (INSTANTIATION_KINDS.has(nodeType)) {
1226
+ else if (INSTANTIATION_KINDS.has(nodeType) || this.isVbnetConstructorShapedArrayCreation(node)) {
1142
1227
  this.extractInstantiation(node);
1143
1228
  // Java/C# `new T(...) { ... }` — anonymous class with body. Without
1144
1229
  // extracting it as a class node + its methods, the interface→impl
@@ -1289,7 +1374,8 @@ class TreeSitterExtractor {
1289
1374
  buildQualifiedName(name) {
1290
1375
  // Build a qualified name from the semantic hierarchy only (no file path).
1291
1376
  // The file path is stored separately in filePath and pollutes FTS if included here.
1292
- const parts = [];
1377
+ // C/C++ enclosing namespaces prefix first (empty for every other language).
1378
+ const parts = [...this.namespacePrefix];
1293
1379
  for (const nodeId of this.nodeStack) {
1294
1380
  const node = this.nodes.find((n) => n.id === nodeId);
1295
1381
  if (node && node.kind !== 'file') {
@@ -2370,7 +2456,8 @@ class TreeSitterExtractor {
2370
2456
  const isExported = this.extractor.isExported?.(node, this.source) ?? false;
2371
2457
  // Extract variable declarators based on language
2372
2458
  if (this.language === 'typescript' || this.language === 'javascript' ||
2373
- this.language === 'tsx' || this.language === 'jsx') {
2459
+ this.language === 'tsx' || this.language === 'jsx' || this.language === 'cfscript' ||
2460
+ this.language === 'arkts') {
2374
2461
  // Handle lexical_declaration and variable_declaration
2375
2462
  // These contain one or more variable_declarator children
2376
2463
  for (let i = 0; i < node.namedChildCount; i++) {
@@ -2784,7 +2871,7 @@ class TreeSitterExtractor {
2784
2871
  // property/method nodes under the type alias so `recorder.stop()`
2785
2872
  // can attach the call edge to `RecorderHandle.stop` instead of
2786
2873
  // an unrelated class method picked by path-proximity (#359).
2787
- if (this.language === 'typescript' || this.language === 'tsx') {
2874
+ if (this.language === 'typescript' || this.language === 'tsx' || this.language === 'arkts') {
2788
2875
  this.extractTsTypeAliasMembers(value, typeAliasNode);
2789
2876
  // `type List = [ Service<'name', Req, Resp>, … ]` — surface each
2790
2877
  // entry's string-literal name as a searchable member (issue #634).
@@ -3005,7 +3092,8 @@ class TreeSitterExtractor {
3005
3092
  // Link each imported binding to its definition so imported-but-not-
3006
3093
  // called/typed symbols still record a cross-file dependency (TS/JS only).
3007
3094
  if (this.language === 'typescript' || this.language === 'tsx' ||
3008
- this.language === 'javascript' || this.language === 'jsx') {
3095
+ this.language === 'javascript' || this.language === 'jsx' ||
3096
+ this.language === 'arkts') {
3009
3097
  const parentId = this.nodeStack[this.nodeStack.length - 1];
3010
3098
  if (parentId)
3011
3099
  this.emitImportBindingRefs(node, parentId);
@@ -3444,12 +3532,295 @@ class TreeSitterExtractor {
3444
3532
  /**
3445
3533
  * Extract a function call
3446
3534
  */
3535
+ /**
3536
+ * The module an Erlang gen_server target expression statically names, or
3537
+ * null when it's dynamic (pid/var/tuple form). Static shapes:
3538
+ * - a bare atom — either this module or another one; OTP's dominant
3539
+ * registration convention (`{local, ?MODULE}`) names a server process
3540
+ * after its module, so `gen_server:call(other_mod, …)` reaches
3541
+ * `other_mod`'s handlers. A registered name that matches no module
3542
+ * resolves to nothing downstream (the qualified ref just drops).
3543
+ * - `?MODULE`, or a macro the file defines as `?MODULE`
3544
+ * (`-define(SERVER, ?MODULE)` — the standard self idiom)
3545
+ * - a macro the file defines as a bare atom
3546
+ * (`-define(STORE, kv_store)` — the cross-module variant)
3547
+ * The macro tables are memoized per file (single entry — extraction is
3548
+ * file-sequential).
3549
+ */
3550
+ erlangServerMacroFile = '';
3551
+ erlangSelfMacros = new Set();
3552
+ erlangAtomMacros = new Map();
3553
+ resolveErlangGenServerTarget(target) {
3554
+ const ownModule = (this.filePath.split('/').pop() ?? '').replace(/\.erl$/, '');
3555
+ if (target.type === 'atom') {
3556
+ const name = (0, tree_sitter_helpers_1.getNodeText)(target, this.source).replace(/^'([\s\S]*)'$/, '$1');
3557
+ return name || null;
3558
+ }
3559
+ if (target.type !== 'macro_call_expr')
3560
+ return null;
3561
+ const nameNode = (0, tree_sitter_helpers_1.getChildByField)(target, 'name');
3562
+ if (!nameNode)
3563
+ return null;
3564
+ const macroName = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
3565
+ if (macroName === 'MODULE')
3566
+ return ownModule || null;
3567
+ if (this.erlangServerMacroFile !== this.filePath) {
3568
+ this.erlangServerMacroFile = this.filePath;
3569
+ this.erlangSelfMacros = new Set();
3570
+ this.erlangAtomMacros = new Map();
3571
+ let root = target;
3572
+ while (root.parent)
3573
+ root = root.parent;
3574
+ for (let i = 0; i < root.namedChildCount; i++) {
3575
+ const form = root.namedChild(i);
3576
+ if (form?.type !== 'pp_define')
3577
+ continue;
3578
+ const lhs = (0, tree_sitter_helpers_1.getChildByField)(form, 'lhs');
3579
+ const defName = lhs ? (0, tree_sitter_helpers_1.getChildByField)(lhs, 'name') : null;
3580
+ const replacement = (0, tree_sitter_helpers_1.getChildByField)(form, 'replacement');
3581
+ if (!defName || !replacement)
3582
+ continue;
3583
+ if (replacement.type === 'macro_call_expr' &&
3584
+ (0, tree_sitter_helpers_1.getChildByField)(replacement, 'name') &&
3585
+ (0, tree_sitter_helpers_1.getNodeText)((0, tree_sitter_helpers_1.getChildByField)(replacement, 'name'), this.source) === 'MODULE') {
3586
+ this.erlangSelfMacros.add((0, tree_sitter_helpers_1.getNodeText)(defName, this.source));
3587
+ }
3588
+ else if (replacement.type === 'atom') {
3589
+ this.erlangAtomMacros.set((0, tree_sitter_helpers_1.getNodeText)(defName, this.source), (0, tree_sitter_helpers_1.getNodeText)(replacement, this.source).replace(/^'([\s\S]*)'$/, '$1'));
3590
+ }
3591
+ }
3592
+ }
3593
+ if (this.erlangSelfMacros.has(macroName))
3594
+ return ownModule || null;
3595
+ return this.erlangAtomMacros.get(macroName) ?? null;
3596
+ }
3447
3597
  extractCall(node) {
3448
3598
  if (this.nodeStack.length === 0)
3449
3599
  return;
3450
3600
  const callerId = this.nodeStack[this.nodeStack.length - 1];
3451
3601
  if (!callerId)
3452
3602
  return;
3603
+ // VB.NET: `foo(args)` is syntactically ambiguous between a call and an
3604
+ // index read, so the grammar parses non-empty parens as
3605
+ // array_access_expression (field `array`, not `function`) — even Roslyn
3606
+ // parses both as InvocationExpression and resolves during binding. Treat
3607
+ // all three shapes as call sites: the callee is the member/identifier
3608
+ // under the array/function field, qualified with a simple-identifier
3609
+ // receiver for resolution. Index reads on collections simply never
3610
+ // resolve to a callable, so they cost nothing.
3611
+ if (this.language === 'vbnet' &&
3612
+ (node.type === 'array_access_expression' ||
3613
+ node.type === 'invocation_expression' ||
3614
+ node.type === 'generic_invocation_expression')) {
3615
+ const fn = (0, tree_sitter_helpers_1.getChildByField)(node, 'function') || (0, tree_sitter_helpers_1.getChildByField)(node, 'array');
3616
+ if (!fn)
3617
+ return;
3618
+ let calleeName = '';
3619
+ if (fn.type === 'member_access_expression') {
3620
+ const member = (0, tree_sitter_helpers_1.getChildByField)(fn, 'member');
3621
+ const memberName = member ? (0, tree_sitter_helpers_1.getNodeText)(member, this.source) : '';
3622
+ if (!memberName)
3623
+ return;
3624
+ const receiver = (0, tree_sitter_helpers_1.getChildByField)(fn, 'object');
3625
+ const SKIP = new Set(['me', 'mybase', 'myclass']);
3626
+ if (receiver && receiver.type === 'identifier' && !SKIP.has((0, tree_sitter_helpers_1.getNodeText)(receiver, this.source).toLowerCase())) {
3627
+ calleeName = `${(0, tree_sitter_helpers_1.getNodeText)(receiver, this.source)}.${memberName}`;
3628
+ }
3629
+ else {
3630
+ calleeName = memberName;
3631
+ }
3632
+ }
3633
+ else if (fn.type === 'identifier') {
3634
+ calleeName = (0, tree_sitter_helpers_1.getNodeText)(fn, this.source);
3635
+ }
3636
+ else {
3637
+ return; // parenthesized/chained receivers: no static name to link
3638
+ }
3639
+ if (calleeName) {
3640
+ this.unresolvedReferences.push({
3641
+ fromNodeId: callerId,
3642
+ referenceName: calleeName,
3643
+ referenceKind: 'calls',
3644
+ line: node.startPosition.row + 1,
3645
+ column: node.startPosition.column,
3646
+ });
3647
+ }
3648
+ return;
3649
+ }
3650
+ // Erlang: a local call is `call(expr: atom, args)`; a remote call nests it
3651
+ // under `remote(module: remote_module, fun: call)` — the module qualifier
3652
+ // lives on the PARENT. Remote calls are emitted as `mod::fn`, which is
3653
+ // byte-identical to the qualifiedName the module namespace gives every
3654
+ // function (see packageTypes in languages/erlang.ts), so they resolve via
3655
+ // matchByQualifiedName. A var/macro callee or module (`F(X)`, `?M(X)`,
3656
+ // `Mod:handle(X)`) has no static target — except `?MODULE:fn(X)`, which the
3657
+ // bare name + same-file preference resolves correctly. `fun name/1` /
3658
+ // `fun mod:name/1` values are function REFERENCES (callback registration),
3659
+ // and record construction/update/index/field-access are `references` to the
3660
+ // record's struct node.
3661
+ if (this.language === 'erlang') {
3662
+ const line = node.startPosition.row + 1;
3663
+ const column = node.startPosition.column;
3664
+ const erlAtom = (n) => (0, tree_sitter_helpers_1.getNodeText)(n, this.source).replace(/^'([\s\S]*)'$/, '$1');
3665
+ if (node.type === 'call') {
3666
+ let callee = (0, tree_sitter_helpers_1.getChildByField)(node, 'expr');
3667
+ let moduleNode = null;
3668
+ // remote(module, fun: call) — the shape the grammar produces today; the
3669
+ // node-types also permit call(expr: remote), so handle both nestings.
3670
+ if (node.parent?.type === 'remote') {
3671
+ moduleNode = (0, tree_sitter_helpers_1.getChildByField)(node.parent, 'module');
3672
+ }
3673
+ else if (callee?.type === 'remote') {
3674
+ moduleNode = (0, tree_sitter_helpers_1.getChildByField)(callee, 'module');
3675
+ callee = (0, tree_sitter_helpers_1.getChildByField)(callee, 'fun');
3676
+ }
3677
+ if (callee?.type === 'atom') {
3678
+ const fnBare = erlAtom(callee);
3679
+ let calleeName = fnBare;
3680
+ const moduleExpr = moduleNode ? (0, tree_sitter_helpers_1.getChildByField)(moduleNode, 'module') : null;
3681
+ if (moduleExpr?.type === 'atom') {
3682
+ calleeName = `${erlAtom(moduleExpr)}::${calleeName}`;
3683
+ }
3684
+ else if (moduleExpr) {
3685
+ // Non-atom module qualifier. `?MODULE:f(X)` targets THIS module —
3686
+ // keep the bare name so same-file preference resolves it. Anything
3687
+ // else (`Mod:f(X)`) is behaviour-style dynamic dispatch with no
3688
+ // static target: emitting the bare name would link an arbitrary
3689
+ // same-named function, so stay silent instead.
3690
+ const macroName = moduleExpr.type === 'macro_call_expr' ? (0, tree_sitter_helpers_1.getChildByField)(moduleExpr, 'name') : null;
3691
+ if (!macroName || (0, tree_sitter_helpers_1.getNodeText)(macroName, this.source) !== 'MODULE')
3692
+ return;
3693
+ }
3694
+ this.unresolvedReferences.push({
3695
+ fromNodeId: callerId,
3696
+ referenceName: calleeName,
3697
+ referenceKind: 'calls',
3698
+ line,
3699
+ column,
3700
+ });
3701
+ // gen_server dispatch: `gen_server:call(?SERVER, Msg)` /
3702
+ // `gen_server:cast(other_mod, Msg)` — a request routes to the TARGET
3703
+ // module's handle_call/handle_cast. The target is static when the
3704
+ // first argument names a module: ?MODULE or a ?MODULE-defined macro
3705
+ // (the self API-wrapper idiom), a bare atom (OTP's `{local, ?MODULE}`
3706
+ // convention names a server after its module, so a cross-module
3707
+ // registered name reaches that module's handlers — and a registered
3708
+ // name matching no module resolves to nothing), or a macro defined
3709
+ // as a bare atom. Pid/var/tuple targets stay silent.
3710
+ if (moduleExpr?.type === 'atom' &&
3711
+ erlAtom(moduleExpr) === 'gen_server' &&
3712
+ (fnBare === 'call' || fnBare === 'cast' || fnBare === 'send_request')) {
3713
+ const argsNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'args');
3714
+ const target = argsNode?.namedChild(0) ?? null;
3715
+ const targetModule = target ? this.resolveErlangGenServerTarget(target) : null;
3716
+ if (targetModule) {
3717
+ this.unresolvedReferences.push({
3718
+ fromNodeId: callerId,
3719
+ referenceName: `${targetModule}::${fnBare === 'cast' ? 'handle_cast' : 'handle_call'}`,
3720
+ referenceKind: 'calls',
3721
+ line,
3722
+ column,
3723
+ });
3724
+ }
3725
+ }
3726
+ // MFA-in-argument dispatch: the spawn/apply family names its real
3727
+ // callee in ARGUMENT position — `proc_lib:spawn_link(?MODULE,
3728
+ // request_process, [Req, Env, Middlewares])` — so the walker above
3729
+ // sees only the spawn itself and the spawned function ends up with
3730
+ // zero callers (measured on cowboy: request_process had no incoming
3731
+ // edges and the agent Read the file to find it). When the (Module,
3732
+ // Function) pair is static, lift it as a call edge. The pair is
3733
+ // found positionally-agnostically (first adjacent module-atom/
3734
+ // ?MODULE + atom pair) so every arity variant works: spawn/3,
3735
+ // spawn(Node,M,F,A)/4, timer:apply_after(Time,M,F,A),
3736
+ // rpc:call(Node,M,F,A). A var module or fun stays silent.
3737
+ const familyKey = moduleExpr?.type === 'atom' ? `${erlAtom(moduleExpr)}:${fnBare}` : fnBare;
3738
+ if (ERLANG_MFA_CALLS.has(familyKey)) {
3739
+ const argsNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'args');
3740
+ const argExprs = argsNode ? argsNode.namedChildren : [];
3741
+ for (let i = 0; i + 1 < argExprs.length; i++) {
3742
+ const m = argExprs[i];
3743
+ const f = argExprs[i + 1];
3744
+ if (f.type !== 'atom')
3745
+ continue;
3746
+ const isLocalModule = m.type === 'macro_call_expr' &&
3747
+ (0, tree_sitter_helpers_1.getChildByField)(m, 'name') !== null &&
3748
+ (0, tree_sitter_helpers_1.getNodeText)((0, tree_sitter_helpers_1.getChildByField)(m, 'name'), this.source) === 'MODULE';
3749
+ if (m.type !== 'atom' && !isLocalModule)
3750
+ continue;
3751
+ this.unresolvedReferences.push({
3752
+ fromNodeId: callerId,
3753
+ referenceName: isLocalModule ? erlAtom(f) : `${erlAtom(m)}::${erlAtom(f)}`,
3754
+ referenceKind: 'calls',
3755
+ line: f.startPosition.row + 1,
3756
+ column: f.startPosition.column,
3757
+ });
3758
+ break;
3759
+ }
3760
+ }
3761
+ }
3762
+ return;
3763
+ }
3764
+ if (node.type === 'internal_fun' || node.type === 'external_fun') {
3765
+ const funNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'fun');
3766
+ if (funNode?.type !== 'atom')
3767
+ return; // fun Mod:F/A with var parts — dynamic
3768
+ let refName = erlAtom(funNode);
3769
+ if (node.type === 'external_fun') {
3770
+ const moduleWrapper = (0, tree_sitter_helpers_1.getChildByField)(node, 'module');
3771
+ const moduleAtom = moduleWrapper ? (0, tree_sitter_helpers_1.getChildByField)(moduleWrapper, 'name') : null;
3772
+ if (moduleAtom?.type !== 'atom')
3773
+ return;
3774
+ refName = `${erlAtom(moduleAtom)}::${refName}`;
3775
+ }
3776
+ this.unresolvedReferences.push({
3777
+ fromNodeId: callerId,
3778
+ referenceName: refName,
3779
+ referenceKind: 'references',
3780
+ line,
3781
+ column,
3782
+ });
3783
+ return;
3784
+ }
3785
+ if (node.type === 'macro_call_expr') {
3786
+ // Macro use site → the `-define` constant node. Function-like uses
3787
+ // (`?LOG_AUDIT(X)` — args present) are inlined code, so they join the
3788
+ // call chain and connect through the macro node to the body's calls
3789
+ // (attributed there by handlePpDefine); bare reads (`?TIMEOUT`) are
3790
+ // `references`, answering "where is this macro used" without
3791
+ // polluting call paths. Compiler-predefined macros carry no
3792
+ // definition to link. The use site's ARGUMENTS are children and keep
3793
+ // walking, so a call nested in `?assertEqual(ok, do_thing())` still
3794
+ // attributes to the enclosing function.
3795
+ const macroName = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
3796
+ if (!macroName)
3797
+ return;
3798
+ const name = (0, tree_sitter_helpers_1.getNodeText)(macroName, this.source);
3799
+ if (ERLANG_PREDEFINED_MACROS.has(name))
3800
+ return;
3801
+ this.unresolvedReferences.push({
3802
+ fromNodeId: callerId,
3803
+ referenceName: name,
3804
+ referenceKind: (0, tree_sitter_helpers_1.getChildByField)(node, 'args') ? 'calls' : 'references',
3805
+ line,
3806
+ column,
3807
+ });
3808
+ return;
3809
+ }
3810
+ // record_expr / record_update_expr / record_index_expr / record_field_expr
3811
+ const recordName = (0, tree_sitter_helpers_1.getChildByField)(node, 'name');
3812
+ const recordAtom = recordName?.type === 'record_name' ? (0, tree_sitter_helpers_1.getChildByField)(recordName, 'name') : null;
3813
+ if (recordAtom?.type === 'atom') {
3814
+ this.unresolvedReferences.push({
3815
+ fromNodeId: callerId,
3816
+ referenceName: erlAtom(recordAtom),
3817
+ referenceKind: 'references',
3818
+ line,
3819
+ column,
3820
+ });
3821
+ }
3822
+ return;
3823
+ }
3453
3824
  // Ruby `call` nodes use `receiver` + `method` fields (tree-sitter-ruby), not
3454
3825
  // the `object`/`name`/`function` fields the branches below expect — so
3455
3826
  // without this they fell through to the generic path, which took the
@@ -3507,6 +3878,176 @@ class TreeSitterExtractor {
3507
3878
  }
3508
3879
  return;
3509
3880
  }
3881
+ // ArkTS build()-DSL handling. Three shapes carry UI-attribute chains, and
3882
+ // all of their attribute names are emitted with a LEADING DOT
3883
+ // (`.titleStyle`, `.width`) — an impossible identifier that routes them to
3884
+ // a dedicated matcher strategy resolving ONLY to decorator-marked
3885
+ // attribute helpers (`@Extend`/`@Styles`/`@AnimatableExtend`/`@Builder`
3886
+ // functions). Bare names would go through global name matching, where
3887
+ // framework attributes (`.width`, `.fontSize`, appearing on nearly every
3888
+ // UI line) hit arbitrary same-named symbols — measured on the OpenHarmony
3889
+ // samples monorepo, that produced 36k wrong edges (17% of all calls),
3890
+ // including single properties with 3,400+ false callers.
3891
+ //
3892
+ // 1. `Column({space:8}) { … }.height('100%')` — ONE
3893
+ // arkui_component_expression: `function:` = the component, chained
3894
+ // attributes as repeated `property:`/`arguments:` field pairs.
3895
+ // The component ref (`Column`, `TodoRow`) stays a PLAIN name — it
3896
+ // resolves to the child `@Component struct`, giving the parent→child
3897
+ // component-tree edge the way JSX children do for React.
3898
+ // 2. `Image(x).width(10).onClick(this.f)` — ordinary nested
3899
+ // call_expressions whose `function:` is a member_expression chained
3900
+ // on a CALL RESULT (never a named receiver, so `svc.save()` /
3901
+ // `this.vm.load()` are untouched and fall through to the generic
3902
+ // paths below).
3903
+ // 3. A nested component whose chain starts on the line AFTER its
3904
+ // closing `}` inside arkui_children — the grammar detaches the chain
3905
+ // into sibling `leading_dot_expression(identifier)` +
3906
+ // `parenthesized_expression(args)` statement pairs; reassemble from
3907
+ // the siblings.
3908
+ //
3909
+ // `.onXxx(this.handler)` METHOD-REFERENCE bindings (no call parens, so
3910
+ // nothing else records them) additionally emit a call ref to the bare
3911
+ // handler name — same-class resolution links the tap→handler hop.
3912
+ // Arrow-function handlers need nothing: their bodies' calls already
3913
+ // attribute to the enclosing build(). Children/argument subtrees are
3914
+ // still walked by the caller, so nested components extract normally.
3915
+ if (this.language === 'arkts') {
3916
+ const emitAttr = (nameNode) => {
3917
+ const attrName = (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source);
3918
+ if (!attrName)
3919
+ return;
3920
+ this.unresolvedReferences.push({
3921
+ fromNodeId: callerId,
3922
+ referenceName: '.' + attrName,
3923
+ referenceKind: 'calls',
3924
+ line: nameNode.startPosition.row + 1,
3925
+ column: nameNode.startPosition.column,
3926
+ });
3927
+ };
3928
+ // Emit `handler` for each bare `this.handler` among an on-attribute's
3929
+ // arguments.
3930
+ const emitThisHandlers = (args) => {
3931
+ if (!args)
3932
+ return;
3933
+ for (let j = 0; j < args.namedChildCount; j++) {
3934
+ const arg = args.namedChild(j);
3935
+ if (arg?.type !== 'member_expression')
3936
+ continue;
3937
+ const obj = (0, tree_sitter_helpers_1.getChildByField)(arg, 'object');
3938
+ const prop = (0, tree_sitter_helpers_1.getChildByField)(arg, 'property');
3939
+ if (obj?.type === 'this' && prop) {
3940
+ this.unresolvedReferences.push({
3941
+ fromNodeId: callerId,
3942
+ referenceName: (0, tree_sitter_helpers_1.getNodeText)(prop, this.source),
3943
+ referenceKind: 'calls',
3944
+ line: arg.startPosition.row + 1,
3945
+ column: arg.startPosition.column,
3946
+ });
3947
+ }
3948
+ }
3949
+ };
3950
+ // Shape 1: arkui_component_expression with property/arguments pairs.
3951
+ if (node.type === 'arkui_component_expression') {
3952
+ const componentField = (0, tree_sitter_helpers_1.getChildByField)(node, 'function');
3953
+ if (componentField && componentField.type === 'identifier') {
3954
+ this.unresolvedReferences.push({
3955
+ fromNodeId: callerId,
3956
+ referenceName: (0, tree_sitter_helpers_1.getNodeText)(componentField, this.source),
3957
+ referenceKind: 'calls',
3958
+ line: node.startPosition.row + 1,
3959
+ column: node.startPosition.column,
3960
+ });
3961
+ }
3962
+ for (let i = 0; i < node.childCount; i++) {
3963
+ const child = node.child(i);
3964
+ if (!child || child.type !== 'property_identifier')
3965
+ continue;
3966
+ emitAttr(child);
3967
+ if (/^on[A-Z]/.test((0, tree_sitter_helpers_1.getNodeText)(child, this.source))) {
3968
+ // The attribute's arguments node is the next `arguments`-typed
3969
+ // child before the following attribute name.
3970
+ let args = null;
3971
+ for (let k = i + 1; k < node.childCount; k++) {
3972
+ const next = node.child(k);
3973
+ if (!next)
3974
+ continue;
3975
+ if (next.type === 'property_identifier')
3976
+ break;
3977
+ if (next.type === 'arguments') {
3978
+ args = next;
3979
+ break;
3980
+ }
3981
+ }
3982
+ emitThisHandlers(args);
3983
+ }
3984
+ }
3985
+ return;
3986
+ }
3987
+ // Shape 2: fluent chain on a call result —
3988
+ // call_expression(function: member_expression(object: <call>)), or the
3989
+ // grammar's DSL-specific arkui_dsl_decorator_member_expression (same
3990
+ // object/property fields; produced e.g. by `Column() { … }.alignItems(x)`
3991
+ // in some chain positions — it ONLY occurs in attribute chains).
3992
+ if (node.type === 'call_expression') {
3993
+ const fn = (0, tree_sitter_helpers_1.getChildByField)(node, 'function');
3994
+ if (fn?.type === 'member_expression' || fn?.type === 'arkui_dsl_decorator_member_expression') {
3995
+ const obj = (0, tree_sitter_helpers_1.getChildByField)(fn, 'object');
3996
+ const prop = (0, tree_sitter_helpers_1.getChildByField)(fn, 'property');
3997
+ if (prop &&
3998
+ (fn.type === 'arkui_dsl_decorator_member_expression' ||
3999
+ obj?.type === 'call_expression' ||
4000
+ obj?.type === 'arkui_component_expression')) {
4001
+ emitAttr(prop);
4002
+ if (/^on[A-Z]/.test((0, tree_sitter_helpers_1.getNodeText)(prop, this.source))) {
4003
+ emitThisHandlers((0, tree_sitter_helpers_1.getChildByField)(node, 'arguments'));
4004
+ }
4005
+ return;
4006
+ }
4007
+ }
4008
+ // The INNERMOST call of a proper-form detached chain
4009
+ // (`.alignItems(x).layoutWeight(1)…` under a leading_dot_expression)
4010
+ // has a BARE IDENTIFIER function — the leading dot was consumed by
4011
+ // the wrapper, so it masquerades as a plain `alignItems(...)` call.
4012
+ // Walk up the member/call alternation; topping out at
4013
+ // leading_dot_expression means the dot belongs to this chain.
4014
+ if (fn?.type === 'identifier') {
4015
+ let p = node.parent;
4016
+ while (p && (p.type === 'member_expression' || p.type === 'call_expression')) {
4017
+ p = p.parent;
4018
+ }
4019
+ if (p?.type === 'leading_dot_expression') {
4020
+ emitAttr(fn);
4021
+ if (/^on[A-Z]/.test((0, tree_sitter_helpers_1.getNodeText)(fn, this.source))) {
4022
+ emitThisHandlers((0, tree_sitter_helpers_1.getChildByField)(node, 'arguments'));
4023
+ }
4024
+ return;
4025
+ }
4026
+ }
4027
+ // Not a chained attribute — fall through to the generic call paths.
4028
+ }
4029
+ // Shape 3: detached chain segment — leading_dot_expression whose only
4030
+ // named child is a bare identifier; its arguments sit in the NEXT
4031
+ // sibling statement as a parenthesized_expression.
4032
+ if (node.type === 'leading_dot_expression') {
4033
+ const only = node.namedChildCount === 1 ? node.namedChild(0) : null;
4034
+ if (only && only.type === 'identifier') {
4035
+ emitAttr(only);
4036
+ if (/^on[A-Z]/.test((0, tree_sitter_helpers_1.getNodeText)(only, this.source))) {
4037
+ const stmt = node.parent; // expression_statement
4038
+ const nextStmt = stmt?.nextNamedSibling;
4039
+ const paren = nextStmt?.namedChild(0);
4040
+ if (paren?.type === 'parenthesized_expression') {
4041
+ emitThisHandlers(paren);
4042
+ }
4043
+ }
4044
+ }
4045
+ // The proper form (child is a call_expression chain, as inside
4046
+ // `@Extend` bodies) needs nothing here — the walker descends into it
4047
+ // and the inner call_expressions take the paths above.
4048
+ return;
4049
+ }
4050
+ }
3510
4051
  // Get the function/method being called
3511
4052
  let calleeName = '';
3512
4053
  // Java/Kotlin method_invocation has 'object' + 'name' fields instead of 'function'
@@ -3727,6 +4268,16 @@ class TreeSitterExtractor {
3727
4268
  (0, tree_sitter_helpers_1.getChildByField)(func, 'operand') ||
3728
4269
  (0, tree_sitter_helpers_1.getChildByField)(func, 'argument') ||
3729
4270
  func.namedChild(0);
4271
+ // A LITERAL receiver — `", ".join(...)`, `"x".toUpperCase()`,
4272
+ // `5.times`, `[].concat(...)` — calls a builtin of the literal's
4273
+ // type, never a project symbol. The bare-name fallback below let
4274
+ // these exact-match an unrelated same-named project function
4275
+ // (`", ".join` bound to a local `join` defined inside a DIFFERENT
4276
+ // function, #1230). Emit nothing: a silent miss, never a wrong
4277
+ // edge. Nested calls in the arguments are visited independently.
4278
+ if (receiver && LITERAL_RECEIVER_TYPES.has(receiver.type)) {
4279
+ return;
4280
+ }
3730
4281
  const SKIP_RECEIVERS = new Set(['self', 'this', 'cls', 'super']);
3731
4282
  if (receiver && (receiver.type === 'identifier' || receiver.type === 'simple_identifier' || receiver.type === 'field_identifier')) {
3732
4283
  const receiverName = (0, tree_sitter_helpers_1.getNodeText)(receiver, this.source);
@@ -3798,6 +4349,34 @@ class TreeSitterExtractor {
3798
4349
  }
3799
4350
  calleeName = reencode ? `${innerCallee}().${methodName}` : methodName;
3800
4351
  }
4352
+ else if (this.language === 'cfscript' &&
4353
+ receiver &&
4354
+ receiver.type === 'member_expression' &&
4355
+ /^(variables|this|local|arguments)\.[A-Za-z_][\w]*$/i.test((0, tree_sitter_helpers_1.getNodeText)(receiver, this.source))) {
4356
+ // CFML scope-prefixed member call — `variables.svc.save()` /
4357
+ // `arguments.svc.save()`: the receiver is a component field,
4358
+ // injected property, or typed argument reached through one of
4359
+ // CFML's file-local scopes. Keep the full receiver chain so
4360
+ // resolution can strip the scope prefix and infer the field's
4361
+ // component type from its declaration (#1108). Gated to these
4362
+ // scope keywords: such calls previously emitted a bare method
4363
+ // name, which either failed to resolve or resolved ambiguously.
4364
+ calleeName = `${(0, tree_sitter_helpers_1.getNodeText)(receiver, this.source)}.${methodName}`;
4365
+ }
4366
+ else if (this.language === 'go' &&
4367
+ receiver &&
4368
+ receiver.type === 'selector_expression' &&
4369
+ /^[A-Za-z_]\w*\.[A-Za-z_]\w*$/.test((0, tree_sitter_helpers_1.getNodeText)(receiver, this.source).replace(/\s+/g, ''))) {
4370
+ // Go 2-hop field chain `target.conn.Exec(...)`: keep the
4371
+ // receiver chain so resolution can infer `conn`'s declared type
4372
+ // from the Target struct. Previously this emitted the bare
4373
+ // method name, and when the field's type is EXTERNAL (sql.DB)
4374
+ // the bare name exact-matched an unrelated same-named local
4375
+ // method — a fabricated internal dependency (#1276). Chained
4376
+ // Go receivers resolve strictly via validated field-hop
4377
+ // inference (see matchGoFieldChainCall) or stay unresolved.
4378
+ calleeName = `${(0, tree_sitter_helpers_1.getNodeText)(receiver, this.source).replace(/\s+/g, '')}.${methodName}`;
4379
+ }
3801
4380
  else {
3802
4381
  calleeName = methodName;
3803
4382
  }
@@ -3840,6 +4419,40 @@ class TreeSitterExtractor {
3840
4419
  if (conv && conv[1])
3841
4420
  calleeName = conv[1];
3842
4421
  }
4422
+ // C/C++ templated callees — a direct templated call (`fn<T, 256>(args)`,
4423
+ // the shape every CUDA kernel-launch site takes once its `<<<…>>>` config
4424
+ // is blanked) or a qualified one (`ns::fn<T>(args)`) — carry template
4425
+ // arguments in the callee text, which can never match the bare name the
4426
+ // function was DEFINED as, so the call edge silently never resolves. Strip
4427
+ // them: the same normalization base-class `extends` refs already get
4428
+ // (#1043). `operator<`/`operator<<` callees are excluded — their `<` is the
4429
+ // operator itself, not a template-argument list.
4430
+ if (calleeName &&
4431
+ calleeName.includes('<') &&
4432
+ (this.language === 'cpp' || this.language === 'c') &&
4433
+ !calleeName.includes('operator')) {
4434
+ calleeName = (0, c_cpp_1.stripCppTemplateArgs)(calleeName);
4435
+ }
4436
+ // C++ call/launch through a local function pointer: `auto kernel =
4437
+ // &flash_fwd_kernel<…>; … kernel<<<grid, block>>>(params);` — the callee
4438
+ // is an unresolvable local name. When the same enclosing symbol bound the
4439
+ // local from `&fn` (each branch assignment counts), emit the call against
4440
+ // every recorded target instead of the local.
4441
+ if (calleeName && this.language === 'cpp' && /^[A-Za-z_]\w*$/.test(calleeName)) {
4442
+ const targets = this.cppLocalFnPtrs.get(callerId)?.get(calleeName);
4443
+ if (targets && targets.size > 0) {
4444
+ for (const target of targets) {
4445
+ this.unresolvedReferences.push({
4446
+ fromNodeId: callerId,
4447
+ referenceName: target,
4448
+ referenceKind: 'calls',
4449
+ line: node.startPosition.row + 1,
4450
+ column: node.startPosition.column,
4451
+ });
4452
+ }
4453
+ return;
4454
+ }
4455
+ }
3843
4456
  if (calleeName) {
3844
4457
  this.unresolvedReferences.push({
3845
4458
  fromNodeId: callerId,
@@ -3859,6 +4472,26 @@ class TreeSitterExtractor {
3859
4472
  * Children are still walked so nested calls inside the constructor
3860
4473
  * arguments (`new Foo(bar())`) get their own `calls` references.
3861
4474
  */
4475
+ /**
4476
+ * VB.NET `New Invoice(1)` is syntactically ambiguous between constructing
4477
+ * Invoice with an argument and allocating an Invoice array of bound 1; the
4478
+ * grammar parses the parenthesized form as array_creation_expression. A
4479
+ * user-defined type with no `{...}` array initializer is overwhelmingly a
4480
+ * constructor call, so treat it as an instantiation. Predefined element
4481
+ * types (`New Byte(1023)`) and brace-initialized forms stay arrays.
4482
+ */
4483
+ isVbnetConstructorShapedArrayCreation(node) {
4484
+ if (this.language !== 'vbnet' || node.type !== 'array_creation_expression')
4485
+ return false;
4486
+ const typeNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
4487
+ if (!typeNode || typeNode.type === 'predefined_type' || typeNode.type === 'array_type')
4488
+ return false;
4489
+ for (const child of node.namedChildren) {
4490
+ if (child?.type === 'array_initializer')
4491
+ return false;
4492
+ }
4493
+ return true;
4494
+ }
3862
4495
  extractInstantiation(node) {
3863
4496
  if (this.nodeStack.length === 0)
3864
4497
  return;
@@ -3921,6 +4554,14 @@ class TreeSitterExtractor {
3921
4554
  const ltIdx = className.indexOf('<');
3922
4555
  if (ltIdx > 0)
3923
4556
  className = className.slice(0, ltIdx);
4557
+ // VB.NET spells generics with parentheses: `New List(Of String)` /
4558
+ // `New Dictionary(Of K, V)(cap)` — strip from the `(` so the bare
4559
+ // type name is what resolution matches.
4560
+ if (this.language === 'vbnet') {
4561
+ const parenIdx = className.indexOf('(');
4562
+ if (parenIdx > 0)
4563
+ className = className.slice(0, parenIdx);
4564
+ }
3924
4565
  // For namespaced/qualified constructors (`new ns.Foo()`,
3925
4566
  // `new ns::Foo()`) keep the trailing identifier — that's what
3926
4567
  // matches a class node in the index.
@@ -4135,6 +4776,28 @@ class TreeSitterExtractor {
4135
4776
  const consider = (n) => {
4136
4777
  if (!n)
4137
4778
  return;
4779
+ // Solidity `modifier_invocation` (unique to that grammar) sits
4780
+ // decorator-position in the function header — OUTSIDE the `body:` field
4781
+ // the call walker descends — but its body executes around the function
4782
+ // via `_;`, so it is a real call-flow hop (`withdraw → onlyOwner →
4783
+ // _checkRole` is the canonical audit trace). The same node type carries
4784
+ // base-constructor invocations (`constructor() ERC20("T","TOK")`), the
4785
+ // constructor-chain hop. Emit `calls`, not `decorates`, so flow
4786
+ // traversal rides it.
4787
+ if (n.type === 'modifier_invocation') {
4788
+ const target = n.namedChild(0);
4789
+ const name = target?.type === 'identifier' ? (0, tree_sitter_helpers_1.getNodeText)(target, this.source) : undefined;
4790
+ if (name) {
4791
+ this.unresolvedReferences.push({
4792
+ fromNodeId: decoratedId,
4793
+ referenceName: name,
4794
+ referenceKind: 'calls',
4795
+ line: n.startPosition.row + 1,
4796
+ column: n.startPosition.column,
4797
+ });
4798
+ }
4799
+ return;
4800
+ }
4138
4801
  // `marker_annotation` is Java's grammar for arg-less annotations
4139
4802
  // (`@Override`, `@Deprecated`); `attribute` is Swift's grammar for
4140
4803
  // attributes and PROPERTY WRAPPERS (`@objc`, `@Argument`, `@Published`,
@@ -4312,6 +4975,43 @@ class TreeSitterExtractor {
4312
4975
  }
4313
4976
  flush();
4314
4977
  }
4978
+ /**
4979
+ * Record a C++ local function-pointer binding (`local = &fn` / `&fn<…>` /
4980
+ * `&ns::fn<…>`) for the CURRENT enclosing symbol, so calls through the local
4981
+ * resolve to the real target (see cppLocalFnPtrs). Only the address-of shape
4982
+ * is accepted — a bare-identifier RHS (`auto x = y;`) is any value copy, and
4983
+ * linking through it would guess.
4984
+ */
4985
+ recordCppFnPtrBinding(localName, value) {
4986
+ if (!value || value.type !== 'pointer_expression')
4987
+ return;
4988
+ if (value.child(0)?.type !== '&')
4989
+ return; // `*p` dereference, not address-of
4990
+ const arg = (0, tree_sitter_helpers_1.getChildByField)(value, 'argument') ?? value.namedChild(0);
4991
+ if (!arg ||
4992
+ (arg.type !== 'identifier' &&
4993
+ arg.type !== 'template_function' &&
4994
+ arg.type !== 'qualified_identifier')) {
4995
+ return;
4996
+ }
4997
+ const callerId = this.nodeStack[this.nodeStack.length - 1];
4998
+ if (!callerId)
4999
+ return;
5000
+ const target = (0, c_cpp_1.stripCppTemplateArgs)((0, tree_sitter_helpers_1.getNodeText)(arg, this.source));
5001
+ if (!target || target === localName)
5002
+ return;
5003
+ let locals = this.cppLocalFnPtrs.get(callerId);
5004
+ if (!locals) {
5005
+ locals = new Map();
5006
+ this.cppLocalFnPtrs.set(callerId, locals);
5007
+ }
5008
+ let targets = locals.get(localName);
5009
+ if (!targets) {
5010
+ targets = new Set();
5011
+ locals.set(localName, targets);
5012
+ }
5013
+ targets.add(target);
5014
+ }
4315
5015
  visitFunctionBody(body, _functionId) {
4316
5016
  if (!this.extractor)
4317
5017
  return;
@@ -4327,7 +5027,7 @@ class TreeSitterExtractor {
4327
5027
  if (this.extractor.callTypes.includes(nodeType)) {
4328
5028
  this.extractCall(node);
4329
5029
  }
4330
- else if (INSTANTIATION_KINDS.has(nodeType)) {
5030
+ else if (INSTANTIATION_KINDS.has(nodeType) || this.isVbnetConstructorShapedArrayCreation(node)) {
4331
5031
  // `new Foo()` inside a function body — emit an `instantiates`
4332
5032
  // reference. Without this branch the body walker only knew
4333
5033
  // about `call_expression`, so constructor invocations
@@ -4369,6 +5069,31 @@ class TreeSitterExtractor {
4369
5069
  if (nodeType === 'declaration' && this.language === 'cpp' && this.isCppStackConstruction(node)) {
4370
5070
  this.extractInstantiation(node);
4371
5071
  }
5072
+ // C++ local function-pointer bindings (see cppLocalFnPtrs): record
5073
+ // `auto kernel = &fn<…>;` declarations and `kernel = &other_fn<…>;`
5074
+ // branch reassignments so a call/launch through the local links to the
5075
+ // real target(s). The body walker sees these in source order, and C++
5076
+ // requires declaration-before-use, so the map is always populated before
5077
+ // the call that consumes it.
5078
+ if (this.language === 'cpp' && this.nodeStack.length > 0) {
5079
+ if (nodeType === 'declaration') {
5080
+ for (let i = 0; i < node.namedChildCount; i++) {
5081
+ const child = node.namedChild(i);
5082
+ if (child?.type !== 'init_declarator')
5083
+ continue;
5084
+ const decl = (0, tree_sitter_helpers_1.getChildByField)(child, 'declarator');
5085
+ if (decl?.type !== 'identifier')
5086
+ continue;
5087
+ this.recordCppFnPtrBinding((0, tree_sitter_helpers_1.getNodeText)(decl, this.source), (0, tree_sitter_helpers_1.getChildByField)(child, 'value'));
5088
+ }
5089
+ }
5090
+ else if (nodeType === 'assignment_expression') {
5091
+ const left = (0, tree_sitter_helpers_1.getChildByField)(node, 'left');
5092
+ if (left?.type === 'identifier') {
5093
+ this.recordCppFnPtrBinding((0, tree_sitter_helpers_1.getNodeText)(left, this.source), (0, tree_sitter_helpers_1.getChildByField)(node, 'right'));
5094
+ }
5095
+ }
5096
+ }
4372
5097
  // Static-member / value-read: `Enum.value`, `Type.CONST`, `Foo::BAR`.
4373
5098
  this.extractStaticMemberRef(node);
4374
5099
  // Local variable type annotations inside a body — `const items: Foo[] = []`,
@@ -4693,6 +5418,33 @@ class TreeSitterExtractor {
4693
5418
  }
4694
5419
  }
4695
5420
  }
5421
+ // VB.NET: `Inherits Base` / `Implements IFoo, IBar(Of T)` are STATEMENTS
5422
+ // inside the class body (children of the class node), not header clauses.
5423
+ // Each name is a simple/qualified/generic reference; generics unwrap to
5424
+ // the base identifier and dotted paths keep the trailing segment.
5425
+ if (this.language === 'vbnet' &&
5426
+ (child.type === 'inherits_statement' || child.type === 'implements_statement')) {
5427
+ const kind = child.type === 'inherits_statement' ? 'extends' : 'implements';
5428
+ for (const ref of child.namedChildren) {
5429
+ if (!ref || (ref.type !== 'simple_name' && ref.type !== 'qualified_name' && ref.type !== 'generic_name' && ref.type !== 'global_qualified_name'))
5430
+ continue;
5431
+ let name = (0, tree_sitter_helpers_1.getNodeText)(ref, this.source);
5432
+ name = name.replace(/\(\s*Of\b[^)]*\)/gi, '');
5433
+ const lastDot = name.lastIndexOf('.');
5434
+ if (lastDot >= 0)
5435
+ name = name.slice(lastDot + 1);
5436
+ name = name.trim();
5437
+ if (!name)
5438
+ continue;
5439
+ this.unresolvedReferences.push({
5440
+ fromNodeId: classId,
5441
+ referenceName: name,
5442
+ referenceKind: kind,
5443
+ line: ref.startPosition.row + 1,
5444
+ column: ref.startPosition.column,
5445
+ });
5446
+ }
5447
+ }
4696
5448
  // C#: `class Movie : BaseItem, IPlugin` → base_list with identifier children
4697
5449
  // base_list combines both base class and interfaces in a single colon-separated list.
4698
5450
  // We emit all as 'extends' since the syntax doesn't distinguish them.
@@ -4768,6 +5520,33 @@ class TreeSitterExtractor {
4768
5520
  if (child.type === 'field_declaration_list' || child.type === 'class_heritage') {
4769
5521
  this.extractInheritance(child, classId);
4770
5522
  }
5523
+ // CFML cfscript `component extends="Base" implements="IFoo,IBar" { ... }`
5524
+ // (also covers `interface extends="IBase" { ... }`, which reuses the same
5525
+ // component_attribute shape). Attributes are generic name=value pairs —
5526
+ // (identifier label, expression value) — not a dedicated extends_clause,
5527
+ // so filter by the label text. `implements` is a comma-separated list.
5528
+ if (child.type === 'component_attribute' && node.type === 'component') {
5529
+ const label = child.namedChildren.find((c) => c.type === 'identifier');
5530
+ const value = child.namedChildren.find((c) => c.type !== 'identifier');
5531
+ if (label && value) {
5532
+ const labelText = (0, tree_sitter_helpers_1.getNodeText)(label, this.source).toLowerCase();
5533
+ if (labelText === 'extends' || labelText === 'implements') {
5534
+ const valueText = (0, tree_sitter_helpers_1.getNodeText)(value, this.source).replace(/^["']|["']$/g, '');
5535
+ const names = labelText === 'implements'
5536
+ ? valueText.split(',').map((s) => s.trim()).filter(Boolean)
5537
+ : [valueText.trim()].filter(Boolean);
5538
+ for (const name of names) {
5539
+ this.unresolvedReferences.push({
5540
+ fromNodeId: classId,
5541
+ referenceName: name,
5542
+ referenceKind: labelText === 'implements' ? 'implements' : 'extends',
5543
+ line: value.startPosition.row + 1,
5544
+ column: value.startPosition.column,
5545
+ });
5546
+ }
5547
+ }
5548
+ }
5549
+ }
4771
5550
  }
4772
5551
  }
4773
5552
  /**
@@ -4827,7 +5606,7 @@ class TreeSitterExtractor {
4827
5606
  * Languages that support type annotations (TypeScript, etc.)
4828
5607
  */
4829
5608
  TYPE_ANNOTATION_LANGUAGES = new Set([
4830
- 'typescript', 'tsx', 'dart', 'kotlin', 'swift', 'rust', 'go', 'java', 'csharp', 'scala', 'php',
5609
+ 'typescript', 'tsx', 'arkts', 'dart', 'kotlin', 'swift', 'rust', 'go', 'java', 'csharp', 'scala', 'php',
4831
5610
  ]);
4832
5611
  /**
4833
5612
  * PHP pseudo-types and `self`/`static`/`parent` that aren't project symbols.
@@ -5721,7 +6500,19 @@ function extractFromSource(filePath, source, language, frameworkNames) {
5721
6500
  const extractor = new mybatis_extractor_1.MyBatisExtractor(filePath, source);
5722
6501
  result = extractor.extract();
5723
6502
  }
6503
+ else if (detectedLanguage === 'cfml' || detectedLanguage === 'cfscript') {
6504
+ // Custom extractor for CFML (.cfc/.cfm) — dialect-switches between the
6505
+ // tag-based cfml grammar and the bare-script cfscript grammar. Standalone
6506
+ // `.cfs` files (language 'cfscript') are always pure script (never `<`-led),
6507
+ // so routing them through here too gets them the same anonymous-component
6508
+ // filename fallback as a bare-script `.cfc` — without it a `.cfs` whose
6509
+ // `component { ... }` declares no name (the grammar has no `name` field;
6510
+ // CFML never spells one in source) stays `<anonymous>`.
6511
+ const extractor = new cfml_extractor_1.CfmlExtractor(filePath, source, detectedLanguage);
6512
+ result = extractor.extract();
6513
+ }
5724
6514
  else if (detectedLanguage === 'arkts') {
6515
+ // HomeGraph uses the arkanalyzer-backed ArkTS extractor (not tree-sitter).
5725
6516
  const extractor = new arkts_1.ArkTSExtractor(filePath, source);
5726
6517
  result = extractor.extract();
5727
6518
  }