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
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ /**
3
+ * WAL checkpoint valve — bounds WAL growth while auto-checkpointing is
4
+ * deferred during a bulk index (#1231).
5
+ *
6
+ * Why deferral: SQLite's default `wal_autocheckpoint` (1000 pages) re-writes
7
+ * hot B-tree/FTS pages into the main DB file over and over during a bulk
8
+ * index — measured at ~95% of ALL disk I/O, and the difference between 45s
9
+ * and 19+ minutes on HDD-class storage (150 random IOPS). Deferring
10
+ * checkpoints turns the store into pure sequential WAL appends; each backfill
11
+ * pass writes distinct pages once, in page order (≈ sequential).
12
+ *
13
+ * Why a valve: unbounded deferral is its own failure mode, both measured in
14
+ * the #1231 repro. The WAL duplicates hot pages per COMMIT, so it grows far
15
+ * faster than the DB (5.9GB WAL for a ~340MB DB on a 3.3k-file index) —
16
+ * filling the disk, and poisoning every subsequent read that must page
17
+ * through it (the first resolution-phase read blocked the main thread >60s
18
+ * and the #850 liveness watchdog killed the healthy index). The valve
19
+ * watches WAL growth on a timer and, past a soft threshold, backfills with
20
+ * `PRAGMA wal_checkpoint(PASSIVE)` on a worker-thread connection — PASSIVE
21
+ * never blocks the writer, and off-thread means the main thread (and the
22
+ * watchdog heartbeat) keep turning regardless of how long a backfill takes.
23
+ *
24
+ * The load-bearing subtlety: a WAL file's SIZE never shrinks. After a full
25
+ * backfill, the writer's next commit RESTARTS the WAL from the top and the
26
+ * frames recycle inside the same file — so raw size says nothing about the
27
+ * un-backfilled backlog, and a size-triggered valve degenerates into firing
28
+ * (and pausing the writer) forever once the file passes its threshold
29
+ * (measured: guava crawled at ~9min per 160 files). Instead the valve
30
+ * tracks `sizeAtLastFullBackfill` — refreshed whenever a checkpoint reports
31
+ * `log === checkpointed` (everything backfilled) — and triggers on GROWTH
32
+ * beyond that baseline, which only happens when genuinely un-backfilled
33
+ * frames push past the file's high-water mark.
34
+ *
35
+ * Backpressure: if the writer outruns the checkpointer past a hard cap of
36
+ * growth (2× soft), {@link backpressure} pauses the writer (at a safe,
37
+ * between-transactions boundary) until a FULL backfill lands. One in-flight
38
+ * pass is not enough: on a disk saturated by the writer, every concurrent
39
+ * PASSIVE pass is already stale by the time it finishes (the writer appended
40
+ * past its snapshot), so neither SQLite's WAL wrap nor the baseline ever
41
+ * trigger and the WAL grows without bound (measured: 5.9GB on guava at 150
42
+ * IOPS, then a >60s read stall and a watchdog kill). With the writer parked,
43
+ * the next pass covers everything, the WAL wraps on the following commit,
44
+ * and the pause is the disk's honest catch-up cost — the correct terminal
45
+ * mode when hardware genuinely can't keep up with the append rate.
46
+ */
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.WalCheckpointValve = void 0;
49
+ exports.resolveWalValveMb = resolveWalValveMb;
50
+ /** Soft WAL-growth threshold (MB) that triggers an off-thread passive checkpoint. */
51
+ const DEFAULT_WAL_VALVE_MB = 256;
52
+ /** Hard cap = this × soft threshold; past it the writer pauses for a full backfill. */
53
+ const HARD_CAP_MULTIPLIER = 2;
54
+ /** File cap = this × soft threshold; past it the barrier also TRUNCATEs the file. */
55
+ const FILE_CAP_MULTIPLIER = 4;
56
+ /** Passes attempted per writer pause before giving up (a pinned reader could stall forever). */
57
+ const MAX_PAUSED_BACKFILL_PASSES = 20;
58
+ /** How often the timer looks at the WAL file size. */
59
+ const CHECK_INTERVAL_MS = 2000;
60
+ /**
61
+ * Resolve the valve's soft threshold from the `HOMEGRAPH_WAL_VALVE_MB`
62
+ * override; non-numeric / non-positive values fall back to the default.
63
+ */
64
+ function resolveWalValveMb(envVal, dbSizeBytes) {
65
+ if (envVal !== undefined && envVal !== '') {
66
+ const n = Number(envVal);
67
+ if (Number.isFinite(n) && n > 0)
68
+ return Math.floor(n);
69
+ }
70
+ // Scale with the project when the caller knows the DB size: every fold
71
+ // re-writes hot B-tree pages into the main file (the #1231 pathology in
72
+ // bounded form — 111s of a kernel-scale batch loop at the flat 256MB cap,
73
+ // §7a.2), so a big project affords a proportionally bigger transient WAL
74
+ // (~dbSize/4 soft ⇒ file cap ≈ dbSize) in exchange for ~4× fewer folds.
75
+ if (dbSizeBytes !== undefined && dbSizeBytes > 0) {
76
+ return Math.min(2048, Math.max(DEFAULT_WAL_VALVE_MB, Math.floor(dbSizeBytes / 4 / (1024 * 1024))));
77
+ }
78
+ return DEFAULT_WAL_VALVE_MB;
79
+ }
80
+ class WalCheckpointValve {
81
+ db;
82
+ intervalMs;
83
+ timer = null;
84
+ inflight = null;
85
+ /** Writer pause in progress (hard cap breached): passes loop until a full backfill. */
86
+ pause = null;
87
+ /**
88
+ * WAL file size observed when a checkpoint last reported the ENTIRE WAL
89
+ * backfilled. Growth is measured against this baseline — see the header
90
+ * comment for why absolute size cannot be used.
91
+ */
92
+ sizeAtLastFullBackfill = 0;
93
+ softBytes;
94
+ hardBytes;
95
+ fileCapBytes;
96
+ /**
97
+ * Futility latch: consecutive backfill give-ups (a reader pinning the WAL)
98
+ * disable further writer pauses for a cooldown, so a pinned phase degrades
99
+ * to the pre-valve behavior (unbounded WAL, folded when the pinner exits)
100
+ * instead of burning a 20-pass checkpoint attempt — each pass a worker
101
+ * thread + fresh connection — at EVERY over-cap boundary. That churn is
102
+ * what turned a pinned kernel-scale resolution from slow into OOM-killed
103
+ * (§7a.1 run 1: 22GB WAL, exit 137 at an envelope the pre-fix build
104
+ * survived).
105
+ */
106
+ consecutiveGiveUps = 0;
107
+ futileUntil = 0;
108
+ constructor(db, softMb = resolveWalValveMb(process.env.HOMEGRAPH_WAL_VALVE_MB), intervalMs = CHECK_INTERVAL_MS, log = () => { }) {
109
+ this.db = db;
110
+ this.intervalMs = intervalMs;
111
+ this.softBytes = softMb * 1024 * 1024;
112
+ this.hardBytes = this.softBytes * HARD_CAP_MULTIPLIER;
113
+ this.fileCapBytes = this.softBytes * FILE_CAP_MULTIPLIER;
114
+ // HOMEGRAPH_WAL_VALVE_DEBUG=1 surfaces valve decisions to stderr without
115
+ // needing the caller's verbose plumbing — the observability gap that let
116
+ // §7a.1 run 1 fail silently (give-ups were verbose-gated and invisible).
117
+ this.log = process.env.HOMEGRAPH_WAL_VALVE_DEBUG
118
+ ? (m) => console.error(`[wal-valve] ${m}`)
119
+ : log;
120
+ }
121
+ log;
122
+ mb(n) {
123
+ return `${Math.round(n / 1024 / 1024)}MB`;
124
+ }
125
+ /** Un-backfilled growth estimate: bytes the WAL has grown past the last full backfill. */
126
+ growthBytes() {
127
+ return this.db.getWalSizeBytes() - this.sizeAtLastFullBackfill;
128
+ }
129
+ /** Begin watching the WAL. Idempotent; the timer never holds the loop open. */
130
+ start() {
131
+ if (this.timer)
132
+ return;
133
+ // One armed line per run under either diagnostics env: §7a.1's failed
134
+ // kernel-scale runs burned three 25-minute cycles before "is the valve
135
+ // even alive?" could be answered.
136
+ if (process.env.HOMEGRAPH_SYNTH_TIMINGS || process.env.HOMEGRAPH_WAL_VALVE_DEBUG) {
137
+ console.error(`[wal-valve] armed soft=${this.mb(this.softBytes)} hard=${this.mb(this.hardBytes)} wal=${this.mb(this.db.getWalSizeBytes())}`);
138
+ }
139
+ let ticks = 0;
140
+ this.timer = setInterval(() => {
141
+ if ((++ticks % 15) === 0) {
142
+ this.log(`alive: wal=${this.mb(this.db.getWalSizeBytes())} baseline=${this.mb(this.sizeAtLastFullBackfill)} inflight=${this.inflight ? 'y' : 'n'} paused=${this.pause ? 'y' : 'n'}`);
143
+ }
144
+ this.check();
145
+ }, this.intervalMs);
146
+ this.timer.unref?.();
147
+ }
148
+ /** Stop watching. Any in-flight checkpoint keeps running — await drain(). */
149
+ stop() {
150
+ if (this.timer) {
151
+ clearInterval(this.timer);
152
+ this.timer = null;
153
+ }
154
+ }
155
+ /** One poll: fire an off-thread passive checkpoint when growth passes the soft threshold. */
156
+ check() {
157
+ if (!this.pause && !this.inflight && this.growthBytes() > this.softBytes)
158
+ this.fire();
159
+ }
160
+ /**
161
+ * Writer-side backstop, called at a between-transactions boundary. Returns
162
+ * null (no wait) while growth is under the hard cap; past it, returns a
163
+ * promise that resolves only once a FULL backfill has landed — see the
164
+ * header comment for why a single pass is not enough on a saturated disk.
165
+ */
166
+ backpressure() {
167
+ if (this.pause)
168
+ return this.pause;
169
+ if (Date.now() < this.futileUntil)
170
+ return null; // pinned reader — parking is churn, not progress
171
+ // Two independent triggers:
172
+ // - growth: un-backfilled BACKLOG past the hard cap (the original valve).
173
+ // - file size: a WAL can stay fully backfilled and still grow without
174
+ // bound — the writer only restarts at frame 0 if a commit finds no
175
+ // reader marks, which §7a.1's instrumented run showed never happens
176
+ // in practice (file marched 361→721MB through two COMPLETE
177
+ // backfills). Past the file cap, park and TRUNCATE at the barrier —
178
+ // the backfill part is instant when the backlog is already folded.
179
+ if (this.growthBytes() <= this.hardBytes && this.db.getWalSizeBytes() <= this.fileCapBytes)
180
+ return null;
181
+ this.log(`backpressure: wal=${this.mb(this.db.getWalSizeBytes())} baseline=${this.mb(this.sizeAtLastFullBackfill)} — pausing writer for full backfill`);
182
+ const t0 = Date.now();
183
+ this.pause = this.backfillFully().finally(() => {
184
+ this.pause = null;
185
+ this.log(`backpressure released after ${Date.now() - t0}ms: wal=${this.mb(this.db.getWalSizeBytes())} baseline=${this.mb(this.sizeAtLastFullBackfill)}`);
186
+ });
187
+ return this.pause;
188
+ }
189
+ /** Await any in-flight checkpoint and writer pause. */
190
+ async drain() {
191
+ while (this.pause || this.inflight) {
192
+ if (this.pause)
193
+ await this.pause;
194
+ if (this.inflight)
195
+ await this.inflight;
196
+ }
197
+ }
198
+ /**
199
+ * Phase-boundary fold: backfill the ENTIRE WAL now (off-thread, awaited).
200
+ * Called between bulk phases — e.g. after parsing, before resolution's
201
+ * first reads — so the next phase never pages a bulk-write-sized WAL on
202
+ * the main thread (the post-parse read against a multi-GB WAL is what
203
+ * blew the #850 watchdog's 60s window in the #1231 repro). The await
204
+ * keeps the event loop (and the watchdog heartbeat) turning.
205
+ */
206
+ async foldNow() {
207
+ await this.drain();
208
+ if (this.growthBytes() <= 0)
209
+ return;
210
+ this.log(`foldNow: wal=${this.mb(this.db.getWalSizeBytes())} baseline=${this.mb(this.sizeAtLastFullBackfill)}`);
211
+ this.pause = this.backfillFully().finally(() => { this.pause = null; });
212
+ await this.pause;
213
+ }
214
+ /**
215
+ * With the writer parked on the returned promise, loop passive passes until
216
+ * one reports the entire WAL backfilled (typically the second: the first
217
+ * drains the pass that was already running against a stale snapshot). Gives
218
+ * up after a bounded number of passes — e.g. a reader pinning the WAL —
219
+ * because unbounded WAL growth degrades; a wedged writer never recovers.
220
+ */
221
+ async backfillFully() {
222
+ for (let i = 0; i < MAX_PAUSED_BACKFILL_PASSES; i++) {
223
+ if (this.inflight)
224
+ await this.inflight; // fold in the stale in-flight pass first
225
+ const res = await this.db.checkpointWalPassive();
226
+ if (!res)
227
+ return; // checkpoint machinery unavailable — don't spin
228
+ this.log(`backfill pass ${i + 1}: busy=${res.busy} log=${res.log} checkpointed=${res.checkpointed} wal=${this.mb(this.db.getWalSizeBytes())}`);
229
+ if (res.busy === 0 && res.log === res.checkpointed) {
230
+ // Backfill complete AND we are at a parked barrier (backfillFully only
231
+ // runs under a writer pause): the no-reader window is guaranteed, so
232
+ // chop the FILE too — a fully-backfilled WAL otherwise keeps growing
233
+ // whenever commits land while pool readers hold marks (§7a.1: 22GB
234
+ // on-disk at kernel scale despite backfills). A racing reader turns
235
+ // this into a no-op (busy=1); the passive result above still stands.
236
+ const trunc = await this.db.checkpointWalTruncate();
237
+ if (trunc)
238
+ this.log(`truncate: busy=${trunc.busy} wal=${this.mb(this.db.getWalSizeBytes())}`);
239
+ this.sizeAtLastFullBackfill = this.db.getWalSizeBytes();
240
+ this.consecutiveGiveUps = 0;
241
+ this.futileUntil = 0;
242
+ return;
243
+ }
244
+ }
245
+ this.consecutiveGiveUps++;
246
+ if (this.consecutiveGiveUps >= 2) {
247
+ this.futileUntil = Date.now() + 60_000;
248
+ }
249
+ const msg = `backfill gave up after ${MAX_PAUSED_BACKFILL_PASSES} passes (streak ${this.consecutiveGiveUps}${this.futileUntil ? ', parking disabled 60s' : ''}) — a reader is pinning the WAL`;
250
+ this.log(msg);
251
+ // Give-ups are rare and load-bearing for §7a.1-class diagnosis — surface
252
+ // them on any timing-instrumented run, not just valve-debug ones.
253
+ if (process.env.HOMEGRAPH_SYNTH_TIMINGS && !process.env.HOMEGRAPH_WAL_VALVE_DEBUG) {
254
+ console.error(`[wal-valve] ${msg}`);
255
+ }
256
+ }
257
+ fire() {
258
+ this.log(`fire: wal=${this.mb(this.db.getWalSizeBytes())} baseline=${this.mb(this.sizeAtLastFullBackfill)}`);
259
+ const p = this.db
260
+ .checkpointWalPassive()
261
+ .then((res) => {
262
+ this.log(`timer pass: ${res ? `busy=${res.busy} log=${res.log} checkpointed=${res.checkpointed}` : 'null (machinery unavailable)'} wal=${this.mb(this.db.getWalSizeBytes())}`);
263
+ // Full backfill (busy 0, every log frame checkpointed) ⇒ the writer's
264
+ // next commit wraps the WAL; the file's current size becomes the new
265
+ // growth baseline. A partial pass (writer appended during it, or a
266
+ // read transaction pinned frames) leaves the baseline alone, so the
267
+ // next tick fires again and copies the remainder. In non-WAL mode
268
+ // SQLite reports log = checkpointed = -1, which is harmless here.
269
+ if (res && res.busy === 0 && res.log === res.checkpointed) {
270
+ this.sizeAtLastFullBackfill = this.db.getWalSizeBytes();
271
+ // NO truncate here. A truncate checkpoint that starts against an
272
+ // ACTIVE writer wins the lock race and then blocks that writer for
273
+ // its entire backfill — after a multi-GB single-transaction burst
274
+ // (edge-index recreate) that exceeds the writer's 5s busy_timeout
275
+ // and fails the index with "database is locked" (§7a.2 record run).
276
+ // The file chop happens exclusively at parked barriers
277
+ // (backpressure/foldNow), where the writer is awaiting us by
278
+ // construction and cannot collide.
279
+ }
280
+ })
281
+ .catch(() => { })
282
+ .finally(() => {
283
+ if (this.inflight === p)
284
+ this.inflight = null;
285
+ });
286
+ this.inflight = p;
287
+ }
288
+ }
289
+ exports.WalCheckpointValve = WalCheckpointValve;
290
+ //# sourceMappingURL=wal-valve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wal-valve.js","sourceRoot":"","sources":["../../src/db/wal-valve.ts"],"names":[],"mappings":"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"}
@@ -77,10 +77,14 @@ export declare function findIndexedSubprojectRoots(root: string, opts?: {
77
77
  max?: number;
78
78
  }): string[];
79
79
  /**
80
- * Does `prompt` contain an explicit structural keyword (English or CJK)? A
81
- * keyword is a strong, self-contained signal, so the front-load hook fires on it
82
- * directly — no graph check needed. (A *code-token* match, by contrast, is only
83
- * a candidate the hook verifies against the graph first; see {@link extractCodeTokens}.)
80
+ * Does `prompt` contain an explicit structural keyword? A keyword is a strong,
81
+ * self-contained signal, so the front-load hook fires on it directly — no graph
82
+ * check needed. (A *code-token* match, by contrast, is only a candidate the
83
+ * hook verifies against the graph first; see {@link extractCodeTokens}.)
84
+ * Coverage is multilingual (#994, #1126): the ~29 languages with the largest
85
+ * developer populations, across Latin, Cyrillic, Greek, CJK, Hangul, Arabic,
86
+ * Hebrew, Thai, and Devanagari scripts. Languages beyond the keyword table
87
+ * still fire through the language-agnostic code-token path.
84
88
  */
85
89
  export declare function hasStructuralKeyword(prompt: string): boolean;
86
90
  /**
@@ -101,7 +105,7 @@ export declare function extractCodeTokens(prompt: string): string[];
101
105
  /**
102
106
  * Cheap, graph-free candidate gate for the front-load hook: could `prompt` be a
103
107
  * structural / flow / impact / "where-how" question worth front-loading context
104
- * for? True on an explicit keyword (English or CJK, issue #994) OR an
108
+ * for? True on an explicit keyword in any covered language (#994, #1126) OR an
105
109
  * identifier-shaped token. A keyword is sufficient to fire on its own; a
106
110
  * token-only match is only a candidate the hook then verifies against the graph
107
111
  * (a brand name like `JavaScript` is token-shaped but isn't a symbol). Every
@@ -1 +1 @@
1
- {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAqBzC;AAED,qFAAqF;AACrF,eAAO,MAAM,aAAa,eAAwB,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOxD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAQ1D;AAED;;;;;;;;GAQG;AACH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8BxE;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBzE;AA2BD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,MAAM,EAAE,CAmBV;AAyBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;yEAEqE;IACrE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;6EAEyE;IACzE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB;;+DAE2D;IAC3D,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAwCxE;AAyDD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAgBzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAuBzD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BnE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA+B5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAYlF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG;IACtD,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CA6BA"}
1
+ {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../src/directory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAqBzC;AAED,qFAAqF;AACrF,eAAO,MAAM,aAAa,eAAwB,CAAC;AAEnD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOxD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAQ1D;AAED;;;;;;;;GAQG;AACH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8BxE;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmBzE;AA2BD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,MAAM,EAAE,CAmBV;AAsND;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAK5D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;yEAEqE;IACrE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;6EAEyE;IACzE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB;;+DAE2D;IAC3D,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAwCxE;AAyDD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAgBzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAuBzD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BnE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA+B5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAYlF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG;IACtD,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CA6BA"}
package/dist/directory.js CHANGED
@@ -263,33 +263,224 @@ function findIndexedSubprojectRoots(root, opts = {}) {
263
263
  return out;
264
264
  }
265
265
  /**
266
- * English structural keywords, matched with `\b` word boundaries so a keyword
267
- * inside a longer word doesn't false-positive ("flow" in "flower").
266
+ * Unicode-aware word-boundary emulation for the keyword lists below. JS's `\b`
267
+ * is ASCII-only it fires only at `[A-Za-z0-9_]` edges so it can never bound
268
+ * a keyword whose first or last character is accented or non-Latin: `/\boù\b/`
269
+ * NEVER matches "où est …" (ù isn't an ASCII word char, so no boundary exists
270
+ * next to it). That is the #994 CJK mechanism resurfaced for Latin scripts and
271
+ * Cyrillic (#1126). A lookaround — "not flanked by a letter, digit, or
272
+ * underscore" — is the script-independent equivalent.
268
273
  */
269
- const STRUCTURAL_EN = /\b(how|where|trace|flow|path|reach(?:es|ed)?|call(?:s|ed|er|ers|ee)?|depend|impact|affect|wired?|connect|implement|architect|structure|breaks?|what calls|why does)\b/i;
274
+ const NOT_WORD_BEFORE = /(?<![\p{L}\p{N}_])/u.source;
275
+ const NOT_WORD_AFTER = /(?![\p{L}\p{N}_])/u.source;
270
276
  /**
271
- * Non-English (CJK) structural keywords, matched WITHOUT `\b`. JS's `\b` is
272
- * ASCII-only it only fires at `[A-Za-z0-9_]` boundaries, never between Han
273
- * characters so a Chinese keyword wrapped in `\b…\b` could never match. That
274
- * was issue #994: the English-only gate silently no-op'd every Chinese prompt,
275
- * so non-English users got no front-load nudge and no error to explain why. The
276
- * set mirrors the English intent (如何=how, 在哪/哪里=where, 流程/流向=flow,
277
- * 路径=path, 调用=call, 依赖=depend, 影响=impact/affect, 实现=implement,
278
- * 架构=architect, 结构=structure, 追踪/跟踪=trace) plus structural-overview words
279
- * with no single clean English equivalent (介绍/解析/分析/原理/机制).
277
+ * Structural keywords matched as EXACT words (boundary on both sides): short
278
+ * or ambiguous tokens where prefix matching would false-positive ("flow" in
279
+ * "flower", "path" in "pathological"). Grouped by language; a term appears once
280
+ * even when several languages share it ("como" is Portuguese for how AND
281
+ * unaccented-typed Spanish "cómo").
280
282
  */
281
- const STRUCTURAL_CJK = /如何|怎么|在哪|哪里|追踪|跟踪|流程|流向|路径|调用|依赖|影响|实现|架构|结构|介绍|解析|分析|原理|机制/;
283
+ const STRUCTURAL_WORDS = [
284
+ // English — the pre-#1126 list minus what moved to STRUCTURAL_STEMS: the
285
+ // bare-stem entries never matched their own derived forms (`\barchitect\b`
286
+ // can't match "architecture"), and "what calls" is subsumed by the "call" stem.
287
+ 'how', 'where', 'tracing', 'flows?', 'paths?', 'reach(?:es|ed)?', 'wired?', 'breaks?', 'why does',
288
+ // French (où=where, flux=flow, chemin=path, casse=breaks)
289
+ 'comment', 'où', 'flux', 'chemins?', 'casse',
290
+ // Spanish (cómo/como=how, dónde/donde=where, flujo=flow, ruta/camino=path,
291
+ // rompe=breaks, llaman / quién llama = call(s) — bare "llama" is excluded:
292
+ // it's also the animal/model name in English prompts)
293
+ 'cómo', 'dónde', 'donde', 'flujos?', 'rutas?', 'caminos?', 'rompe', 'llaman', 'quién llama', 'quien llama',
294
+ // Portuguese (como=how — also covers unaccented Spanish; onde=where,
295
+ // fluxo=flow, caminho=path)
296
+ 'como', 'onde', 'fluxos?', 'caminhos?',
297
+ // German (wie=how, wo/woher/wohin=where, Pfad=path, Fluss/Ablauf=flow,
298
+ // bricht/kaputt=breaks, ruft=calls, hängt=depends — "hängt … von X ab"
299
+ // splits the separable verb "abhängen", so the "abhäng" stem can't catch it)
300
+ 'wie', 'wo', 'woher', 'wohin', 'pfade?', 'fluss', 'ablauf', 'bricht', 'kaputt', 'ruft', 'hängt',
301
+ // Italian (dove=where, flusso=flow, percorso/i=path)
302
+ 'dove', 'flusso', 'percors[oi]',
303
+ // Russian (как=how, где=where, путь/пути=path, работает=works)
304
+ 'как', 'где', 'путь', 'пути', 'работает',
305
+ // Ukrainian (як=how, де=where, потік=flow — обліque cases reuse the RU
306
+ // "поток" stem; працює=works)
307
+ 'як', 'де', 'потік', 'працює',
308
+ // Dutch (hoe=how, waar=where, roept=calls, werkt=works, aangeroepen=called —
309
+ // the ge- participle escapes the "aanroep" stem)
310
+ 'hoe', 'waar', 'roept', 'werkt', 'aangeroepen',
311
+ // Polish + Czech (jak=how — shared; gdzie/kde=where, cesta=path)
312
+ 'jak', 'gdzie', 'kde', 'cesta',
313
+ // Romanian (cum=how, unde=where; flux is shared with French)
314
+ 'cum', 'unde',
315
+ // Hungarian (hogyan=how, hol=where)
316
+ 'hogyan', 'hol',
317
+ // Turkish (nasıl=how, mimari=architecture, takip=trace/follow)
318
+ 'nasıl', 'mimari', 'takip',
319
+ // Indonesian/Malay (bagaimana=how, di mana/dimana=where, alur=flow, jalur=path)
320
+ 'bagaimana', 'di mana', 'dimana', 'alur', 'jalur',
321
+ // Vietnamese — spaced Latin with heavy diacritics, the exact class ASCII `\b`
322
+ // breaks (làm sao/thế nào=how, ở đâu=where, gọi=call, phụ thuộc=depend,
323
+ // ảnh hưởng=affect, kiến trúc=architecture, cấu trúc=structure, luồng=flow,
324
+ // đường dẫn=path, hoạt động=works, giải thích=explain, theo dõi=trace)
325
+ 'làm sao', 'thế nào', 'ở đâu', 'gọi', 'phụ thuộc', 'ảnh hưởng', 'kiến trúc',
326
+ 'cấu trúc', 'luồng', 'đường dẫn', 'hoạt động', 'giải thích', 'theo dõi',
327
+ // Swedish / Danish / Norwegian (hur/hvordan=how, hvor=where, beror=depends,
328
+ // flöde=flow)
329
+ 'hur', 'hvordan', 'hvor', 'beror', 'flöde',
330
+ // Finnish (miten=how, missä=where, toimii=works)
331
+ 'miten', 'missä', 'toimii',
332
+ // Greek (πώς=how, πού=where — accented forms only: unaccented πως/που are
333
+ // ubiquitous conjunctions; καλεί=calls, δομή=structure, ροή=flow)
334
+ 'πώς', 'πού', 'καλεί', 'δομή', 'ροή',
335
+ // Hindi (कैसे=how, कहाँ/कहां=where, कॉल=call, निर्भर=depends,
336
+ // संरचना=structure, प्रवाह=flow)
337
+ 'कैसे', 'कहाँ', 'कहां', 'कॉल', 'निर्भर', 'संरचना', 'प्रवाह',
338
+ ];
339
+ /**
340
+ * Structural keyword STEMS matched as word PREFIXES (boundary on the left
341
+ * only), so derived forms match without enumerating each: "architect" fires on
342
+ * architecture/architectural, "depend" on depends/dependency/dependencies,
343
+ * "вызыва" on вызывает/вызывается. Mid-word occurrences stay excluded —
344
+ * "restructure"/"independent" don't fire — so precision stays close to the
345
+ * exact-word class. Add a stem only when every plausible completion is still a
346
+ * structural word; a stem with ordinary-English completions must instead
347
+ * enumerate its structural suffixes and re-assert the right boundary (see the
348
+ * four bounded English entries below, #1138).
349
+ */
350
+ const STRUCTURAL_STEMS = [
351
+ // English + the Latin-script languages that share the spelling (French
352
+ // architecture/structure/trace/impact, Spanish depende/implementa/impacto, …).
353
+ // call/trace/affect/connect are NOT safe as open prefixes — callus,
354
+ // calligraphy, Connecticut, connective, affectionate, Tracey are ordinary
355
+ // words that would false-fire the full-explore tier (#1138) — so they carry
356
+ // an enumerated suffix set + right boundary. "tracing" lives in
357
+ // STRUCTURAL_WORDS (the e is dropped, so no trace-prefix form matches it).
358
+ 'architect', 'structur', 'depend', 'implement', 'impact', 'explain',
359
+ `call(?:s|ing|ed|ers?|backs?|able|sites?)?${NOT_WORD_AFTER}`,
360
+ `trace(?:s|d|rs?)?${NOT_WORD_AFTER}`,
361
+ `affect(?:s|ed|ing)?${NOT_WORD_AFTER}`,
362
+ `connect(?:s|ed|ing|ions?|ors?|ivity)?${NOT_WORD_AFTER}`,
363
+ // French (appel(le)=call, dépend=depends, implément(e)=implement,
364
+ // connex(ion)=connection, expliqu(e)=explain, fonctionn(e/ement)=works)
365
+ 'appel', 'dépend', 'implément', 'connex', 'expliqu', 'fonctionn',
366
+ // Spanish (llamad(a)=call, afect(a)=affect, conect(a)/conexi(ón)=connect,
367
+ // arquitec(tura)=architecture, estructur(a)=structure, funcion(a)=works,
368
+ // traza(r)=trace, explica=explain)
369
+ 'llamad', 'afect', 'conect', 'conexi', 'arquitec', 'estructur', 'funcion', 'traza', 'explica',
370
+ // Portuguese (chama(da)=call, afeta=affect, arquitet(ura)=architecture,
371
+ // estrutur(a)=structure, quebra(do)=breaks)
372
+ 'chama', 'afeta', 'arquitet', 'estrutur', 'quebra',
373
+ // German (abhäng(t)=depend, Auswirkung=impact, beeinfluss(t)=affect,
374
+ // verbind(et)=connect, Architektur, Struktur, funktionier(t)=works,
375
+ // Aufruf/aufgerufen=call, erklär(t)=explain, verfolg(en)=trace)
376
+ 'abhäng', 'auswirkung', 'beeinfluss', 'verbind', 'architekt', 'struktur', 'funktionier', 'aufruf', 'aufgerufen', 'erklär', 'verfolg',
377
+ // Italian (chiam(a/ata)=call, dipend(e/enza)=depend, impatt(o)=impact,
378
+ // connett(e)/conness(ione)=connect, architett(ura), struttur(a),
379
+ // funzion(a/amento)=works, tracci(a)=trace, spiega(mi)=explain)
380
+ 'chiam', 'dipend', 'impatt', 'connett', 'conness', 'architett', 'struttur', 'funzion', 'tracci', 'spiega',
381
+ // Russian (вызыва(ет)=calls, завис(ит)=depends, влия(ет)=affects,
382
+ // реализ(ация)=implementation, структур(а), архитектур(а),
383
+ // трассир(овка)=trace, лома(ет)=breaks, объясн(и)=explain, поток=flow)
384
+ 'вызыва', 'завис', 'влия', 'реализ', 'структур', 'архитектур', 'трассир', 'лома', 'объясн', 'поток',
385
+ // Ukrainian — і/и spellings diverge from Russian (виклика(є)=calls,
386
+ // залеж(ить)=depends, вплива(є)=affects, архітектур(а), реаліз(ація),
387
+ // поясн(и)=explain, шлях(у)=path; структур(а) is shared with Russian)
388
+ 'виклика', 'залеж', 'вплива', 'архітектур', 'реаліз', 'поясн', 'шлях',
389
+ // Dutch (aanroep(en)=call, afhankelijk(heid)=depends, beïnvloed(t)=affects,
390
+ // structuur — "structur" can't reach the uu; uitleg(gen)=explain)
391
+ 'aanroep', 'afhankelijk', 'beïnvloed', 'structuur', 'uitleg',
392
+ // Polish (wywoł(uje)=calls, zależ(y)=depends, wpływ(a)=affects/impact,
393
+ // przepływ=flow, ścieżk(a)=path, działa(nie)=works, wyjaśni(j)=explain,
394
+ // śledz(enie)=trace; architektura/struktura fire via the German stems)
395
+ 'wywoł', 'zależ', 'wpływ', 'przepływ', 'ścieżk', 'działa', 'wyjaśni', 'śledz',
396
+ // Czech (volá(ní)=calls, závis(í)=depends, ovlivň(uje)=affects,
397
+ // funguj(e)=works, vysvětl(i)=explain)
398
+ 'volá', 'závis', 'ovlivň', 'funguj', 'vysvětl',
399
+ // Romanian (apel(ează)=calls, depind(e)=depends — i not e, so "depend" misses
400
+ // it; arhitectur(a) — no c; funcțion(ează)=works, explică=explain)
401
+ 'apel', 'depind', 'arhitectur', 'funcțion', 'explică',
402
+ // Hungarian (hív(ja)=calls, függ(őség)=depends, működ(ik)=works,
403
+ // struktúr(a) — ú escapes "struktur"; magyaráz(d)=explain;
404
+ // architektúra fires via the German stem)
405
+ 'hív', 'függ', 'működ', 'struktúr', 'magyaráz',
406
+ // Turkish — agglutinative, so stems beat exact words (nere(de/ye/den)=where,
407
+ // çağır/çağrı=call, bağıml(ı)=depends, bağlant(ı)=connection, akış(ı)=flow,
408
+ // etkile(r)/etkisi=affects/impact)
409
+ 'nere', 'çağır', 'çağrı', 'bağıml', 'bağlant', 'akış', 'etkile', 'etkisi',
410
+ // Indonesian/Malay — me-/di-/ber- prefixes block a bare stem, so affixed
411
+ // forms are listed too (panggil(an)/memanggil/dipanggil=call,
412
+ // bergantung/tergantung=depends, pengaruh/mempengaruhi/memengaruhi=affect,
413
+ // arsitektur=architecture, fungsi/berfungsi=works,
414
+ // jelaskan/menjelaskan=explain)
415
+ 'panggil', 'memanggil', 'dipanggil', 'bergantung', 'tergantung', 'pengaruh',
416
+ 'mempengaruhi', 'memengaruhi', 'arsitektur', 'fungsi', 'berfungsi', 'jelaskan', 'menjelaskan',
417
+ // Swedish / Danish / Norwegian (anrop(ar)=calls, påverk(ar)/påvirk(er)=affects,
418
+ // afhæng(er)/avheng(er)=depends, förklar(a)/forklar=explain,
419
+ // arkitektur — k not ch; funger(ar/er)=works)
420
+ 'anrop', 'påverk', 'påvirk', 'afhæng', 'avheng', 'förklar', 'forklar', 'arkitektur', 'funger',
421
+ // Finnish (kutsu(u)=calls, riippu(u)=depends, arkkitehtuur(i),
422
+ // rakente(en)=structure, selit(ä)=explain)
423
+ 'kutsu', 'riippu', 'arkkitehtuur', 'rakente', 'selit',
424
+ // Greek — accented and unaccented stem spellings both occur
425
+ // (εξαρτ(άται)=depends, επηρε(άζει)=affects, αρχιτεκτονικ(ή),
426
+ // διαδρομ(ή)=path, εξηγ/εξήγ(ησε)=explain)
427
+ 'εξαρτ', 'επηρε', 'αρχιτεκτονικ', 'διαδρομ', 'εξηγ', 'εξήγ',
428
+ // Hindi (समझा(ओ/इए)=explain, आर्किटेक्चर=architecture)
429
+ 'समझा', 'आर्किटेक्चर',
430
+ ];
431
+ const STRUCTURAL_WORDS_RE = new RegExp(`${NOT_WORD_BEFORE}(?:${STRUCTURAL_WORDS.join('|')})${NOT_WORD_AFTER}`, 'iu');
432
+ const STRUCTURAL_STEMS_RE = new RegExp(`${NOT_WORD_BEFORE}(?:${STRUCTURAL_STEMS.join('|')})`, 'iu');
433
+ /**
434
+ * Structural keywords matched as bare SUBSTRINGS, for languages where a
435
+ * boundary can't be relied on: scripts with no word separators (Chinese —
436
+ * simplified AND traditional; the original #994 set was simplified-only —
437
+ * Japanese, Thai), Korean (spaced, but particles attach directly to the noun:
438
+ * 구조가/구조를), and Arabic / Farsi / Hebrew (spaced, but proclitics attach to
439
+ * the word: وكيف "and-how", והמבנה "and-the-structure"). JS's `\b` can never
440
+ * fire between Han characters, which was issue #994: the English-only gate
441
+ * silently no-op'd every Chinese prompt, so non-English users got no front-load
442
+ * nudge and no error to explain why. The sets mirror the English intent
443
+ * (如何/怎么/怎麼/どうやって/どのように/어떻게/كيف/چگونه/چطور/איך/อย่างไร/ยังไง=how,
444
+ * 在哪/哪里/哪裡/어디/أين/كجا/איפה/ที่ไหน=where, 流程/流向/流れ/흐름/تدفق/זרימה=flow,
445
+ * 路径/路徑/経路/경로/مسار/مسیر/נתיב/เส้นทาง=path,
446
+ * 调用/調用/呼び出/호출/يستدعي/استدعاء/فراخوان/קורא/เรียกใช้=call,
447
+ * 依赖/依賴/依存/의존/يعتمد/تعتمد/وابسته/תלוי/ขึ้นอยู่กับ=depend,
448
+ * 影响/影響/영향/يؤثر/تأثير/تأثیر/משפיע/ผลกระทบ=impact/affect,
449
+ * 实现/實現/実装/구현=implement,
450
+ * 架构/架構/アーキテクチャ/아키텍처/معماري/معماری/ארכיטקטור/สถาปัตยกรรม=architecture,
451
+ * 结构/結構/構造/구조/بنية/هيكل/ساختار/מבנה/โครงสร้าง=structure,
452
+ * 追踪/跟踪/追蹤/追跡/トレース/추적/تتبع/ติดตาม=trace,
453
+ * يعمل/تعمل/ทำงาน=works) plus structural-overview words with no single clean
454
+ * English equivalent (介绍/介紹/解析/分析/原理/机制/機制/仕組み/説明/설명/動作/동작/작동/
455
+ * اشرح/شرح/توضیح/הסבר/อธิบาย=explain).
456
+ *
457
+ * KNOWN, ACCEPTED false-positive class (#1140): substring matching cannot see
458
+ * homograph compounds — Korean 구조 (structure) also fires inside 구조대
459
+ * (rescue squad). Verified unfixable at this layer: ICU word segmentation
460
+ * (Intl.Segmenter) returns 구조대 and the particle form 구조가 (which the gate
461
+ * MUST keep matching) as equally opaque single segments, and a 구조대 denylist
462
+ * would break 구조대로 ("according to the structure" — 구조 + the 대로
463
+ * particle), a legitimate structural prompt. The miss rate this design avoids
464
+ * (silently no-op'ing every prompt in these languages, #994) outweighs the
465
+ * occasional off-domain fire.
466
+ */
467
+ const STRUCTURAL_UNSEGMENTED = /如何|怎么|怎麼|在哪|哪里|哪裡|追踪|跟踪|追蹤|追跡|トレース|流程|流向|流れ|路径|路徑|経路|调用|調用|呼び出|依赖|依賴|依存|影响|影響|实现|實現|実装|架构|架構|アーキテクチャ|结构|結構|構造|介绍|介紹|解析|分析|原理|机制|機制|仕組み|説明|動作|どうやって|どのように|어떻게|어디|호출|흐름|경로|의존|영향|구현|구조|아키텍처|추적|동작|작동|설명|كيف|أين|اين|يستدعي|استدعاء|يعتمد|تعتمد|يؤثر|تأثير|معماري|بنية|هيكل|تدفق|مسار|تتبع|يعمل|تعمل|اشرح|شرح|چگونه|چطور|کجا|فراخوان|وابسته|تأثیر|معماری|ساختار|مسیر|توضیح|איך|איפה|קורא|תלוי|משפיע|ארכיטקטור|מבנה|זרימה|נתיב|הסבר|อย่างไร|ยังไง|ที่ไหน|เรียกใช้|ขึ้นอยู่กับ|ผลกระทบ|สถาปัตยกรรม|โครงสร้าง|เส้นทาง|ติดตาม|ทำงาน|อธิบาย/;
282
468
  /** Doc/data/asset file extensions — a `name.ext` of this kind is a file
283
469
  * reference, not a code symbol, so it must not trip the member-access signal. */
284
470
  const DOC_DATA_EXT = /\.(md|markdown|txt|rst|json|ya?ml|toml|lock|csv|tsv|log|ini|cfg|conf|env|xml|html?|png|jpe?g|gif|svg|pdf)$/i;
285
471
  /**
286
- * Does `prompt` contain an explicit structural keyword (English or CJK)? A
287
- * keyword is a strong, self-contained signal, so the front-load hook fires on it
288
- * directly — no graph check needed. (A *code-token* match, by contrast, is only
289
- * a candidate the hook verifies against the graph first; see {@link extractCodeTokens}.)
472
+ * Does `prompt` contain an explicit structural keyword? A keyword is a strong,
473
+ * self-contained signal, so the front-load hook fires on it directly — no graph
474
+ * check needed. (A *code-token* match, by contrast, is only a candidate the
475
+ * hook verifies against the graph first; see {@link extractCodeTokens}.)
476
+ * Coverage is multilingual (#994, #1126): the ~29 languages with the largest
477
+ * developer populations, across Latin, Cyrillic, Greek, CJK, Hangul, Arabic,
478
+ * Hebrew, Thai, and Devanagari scripts. Languages beyond the keyword table
479
+ * still fire through the language-agnostic code-token path.
290
480
  */
291
481
  function hasStructuralKeyword(prompt) {
292
- return !!prompt && (STRUCTURAL_EN.test(prompt) || STRUCTURAL_CJK.test(prompt));
482
+ return (!!prompt &&
483
+ (STRUCTURAL_WORDS_RE.test(prompt) || STRUCTURAL_STEMS_RE.test(prompt) || STRUCTURAL_UNSEGMENTED.test(prompt)));
293
484
  }
294
485
  /**
295
486
  * Identifier-shaped tokens in `prompt` — camelCase / PascalCase-with-inner-cap,
@@ -333,7 +524,7 @@ function extractCodeTokens(prompt) {
333
524
  /**
334
525
  * Cheap, graph-free candidate gate for the front-load hook: could `prompt` be a
335
526
  * structural / flow / impact / "where-how" question worth front-loading context
336
- * for? True on an explicit keyword (English or CJK, issue #994) OR an
527
+ * for? True on an explicit keyword in any covered language (#994, #1126) OR an
337
528
  * identifier-shaped token. A keyword is sufficient to fire on its own; a
338
529
  * token-only match is only a candidate the hook then verifies against the graph
339
530
  * (a brand name like `JavaScript` is token-shaped but isn't a symbol). Every