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
@@ -46,6 +46,7 @@ const query_utils_1 = require("../search/query-utils");
46
46
  const query_parser_1 = require("../search/query-parser");
47
47
  const generated_detection_1 = require("../extraction/generated-detection");
48
48
  const arkts_1 = require("../extraction/languages/arkts");
49
+ const identifier_segments_1 = require("../search/identifier-segments");
49
50
  /**
50
51
  * Path-only heuristic for files that should not be candidates for
51
52
  * "dominant file" detection: test/spec files and tool-generated files.
@@ -69,6 +70,14 @@ function isLowValueFile(filePath) {
69
70
  (0, generated_detection_1.isGeneratedFile)(filePath));
70
71
  }
71
72
  const SQLITE_PARAM_CHUNK_SIZE = 500;
73
+ /**
74
+ * Last segment of a (possibly dotted/qualified) reference name — the part a
75
+ * new symbol's plain node name could match: 'util.greet' → 'greet'.
76
+ */
77
+ function referenceNameTail(referenceName) {
78
+ const idx = Math.max(referenceName.lastIndexOf('.'), referenceName.lastIndexOf(':'));
79
+ return idx >= 0 ? referenceName.slice(idx + 1) : referenceName;
80
+ }
72
81
  /**
73
82
  * Convert database row to Node object
74
83
  */
@@ -136,6 +145,8 @@ class QueryBuilder {
136
145
  // whole project, not a symbol, so it carries no discriminative signal (#720).
137
146
  // Set once by the HomeGraph instance; empty by default (no down-weighting).
138
147
  projectNameTokens = new Set();
148
+ segmentedNames = new Set();
149
+ static MAX_SEGMENTED_NAMES = 65536;
139
150
  // Node cache for frequently accessed nodes (LRU-style, max 1000 entries)
140
151
  nodeCache = new Map();
141
152
  maxCacheSize = 1000;
@@ -143,9 +154,54 @@ class QueryBuilder {
143
154
  ohosApiDbPath = null;
144
155
  // Prepared statements (lazily initialized)
145
156
  stmts = {};
157
+ // Multi-row INSERT statements, cached per (statement kind × row count).
158
+ batchStmts = new Map();
159
+ static BATCH_SIZES = [128, 32, 8, 1];
160
+ /**
161
+ * Run `rows` through a multi-row `INSERT` built as `head + (tuple,)*n`,
162
+ * decomposed greedily into the cached batch sizes. Preserves row order.
163
+ */
164
+ runBatched(kind, head, tuple, rows) {
165
+ if (rows.length === 0)
166
+ return;
167
+ let i = 0;
168
+ for (const size of QueryBuilder.BATCH_SIZES) {
169
+ while (rows.length - i >= size) {
170
+ const key = `${kind}:${size}`;
171
+ let stmt = this.batchStmts.get(key);
172
+ if (!stmt) {
173
+ stmt = this.db.prepare(head + new Array(size).fill(tuple).join(','));
174
+ this.batchStmts.set(key, stmt);
175
+ }
176
+ if (size === 1) {
177
+ stmt.run(...rows[i]);
178
+ }
179
+ else {
180
+ const params = [];
181
+ for (let r = 0; r < size; r++) {
182
+ const row = rows[i + r];
183
+ for (let c = 0; c < row.length; c++)
184
+ params.push(row[c]);
185
+ }
186
+ stmt.run(...params);
187
+ }
188
+ i += size;
189
+ }
190
+ }
191
+ }
146
192
  constructor(db) {
147
193
  this.db = db;
148
194
  }
195
+ /**
196
+ * Swap the underlying connection in place. Used by pool workers'
197
+ * connection recycling: a long-lived read connection pins WAL checkpoint
198
+ * progress; workers close and reopen at the pool-idle boundary.
199
+ */
200
+ rebind(db) {
201
+ this.db = db;
202
+ this.stmts = {};
203
+ this.batchStmts.clear();
204
+ }
149
205
  /** Attach a versioned OHOS API db for federated symbol lookup. */
150
206
  attachOhosApiDb(dbPath) {
151
207
  if (dbPath === this.ohosApiDbPath)
@@ -254,6 +310,10 @@ class QueryBuilder {
254
310
  returnType: node.returnType ?? null,
255
311
  updatedAt: node.updatedAt ?? Date.now(),
256
312
  });
313
+ // Segment vocabulary rides the same write path so it never drifts ahead of
314
+ // the nodes it describes. File/import nodes are excluded (#1144).
315
+ if (this.isSegmentableKind(node.kind))
316
+ this.insertNameSegments(node.name);
257
317
  }
258
318
  /**
259
319
  * Insert multiple nodes in a transaction
@@ -265,6 +325,40 @@ class QueryBuilder {
265
325
  }
266
326
  })();
267
327
  }
328
+ /**
329
+ * Store one file's whole extraction bundle — nodes, edges, unresolved refs,
330
+ * and the file record — in a SINGLE transaction. The bulk-index path calls
331
+ * this once per file instead of opening one transaction per table (#1015
332
+ * file-order commit discipline is unchanged: callers still invoke it in file
333
+ * order, and row order within is input order).
334
+ *
335
+ * Edges MUST already be endpoint-filtered by the caller (the store path
336
+ * filters to the file's own inserted node ids), so the per-file existence
337
+ * SELECT that insertEdges() pays is skipped here.
338
+ */
339
+ storeFileBundle(bundle) {
340
+ this.db.transaction(() => {
341
+ this.insertNodes(bundle.nodes);
342
+ if (bundle.edges.length > 0) {
343
+ const rows = [];
344
+ for (const edge of bundle.edges) {
345
+ rows.push([
346
+ edge.source,
347
+ edge.target,
348
+ edge.kind,
349
+ edge.metadata ? JSON.stringify(edge.metadata) : null,
350
+ edge.line ?? null,
351
+ edge.column ?? null,
352
+ edge.provenance ?? null,
353
+ ]);
354
+ }
355
+ this.runBatched('insertEdges', 'INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance) VALUES ', '(?,?,?,?,?,?,?)', rows);
356
+ }
357
+ if (bundle.refs.length > 0)
358
+ this.insertUnresolvedRefsBatch(bundle.refs);
359
+ this.upsertFile(bundle.file);
360
+ })();
361
+ }
268
362
  /**
269
363
  * Update an existing node
270
364
  */
@@ -325,6 +419,9 @@ class QueryBuilder {
325
419
  returnType: node.returnType ?? null,
326
420
  updatedAt: node.updatedAt ?? Date.now(),
327
421
  });
422
+ // Framework post-extract renames must reach the segment vocabulary (#1141).
423
+ if (this.isSegmentableKind(node.kind))
424
+ this.insertNameSegments(node.name);
328
425
  }
329
426
  /**
330
427
  * Delete a node by ID
@@ -352,6 +449,104 @@ class QueryBuilder {
352
449
  }
353
450
  this.stmts.deleteNodesByFile.run(filePath);
354
451
  }
452
+ /** Which node kinds contribute their name to the segment vocabulary. */
453
+ isSegmentableKind(kind) {
454
+ return kind !== 'file' && kind !== 'import';
455
+ }
456
+ /** Write `name`'s segments into name_segment_vocab (idempotent). */
457
+ insertNameSegments(name) {
458
+ if (this.segmentedNames.has(name))
459
+ return;
460
+ if (this.segmentedNames.size >= QueryBuilder.MAX_SEGMENTED_NAMES)
461
+ this.segmentedNames.clear();
462
+ this.segmentedNames.add(name);
463
+ if (!this.stmts.insertNameSegment) {
464
+ this.stmts.insertNameSegment = this.db.prepare('INSERT OR IGNORE INTO name_segment_vocab (segment, name) VALUES (?, ?)');
465
+ }
466
+ for (const segment of (0, identifier_segments_1.splitIdentifierSegments)(name)) {
467
+ this.stmts.insertNameSegment.run(segment, name);
468
+ }
469
+ }
470
+ // ===========================================================================
471
+ // Name-segment vocabulary (prompt-hook graph-derived gate)
472
+ // ===========================================================================
473
+ /** Wipe the segment vocabulary. A full index calls this at its start; the
474
+ * node write path repopulates it as files (re-)index, so the end state is
475
+ * exactly the current names with no orphan rows. */
476
+ clearNameSegmentVocab() {
477
+ this.db.exec('DELETE FROM name_segment_vocab');
478
+ this.segmentedNames.clear();
479
+ }
480
+ /** True when the vocab has no rows — an index built before the table existed.
481
+ * `sync` uses this to heal such databases (see rebuildNameSegmentVocabFrom). */
482
+ isNameSegmentVocabEmpty() {
483
+ const row = this.db.prepare('SELECT 1 FROM name_segment_vocab LIMIT 1').get();
484
+ return row === undefined;
485
+ }
486
+ /** One page of distinct segmentable node names, for batched vocab rebuilds
487
+ * (file basenames and import specifiers are excluded from the vocab — see
488
+ * insertNode). */
489
+ getDistinctNodeNames(limit, offset) {
490
+ const rows = this.db
491
+ .prepare("SELECT DISTINCT name FROM nodes WHERE kind NOT IN ('file', 'import') ORDER BY name LIMIT ? OFFSET ?")
492
+ .all(limit, offset);
493
+ return rows.map((r) => r.name);
494
+ }
495
+ /** Insert segments for a batch of names in one transaction (vocab heal path). */
496
+ insertNameSegmentsBatch(names) {
497
+ this.db.transaction(() => {
498
+ for (const name of names)
499
+ this.insertNameSegments(name);
500
+ })();
501
+ }
502
+ /**
503
+ * Names whose segments cover at least `minWords` distinct PROMPT WORDS —
504
+ * the co-occurrence probe behind the prompt hook's medium tier: the words
505
+ * "state" and "machine" both being segments of `OrderStateMachine` is strong
506
+ * evidence the prompt names that symbol in prose. Ordered by coverage.
507
+ *
508
+ * Takes (segment variant → original word) pairs and folds variants back to
509
+ * their word INSIDE the SQL: a name matching both `service` and `services`
510
+ * counts ONE word, not two. Counting raw variants let plural-variant pairs
511
+ * of a single word tie with genuine two-word matches and — because ORDER
512
+ * BY/LIMIT run here, before any JS-side re-check — crowd a real match past
513
+ * the LIMIT on vocab-heavy repos (#1146).
514
+ */
515
+ getSegmentCoOccurrence(variants, minWords, limit) {
516
+ if (variants.length === 0)
517
+ return [];
518
+ const placeholders = variants.map(() => '?').join(', ');
519
+ const whens = variants.map(() => 'WHEN ? THEN ?').join(' ');
520
+ const rows = this.db
521
+ .prepare(`SELECT name, COUNT(DISTINCT CASE segment ${whens} END) AS matches
522
+ FROM name_segment_vocab
523
+ WHERE segment IN (${placeholders})
524
+ GROUP BY name
525
+ HAVING matches >= ?
526
+ ORDER BY matches DESC, length(name) ASC
527
+ LIMIT ?`)
528
+ .all(...variants.flatMap((v) => [v.segment, v.word]), ...variants.map((v) => v.segment), minWords, limit);
529
+ return rows;
530
+ }
531
+ /** How many distinct names each segment appears in — the rarity signal that
532
+ * separates a discriminative word ("checkout") from a ubiquitous one ("state"). */
533
+ getSegmentNameCounts(segments) {
534
+ if (segments.length === 0)
535
+ return new Map();
536
+ const placeholders = segments.map(() => '?').join(', ');
537
+ const rows = this.db
538
+ .prepare(`SELECT segment, COUNT(*) AS n FROM name_segment_vocab
539
+ WHERE segment IN (${placeholders}) GROUP BY segment`)
540
+ .all(...segments);
541
+ return new Map(rows.map((r) => [r.segment, r.n]));
542
+ }
543
+ /** Names containing the given segment (rare-single-word tier). */
544
+ getNamesForSegment(segment, limit) {
545
+ const rows = this.db
546
+ .prepare('SELECT name FROM name_segment_vocab WHERE segment = ? ORDER BY length(name) ASC LIMIT ?')
547
+ .all(segment, limit);
548
+ return rows.map((r) => r.name);
549
+ }
355
550
  /**
356
551
  * Get a node by ID
357
552
  */
@@ -645,6 +840,33 @@ class QueryBuilder {
645
840
  yield rowToNode(row);
646
841
  }
647
842
  }
843
+ /**
844
+ * Stream nodes of a language whose `decorators` JSON array contains a
845
+ * quoted decorator name. LIKE is a substring filter (a decorator name can
846
+ * appear as a substring of another), so callers must still exact-check
847
+ * `node.decorators.includes(decorator)`. Exists so the kotlin expect/actual
848
+ * synthesizer never materializes the whole node table the way
849
+ * `getAllNodes().filter(...)` did — that array alone OOM'd Node's default
850
+ * heap on a 2M-node graph (#1212).
851
+ */
852
+ *iterateNodesByLanguageWithDecorator(language, decorator) {
853
+ // Fresh statement per call — an iterator holds an open cursor (see
854
+ // iterateNodesByKind).
855
+ const stmt = this.db.prepare("SELECT * FROM nodes WHERE language = ? AND decorators LIKE '%' || ? || '%'");
856
+ for (const row of stmt.iterate(language, `"${decorator}"`)) {
857
+ yield rowToNode(row);
858
+ }
859
+ }
860
+ /**
861
+ * Distinct languages present in the files table. One indexed aggregate —
862
+ * lets the dynamic-edge synthesizers skip passes for languages the project
863
+ * doesn't contain at all (a Kotlin pass has no work on a pure-C repo), so
864
+ * their cost is zero rather than a full-graph scan that finds nothing (#1212).
865
+ */
866
+ getDistinctFileLanguages() {
867
+ const rows = this.db.prepare('SELECT DISTINCT language FROM files').all();
868
+ return new Set(rows.map((r) => r.language));
869
+ }
648
870
  /**
649
871
  * Get all nodes in the database
650
872
  */
@@ -1259,12 +1481,23 @@ class QueryBuilder {
1259
1481
  /**
1260
1482
  * Get incoming edges to a node
1261
1483
  */
1262
- getIncomingEdges(targetId, kinds) {
1484
+ getIncomingEdges(targetId, kinds, limit) {
1485
+ const cap = typeof limit === 'number' && Number.isFinite(limit)
1486
+ ? Math.max(1, Math.min(Math.floor(limit), 2000))
1487
+ : undefined;
1263
1488
  if (kinds && kinds.length > 0) {
1264
- const sql = `SELECT * FROM edges WHERE target = ? AND kind IN (${kinds.map(() => '?').join(',')})`;
1489
+ let sql = `SELECT * FROM edges WHERE target = ? AND kind IN (${kinds.map(() => '?').join(',')})`;
1490
+ if (cap !== undefined)
1491
+ sql += ` LIMIT ${cap}`;
1265
1492
  const rows = this.db.prepare(sql).all(targetId, ...kinds);
1266
1493
  return rows.map(rowToEdge);
1267
1494
  }
1495
+ if (cap !== undefined) {
1496
+ const rows = this.db
1497
+ .prepare('SELECT * FROM edges WHERE target = ? LIMIT ?')
1498
+ .all(targetId, cap);
1499
+ return rows.map(rowToEdge);
1500
+ }
1268
1501
  if (!this.stmts.getEdgesByTarget) {
1269
1502
  this.stmts.getEdgesByTarget = this.db.prepare('SELECT * FROM edges WHERE target = ?');
1270
1503
  }
@@ -1343,7 +1576,8 @@ class QueryBuilder {
1343
1576
  * {@link getDependentFilePaths}: all kinds except `contains`.
1344
1577
  */
1345
1578
  getCrossFileIncomingEdgesWithTarget(filePath) {
1346
- const sql = `SELECT e.*, tgt.name AS target_name, tgt.kind AS target_kind
1579
+ const sql = `SELECT e.*, tgt.name AS target_name, tgt.kind AS target_kind,
1580
+ src.file_path AS source_file_path, src.language AS source_language
1347
1581
  FROM edges e
1348
1582
  JOIN nodes tgt ON tgt.id = e.target
1349
1583
  JOIN nodes src ON src.id = e.source
@@ -1355,6 +1589,8 @@ class QueryBuilder {
1355
1589
  ...rowToEdge(row),
1356
1590
  targetName: row.target_name,
1357
1591
  targetKind: row.target_kind,
1592
+ sourceFilePath: row.source_file_path,
1593
+ sourceLanguage: row.source_language,
1358
1594
  }));
1359
1595
  }
1360
1596
  /**
@@ -1541,7 +1777,7 @@ class QueryBuilder {
1541
1777
  */
1542
1778
  getUnresolvedReferencesCount() {
1543
1779
  if (!this.stmts.getUnresolvedCount) {
1544
- this.stmts.getUnresolvedCount = this.db.prepare('SELECT COUNT(*) as count FROM unresolved_refs');
1780
+ this.stmts.getUnresolvedCount = this.db.prepare("SELECT COUNT(*) as count FROM unresolved_refs WHERE status = 'pending'");
1545
1781
  }
1546
1782
  const row = this.stmts.getUnresolvedCount.get();
1547
1783
  return row.count;
@@ -1552,7 +1788,7 @@ class QueryBuilder {
1552
1788
  */
1553
1789
  getUnresolvedReferencesBatch(offset, limit) {
1554
1790
  if (!this.stmts.getUnresolvedBatch) {
1555
- this.stmts.getUnresolvedBatch = this.db.prepare('SELECT * FROM unresolved_refs LIMIT ? OFFSET ?');
1791
+ this.stmts.getUnresolvedBatch = this.db.prepare("SELECT * FROM unresolved_refs WHERE status = 'pending' ORDER BY rowid LIMIT ? OFFSET ?");
1556
1792
  }
1557
1793
  const rows = this.stmts.getUnresolvedBatch.all(limit, offset);
1558
1794
  return rows.map((row) => ({
@@ -1564,6 +1800,32 @@ class QueryBuilder {
1564
1800
  candidates: row.candidates ? (0, utils_1.safeJsonParse)(row.candidates, undefined) : undefined,
1565
1801
  filePath: row.file_path,
1566
1802
  language: row.language,
1803
+ rowId: row.id,
1804
+ }));
1805
+ }
1806
+ /**
1807
+ * Keyset variant of {@link getUnresolvedReferencesBatch} for the batched
1808
+ * resolution loop: seek past the last-seen row id instead of OFFSET-walking.
1809
+ * OFFSET reads re-scan the accumulated failed-row prefix on every batch —
1810
+ * O(failed rows) per read, measured at 54.6s of the kernel-scale batch loop
1811
+ * (§7a.2) — while the seek is O(batch) forever. `id` is the rowid alias, so
1812
+ * the enumeration order is identical to the OFFSET reader's.
1813
+ */
1814
+ getUnresolvedReferencesBatchAfter(afterRowId, limit) {
1815
+ if (!this.stmts.getUnresolvedBatchAfter) {
1816
+ this.stmts.getUnresolvedBatchAfter = this.db.prepare("SELECT * FROM unresolved_refs WHERE status = 'pending' AND id > ? ORDER BY id LIMIT ?");
1817
+ }
1818
+ const rows = this.stmts.getUnresolvedBatchAfter.all(afterRowId, limit);
1819
+ return rows.map((row) => ({
1820
+ fromNodeId: row.from_node_id,
1821
+ referenceName: row.reference_name,
1822
+ referenceKind: row.reference_kind,
1823
+ line: row.line,
1824
+ column: row.col,
1825
+ candidates: row.candidates ? (0, utils_1.safeJsonParse)(row.candidates, undefined) : undefined,
1826
+ filePath: row.file_path,
1827
+ language: row.language,
1828
+ rowId: row.id,
1567
1829
  }));
1568
1830
  }
1569
1831
  /**
@@ -1586,6 +1848,152 @@ class QueryBuilder {
1586
1848
  const rows = this.stmts.getAllNodeNames.all();
1587
1849
  return rows.map((r) => r.name);
1588
1850
  }
1851
+ /**
1852
+ * Stream distinct node names one row at a time — for resolver cache warm-up
1853
+ * that needs to yield to the event loop mid-scan.
1854
+ */
1855
+ *iterateNodeNames() {
1856
+ const stmt = this.db.prepare('SELECT DISTINCT name FROM nodes');
1857
+ for (const row of stmt.iterate()) {
1858
+ yield row.name;
1859
+ }
1860
+ }
1861
+ /**
1862
+ * Park refs as status='failed' so drain loops skip them while sync can retry
1863
+ * when a later file change introduces a matching symbol.
1864
+ */
1865
+ markReferencesFailed(refs) {
1866
+ if (refs.length === 0)
1867
+ return 0;
1868
+ const stmt = this.db.prepare("UPDATE unresolved_refs SET status = 'failed', name_tail = ? WHERE from_node_id = ? AND reference_name = ? AND reference_kind = ?");
1869
+ let changed = 0;
1870
+ const markMany = this.db.transaction((items) => {
1871
+ for (const ref of items) {
1872
+ changed += stmt.run(referenceNameTail(ref.referenceName), ref.fromNodeId, ref.referenceName, ref.referenceKind).changes;
1873
+ }
1874
+ });
1875
+ markMany(refs);
1876
+ return changed;
1877
+ }
1878
+ /**
1879
+ * Delete unresolved-ref rows by row id — the precise cleanup for refs a
1880
+ * resolution pass actually processed. The key-tuple variant above also
1881
+ * deletes SIBLING rows (same caller calling the same callee at other lines)
1882
+ * that a later batch hasn't attempted yet, so when a batch boundary split a
1883
+ * caller's same-named call sites, the later sites' edges were silently never
1884
+ * created (#1269).
1885
+ */
1886
+ deleteReferencesByRowIds(rowIds) {
1887
+ if (rowIds.length === 0)
1888
+ return 0;
1889
+ let changed = 0;
1890
+ this.db.transaction(() => {
1891
+ for (let i = 0; i < rowIds.length; i += SQLITE_PARAM_CHUNK_SIZE) {
1892
+ const chunk = rowIds.slice(i, i + SQLITE_PARAM_CHUNK_SIZE);
1893
+ if (chunk.length === SQLITE_PARAM_CHUNK_SIZE) {
1894
+ if (!this.stmts.deleteRefsByRowIdsFull) {
1895
+ const placeholders = new Array(SQLITE_PARAM_CHUNK_SIZE).fill('?').join(',');
1896
+ this.stmts.deleteRefsByRowIdsFull = this.db.prepare(`DELETE FROM unresolved_refs WHERE id IN (${placeholders})`);
1897
+ }
1898
+ changed += this.stmts.deleteRefsByRowIdsFull.run(...chunk).changes;
1899
+ }
1900
+ else {
1901
+ const placeholders = chunk.map(() => '?').join(',');
1902
+ changed += this.db.prepare(`DELETE FROM unresolved_refs WHERE id IN (${placeholders})`).run(...chunk).changes;
1903
+ }
1904
+ }
1905
+ })();
1906
+ return changed;
1907
+ }
1908
+ /**
1909
+ * Park refs as status='failed' by row id — the precise counterpart of
1910
+ * markReferencesFailed, for the same reason as deleteReferencesByRowIds:
1911
+ * the key-tuple variant also flips same-key sibling rows in later batches
1912
+ * to 'failed' before they were ever attempted (#1269). Resolution outcome
1913
+ * can differ per call site (receiver-type inference reads the ref's line),
1914
+ * so a sibling must not inherit this row's failure.
1915
+ */
1916
+ markReferencesFailedByRowIds(refs) {
1917
+ if (refs.length === 0)
1918
+ return 0;
1919
+ const stmt = this.db.prepare("UPDATE unresolved_refs SET status = 'failed', name_tail = ? WHERE id = ?");
1920
+ let changed = 0;
1921
+ const markMany = this.db.transaction((items) => {
1922
+ for (const ref of items) {
1923
+ changed += stmt.run(referenceNameTail(ref.referenceName), ref.rowId).changes;
1924
+ }
1925
+ });
1926
+ markMany(refs);
1927
+ return changed;
1928
+ }
1929
+ /**
1930
+ * Failed refs whose name tail matches one of the given symbol names — the
1931
+ * candidates a sync should retry after files carrying those names changed
1932
+ * (#1240). Names matching more than `perNameCeiling` failed refs are
1933
+ * skipped entirely: at that population a name is external/builtin noise
1934
+ * (`get`, `map`, …) that one new definition won't resolve — the same
1935
+ * rationale as resolution's AMBIGUOUS_NAME_CEILING (#999) — and retrying an
1936
+ * arbitrary subset would be both wasted work and incoherent coverage.
1937
+ */
1938
+ getRetryableFailedReferences(names, perNameCeiling = 500) {
1939
+ if (names.length === 0)
1940
+ return [];
1941
+ // Pass 1: per-tail counts, chunked under the SQLite parameter limit.
1942
+ const retryNames = [];
1943
+ for (let i = 0; i < names.length; i += SQLITE_PARAM_CHUNK_SIZE) {
1944
+ const chunk = names.slice(i, i + SQLITE_PARAM_CHUNK_SIZE);
1945
+ const placeholders = chunk.map(() => '?').join(',');
1946
+ const counts = this.db
1947
+ .prepare(`SELECT name_tail, COUNT(*) as count FROM unresolved_refs WHERE status = 'failed' AND name_tail IN (${placeholders}) GROUP BY name_tail`)
1948
+ .all(...chunk);
1949
+ for (const row of counts) {
1950
+ if (row.count <= perNameCeiling)
1951
+ retryNames.push(row.name_tail);
1952
+ }
1953
+ }
1954
+ if (retryNames.length === 0)
1955
+ return [];
1956
+ // Pass 2: load the surviving rows.
1957
+ const rows = [];
1958
+ for (let i = 0; i < retryNames.length; i += SQLITE_PARAM_CHUNK_SIZE) {
1959
+ const chunk = retryNames.slice(i, i + SQLITE_PARAM_CHUNK_SIZE);
1960
+ const placeholders = chunk.map(() => '?').join(',');
1961
+ const chunkRows = this.db
1962
+ .prepare(`SELECT * FROM unresolved_refs WHERE status = 'failed' AND name_tail IN (${placeholders})`)
1963
+ .all(...chunk);
1964
+ rows.push(...chunkRows);
1965
+ }
1966
+ return rows.map((row) => ({
1967
+ fromNodeId: row.from_node_id,
1968
+ referenceName: row.reference_name,
1969
+ referenceKind: row.reference_kind,
1970
+ line: row.line,
1971
+ column: row.col,
1972
+ candidates: row.candidates ? (0, utils_1.safeJsonParse)(row.candidates, undefined) : undefined,
1973
+ filePath: row.file_path,
1974
+ language: row.language,
1975
+ rowId: row.id,
1976
+ }));
1977
+ }
1978
+ /**
1979
+ * Distinct node names present in the given files — the symbol names a sync
1980
+ * pass uses to look up retryable failed refs after those files changed.
1981
+ */
1982
+ getNodeNamesByFiles(filePaths) {
1983
+ if (filePaths.length === 0)
1984
+ return [];
1985
+ const names = new Set();
1986
+ for (let i = 0; i < filePaths.length; i += SQLITE_PARAM_CHUNK_SIZE) {
1987
+ const chunk = filePaths.slice(i, i + SQLITE_PARAM_CHUNK_SIZE);
1988
+ const placeholders = chunk.map(() => '?').join(',');
1989
+ const rows = this.db
1990
+ .prepare(`SELECT DISTINCT name FROM nodes WHERE file_path IN (${placeholders})`)
1991
+ .all(...chunk);
1992
+ for (const row of rows)
1993
+ names.add(row.name);
1994
+ }
1995
+ return [...names];
1996
+ }
1589
1997
  /**
1590
1998
  * Get unresolved references scoped to specific file paths.
1591
1999
  * Uses the idx_unresolved_file_path index for efficient lookup.
@@ -1602,7 +2010,7 @@ class QueryBuilder {
1602
2010
  const chunk = filePaths.slice(i, i + SQLITE_PARAM_CHUNK_SIZE);
1603
2011
  const placeholders = chunk.map(() => '?').join(',');
1604
2012
  const chunkRows = this.db
1605
- .prepare(`SELECT * FROM unresolved_refs WHERE file_path IN (${placeholders})`)
2013
+ .prepare(`SELECT * FROM unresolved_refs WHERE status = 'pending' AND file_path IN (${placeholders})`)
1606
2014
  .all(...chunk);
1607
2015
  rows.push(...chunkRows);
1608
2016
  }
@@ -1633,7 +2041,7 @@ class QueryBuilder {
1633
2041
  // this file. The internal resolution path uses deleteSpecificResolvedReferences
1634
2042
  // instead, but QueryBuilder is part of the public API, so a library consumer
1635
2043
  // passing more ids than SQLITE_MAX_VARIABLE_NUMBER (32766 on the bundled
1636
- // node:sqlite) would otherwise hit "too many SQL variables". (#540, #1001)
2044
+ // SQLite would otherwise hit "too many SQL variables". (#540, #1001)
1637
2045
  for (let i = 0; i < fromNodeIds.length; i += SQLITE_PARAM_CHUNK_SIZE) {
1638
2046
  const chunk = fromNodeIds.slice(i, i + SQLITE_PARAM_CHUNK_SIZE);
1639
2047
  const placeholders = chunk.map(() => '?').join(',');
@@ -1646,14 +2054,16 @@ class QueryBuilder {
1646
2054
  */
1647
2055
  deleteSpecificResolvedReferences(refs) {
1648
2056
  if (refs.length === 0)
1649
- return;
2057
+ return 0;
1650
2058
  const stmt = this.db.prepare('DELETE FROM unresolved_refs WHERE from_node_id = ? AND reference_name = ? AND reference_kind = ?');
2059
+ let changed = 0;
1651
2060
  const deleteMany = this.db.transaction((items) => {
1652
2061
  for (const ref of items) {
1653
- stmt.run(ref.fromNodeId, ref.referenceName, ref.referenceKind);
2062
+ changed += stmt.run(ref.fromNodeId, ref.referenceName, ref.referenceKind).changes;
1654
2063
  }
1655
2064
  });
1656
2065
  deleteMany(refs);
2066
+ return changed;
1657
2067
  }
1658
2068
  // ===========================================================================
1659
2069
  // Statistics
@@ -1752,6 +2162,13 @@ class QueryBuilder {
1752
2162
  .get(cacheKey);
1753
2163
  return row ?? null;
1754
2164
  }
2165
+ /** All cache keys — used to warm the in-memory key index after daemon restart. */
2166
+ listMcpQueryCacheKeys() {
2167
+ const rows = this.db
2168
+ .prepare('SELECT cache_key FROM mcp_query_cache')
2169
+ .all();
2170
+ return rows.map((r) => r.cache_key);
2171
+ }
1755
2172
  setMcpQueryCache(cacheKey, tool, response, createdAt) {
1756
2173
  this.db
1757
2174
  .prepare('INSERT INTO mcp_query_cache (cache_key, tool, response, created_at) VALUES (?, ?, ?, ?) ' +