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
package/dist/index.js CHANGED
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.HomeGraph = exports.MCPServer = exports.LockUnavailableError = exports.FileWatcher = exports.MemoryMonitor = exports.throttle = exports.debounce = exports.processInBatches = exports.FileLock = exports.Mutex = exports.defaultLogger = exports.silentLogger = exports.getLogger = exports.setLogger = exports.ConfigError = exports.VectorError = exports.SearchError = exports.DatabaseError = exports.ParseError = exports.FileError = exports.HomeGraphError = exports.loadAllGrammars = exports.loadGrammarsForLanguages = exports.initGrammars = exports.getSupportedLanguages = exports.isGrammarLoaded = exports.isLanguageSupported = exports.detectLanguage = exports.HOMEGRAPH_DIR = exports.findNearestHomeGraphRoot = exports.isInitialized = exports.getHomeGraphDir = exports.QueryBuilder = exports.DatabaseConnection = exports.getDatabasePath = void 0;
46
46
  const path = __importStar(require("path"));
47
47
  const db_1 = require("./db");
48
+ const wal_valve_1 = require("./db/wal-valve");
48
49
  const queries_1 = require("./db/queries");
49
50
  const directory_1 = require("./directory");
50
51
  const extraction_1 = require("./extraction");
@@ -58,6 +59,9 @@ const sync_1 = require("./sync");
58
59
  const extraction_version_1 = require("./extraction/extraction-version");
59
60
  const directory_2 = require("./directory");
60
61
  const query_utils_1 = require("./search/query-utils");
62
+ const identifier_segments_1 = require("./search/identifier-segments");
63
+ const cooperative_yield_1 = require("./resolution/cooperative-yield");
64
+ const resolver_pool_1 = require("./resolution/resolver-pool");
61
65
  const version_1 = require("./mcp/version");
62
66
  // Re-export types for consumers
63
67
  __exportStar(require("./types"), exports);
@@ -375,26 +379,74 @@ class HomeGraph {
375
379
  catch {
376
380
  return { success: false, filesIndexed: 0, filesSkipped: 0, filesErrored: 0, nodesCreated: 0, edgesCreated: 0, errors: [{ message: 'Could not acquire file lock - another process may be indexing', severity: 'error' }], durationMs: 0 };
377
381
  }
382
+ const freshDb = this.queries.getNodeAndEdgeCount().nodes === 0;
383
+ const fastInit = process.env.HOMEGRAPH_NO_FAST_INIT !== '1' && freshDb;
384
+ if (fastInit) {
385
+ try {
386
+ this.db.getDb().pragma('journal_mode = MEMORY');
387
+ this.db.getDb().pragma('synchronous = OFF');
388
+ }
389
+ catch { /* keep WAL */ }
390
+ }
391
+ const deferWal = !fastInit && process.env.HOMEGRAPH_NO_WAL_DEFER !== '1' && this.db.getJournalMode() === 'wal';
392
+ let walValve = null;
393
+ let priorAutocheckpoint = 1000;
394
+ let restoreAutocheckpoint = false;
395
+ if (deferWal) {
396
+ priorAutocheckpoint = this.db.getWalAutocheckpoint();
397
+ this.db.setWalAutocheckpoint(0);
398
+ walValve = new wal_valve_1.WalCheckpointValve(this.db, (0, wal_valve_1.resolveWalValveMb)(process.env.HOMEGRAPH_WAL_VALVE_MB, this.db.getDbFileSizeBytes()), undefined, options.verbose ? (m) => console.log(`[wal-valve] ${m}`) : undefined);
399
+ walValve.start();
400
+ }
378
401
  try {
379
402
  const before = this.queries.getNodeAndEdgeCount();
380
- const result = await this.orchestrator.indexAll(options.onProgress, options.signal, options.verbose);
381
- // Re-detect frameworks now that the index is populated. The resolver
382
- // is constructed with createResolver() before any files exist, so
383
- // framework resolvers whose detect() consults the indexed file list
384
- // (e.g. UIKit/SwiftUI scanning for imports, swift-objc-bridge looking
385
- // for both Swift and ObjC files) all return false on that initial pass
386
- // and silently drop themselves. Re-initializing here gives them a
387
- // chance to see the actual project before resolution runs.
403
+ try {
404
+ this.queries.setMetadata('index_state', 'indexing');
405
+ }
406
+ catch { /* metadata is advisory */ }
407
+ try {
408
+ this.queries.clearNameSegmentVocab();
409
+ }
410
+ catch { /* vocab is advisory never fail an index over it */ }
411
+ this.db.beginBulkNodeLoad();
412
+ if (freshDb)
413
+ this.db.beginBulkParseLoad();
414
+ let result;
415
+ try {
416
+ result = await this.orchestrator.indexAll(options.onProgress, options.signal, options.verbose, walValve ? () => walValve.backpressure() : undefined, freshDb ? { dbPath: this.db.getPath(), fastInit } : null);
417
+ }
418
+ finally {
419
+ if (freshDb) {
420
+ const tIdx = Date.now();
421
+ await this.db.endBulkParseLoad();
422
+ if (process.env.HOMEGRAPH_SYNTH_TIMINGS)
423
+ console.error(`[phase-timing] parse-index-rebuild: ${Date.now() - tIdx}ms`);
424
+ }
425
+ const tFts = Date.now();
426
+ this.db.endBulkNodeLoad();
427
+ if (process.env.HOMEGRAPH_SYNTH_TIMINGS)
428
+ console.error(`[phase-timing] fts-rebuild: ${Date.now() - tFts}ms`);
429
+ }
430
+ if (walValve)
431
+ await walValve.foldNow();
388
432
  if (result.success && result.filesIndexed > 0) {
389
433
  this.resolver.initialize();
390
- // Cross-file finalization (e.g. NestJS RouterModule prefixes). Runs
391
- // before resolution so updated names show up in subsequent reads.
392
434
  this.resolver.runPostExtract();
393
435
  }
394
- // Resolve references to create call/import/extends edges
395
436
  if (result.success && result.filesIndexed > 0) {
396
- // Get count without loading all refs into memory
397
437
  const unresolvedCount = this.queries.getUnresolvedReferencesCount();
438
+ if (fastInit && unresolvedCount >= (0, resolver_pool_1.minRefsForPool)()) {
439
+ try {
440
+ this.db.getDb().pragma('synchronous = NORMAL');
441
+ this.db.getDb().pragma('journal_mode = WAL');
442
+ priorAutocheckpoint = this.db.getWalAutocheckpoint();
443
+ this.db.setWalAutocheckpoint(0);
444
+ restoreAutocheckpoint = true;
445
+ walValve = new wal_valve_1.WalCheckpointValve(this.db, undefined, undefined, options.verbose ? (m) => console.log(`[wal-valve] ${m}`) : undefined);
446
+ walValve.start();
447
+ }
448
+ catch { /* keep current mode; resolution still works sequentially */ }
449
+ }
398
450
  options.onProgress?.({
399
451
  phase: 'resolving',
400
452
  current: 0,
@@ -406,34 +458,28 @@ class HomeGraph {
406
458
  current,
407
459
  total,
408
460
  });
409
- });
410
- // Second pass: chained calls whose method lives on a supertype the
411
- // receiver conforms to (protocol-extension / inherited / default-
412
- // interface). Needs the implements/extends edges the main pass just
413
- // built, so it runs after resolution (#750).
461
+ }, (done, totalPasses) => {
462
+ options.onProgress?.({
463
+ phase: 'linking',
464
+ current: done,
465
+ total: totalPasses,
466
+ });
467
+ }, walValve ? () => walValve.backpressure() : undefined);
414
468
  await this.resolver.resolveChainedCallsViaConformance();
415
- // Same lifecycle for `this.<member>` callback registrations whose
416
- // member is inherited from a supertype (#808).
417
469
  await this.resolver.resolveDeferredThisMemberRefs();
418
470
  }
419
- // Refresh planner stats + checkpoint the WAL after bulk writes.
420
- // Cheap and non-blocking; never load-bearing for correctness.
421
471
  if (result.success && result.filesIndexed > 0) {
422
- this.db.runMaintenance();
472
+ if (walValve) {
473
+ walValve.stop();
474
+ await walValve.drain();
475
+ }
476
+ await this.db.runMaintenance();
423
477
  }
424
- // The orchestrator only sees extraction-phase counts; resolution and
425
- // synthesizer edges (often >50% of the graph on JVM repos) come later.
426
- // Recompute against the DB so the CLI summary reports the true totals.
427
478
  if (result.success && result.filesIndexed > 0) {
428
479
  const after = this.queries.getNodeAndEdgeCount();
429
480
  result.nodesCreated = after.nodes - before.nodes;
430
481
  result.edgesCreated = after.edges - before.edges;
431
482
  }
432
- // Stamp the index with the engine that built it, so `homegraph status`
433
- // and `homegraph upgrade` can recommend a re-index when the running
434
- // engine produces richer extraction than the one on disk. Only on a
435
- // real full index — a sync touches a subset, so it must NOT advance the
436
- // extraction stamp (the bulk would still be stale). See extraction-version.ts.
437
483
  if (result.success && result.filesIndexed > 0) {
438
484
  try {
439
485
  this.queries.setMetadata('indexed_with_version', version_1.HomeGraphPackageVersion);
@@ -448,9 +494,54 @@ class HomeGraph {
448
494
  result.errors.push({ message: ohosBinding.message, severity: 'warning', code: ohosBinding.code });
449
495
  }
450
496
  }
497
+ try {
498
+ if (!result.success) {
499
+ this.queries.setMetadata('index_state', 'failed');
500
+ }
501
+ else {
502
+ const accounted = result.filesIndexed + result.filesSkipped + result.filesErrored;
503
+ const discovered = result.filesDiscovered;
504
+ const shortfall = discovered !== undefined ? discovered - accounted : 0;
505
+ if (discovered !== undefined && shortfall > 0) {
506
+ this.queries.setMetadata('index_state', 'partial');
507
+ this.queries.setMetadata('index_files_discovered', String(discovered));
508
+ this.queries.setMetadata('index_files_accounted', String(accounted));
509
+ result.errors.push({
510
+ message: `Index is missing ${shortfall} of ${discovered} discovered files (indexed ${result.filesIndexed}, skipped ${result.filesSkipped}, errored ${result.filesErrored}). The index is PARTIAL — re-run \`homegraph index\`.`,
511
+ severity: 'warning',
512
+ code: 'index_partial',
513
+ });
514
+ }
515
+ else {
516
+ this.queries.setMetadata('index_state', 'complete');
517
+ if (discovered !== undefined) {
518
+ this.queries.setMetadata('index_files_discovered', String(discovered));
519
+ this.queries.setMetadata('index_files_accounted', String(accounted));
520
+ }
521
+ }
522
+ }
523
+ }
524
+ catch { /* metadata is advisory — never fail an index over it */ }
451
525
  return result;
452
526
  }
453
527
  finally {
528
+ if (walValve) {
529
+ walValve.stop();
530
+ await walValve.drain();
531
+ }
532
+ if (deferWal || restoreAutocheckpoint) {
533
+ try {
534
+ this.db.setWalAutocheckpoint(priorAutocheckpoint);
535
+ }
536
+ catch { /* connection may be closing */ }
537
+ }
538
+ if (fastInit) {
539
+ try {
540
+ this.db.getDb().pragma('synchronous = NORMAL');
541
+ this.db.getDb().pragma('journal_mode = WAL');
542
+ }
543
+ catch { /* connection may be closing */ }
544
+ }
454
545
  this.fileLock.release();
455
546
  }
456
547
  });
@@ -489,20 +580,41 @@ class HomeGraph {
489
580
  catch {
490
581
  return { filesChecked: 0, filesAdded: 0, filesModified: 0, filesRemoved: 0, nodesUpdated: 0, durationMs: 0 };
491
582
  }
583
+ const deferWal = process.env.HOMEGRAPH_NO_WAL_DEFER !== '1' && this.db.getJournalMode() === 'wal';
584
+ let walValve = null;
585
+ let priorAutocheckpoint = 1000;
586
+ if (deferWal) {
587
+ priorAutocheckpoint = this.db.getWalAutocheckpoint();
588
+ this.db.setWalAutocheckpoint(0);
589
+ walValve = new wal_valve_1.WalCheckpointValve(this.db, (0, wal_valve_1.resolveWalValveMb)(process.env.HOMEGRAPH_WAL_VALVE_MB, this.db.getDbFileSizeBytes()), undefined, options.verbose ? (m) => console.log(`[wal-valve] ${m}`) : undefined);
590
+ walValve.start();
591
+ }
492
592
  try {
493
- const result = await this.orchestrator.sync(options.onProgress);
494
- // Cross-file finalization (e.g. NestJS RouterModule prefixes). Run on
495
- // every sync that touched files so edits to `app.module.ts` propagate
496
- // to controllers in unchanged files. The pass is idempotent and cheap
497
- // (regex over *.module.ts only).
593
+ const vocabWasEmpty = (() => {
594
+ try {
595
+ return this.queries.isNameSegmentVocabEmpty();
596
+ }
597
+ catch {
598
+ return false;
599
+ }
600
+ })();
601
+ const result = await this.orchestrator.sync(options.onProgress, options.paths);
602
+ if (walValve)
603
+ await walValve.foldNow();
498
604
  if (result.filesAdded > 0 || result.filesModified > 0) {
499
605
  this.resolver.runPostExtract();
500
606
  }
501
- // Resolve references if files were updated
502
- if (result.filesAdded > 0 || result.filesModified > 0) {
607
+ else if (result.filesRemoved > 0) {
608
+ this.resolver.clearCaches();
609
+ }
610
+ const filesChanged = result.filesAdded > 0 || result.filesModified > 0;
611
+ const backpressure = walValve ? () => walValve.backpressure() : undefined;
612
+ if (filesChanged) {
503
613
  if (result.changedFilePaths) {
504
- // Scope resolution to changed files (git fast path — bounded set)
614
+ const tRefLoad = Date.now();
505
615
  const unresolvedRefs = this.queries.getUnresolvedReferencesByFiles(result.changedFilePaths);
616
+ if (process.env.HOMEGRAPH_SYNTH_TIMINGS)
617
+ console.error(`[phase-timing] sync-ref-load: ${Date.now() - tRefLoad}ms (${unresolvedRefs.length} refs)`);
506
618
  options.onProgress?.({
507
619
  phase: 'resolving',
508
620
  current: 0,
@@ -515,9 +627,25 @@ class HomeGraph {
515
627
  total,
516
628
  });
517
629
  });
630
+ const tRetry = Date.now();
631
+ const retryable = this.queries.getRetryableFailedReferences(this.queries.getNodeNamesByFiles(result.changedFilePaths));
632
+ if (retryable.length > 0) {
633
+ options.onProgress?.({
634
+ phase: 'resolving',
635
+ current: 0,
636
+ total: retryable.length,
637
+ });
638
+ await this.resolver.resolveAndPersistListYielding(retryable);
639
+ options.onProgress?.({
640
+ phase: 'resolving',
641
+ current: retryable.length,
642
+ total: retryable.length,
643
+ });
644
+ }
645
+ if (process.env.HOMEGRAPH_SYNTH_TIMINGS)
646
+ console.error(`[phase-timing] sync-failed-ref-retry: ${Date.now() - tRetry}ms (${retryable.length} refs)`);
518
647
  }
519
648
  else {
520
- // No git info — use batched resolution to avoid OOM
521
649
  const unresolvedCount = this.queries.getUnresolvedReferencesCount();
522
650
  options.onProgress?.({
523
651
  phase: 'resolving',
@@ -530,23 +658,62 @@ class HomeGraph {
530
658
  current,
531
659
  total,
532
660
  });
533
- });
661
+ }, (done, totalPasses) => {
662
+ options.onProgress?.({
663
+ phase: 'linking',
664
+ current: done,
665
+ total: totalPasses,
666
+ });
667
+ }, backpressure);
534
668
  }
535
- // Second pass: chained calls whose method lives on a supertype the
536
- // receiver conforms to (protocol-extension / inherited). Needs the
537
- // implements/extends edges built above (#750).
669
+ }
670
+ const orphanCount = this.queries.getUnresolvedReferencesCount();
671
+ if (orphanCount > 0) {
672
+ options.onProgress?.({
673
+ phase: 'resolving',
674
+ current: 0,
675
+ total: orphanCount,
676
+ });
677
+ await this.resolveReferencesBatched((current, total) => {
678
+ options.onProgress?.({
679
+ phase: 'resolving',
680
+ current,
681
+ total,
682
+ });
683
+ }, (done, totalPasses) => {
684
+ options.onProgress?.({
685
+ phase: 'linking',
686
+ current: done,
687
+ total: totalPasses,
688
+ });
689
+ }, backpressure);
690
+ }
691
+ if (filesChanged || orphanCount > 0) {
538
692
  await this.resolver.resolveChainedCallsViaConformance();
539
- // Same lifecycle for `this.<member>` callback registrations whose
540
- // member is inherited from a supertype (#808).
541
693
  await this.resolver.resolveDeferredThisMemberRefs();
542
694
  }
543
- // Refresh planner stats + checkpoint the WAL after bulk writes.
544
- if (result.filesAdded > 0 || result.filesModified > 0 || result.filesRemoved > 0) {
545
- this.db.runMaintenance();
695
+ if (filesChanged || result.filesRemoved > 0 || orphanCount > 0) {
696
+ await this.db.runMaintenance();
697
+ }
698
+ try {
699
+ if (vocabWasEmpty && this.queries.getNodeAndEdgeCount().nodes > 0) {
700
+ await this.rebuildNameSegmentVocab();
701
+ }
546
702
  }
703
+ catch { /* vocab is advisory — never fail a sync over it */ }
547
704
  return result;
548
705
  }
549
706
  finally {
707
+ if (walValve) {
708
+ walValve.stop();
709
+ await walValve.drain();
710
+ }
711
+ if (deferWal) {
712
+ try {
713
+ this.db.setWalAutocheckpoint(priorAutocheckpoint);
714
+ }
715
+ catch { /* connection may be closing */ }
716
+ }
550
717
  this.fileLock.release();
551
718
  }
552
719
  });
@@ -572,8 +739,8 @@ class HomeGraph {
572
739
  watch(options = {}) {
573
740
  if (this.watcher?.isActive())
574
741
  return true;
575
- this.watcher = new sync_1.FileWatcher(this.projectRoot, async () => {
576
- const result = await this.sync();
742
+ this.watcher = new sync_1.FileWatcher(this.projectRoot, async (paths) => {
743
+ const result = await this.sync({ paths });
577
744
  // sync() returns this exact zero-shape iff it failed to acquire the
578
745
  // file lock (a real empty sync always has filesChecked > 0 because
579
746
  // scanDirectory ran). Surface that to the watcher as a typed error
@@ -660,6 +827,18 @@ class HomeGraph {
660
827
  getQueryBuilder() {
661
828
  return this.queries;
662
829
  }
830
+ /**
831
+ * Completeness of the last full index run. `'complete'` is the only good
832
+ * state. `'indexing'` after the fact means a run was killed mid-index;
833
+ * `'partial'` means the run finished but silently dropped files;
834
+ * `'failed'` means it reported failure. `null` = index predates this marker.
835
+ */
836
+ getIndexState() {
837
+ const raw = this.queries.getMetadata('index_state');
838
+ return raw === 'indexing' || raw === 'complete' || raw === 'partial' || raw === 'failed'
839
+ ? raw
840
+ : null;
841
+ }
663
842
  /**
664
843
  * Which engine built the current index: the package version + extraction
665
844
  * version stamped at the last full `indexAll`. Either field is null for an
@@ -725,12 +904,33 @@ class HomeGraph {
725
904
  * Resolve references in batches to keep memory bounded on large codebases.
726
905
  * Processes chunks of unresolved refs, persisting results after each batch.
727
906
  */
728
- async resolveReferencesBatched(onProgress) {
729
- return this.resolver.resolveAndPersistBatched(onProgress);
907
+ async resolveReferencesBatched(onProgress, onSynthesisProgress, backpressure) {
908
+ return this.resolver.resolveAndPersistBatched(onProgress, undefined, onSynthesisProgress, {
909
+ dbPath: this.db.getPath(),
910
+ bulkEdgeLoad: {
911
+ begin: () => this.db.beginBulkEdgeLoad(),
912
+ end: () => this.db.endBulkEdgeLoad(),
913
+ },
914
+ refIndexLoad: {
915
+ begin: () => this.db.beginBulkRefLoad(),
916
+ end: () => this.db.endBulkRefLoad(),
917
+ },
918
+ backpressure,
919
+ });
730
920
  }
731
921
  /**
732
922
  * Get detected frameworks in the project
733
923
  */
924
+ /**
925
+ * References extracted but never attempted by a resolution pass. Zero on a
926
+ * healthy index — a completed pass consumes every pending row (resolving it
927
+ * or parking it as failed, #1240). Non-zero at rest means a pass was
928
+ * interrupted mid-run (#1187), so some files' call edges are missing; the
929
+ * next `sync` sweeps them.
930
+ */
931
+ getPendingReferenceCount() {
932
+ return this.queries.getUnresolvedReferencesCount();
933
+ }
734
934
  getDetectedFrameworks() {
735
935
  return this.resolver.getDetectedFrameworks();
736
936
  }
@@ -752,9 +952,8 @@ class HomeGraph {
752
952
  return stats;
753
953
  }
754
954
  /**
755
- * Active SQLite backend for this project's connection (`node-sqlite` — Node's
756
- * built-in real-SQLite module). Surfaced via `homegraph status` and the
757
- * `homegraph_status` MCP tool alongside the effective journal mode.
955
+ * Active SQLite backend (`native` = better-sqlite3, or `wasm` fallback).
956
+ * Surfaced via `homegraph status` / `homegraph_status` with journal mode.
758
957
  */
759
958
  getBackend() {
760
959
  return this.db.getBackend();
@@ -797,6 +996,16 @@ class HomeGraph {
797
996
  getNodesByName(name) {
798
997
  return this.queries.getNodesByName(name);
799
998
  }
999
+ /**
1000
+ * Nodes whose name CONTAINS `substring` (LIKE scan, ASCII-case-insensitive,
1001
+ * shortest-first). The camel-infix lookup FTS can't do — `profileInfo`
1002
+ * inside `getProfileInfoV2` is one FTS token (#1196).
1003
+ */
1004
+ getNodesByNameSubstring(substring, options = {}) {
1005
+ return this.queries
1006
+ .findNodesByNameSubstring(substring, options)
1007
+ .map((r) => r.node);
1008
+ }
800
1009
  /**
801
1010
  * Search nodes by text
802
1011
  */
@@ -810,6 +1019,178 @@ class HomeGraph {
810
1019
  * bias, which would otherwise pull overloaded tokens toward whichever stack
811
1020
  * embeds the project name.
812
1021
  */
1022
+ /**
1023
+ * Graph-derived prompt matching for the front-load hook's MEDIUM tier:
1024
+ * which indexed symbols do these prose words name? "state machine des
1025
+ * commandes" → `OrderStateMachine`, in any human language whose technical
1026
+ * nouns are Latin script — no keyword list involved.
1027
+ *
1028
+ * Precision comes from the repo's own naming statistics, not vocabulary:
1029
+ * - CO-OCCURRENCE: ≥2 words that are segments of the SAME name ("state" +
1030
+ * "machine" → OrderStateMachine) is strong evidence and always qualifies.
1031
+ * - RARITY: a single matched word qualifies only when its segment is
1032
+ * discriminative here (≤ {@link SEGMENT_RARITY_CEILING} distinct names) —
1033
+ * "checkout" in a shop backend yes, "state" in a react app no.
1034
+ * Every candidate is re-verified against `nodes` before being returned
1035
+ * (vocab rows are proposals; deletions leave orphans by design), so a
1036
+ * returned symbol is guaranteed to exist right now.
1037
+ */
1038
+ getSegmentMatches(words, limit = 6) {
1039
+ if (words.length === 0)
1040
+ return [];
1041
+ // Variant → original word (plural folding), for coverage accounting.
1042
+ const variantToWord = new Map();
1043
+ for (const word of words) {
1044
+ for (const variant of (0, identifier_segments_1.segmentLookupVariants)(word)) {
1045
+ if (!variantToWord.has(variant))
1046
+ variantToWord.set(variant, word);
1047
+ }
1048
+ }
1049
+ const variants = [...variantToWord.keys()];
1050
+ // Tier A: co-occurrence. The SQL folds variants back to their original
1051
+ // word (#1146), so minWords=2 means two distinct PROMPT WORDS — a name
1052
+ // matching both `service` and `services` can't tie with (or crowd past
1053
+ // the LIMIT) a genuine two-word match. The JS re-check below recomputes
1054
+ // the fold from live segments as the honesty layer.
1055
+ const variantPairs = [...variantToWord.entries()].map(([segment, word]) => ({ segment, word }));
1056
+ const candidates = [];
1057
+ for (const hit of this.queries.getSegmentCoOccurrence(variantPairs, 2, 24)) {
1058
+ const matched = this.wordsMatchingName(hit.name, variantToWord);
1059
+ if (matched.size >= 2)
1060
+ candidates.push({ name: hit.name, matchedWords: matched });
1061
+ }
1062
+ // Tier B: single rare word. Only when co-occurrence found nothing — a
1063
+ // co-occurring name is categorically stronger evidence — and under
1064
+ // stricter rules, because one word is thin: the word must be ≥5 chars
1065
+ // (measured FPs: "this", "typo"); the segment must appear in AT LEAST TWO
1066
+ // names (a concept the codebase is about clusters across names —
1067
+ // CheckoutService/CheckoutController — while a prose coincidence is a
1068
+ // singleton: measured FP "deploy to PRODUCTION" → the one name
1069
+ // matchesNonProductionDir); and the candidate name must have ≥2 segments
1070
+ // (a bare common verb matching a bare function name — "write" → `write` —
1071
+ // is prose coincidence, not the user naming a symbol).
1072
+ if (candidates.length === 0) {
1073
+ const singleWordVariants = variants.filter((v) => variantToWord.get(v).length >= 5);
1074
+ const counts = this.queries.getSegmentNameCounts(singleWordVariants);
1075
+ const rare = [...counts.entries()]
1076
+ .filter(([, n]) => n >= 2 && n <= HomeGraph.SEGMENT_RARITY_CEILING)
1077
+ .sort((a, b) => a[1] - b[1])
1078
+ .slice(0, 2);
1079
+ for (const [variant] of rare) {
1080
+ const word = variantToWord.get(variant);
1081
+ for (const name of this.queries.getNamesForSegment(variant, 12)) {
1082
+ if ((0, identifier_segments_1.splitIdentifierSegments)(name).length < 2)
1083
+ continue;
1084
+ candidates.push({ name, matchedWords: new Set([word]) });
1085
+ }
1086
+ }
1087
+ }
1088
+ // Verify against nodes (the honesty gate) and pick a representative
1089
+ // definition per name. A name whose only nodes are file/import kind has
1090
+ // no real definition to point at — surfacing the import statement instead
1091
+ // reads as a matched symbol but isn't one (#1144) — so it's skipped, the
1092
+ // same way an orphaned vocab row is. (Import names no longer enter the
1093
+ // vocab at write time, but rows written before that exclusion persist
1094
+ // until the next full index.)
1095
+ const out = [];
1096
+ const seen = new Set();
1097
+ candidates.sort((a, b) => b.matchedWords.size - a.matchedWords.size || a.name.length - b.name.length);
1098
+ for (const candidate of candidates) {
1099
+ if (out.length >= limit)
1100
+ break;
1101
+ if (seen.has(candidate.name))
1102
+ continue;
1103
+ seen.add(candidate.name);
1104
+ const nodes = this.queries.getNodesByName(candidate.name);
1105
+ if (nodes.length === 0)
1106
+ continue; // orphaned vocab row — name no longer exists
1107
+ const rep = nodes.find((n) => n.kind !== 'file' && n.kind !== 'import');
1108
+ if (!rep)
1109
+ continue; // no real definition — don't surface an import/file as one
1110
+ out.push({
1111
+ name: candidate.name,
1112
+ kind: rep.kind,
1113
+ filePath: rep.filePath,
1114
+ startLine: rep.startLine ?? 0,
1115
+ matchedWords: [...candidate.matchedWords].sort(),
1116
+ });
1117
+ }
1118
+ return out;
1119
+ }
1120
+ /** A single word ("state") can match hundreds of names in a big repo — that
1121
+ * is noise, not signal. Ceiling for the single-word tier; co-occurrence is
1122
+ * exempt because two words on one name is already discriminative. */
1123
+ static SEGMENT_RARITY_CEILING = 25;
1124
+ /** Which of the prompt's original words match `name`'s segments (via
1125
+ * variants). Segments are recomputed in JS — a name-keyed vocab lookup
1126
+ * would scan the (segment, name) primary key. */
1127
+ wordsMatchingName(name, variantToWord) {
1128
+ const segments = new Set((0, identifier_segments_1.splitIdentifierSegments)(name));
1129
+ const matched = new Set();
1130
+ for (const [variant, word] of variantToWord) {
1131
+ if (segments.has(variant))
1132
+ matched.add(word);
1133
+ }
1134
+ return matched;
1135
+ }
1136
+ /**
1137
+ * One-shot upgrade heal for callers that open the graph WITHOUT syncing —
1138
+ * concretely the prompt hook, whose MEDIUM tier reads the segment
1139
+ * vocabulary: a database migrated from before the vocab table existed
1140
+ * starts with it empty, and the only other backfill lives inside `sync()`,
1141
+ * which such callers never run (#1142). Returns true when the vocab is
1142
+ * usable (already populated — the overwhelmingly common one-SELECT case —
1143
+ * or healed here); false when it isn't (empty graph, or another process
1144
+ * holds the index lock — that process's own sync heals it).
1145
+ */
1146
+ async healSegmentVocabIfEmpty() {
1147
+ const empty = (() => {
1148
+ try {
1149
+ return this.queries.isNameSegmentVocabEmpty();
1150
+ }
1151
+ catch {
1152
+ return false;
1153
+ }
1154
+ })();
1155
+ if (!empty)
1156
+ return true;
1157
+ if (this.queries.getNodeAndEdgeCount().nodes === 0)
1158
+ return false;
1159
+ return this.indexMutex.withLock(async () => {
1160
+ try {
1161
+ this.fileLock.acquire();
1162
+ }
1163
+ catch {
1164
+ return false; // an index/sync is running — it backfills the vocab itself
1165
+ }
1166
+ try {
1167
+ if (!this.queries.isNameSegmentVocabEmpty())
1168
+ return true; // raced: healed meanwhile
1169
+ await this.rebuildNameSegmentVocab();
1170
+ return true;
1171
+ }
1172
+ finally {
1173
+ this.fileLock.release();
1174
+ }
1175
+ });
1176
+ }
1177
+ /**
1178
+ * Rebuild the segment vocabulary from the current graph, batched and
1179
+ * yielding — the upgrade-heal path for indexes built before the vocab table
1180
+ * existed. Runs inside the index mutex/lock (sync and
1181
+ * healSegmentVocabIfEmpty hold them).
1182
+ */
1183
+ async rebuildNameSegmentVocab() {
1184
+ const maybeYield = (0, cooperative_yield_1.createYielder)();
1185
+ const BATCH = 2000;
1186
+ for (let offset = 0;; offset += BATCH) {
1187
+ const names = this.queries.getDistinctNodeNames(BATCH, offset);
1188
+ if (names.length === 0)
1189
+ break;
1190
+ this.queries.insertNameSegmentsBatch(names);
1191
+ await maybeYield();
1192
+ }
1193
+ }
813
1194
  getProjectNameTokens() {
814
1195
  return this.queries.getProjectNameTokens();
815
1196
  }