homegraph 1.1.2 → 1.2.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 (361) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +268 -243
  3. package/dist/arkts/ohos-api-index.d.ts +15 -0
  4. package/dist/arkts/ohos-api-index.d.ts.map +1 -0
  5. package/dist/arkts/ohos-api-index.js +190 -0
  6. package/dist/arkts/ohos-api-index.js.map +1 -0
  7. package/dist/arkts/ohos-sdk-input.d.ts +36 -0
  8. package/dist/arkts/ohos-sdk-input.d.ts.map +1 -0
  9. package/dist/arkts/ohos-sdk-input.js +214 -0
  10. package/dist/arkts/ohos-sdk-input.js.map +1 -0
  11. package/dist/bin/command-supervision.d.ts +12 -0
  12. package/dist/bin/command-supervision.d.ts.map +1 -0
  13. package/dist/bin/command-supervision.js +86 -0
  14. package/dist/bin/command-supervision.js.map +1 -0
  15. package/dist/bin/homegraph.d.ts +1 -1
  16. package/dist/bin/homegraph.js +971 -71
  17. package/dist/bin/homegraph.js.map +1 -1
  18. package/dist/db/index.d.ts +20 -0
  19. package/dist/db/index.d.ts.map +1 -1
  20. package/dist/db/index.js +39 -0
  21. package/dist/db/index.js.map +1 -1
  22. package/dist/db/migrations.d.ts +1 -1
  23. package/dist/db/migrations.d.ts.map +1 -1
  24. package/dist/db/migrations.js +58 -19
  25. package/dist/db/migrations.js.map +1 -1
  26. package/dist/db/queries.d.ts +14 -0
  27. package/dist/db/queries.d.ts.map +1 -1
  28. package/dist/db/queries.js +314 -143
  29. package/dist/db/queries.js.map +1 -1
  30. package/dist/db/schema.sql +172 -152
  31. package/dist/directory.d.ts +32 -0
  32. package/dist/directory.d.ts.map +1 -1
  33. package/dist/directory.js +88 -5
  34. package/dist/directory.js.map +1 -1
  35. package/dist/extraction/arkts-batch-worker.d.ts +2 -0
  36. package/dist/extraction/arkts-batch-worker.d.ts.map +1 -0
  37. package/dist/extraction/arkts-batch-worker.js +28 -0
  38. package/dist/extraction/arkts-batch-worker.js.map +1 -0
  39. package/dist/extraction/context.d.ts +11 -0
  40. package/dist/extraction/context.d.ts.map +1 -1
  41. package/dist/extraction/context.js +20 -0
  42. package/dist/extraction/context.js.map +1 -1
  43. package/dist/extraction/index.d.ts +16 -2
  44. package/dist/extraction/index.d.ts.map +1 -1
  45. package/dist/extraction/index.js +619 -380
  46. package/dist/extraction/index.js.map +1 -1
  47. package/dist/extraction/languages/arkts-state-decorators.d.ts +13 -0
  48. package/dist/extraction/languages/arkts-state-decorators.d.ts.map +1 -0
  49. package/dist/extraction/languages/arkts-state-decorators.js +26 -0
  50. package/dist/extraction/languages/arkts-state-decorators.js.map +1 -0
  51. package/dist/extraction/languages/arkts-viewtree.d.ts +4 -2
  52. package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -1
  53. package/dist/extraction/languages/arkts-viewtree.js +21 -6
  54. package/dist/extraction/languages/arkts-viewtree.js.map +1 -1
  55. package/dist/extraction/languages/arkts.d.ts +98 -2
  56. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  57. package/dist/extraction/languages/arkts.js +1290 -61
  58. package/dist/extraction/languages/arkts.js.map +1 -1
  59. package/dist/extraction/languages/c-cpp.d.ts +56 -0
  60. package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  61. package/dist/extraction/languages/c-cpp.js +198 -1
  62. package/dist/extraction/languages/c-cpp.js.map +1 -1
  63. package/dist/extraction/languages/ohos-api-consumer.d.ts +34 -0
  64. package/dist/extraction/languages/ohos-api-consumer.d.ts.map +1 -0
  65. package/dist/extraction/languages/ohos-api-consumer.js +283 -0
  66. package/dist/extraction/languages/ohos-api-consumer.js.map +1 -0
  67. package/dist/extraction/parse-pool.d.ts +126 -0
  68. package/dist/extraction/parse-pool.d.ts.map +1 -0
  69. package/dist/extraction/parse-pool.js +319 -0
  70. package/dist/extraction/parse-pool.js.map +1 -0
  71. package/dist/extraction/tree-sitter-types.d.ts +17 -0
  72. package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  73. package/dist/extraction/tree-sitter.d.ts +21 -0
  74. package/dist/extraction/tree-sitter.d.ts.map +1 -1
  75. package/dist/extraction/tree-sitter.js +198 -27
  76. package/dist/extraction/tree-sitter.js.map +1 -1
  77. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  78. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  79. package/dist/graph/traversal.d.ts.map +1 -1
  80. package/dist/graph/traversal.js +76 -17
  81. package/dist/graph/traversal.js.map +1 -1
  82. package/dist/index.d.ts +25 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +78 -4
  85. package/dist/index.js.map +1 -1
  86. package/dist/installer/instructions-template.js +9 -9
  87. package/dist/installer/targets/shared.d.ts +5 -6
  88. package/dist/installer/targets/shared.d.ts.map +1 -1
  89. package/dist/installer/targets/shared.js +5 -6
  90. package/dist/installer/targets/shared.js.map +1 -1
  91. package/dist/mcp/daemon-paths.d.ts +30 -3
  92. package/dist/mcp/daemon-paths.d.ts.map +1 -1
  93. package/dist/mcp/daemon-paths.js +50 -10
  94. package/dist/mcp/daemon-paths.js.map +1 -1
  95. package/dist/mcp/daemon-registry.d.ts.map +1 -1
  96. package/dist/mcp/daemon-registry.js +7 -3
  97. package/dist/mcp/daemon-registry.js.map +1 -1
  98. package/dist/mcp/daemon.d.ts +48 -0
  99. package/dist/mcp/daemon.d.ts.map +1 -1
  100. package/dist/mcp/daemon.js +196 -32
  101. package/dist/mcp/daemon.js.map +1 -1
  102. package/dist/mcp/engine.d.ts +17 -0
  103. package/dist/mcp/engine.d.ts.map +1 -1
  104. package/dist/mcp/engine.js +73 -1
  105. package/dist/mcp/engine.js.map +1 -1
  106. package/dist/mcp/index.d.ts.map +1 -1
  107. package/dist/mcp/index.js +25 -43
  108. package/dist/mcp/index.js.map +1 -1
  109. package/dist/mcp/liveness-watchdog.js +16 -16
  110. package/dist/mcp/ppid-watchdog.d.ts +18 -0
  111. package/dist/mcp/ppid-watchdog.d.ts.map +1 -1
  112. package/dist/mcp/ppid-watchdog.js +37 -0
  113. package/dist/mcp/ppid-watchdog.js.map +1 -1
  114. package/dist/mcp/query-cache.d.ts +25 -0
  115. package/dist/mcp/query-cache.d.ts.map +1 -0
  116. package/dist/mcp/query-cache.js +191 -0
  117. package/dist/mcp/query-cache.js.map +1 -0
  118. package/dist/mcp/query-pool.d.ts +94 -0
  119. package/dist/mcp/query-pool.d.ts.map +1 -0
  120. package/dist/mcp/query-pool.js +297 -0
  121. package/dist/mcp/query-pool.js.map +1 -0
  122. package/dist/mcp/query-worker.d.ts +24 -0
  123. package/dist/mcp/query-worker.d.ts.map +1 -0
  124. package/dist/mcp/query-worker.js +87 -0
  125. package/dist/mcp/query-worker.js.map +1 -0
  126. package/dist/mcp/server-instructions.d.ts +5 -7
  127. package/dist/mcp/server-instructions.d.ts.map +1 -1
  128. package/dist/mcp/server-instructions.js +72 -74
  129. package/dist/mcp/server-instructions.js.map +1 -1
  130. package/dist/mcp/tools.d.ts +94 -4
  131. package/dist/mcp/tools.d.ts.map +1 -1
  132. package/dist/mcp/tools.js +877 -71
  133. package/dist/mcp/tools.js.map +1 -1
  134. package/dist/project-config.d.ts +20 -0
  135. package/dist/project-config.d.ts.map +1 -1
  136. package/dist/project-config.js +42 -2
  137. package/dist/project-config.js.map +1 -1
  138. package/dist/reasoning/login.js +1 -1
  139. package/dist/reasoning/login.js.map +1 -1
  140. package/dist/reasoning/reasoner.js +32 -32
  141. package/dist/resolution/c-fnptr-synthesizer.d.ts +0 -28
  142. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
  143. package/dist/resolution/c-fnptr-synthesizer.js +765 -79
  144. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
  145. package/dist/resolution/callback-synthesizer.d.ts +1 -1
  146. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  147. package/dist/resolution/callback-synthesizer.js +72 -11
  148. package/dist/resolution/callback-synthesizer.js.map +1 -1
  149. package/dist/resolution/cooperative-yield.d.ts +32 -0
  150. package/dist/resolution/cooperative-yield.d.ts.map +1 -0
  151. package/dist/resolution/cooperative-yield.js +42 -0
  152. package/dist/resolution/cooperative-yield.js.map +1 -0
  153. package/dist/resolution/index.d.ts +11 -2
  154. package/dist/resolution/index.d.ts.map +1 -1
  155. package/dist/resolution/index.js +72 -4
  156. package/dist/resolution/index.js.map +1 -1
  157. package/dist/resolution/name-matcher.d.ts +22 -0
  158. package/dist/resolution/name-matcher.d.ts.map +1 -1
  159. package/dist/resolution/name-matcher.js +317 -20
  160. package/dist/resolution/name-matcher.js.map +1 -1
  161. package/dist/spec/config.d.ts +39 -0
  162. package/dist/spec/config.d.ts.map +1 -0
  163. package/dist/spec/config.js +304 -0
  164. package/dist/spec/config.js.map +1 -0
  165. package/dist/spec/db/commit-node.d.ts +23 -0
  166. package/dist/spec/db/commit-node.d.ts.map +1 -0
  167. package/dist/spec/db/commit-node.js +62 -0
  168. package/dist/spec/db/commit-node.js.map +1 -0
  169. package/dist/spec/db/fragment-node.d.ts +24 -0
  170. package/dist/spec/db/fragment-node.d.ts.map +1 -0
  171. package/dist/spec/db/fragment-node.js +128 -0
  172. package/dist/spec/db/fragment-node.js.map +1 -0
  173. package/dist/spec/db/fts.d.ts +74 -0
  174. package/dist/spec/db/fts.d.ts.map +1 -0
  175. package/dist/spec/db/fts.js +324 -0
  176. package/dist/spec/db/fts.js.map +1 -0
  177. package/dist/spec/db/index.d.ts +13 -0
  178. package/dist/spec/db/index.d.ts.map +1 -0
  179. package/dist/spec/db/index.js +50 -0
  180. package/dist/spec/db/index.js.map +1 -0
  181. package/dist/spec/db/relations.d.ts +55 -0
  182. package/dist/spec/db/relations.d.ts.map +1 -0
  183. package/dist/spec/db/relations.js +158 -0
  184. package/dist/spec/db/relations.js.map +1 -0
  185. package/dist/spec/db/schema.d.ts +33 -0
  186. package/dist/spec/db/schema.d.ts.map +1 -0
  187. package/dist/spec/db/schema.js +119 -0
  188. package/dist/spec/db/schema.js.map +1 -0
  189. package/dist/spec/db/schema.sql +117 -0
  190. package/dist/spec/db/spec-node.d.ts +41 -0
  191. package/dist/spec/db/spec-node.d.ts.map +1 -0
  192. package/dist/spec/db/spec-node.js +114 -0
  193. package/dist/spec/db/spec-node.js.map +1 -0
  194. package/dist/spec/evolve/impact-locator.d.ts +13 -0
  195. package/dist/spec/evolve/impact-locator.d.ts.map +1 -0
  196. package/dist/spec/evolve/impact-locator.js +25 -0
  197. package/dist/spec/evolve/impact-locator.js.map +1 -0
  198. package/dist/spec/evolve/llm-client.d.ts +50 -0
  199. package/dist/spec/evolve/llm-client.d.ts.map +1 -0
  200. package/dist/spec/evolve/llm-client.js +176 -0
  201. package/dist/spec/evolve/llm-client.js.map +1 -0
  202. package/dist/spec/evolve/logic-checker.d.ts +12 -0
  203. package/dist/spec/evolve/logic-checker.d.ts.map +1 -0
  204. package/dist/spec/evolve/logic-checker.js +24 -0
  205. package/dist/spec/evolve/logic-checker.js.map +1 -0
  206. package/dist/spec/evolve/pipeline.d.ts +42 -0
  207. package/dist/spec/evolve/pipeline.d.ts.map +1 -0
  208. package/dist/spec/evolve/pipeline.js +567 -0
  209. package/dist/spec/evolve/pipeline.js.map +1 -0
  210. package/dist/spec/evolve/spec-rewriter.d.ts +42 -0
  211. package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -0
  212. package/dist/spec/evolve/spec-rewriter.js +230 -0
  213. package/dist/spec/evolve/spec-rewriter.js.map +1 -0
  214. package/dist/spec/graph/queries.d.ts +155 -0
  215. package/dist/spec/graph/queries.d.ts.map +1 -0
  216. package/dist/spec/graph/queries.js +440 -0
  217. package/dist/spec/graph/queries.js.map +1 -0
  218. package/dist/spec/llm/client.d.ts +29 -0
  219. package/dist/spec/llm/client.d.ts.map +1 -0
  220. package/dist/spec/llm/client.js +123 -0
  221. package/dist/spec/llm/client.js.map +1 -0
  222. package/dist/spec/llm/index.d.ts +3 -0
  223. package/dist/spec/llm/index.d.ts.map +1 -0
  224. package/dist/spec/llm/index.js +11 -0
  225. package/dist/spec/llm/index.js.map +1 -0
  226. package/dist/spec/llm/prompts.d.ts +13 -0
  227. package/dist/spec/llm/prompts.d.ts.map +1 -0
  228. package/dist/spec/llm/prompts.js +75 -0
  229. package/dist/spec/llm/prompts.js.map +1 -0
  230. package/dist/spec/mining/diff-parser.d.ts +33 -0
  231. package/dist/spec/mining/diff-parser.d.ts.map +1 -0
  232. package/dist/spec/mining/diff-parser.js +166 -0
  233. package/dist/spec/mining/diff-parser.js.map +1 -0
  234. package/dist/spec/mining/git-scanner.d.ts +103 -0
  235. package/dist/spec/mining/git-scanner.d.ts.map +1 -0
  236. package/dist/spec/mining/git-scanner.js +307 -0
  237. package/dist/spec/mining/git-scanner.js.map +1 -0
  238. package/dist/spec/mining/pipeline.d.ts +53 -0
  239. package/dist/spec/mining/pipeline.d.ts.map +1 -0
  240. package/dist/spec/mining/pipeline.js +178 -0
  241. package/dist/spec/mining/pipeline.js.map +1 -0
  242. package/dist/spec/mining/scope-resolver.d.ts +45 -0
  243. package/dist/spec/mining/scope-resolver.d.ts.map +1 -0
  244. package/dist/spec/mining/scope-resolver.js +103 -0
  245. package/dist/spec/mining/scope-resolver.js.map +1 -0
  246. package/dist/spec/mining/spec-extractor.d.ts +69 -0
  247. package/dist/spec/mining/spec-extractor.d.ts.map +1 -0
  248. package/dist/spec/mining/spec-extractor.js +369 -0
  249. package/dist/spec/mining/spec-extractor.js.map +1 -0
  250. package/dist/spec/types.d.ts +149 -0
  251. package/dist/spec/types.d.ts.map +1 -0
  252. package/dist/spec/types.js +15 -0
  253. package/dist/spec/types.js.map +1 -0
  254. package/dist/spec/utils.d.ts +167 -0
  255. package/dist/spec/utils.d.ts.map +1 -0
  256. package/dist/spec/utils.js +463 -0
  257. package/dist/spec/utils.js.map +1 -0
  258. package/dist/sync/worktree.d.ts +9 -0
  259. package/dist/sync/worktree.d.ts.map +1 -1
  260. package/dist/sync/worktree.js +40 -0
  261. package/dist/sync/worktree.js.map +1 -1
  262. package/dist/types.d.ts +6 -1
  263. package/dist/types.d.ts.map +1 -1
  264. package/dist/ui/shimmer-progress.d.ts +2 -0
  265. package/dist/ui/shimmer-progress.d.ts.map +1 -1
  266. package/dist/ui/shimmer-progress.js +19 -2
  267. package/dist/ui/shimmer-progress.js.map +1 -1
  268. package/dist/upgrade/index.js +1 -1
  269. package/dist/upgrade/index.js.map +1 -1
  270. package/package.json +58 -57
  271. package/scripts/add-lang/bench.sh +60 -60
  272. package/scripts/add-lang/check-grammar.mjs +75 -75
  273. package/scripts/add-lang/dump-ast.mjs +103 -103
  274. package/scripts/add-lang/verify-extraction.mjs +70 -70
  275. package/scripts/agent-eval/ab-adoption.sh +91 -91
  276. package/scripts/agent-eval/ab-hook.sh +86 -86
  277. package/scripts/agent-eval/ab-impl.sh +78 -78
  278. package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -102
  279. package/scripts/agent-eval/ab-sufficiency.sh +78 -78
  280. package/scripts/agent-eval/arms-F.sh +21 -21
  281. package/scripts/agent-eval/arms-matrix.sh +37 -37
  282. package/scripts/agent-eval/audit.sh +68 -68
  283. package/scripts/agent-eval/bench-readme.sh +28 -28
  284. package/scripts/agent-eval/bench-why-repo.sh +22 -22
  285. package/scripts/agent-eval/block-read-hook.sh +19 -19
  286. package/scripts/agent-eval/hook-settings.json +15 -15
  287. package/scripts/agent-eval/itrun.sh +120 -120
  288. package/scripts/agent-eval/offload-eval-3arm.sh +72 -72
  289. package/scripts/agent-eval/offload-eval-cost.mjs +133 -133
  290. package/scripts/agent-eval/offload-eval-effort.mjs +108 -108
  291. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -25
  292. package/scripts/agent-eval/offload-eval-frontload.sh +47 -47
  293. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -18
  294. package/scripts/agent-eval/offload-eval-hook.mjs +84 -84
  295. package/scripts/agent-eval/offload-eval-judge.mjs +103 -103
  296. package/scripts/agent-eval/offload-eval-matrix.sh +20 -20
  297. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -94
  298. package/scripts/agent-eval/offload-eval-refs1.sh +50 -50
  299. package/scripts/agent-eval/offload-eval-setup.sh +24 -24
  300. package/scripts/agent-eval/offload-eval-styles.sh +71 -71
  301. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -68
  302. package/scripts/agent-eval/offload-eval.md +76 -76
  303. package/scripts/agent-eval/parse-arms.mjs +116 -116
  304. package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
  305. package/scripts/agent-eval/parse-run.mjs +45 -45
  306. package/scripts/agent-eval/parse-session.mjs +93 -93
  307. package/scripts/agent-eval/probe-context.mjs +21 -21
  308. package/scripts/agent-eval/probe-explore.mjs +40 -40
  309. package/scripts/agent-eval/probe-node.mjs +20 -20
  310. package/scripts/agent-eval/probe-sweep.mjs +119 -119
  311. package/scripts/agent-eval/probe-trace.mjs +20 -20
  312. package/scripts/agent-eval/redirect-read-hook.sh +38 -38
  313. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
  314. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
  315. package/scripts/agent-eval/run-agent.sh +34 -34
  316. package/scripts/agent-eval/run-all.sh +69 -69
  317. package/scripts/agent-eval/run-arms.sh +56 -56
  318. package/scripts/agent-eval/seq-matrix.mjs +137 -137
  319. package/scripts/build-bundle.sh +118 -118
  320. package/scripts/exp_boundary_eval/README.md +247 -0
  321. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  322. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  323. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-310.pyc +0 -0
  324. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  325. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  326. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  327. package/scripts/exp_boundary_eval/_test_mcp_chain.py +78 -0
  328. package/scripts/exp_boundary_eval/_test_stdin.py +8 -0
  329. package/scripts/exp_boundary_eval/_utils.py +1116 -0
  330. package/scripts/exp_boundary_eval/analyze.py +1313 -0
  331. package/scripts/exp_boundary_eval/data/agents.json +109 -0
  332. package/scripts/exp_boundary_eval/data/experiments.json +140 -0
  333. package/scripts/exp_boundary_eval/deveco_arm.py +519 -0
  334. package/scripts/exp_boundary_eval/run_all.py +378 -0
  335. package/scripts/exp_boundary_eval/run_one.py +165 -0
  336. package/scripts/exp_boundary_eval/run_session.py +158 -0
  337. package/scripts/exp_boundary_eval/setup.py +120 -0
  338. package/scripts/exp_boundary_eval/win_mcp_launcher.py +73 -0
  339. package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +36 -0
  340. package/scripts/exp_boundary_eval/win_node_launcher.py +24 -0
  341. package/scripts/extract-release-notes.mjs +130 -130
  342. package/scripts/local-install.sh +41 -41
  343. package/scripts/npm-sdk.js +75 -75
  344. package/scripts/npm-shim.js +268 -246
  345. package/scripts/ohos-sdk-publish.mjs +133 -0
  346. package/scripts/pack-npm.sh +119 -119
  347. package/scripts/prepare-release.mjs +270 -270
  348. package/scripts/qa_eval/README.md +407 -404
  349. package/scripts/qa_eval/_test_deveco_probe.py +41 -41
  350. package/scripts/qa_eval/agent_runner.py +526 -526
  351. package/scripts/qa_eval/data/.gitignore +4 -4
  352. package/scripts/qa_eval/data/test-set.jsonl +2 -22
  353. package/scripts/qa_eval/eval_metrics.py +274 -233
  354. package/scripts/qa_eval/external_agent.py +976 -671
  355. package/scripts/qa_eval/llm_config.py +92 -92
  356. package/scripts/qa_eval/memory_monitor.py +132 -132
  357. package/scripts/qa_eval/my_answer_accuracy.py +187 -187
  358. package/scripts/qa_eval/requirements.txt +2 -2
  359. package/scripts/qa_eval/run_pipeline.py +804 -711
  360. package/scripts/qa_eval/stats_efficiency.py +279 -279
  361. package/scripts/qa_eval/stats_scores.py +207 -207
@@ -4,12 +4,48 @@
4
4
  *
5
5
  * Prepared statements for CRUD operations on the knowledge graph.
6
6
  */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
7
40
  Object.defineProperty(exports, "__esModule", { value: true });
8
41
  exports.QueryBuilder = void 0;
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
9
44
  const utils_1 = require("../utils");
10
45
  const query_utils_1 = require("../search/query-utils");
11
46
  const query_parser_1 = require("../search/query-parser");
12
47
  const generated_detection_1 = require("../extraction/generated-detection");
48
+ const arkts_1 = require("../extraction/languages/arkts");
13
49
  /**
14
50
  * Path-only heuristic for files that should not be candidates for
15
51
  * "dominant file" detection: test/spec files and tool-generated files.
@@ -103,11 +139,49 @@ class QueryBuilder {
103
139
  // Node cache for frequently accessed nodes (LRU-style, max 1000 entries)
104
140
  nodeCache = new Map();
105
141
  maxCacheSize = 1000;
142
+ /** Attached prebuilt OHOS API db (see arkts.ts). */
143
+ ohosApiDbPath = null;
106
144
  // Prepared statements (lazily initialized)
107
145
  stmts = {};
108
146
  constructor(db) {
109
147
  this.db = db;
110
148
  }
149
+ /** Attach a versioned OHOS API db for federated symbol lookup. */
150
+ attachOhosApiDb(dbPath) {
151
+ if (dbPath === this.ohosApiDbPath)
152
+ return;
153
+ if (this.ohosApiDbPath) {
154
+ try {
155
+ this.db.exec('DETACH DATABASE ohos_api');
156
+ }
157
+ catch {
158
+ /* already detached */
159
+ }
160
+ this.ohosApiDbPath = null;
161
+ }
162
+ if (!dbPath)
163
+ return;
164
+ const resolved = path.resolve(dbPath);
165
+ if (!fs.existsSync(resolved)) {
166
+ throw new Error(`OHOS API db not found: ${resolved}`);
167
+ }
168
+ const escaped = resolved.replace(/'/g, "''");
169
+ this.db.exec(`ATTACH DATABASE '${escaped}' AS ohos_api`);
170
+ this.ohosApiDbPath = resolved;
171
+ this.stmts = {};
172
+ this.nodeCache.clear();
173
+ }
174
+ getOhosApiDbPath() {
175
+ return this.ohosApiDbPath;
176
+ }
177
+ hasOhosApiAttached() {
178
+ return this.ohosApiDbPath != null;
179
+ }
180
+ mapOhosApiNodeRow(row) {
181
+ const node = rowToNode(row);
182
+ node.filePath = (0, arkts_1.markOhosApiFilePath)(node.filePath);
183
+ return node;
184
+ }
111
185
  /** Set the normalized project-name tokens used to down-weight non-discriminative
112
186
  * query words in path scoring (#720). Called once when the project opens. */
113
187
  setProjectNameTokens(tokens) {
@@ -125,20 +199,20 @@ class QueryBuilder {
125
199
  */
126
200
  insertNode(node) {
127
201
  if (!this.stmts.insertNode) {
128
- this.stmts.insertNode = this.db.prepare(`
129
- INSERT OR REPLACE INTO nodes (
130
- id, kind, name, qualified_name, file_path, language,
131
- start_line, end_line, start_column, end_column,
132
- docstring, signature, visibility,
133
- is_exported, is_async, is_static, is_abstract,
134
- decorators, type_parameters, return_type, updated_at
135
- ) VALUES (
136
- @id, @kind, @name, @qualifiedName, @filePath, @language,
137
- @startLine, @endLine, @startColumn, @endColumn,
138
- @docstring, @signature, @visibility,
139
- @isExported, @isAsync, @isStatic, @isAbstract,
140
- @decorators, @typeParameters, @returnType, @updatedAt
141
- )
202
+ this.stmts.insertNode = this.db.prepare(`
203
+ INSERT OR REPLACE INTO nodes (
204
+ id, kind, name, qualified_name, file_path, language,
205
+ start_line, end_line, start_column, end_column,
206
+ docstring, signature, visibility,
207
+ is_exported, is_async, is_static, is_abstract,
208
+ decorators, type_parameters, return_type, updated_at
209
+ ) VALUES (
210
+ @id, @kind, @name, @qualifiedName, @filePath, @language,
211
+ @startLine, @endLine, @startColumn, @endColumn,
212
+ @docstring, @signature, @visibility,
213
+ @isExported, @isAsync, @isStatic, @isAbstract,
214
+ @decorators, @typeParameters, @returnType, @updatedAt
215
+ )
142
216
  `);
143
217
  }
144
218
  // Validate required fields to prevent SQLite bind errors
@@ -196,29 +270,29 @@ class QueryBuilder {
196
270
  */
197
271
  updateNode(node) {
198
272
  if (!this.stmts.updateNode) {
199
- this.stmts.updateNode = this.db.prepare(`
200
- UPDATE nodes SET
201
- kind = @kind,
202
- name = @name,
203
- qualified_name = @qualifiedName,
204
- file_path = @filePath,
205
- language = @language,
206
- start_line = @startLine,
207
- end_line = @endLine,
208
- start_column = @startColumn,
209
- end_column = @endColumn,
210
- docstring = @docstring,
211
- signature = @signature,
212
- visibility = @visibility,
213
- is_exported = @isExported,
214
- is_async = @isAsync,
215
- is_static = @isStatic,
216
- is_abstract = @isAbstract,
217
- decorators = @decorators,
218
- type_parameters = @typeParameters,
219
- return_type = @returnType,
220
- updated_at = @updatedAt
221
- WHERE id = @id
273
+ this.stmts.updateNode = this.db.prepare(`
274
+ UPDATE nodes SET
275
+ kind = @kind,
276
+ name = @name,
277
+ qualified_name = @qualifiedName,
278
+ file_path = @filePath,
279
+ language = @language,
280
+ start_line = @startLine,
281
+ end_line = @endLine,
282
+ start_column = @startColumn,
283
+ end_column = @endColumn,
284
+ docstring = @docstring,
285
+ signature = @signature,
286
+ visibility = @visibility,
287
+ is_exported = @isExported,
288
+ is_async = @isAsync,
289
+ is_static = @isStatic,
290
+ is_abstract = @isAbstract,
291
+ decorators = @decorators,
292
+ type_parameters = @typeParameters,
293
+ return_type = @returnType,
294
+ updated_at = @updatedAt
295
+ WHERE id = @id
222
296
  `);
223
297
  }
224
298
  // Invalidate cache before update
@@ -426,15 +500,15 @@ class QueryBuilder {
426
500
  // protobuf stub) outranks the real `server/etcdserver/server.go`
427
501
  // (470 edges) by 4×, and the boost would push the agent toward
428
502
  // generated code.
429
- this.stmts.getDominantFile = this.db.prepare(`
430
- SELECT n.file_path AS file_path, COUNT(*) AS edge_count
431
- FROM edges e
432
- JOIN nodes n ON e.source = n.id
433
- JOIN nodes m ON e.target = m.id
434
- WHERE n.file_path = m.file_path
435
- GROUP BY n.file_path
436
- ORDER BY edge_count DESC
437
- LIMIT 20
503
+ this.stmts.getDominantFile = this.db.prepare(`
504
+ SELECT n.file_path AS file_path, COUNT(*) AS edge_count
505
+ FROM edges e
506
+ JOIN nodes n ON e.source = n.id
507
+ JOIN nodes m ON e.target = m.id
508
+ WHERE n.file_path = m.file_path
509
+ GROUP BY n.file_path
510
+ ORDER BY edge_count DESC
511
+ LIMIT 20
438
512
  `);
439
513
  }
440
514
  const rows = this.stmts.getDominantFile.all();
@@ -461,13 +535,13 @@ class QueryBuilder {
461
535
  */
462
536
  getTopRouteFile() {
463
537
  if (!this.stmts.getTopRouteFile) {
464
- this.stmts.getTopRouteFile = this.db.prepare(`
465
- SELECT file_path, COUNT(*) AS cnt
466
- FROM nodes
467
- WHERE kind = 'route'
468
- GROUP BY file_path
469
- ORDER BY cnt DESC
470
- LIMIT 20
538
+ this.stmts.getTopRouteFile = this.db.prepare(`
539
+ SELECT file_path, COUNT(*) AS cnt
540
+ FROM nodes
541
+ WHERE kind = 'route'
542
+ GROUP BY file_path
543
+ ORDER BY cnt DESC
544
+ LIMIT 20
471
545
  `);
472
546
  }
473
547
  const rows = this.stmts.getTopRouteFile.all();
@@ -498,21 +572,21 @@ class QueryBuilder {
498
572
  // Edge kind varies across framework resolvers: Spring/Rails/
499
573
  // Laravel/Drupal emit `references`, Express emits `calls`. Accept
500
574
  // both — the semantic is the same (route → its handler).
501
- this.stmts.getRoutingManifest = this.db.prepare(`
502
- SELECT
503
- r.name AS url,
504
- h.name AS handler,
505
- h.file_path AS handler_file,
506
- h.start_line AS handler_line,
507
- h.kind AS handler_kind
508
- FROM nodes r
509
- JOIN edges e ON e.source = r.id
510
- JOIN nodes h ON e.target = h.id
511
- WHERE r.kind = 'route'
512
- AND e.kind IN ('references', 'calls')
513
- AND h.kind IN ('function', 'method', 'class')
514
- ORDER BY r.file_path, r.start_line
515
- LIMIT ?
575
+ this.stmts.getRoutingManifest = this.db.prepare(`
576
+ SELECT
577
+ r.name AS url,
578
+ h.name AS handler,
579
+ h.file_path AS handler_file,
580
+ h.start_line AS handler_line,
581
+ h.kind AS handler_kind
582
+ FROM nodes r
583
+ JOIN edges e ON e.source = r.id
584
+ JOIN nodes h ON e.target = h.id
585
+ WHERE r.kind = 'route'
586
+ AND e.kind IN ('references', 'calls')
587
+ AND h.kind IN ('function', 'method', 'class')
588
+ ORDER BY r.file_path, r.start_line
589
+ LIMIT ?
516
590
  `);
517
591
  }
518
592
  const rows = this.stmts.getRoutingManifest.all(limit);
@@ -586,7 +660,15 @@ class QueryBuilder {
586
660
  this.stmts.getNodesByName = this.db.prepare('SELECT * FROM nodes WHERE name = ?');
587
661
  }
588
662
  const rows = this.stmts.getNodesByName.all(name);
589
- return rows.map(rowToNode);
663
+ const main = rows.map(rowToNode);
664
+ if (!this.hasOhosApiAttached())
665
+ return main;
666
+ const apiRows = this.db
667
+ .prepare('SELECT * FROM ohos_api.nodes WHERE name = ?')
668
+ .all(name);
669
+ const seen = new Set(main.map((n) => n.id));
670
+ const api = apiRows.map((r) => this.mapOhosApiNodeRow(r)).filter((n) => !seen.has(n.id));
671
+ return [...main, ...api];
590
672
  }
591
673
  /**
592
674
  * Get nodes by exact qualified name match (uses idx_nodes_qualified_name index)
@@ -722,8 +804,44 @@ class QueryBuilder {
722
804
  return lowered.some((n) => nm.includes(n));
723
805
  });
724
806
  }
807
+ if (this.hasOhosApiAttached() && text.length >= 2) {
808
+ results = this.mergeOhosApiTextSearch(text, { kinds, languages, limit }, results);
809
+ }
725
810
  return results;
726
811
  }
812
+ mergeOhosApiTextSearch(text, options, existing) {
813
+ const { kinds, languages, limit = 100 } = options;
814
+ const seen = new Set(existing.map((r) => r.node.id));
815
+ const merged = [...existing];
816
+ const apiLimit = Math.min(20, Math.max(5, Math.floor(limit / 4)));
817
+ let sql = `
818
+ SELECT nodes.*, 0.9 as score
819
+ FROM ohos_api.nodes
820
+ WHERE (name LIKE ? OR qualified_name LIKE ?)
821
+ `;
822
+ const pattern = `%${text}%`;
823
+ const params = [pattern, pattern];
824
+ if (kinds && kinds.length > 0) {
825
+ sql += ` AND kind IN (${kinds.map(() => '?').join(',')})`;
826
+ params.push(...kinds);
827
+ }
828
+ if (languages && languages.length > 0) {
829
+ sql += ` AND language IN (${languages.map(() => '?').join(',')})`;
830
+ params.push(...languages);
831
+ }
832
+ sql += ' LIMIT ?';
833
+ params.push(apiLimit);
834
+ const rows = this.db.prepare(sql).all(...params);
835
+ for (const row of rows) {
836
+ const node = this.mapOhosApiNodeRow(row);
837
+ if (seen.has(node.id))
838
+ continue;
839
+ seen.add(node.id);
840
+ merged.push({ node, score: row.score });
841
+ }
842
+ merged.sort((a, b) => b.score - a.score);
843
+ return merged.slice(0, limit);
844
+ }
727
845
  /**
728
846
  * Match-everything path used when the user supplied only field
729
847
  * filters (`kind:function lang:typescript`) with no text. Returns
@@ -838,11 +956,11 @@ class QueryBuilder {
838
956
  // Fetch 5x requested limit so post-hoc rescoring (kindBonus, pathRelevance,
839
957
  // nameMatchBonus) can promote results that BM25 alone undervalues.
840
958
  const ftsLimit = Math.max(limit * 5, 100);
841
- let sql = `
842
- SELECT nodes.*, bm25(nodes_fts, 0, 20, 5, 1, 2) as score
843
- FROM nodes_fts
844
- JOIN nodes ON nodes_fts.id = nodes.id
845
- WHERE nodes_fts MATCH ?
959
+ let sql = `
960
+ SELECT nodes.*, bm25(nodes_fts, 0, 20, 5, 1, 2) as score
961
+ FROM nodes_fts
962
+ JOIN nodes ON nodes_fts.id = nodes.id
963
+ WHERE nodes_fts MATCH ?
846
964
  `;
847
965
  const params = [ftsQuery];
848
966
  if (kinds && kinds.length > 0) {
@@ -873,21 +991,21 @@ class QueryBuilder {
873
991
  */
874
992
  searchNodesLike(query, options) {
875
993
  const { kinds, languages, limit = 100, offset = 0 } = options;
876
- let sql = `
877
- SELECT nodes.*,
878
- CASE
879
- WHEN name = ? THEN 1.0
880
- WHEN name LIKE ? THEN 0.9
881
- WHEN name LIKE ? THEN 0.8
882
- WHEN qualified_name LIKE ? THEN 0.7
883
- ELSE 0.5
884
- END as score
885
- FROM nodes
886
- WHERE (
887
- name LIKE ? OR
888
- qualified_name LIKE ? OR
889
- name LIKE ?
890
- )
994
+ let sql = `
995
+ SELECT nodes.*,
996
+ CASE
997
+ WHEN name = ? THEN 1.0
998
+ WHEN name LIKE ? THEN 0.9
999
+ WHEN name LIKE ? THEN 0.8
1000
+ WHEN qualified_name LIKE ? THEN 0.7
1001
+ ELSE 0.5
1002
+ END as score
1003
+ FROM nodes
1004
+ WHERE (
1005
+ name LIKE ? OR
1006
+ qualified_name LIKE ? OR
1007
+ name LIKE ?
1008
+ )
891
1009
  `;
892
1010
  // Pattern variants for better matching
893
1011
  const exactMatch = query;
@@ -961,10 +1079,10 @@ class QueryBuilder {
961
1079
  const allResults = [];
962
1080
  const seenIds = new Set();
963
1081
  for (const name of names) {
964
- let sql = `
965
- SELECT nodes.*, 1.0 as score
966
- FROM nodes
967
- WHERE name COLLATE NOCASE = ?
1082
+ let sql = `
1083
+ SELECT nodes.*, 1.0 as score
1084
+ FROM nodes
1085
+ WHERE name COLLATE NOCASE = ?
968
1086
  `;
969
1087
  const params = [name];
970
1088
  if (kinds && kinds.length > 0) {
@@ -994,6 +1112,32 @@ class QueryBuilder {
994
1112
  seenIds.add(r.node.id);
995
1113
  allResults.push(r);
996
1114
  }
1115
+ if (this.hasOhosApiAttached()) {
1116
+ let apiSql = `
1117
+ SELECT nodes.*, 0.95 as score
1118
+ FROM ohos_api.nodes
1119
+ WHERE name COLLATE NOCASE = ?
1120
+ `;
1121
+ const apiParams = [name];
1122
+ if (kinds && kinds.length > 0) {
1123
+ apiSql += ` AND kind IN (${kinds.map(() => '?').join(',')})`;
1124
+ apiParams.push(...kinds);
1125
+ }
1126
+ if (languages && languages.length > 0) {
1127
+ apiSql += ` AND language IN (${languages.map(() => '?').join(',')})`;
1128
+ apiParams.push(...languages);
1129
+ }
1130
+ apiSql += ' LIMIT ?';
1131
+ apiParams.push(perNameLimit);
1132
+ const apiRows = this.db.prepare(apiSql).all(...apiParams);
1133
+ for (const row of apiRows) {
1134
+ const node = this.mapOhosApiNodeRow(row);
1135
+ if (seenIds.has(node.id))
1136
+ continue;
1137
+ seenIds.add(node.id);
1138
+ allResults.push({ node, score: row.score });
1139
+ }
1140
+ }
997
1141
  }
998
1142
  // Sort all results by score so co-located results bubble up
999
1143
  allResults.sort((a, b) => b.score - a.score);
@@ -1008,10 +1152,10 @@ class QueryBuilder {
1008
1152
  */
1009
1153
  findNodesByNameSubstring(substring, options = {}) {
1010
1154
  const { kinds, languages, limit = 30, excludePrefix } = options;
1011
- let sql = `
1012
- SELECT nodes.*, 1.0 as score
1013
- FROM nodes
1014
- WHERE name LIKE ?
1155
+ let sql = `
1156
+ SELECT nodes.*, 1.0 as score
1157
+ FROM nodes
1158
+ WHERE name LIKE ?
1015
1159
  `;
1016
1160
  const params = [`%${substring}%`];
1017
1161
  // Exclude prefix matches (handled by FTS-based prefix search in Step 2b)
@@ -1043,9 +1187,9 @@ class QueryBuilder {
1043
1187
  */
1044
1188
  insertEdge(edge) {
1045
1189
  if (!this.stmts.insertEdge) {
1046
- this.stmts.insertEdge = this.db.prepare(`
1047
- INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance)
1048
- VALUES (@source, @target, @kind, @metadata, @line, @col, @provenance)
1190
+ this.stmts.insertEdge = this.db.prepare(`
1191
+ INSERT OR IGNORE INTO edges (source, target, kind, metadata, line, col, provenance)
1192
+ VALUES (@source, @target, @kind, @metadata, @line, @col, @provenance)
1049
1193
  `);
1050
1194
  }
1051
1195
  this.stmts.insertEdge.run({
@@ -1161,12 +1305,12 @@ class QueryBuilder {
1161
1305
  * it. One indexed query (idx_nodes_file_path + idx_edges_target_kind).
1162
1306
  */
1163
1307
  getDependentFilePaths(filePath) {
1164
- const sql = `SELECT DISTINCT src.file_path AS fp
1165
- FROM edges e
1166
- JOIN nodes tgt ON tgt.id = e.target
1167
- JOIN nodes src ON src.id = e.source
1168
- WHERE tgt.file_path = ?
1169
- AND e.kind != 'contains'
1308
+ const sql = `SELECT DISTINCT src.file_path AS fp
1309
+ FROM edges e
1310
+ JOIN nodes tgt ON tgt.id = e.target
1311
+ JOIN nodes src ON src.id = e.source
1312
+ WHERE tgt.file_path = ?
1313
+ AND e.kind != 'contains'
1170
1314
  AND src.file_path != ?`;
1171
1315
  const rows = this.db.prepare(sql).all(filePath, filePath);
1172
1316
  return rows.map((r) => r.fp);
@@ -1178,12 +1322,12 @@ class QueryBuilder {
1178
1322
  * (all kinds except `contains`); same reason imports-only is insufficient.
1179
1323
  */
1180
1324
  getDependencyFilePaths(filePath) {
1181
- const sql = `SELECT DISTINCT tgt.file_path AS fp
1182
- FROM edges e
1183
- JOIN nodes src ON src.id = e.source
1184
- JOIN nodes tgt ON tgt.id = e.target
1185
- WHERE src.file_path = ?
1186
- AND e.kind != 'contains'
1325
+ const sql = `SELECT DISTINCT tgt.file_path AS fp
1326
+ FROM edges e
1327
+ JOIN nodes src ON src.id = e.source
1328
+ JOIN nodes tgt ON tgt.id = e.target
1329
+ WHERE src.file_path = ?
1330
+ AND e.kind != 'contains'
1187
1331
  AND tgt.file_path != ?`;
1188
1332
  const rows = this.db.prepare(sql).all(filePath, filePath);
1189
1333
  return rows.map((r) => r.fp);
@@ -1199,12 +1343,12 @@ class QueryBuilder {
1199
1343
  * {@link getDependentFilePaths}: all kinds except `contains`.
1200
1344
  */
1201
1345
  getCrossFileIncomingEdgesWithTarget(filePath) {
1202
- const sql = `SELECT e.*, tgt.name AS target_name, tgt.kind AS target_kind
1203
- FROM edges e
1204
- JOIN nodes tgt ON tgt.id = e.target
1205
- JOIN nodes src ON src.id = e.source
1206
- WHERE tgt.file_path = ?
1207
- AND e.kind != 'contains'
1346
+ const sql = `SELECT e.*, tgt.name AS target_name, tgt.kind AS target_kind
1347
+ FROM edges e
1348
+ JOIN nodes tgt ON tgt.id = e.target
1349
+ JOIN nodes src ON src.id = e.source
1350
+ WHERE tgt.file_path = ?
1351
+ AND e.kind != 'contains'
1208
1352
  AND src.file_path != ?`;
1209
1353
  const rows = this.db.prepare(sql).all(filePath, filePath);
1210
1354
  return rows.map(row => ({
@@ -1219,10 +1363,10 @@ class QueryBuilder {
1219
1363
  */
1220
1364
  deleteArkTSCrossFileCallEdges() {
1221
1365
  const result = this.db
1222
- .prepare(`DELETE FROM edges
1223
- WHERE kind = 'calls'
1224
- AND provenance = 'heuristic'
1225
- AND metadata LIKE '%"synthesizedBy":"arkanalyzer"%'
1366
+ .prepare(`DELETE FROM edges
1367
+ WHERE kind = 'calls'
1368
+ AND provenance = 'heuristic'
1369
+ AND metadata LIKE '%"synthesizedBy":"arkanalyzer"%'
1226
1370
  AND metadata LIKE '%"sourceFile"%'`)
1227
1371
  .run();
1228
1372
  return result.changes;
@@ -1235,17 +1379,17 @@ class QueryBuilder {
1235
1379
  */
1236
1380
  upsertFile(file) {
1237
1381
  if (!this.stmts.upsertFile) {
1238
- this.stmts.upsertFile = this.db.prepare(`
1239
- INSERT INTO files (path, content_hash, language, size, modified_at, indexed_at, node_count, errors)
1240
- VALUES (@path, @contentHash, @language, @size, @modifiedAt, @indexedAt, @nodeCount, @errors)
1241
- ON CONFLICT(path) DO UPDATE SET
1242
- content_hash = @contentHash,
1243
- language = @language,
1244
- size = @size,
1245
- modified_at = @modifiedAt,
1246
- indexed_at = @indexedAt,
1247
- node_count = @nodeCount,
1248
- errors = @errors
1382
+ this.stmts.upsertFile = this.db.prepare(`
1383
+ INSERT INTO files (path, content_hash, language, size, modified_at, indexed_at, node_count, errors)
1384
+ VALUES (@path, @contentHash, @language, @size, @modifiedAt, @indexedAt, @nodeCount, @errors)
1385
+ ON CONFLICT(path) DO UPDATE SET
1386
+ content_hash = @contentHash,
1387
+ language = @language,
1388
+ size = @size,
1389
+ modified_at = @modifiedAt,
1390
+ indexed_at = @indexedAt,
1391
+ node_count = @nodeCount,
1392
+ errors = @errors
1249
1393
  `);
1250
1394
  }
1251
1395
  this.stmts.upsertFile.run({
@@ -1319,9 +1463,9 @@ class QueryBuilder {
1319
1463
  */
1320
1464
  insertUnresolvedRef(ref) {
1321
1465
  if (!this.stmts.insertUnresolved) {
1322
- this.stmts.insertUnresolved = this.db.prepare(`
1323
- INSERT INTO unresolved_refs (from_node_id, reference_name, reference_kind, line, col, candidates, file_path, language)
1324
- VALUES (@fromNodeId, @referenceName, @referenceKind, @line, @col, @candidates, @filePath, @language)
1466
+ this.stmts.insertUnresolved = this.db.prepare(`
1467
+ INSERT INTO unresolved_refs (from_node_id, reference_name, reference_kind, line, col, candidates, file_path, language)
1468
+ VALUES (@fromNodeId, @referenceName, @referenceKind, @line, @col, @candidates, @filePath, @language)
1325
1469
  `);
1326
1470
  }
1327
1471
  this.stmts.insertUnresolved.run({
@@ -1485,8 +1629,16 @@ class QueryBuilder {
1485
1629
  deleteResolvedReferences(fromNodeIds) {
1486
1630
  if (fromNodeIds.length === 0)
1487
1631
  return;
1488
- const placeholders = fromNodeIds.map(() => '?').join(',');
1489
- this.db.prepare(`DELETE FROM unresolved_refs WHERE from_node_id IN (${placeholders})`).run(...fromNodeIds);
1632
+ // Chunk under SQLite's parameter limit, matching every other IN-list in
1633
+ // this file. The internal resolution path uses deleteSpecificResolvedReferences
1634
+ // instead, but QueryBuilder is part of the public API, so a library consumer
1635
+ // passing more ids than SQLITE_MAX_VARIABLE_NUMBER (32766 on the bundled
1636
+ // node:sqlite) would otherwise hit "too many SQL variables". (#540, #1001)
1637
+ for (let i = 0; i < fromNodeIds.length; i += SQLITE_PARAM_CHUNK_SIZE) {
1638
+ const chunk = fromNodeIds.slice(i, i + SQLITE_PARAM_CHUNK_SIZE);
1639
+ const placeholders = chunk.map(() => '?').join(',');
1640
+ this.db.prepare(`DELETE FROM unresolved_refs WHERE from_node_id IN (${placeholders})`).run(...chunk);
1641
+ }
1490
1642
  }
1491
1643
  /**
1492
1644
  * Delete specific resolved references by (fromNodeId, referenceName, referenceKind) tuples.
@@ -1523,11 +1675,11 @@ class QueryBuilder {
1523
1675
  */
1524
1676
  getStats() {
1525
1677
  // Single query for all three aggregate counts
1526
- const counts = this.db.prepare(`
1527
- SELECT
1528
- (SELECT COUNT(*) FROM nodes) AS node_count,
1529
- (SELECT COUNT(*) FROM edges) AS edge_count,
1530
- (SELECT COUNT(*) FROM files) AS file_count
1678
+ const counts = this.db.prepare(`
1679
+ SELECT
1680
+ (SELECT COUNT(*) FROM nodes) AS node_count,
1681
+ (SELECT COUNT(*) FROM edges) AS edge_count,
1682
+ (SELECT COUNT(*) FROM files) AS file_count
1531
1683
  `).get();
1532
1684
  const nodesByKind = {};
1533
1685
  const nodeKindRows = this.db
@@ -1588,12 +1740,31 @@ class QueryBuilder {
1588
1740
  }
1589
1741
  return result;
1590
1742
  }
1743
+ // ===========================================================================
1744
+ // MCP Query Cache
1745
+ // ===========================================================================
1746
+ clearMcpQueryCache() {
1747
+ this.db.exec('DELETE FROM mcp_query_cache');
1748
+ }
1749
+ getMcpQueryCache(cacheKey) {
1750
+ const row = this.db
1751
+ .prepare('SELECT tool, response FROM mcp_query_cache WHERE cache_key = ?')
1752
+ .get(cacheKey);
1753
+ return row ?? null;
1754
+ }
1755
+ setMcpQueryCache(cacheKey, tool, response, createdAt) {
1756
+ this.db
1757
+ .prepare('INSERT INTO mcp_query_cache (cache_key, tool, response, created_at) VALUES (?, ?, ?, ?) ' +
1758
+ 'ON CONFLICT(cache_key) DO UPDATE SET tool = excluded.tool, response = excluded.response, created_at = excluded.created_at')
1759
+ .run(cacheKey, tool, response, createdAt);
1760
+ }
1591
1761
  /**
1592
1762
  * Clear all data from the database
1593
1763
  */
1594
1764
  clear() {
1595
1765
  this.nodeCache.clear();
1596
1766
  this.db.transaction(() => {
1767
+ this.db.exec('DELETE FROM mcp_query_cache');
1597
1768
  this.db.exec('DELETE FROM unresolved_refs');
1598
1769
  this.db.exec('DELETE FROM edges');
1599
1770
  this.db.exec('DELETE FROM nodes');