@ltm-alpha/alpha-cs 1.6.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 (1107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +972 -0
  3. package/dist/bin/command-supervision.d.ts +49 -0
  4. package/dist/bin/command-supervision.d.ts.map +1 -0
  5. package/dist/bin/command-supervision.js +95 -0
  6. package/dist/bin/command-supervision.js.map +1 -0
  7. package/dist/bin/fatal-handler.d.ts +20 -0
  8. package/dist/bin/fatal-handler.d.ts.map +1 -0
  9. package/dist/bin/fatal-handler.js +118 -0
  10. package/dist/bin/fatal-handler.js.map +1 -0
  11. package/dist/bin/ltm-alpha-cs.d.ts +27 -0
  12. package/dist/bin/ltm-alpha-cs.d.ts.map +1 -0
  13. package/dist/bin/ltm-alpha-cs.js +2643 -0
  14. package/dist/bin/ltm-alpha-cs.js.map +1 -0
  15. package/dist/bin/node-version-check.d.ts +37 -0
  16. package/dist/bin/node-version-check.d.ts.map +1 -0
  17. package/dist/bin/node-version-check.js +79 -0
  18. package/dist/bin/node-version-check.js.map +1 -0
  19. package/dist/bin/uninstall.d.ts +14 -0
  20. package/dist/bin/uninstall.d.ts.map +1 -0
  21. package/dist/bin/uninstall.js +36 -0
  22. package/dist/bin/uninstall.js.map +1 -0
  23. package/dist/context/formatter.d.ts +36 -0
  24. package/dist/context/formatter.d.ts.map +1 -0
  25. package/dist/context/formatter.js +269 -0
  26. package/dist/context/formatter.js.map +1 -0
  27. package/dist/context/index.d.ts +131 -0
  28. package/dist/context/index.d.ts.map +1 -0
  29. package/dist/context/index.js +1378 -0
  30. package/dist/context/index.js.map +1 -0
  31. package/dist/context/markers.d.ts +19 -0
  32. package/dist/context/markers.d.ts.map +1 -0
  33. package/dist/context/markers.js +22 -0
  34. package/dist/context/markers.js.map +1 -0
  35. package/dist/db/index.d.ts +385 -0
  36. package/dist/db/index.d.ts.map +1 -0
  37. package/dist/db/index.js +902 -0
  38. package/dist/db/index.js.map +1 -0
  39. package/dist/db/migrations.d.ts +44 -0
  40. package/dist/db/migrations.d.ts.map +1 -0
  41. package/dist/db/migrations.js +236 -0
  42. package/dist/db/migrations.js.map +1 -0
  43. package/dist/db/queries.d.ts +1095 -0
  44. package/dist/db/queries.d.ts.map +1 -0
  45. package/dist/db/queries.js +3285 -0
  46. package/dist/db/queries.js.map +1 -0
  47. package/dist/db/schema.sql +207 -0
  48. package/dist/db/sqlite-adapter.d.ts +55 -0
  49. package/dist/db/sqlite-adapter.d.ts.map +1 -0
  50. package/dist/db/sqlite-adapter.js +135 -0
  51. package/dist/db/sqlite-adapter.js.map +1 -0
  52. package/dist/db/wal-valve.d.ts +139 -0
  53. package/dist/db/wal-valve.d.ts.map +1 -0
  54. package/dist/db/wal-valve.js +333 -0
  55. package/dist/db/wal-valve.js.map +1 -0
  56. package/dist/directory.d.ts +232 -0
  57. package/dist/directory.d.ts.map +1 -0
  58. package/dist/directory.js +877 -0
  59. package/dist/directory.js.map +1 -0
  60. package/dist/errors.d.ts +150 -0
  61. package/dist/errors.d.ts.map +1 -0
  62. package/dist/errors.js +234 -0
  63. package/dist/errors.js.map +1 -0
  64. package/dist/extraction/astro-extractor.d.ts +79 -0
  65. package/dist/extraction/astro-extractor.d.ts.map +1 -0
  66. package/dist/extraction/astro-extractor.js +320 -0
  67. package/dist/extraction/astro-extractor.js.map +1 -0
  68. package/dist/extraction/cfml-extractor.d.ts +107 -0
  69. package/dist/extraction/cfml-extractor.d.ts.map +1 -0
  70. package/dist/extraction/cfml-extractor.js +505 -0
  71. package/dist/extraction/cfml-extractor.js.map +1 -0
  72. package/dist/extraction/dfm-extractor.d.ts +31 -0
  73. package/dist/extraction/dfm-extractor.d.ts.map +1 -0
  74. package/dist/extraction/dfm-extractor.js +151 -0
  75. package/dist/extraction/dfm-extractor.js.map +1 -0
  76. package/dist/extraction/extraction-version.d.ts +25 -0
  77. package/dist/extraction/extraction-version.d.ts.map +1 -0
  78. package/dist/extraction/extraction-version.js +28 -0
  79. package/dist/extraction/extraction-version.js.map +1 -0
  80. package/dist/extraction/function-ref.d.ts +118 -0
  81. package/dist/extraction/function-ref.d.ts.map +1 -0
  82. package/dist/extraction/function-ref.js +746 -0
  83. package/dist/extraction/function-ref.js.map +1 -0
  84. package/dist/extraction/generated-detection.d.ts +66 -0
  85. package/dist/extraction/generated-detection.d.ts.map +1 -0
  86. package/dist/extraction/generated-detection.js +248 -0
  87. package/dist/extraction/generated-detection.js.map +1 -0
  88. package/dist/extraction/grammars.d.ts +148 -0
  89. package/dist/extraction/grammars.d.ts.map +1 -0
  90. package/dist/extraction/grammars.js +743 -0
  91. package/dist/extraction/grammars.js.map +1 -0
  92. package/dist/extraction/index.d.ts +455 -0
  93. package/dist/extraction/index.d.ts.map +1 -0
  94. package/dist/extraction/index.js +3208 -0
  95. package/dist/extraction/index.js.map +1 -0
  96. package/dist/extraction/kernel/decode.d.ts +9 -0
  97. package/dist/extraction/kernel/decode.d.ts.map +1 -0
  98. package/dist/extraction/kernel/decode.js +162 -0
  99. package/dist/extraction/kernel/decode.js.map +1 -0
  100. package/dist/extraction/kernel/index.d.ts +64 -0
  101. package/dist/extraction/kernel/index.d.ts.map +1 -0
  102. package/dist/extraction/kernel/index.js +279 -0
  103. package/dist/extraction/kernel/index.js.map +1 -0
  104. package/dist/extraction/kernel/layout.d.ts +101 -0
  105. package/dist/extraction/kernel/layout.d.ts.map +1 -0
  106. package/dist/extraction/kernel/layout.js +104 -0
  107. package/dist/extraction/kernel/layout.js.map +1 -0
  108. package/dist/extraction/kernel/loader.d.ts +103 -0
  109. package/dist/extraction/kernel/loader.d.ts.map +1 -0
  110. package/dist/extraction/kernel/loader.js +146 -0
  111. package/dist/extraction/kernel/loader.js.map +1 -0
  112. package/dist/extraction/languages/arkts.d.ts +3 -0
  113. package/dist/extraction/languages/arkts.d.ts.map +1 -0
  114. package/dist/extraction/languages/arkts.js +127 -0
  115. package/dist/extraction/languages/arkts.js.map +1 -0
  116. package/dist/extraction/languages/c-cpp.d.ts +167 -0
  117. package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
  118. package/dist/extraction/languages/c-cpp.js +1850 -0
  119. package/dist/extraction/languages/c-cpp.js.map +1 -0
  120. package/dist/extraction/languages/cfquery.d.ts +12 -0
  121. package/dist/extraction/languages/cfquery.d.ts.map +1 -0
  122. package/dist/extraction/languages/cfquery.js +28 -0
  123. package/dist/extraction/languages/cfquery.js.map +1 -0
  124. package/dist/extraction/languages/cfscript.d.ts +3 -0
  125. package/dist/extraction/languages/cfscript.d.ts.map +1 -0
  126. package/dist/extraction/languages/cfscript.js +73 -0
  127. package/dist/extraction/languages/cfscript.js.map +1 -0
  128. package/dist/extraction/languages/cobol.d.ts +33 -0
  129. package/dist/extraction/languages/cobol.d.ts.map +1 -0
  130. package/dist/extraction/languages/cobol.js +499 -0
  131. package/dist/extraction/languages/cobol.js.map +1 -0
  132. package/dist/extraction/languages/csharp.d.ts +25 -0
  133. package/dist/extraction/languages/csharp.d.ts.map +1 -0
  134. package/dist/extraction/languages/csharp.js +175 -0
  135. package/dist/extraction/languages/csharp.js.map +1 -0
  136. package/dist/extraction/languages/dart.d.ts +3 -0
  137. package/dist/extraction/languages/dart.d.ts.map +1 -0
  138. package/dist/extraction/languages/dart.js +374 -0
  139. package/dist/extraction/languages/dart.js.map +1 -0
  140. package/dist/extraction/languages/erlang.d.ts +3 -0
  141. package/dist/extraction/languages/erlang.d.ts.map +1 -0
  142. package/dist/extraction/languages/erlang.js +386 -0
  143. package/dist/extraction/languages/erlang.js.map +1 -0
  144. package/dist/extraction/languages/go.d.ts +3 -0
  145. package/dist/extraction/languages/go.d.ts.map +1 -0
  146. package/dist/extraction/languages/go.js +111 -0
  147. package/dist/extraction/languages/go.js.map +1 -0
  148. package/dist/extraction/languages/index.d.ts +10 -0
  149. package/dist/extraction/languages/index.d.ts.map +1 -0
  150. package/dist/extraction/languages/index.js +71 -0
  151. package/dist/extraction/languages/index.js.map +1 -0
  152. package/dist/extraction/languages/java.d.ts +3 -0
  153. package/dist/extraction/languages/java.d.ts.map +1 -0
  154. package/dist/extraction/languages/java.js +315 -0
  155. package/dist/extraction/languages/java.js.map +1 -0
  156. package/dist/extraction/languages/javascript.d.ts +3 -0
  157. package/dist/extraction/languages/javascript.d.ts.map +1 -0
  158. package/dist/extraction/languages/javascript.js +106 -0
  159. package/dist/extraction/languages/javascript.js.map +1 -0
  160. package/dist/extraction/languages/kotlin.d.ts +3 -0
  161. package/dist/extraction/languages/kotlin.d.ts.map +1 -0
  162. package/dist/extraction/languages/kotlin.js +512 -0
  163. package/dist/extraction/languages/kotlin.js.map +1 -0
  164. package/dist/extraction/languages/lua.d.ts +3 -0
  165. package/dist/extraction/languages/lua.d.ts.map +1 -0
  166. package/dist/extraction/languages/lua.js +153 -0
  167. package/dist/extraction/languages/lua.js.map +1 -0
  168. package/dist/extraction/languages/luau.d.ts +3 -0
  169. package/dist/extraction/languages/luau.d.ts.map +1 -0
  170. package/dist/extraction/languages/luau.js +37 -0
  171. package/dist/extraction/languages/luau.js.map +1 -0
  172. package/dist/extraction/languages/nix.d.ts +3 -0
  173. package/dist/extraction/languages/nix.d.ts.map +1 -0
  174. package/dist/extraction/languages/nix.js +294 -0
  175. package/dist/extraction/languages/nix.js.map +1 -0
  176. package/dist/extraction/languages/objc.d.ts +3 -0
  177. package/dist/extraction/languages/objc.d.ts.map +1 -0
  178. package/dist/extraction/languages/objc.js +179 -0
  179. package/dist/extraction/languages/objc.js.map +1 -0
  180. package/dist/extraction/languages/pascal.d.ts +3 -0
  181. package/dist/extraction/languages/pascal.d.ts.map +1 -0
  182. package/dist/extraction/languages/pascal.js +77 -0
  183. package/dist/extraction/languages/pascal.js.map +1 -0
  184. package/dist/extraction/languages/php.d.ts +3 -0
  185. package/dist/extraction/languages/php.d.ts.map +1 -0
  186. package/dist/extraction/languages/php.js +196 -0
  187. package/dist/extraction/languages/php.js.map +1 -0
  188. package/dist/extraction/languages/python.d.ts +3 -0
  189. package/dist/extraction/languages/python.d.ts.map +1 -0
  190. package/dist/extraction/languages/python.js +56 -0
  191. package/dist/extraction/languages/python.js.map +1 -0
  192. package/dist/extraction/languages/r.d.ts +3 -0
  193. package/dist/extraction/languages/r.d.ts.map +1 -0
  194. package/dist/extraction/languages/r.js +314 -0
  195. package/dist/extraction/languages/r.js.map +1 -0
  196. package/dist/extraction/languages/ruby.d.ts +3 -0
  197. package/dist/extraction/languages/ruby.d.ts.map +1 -0
  198. package/dist/extraction/languages/ruby.js +149 -0
  199. package/dist/extraction/languages/ruby.js.map +1 -0
  200. package/dist/extraction/languages/rust.d.ts +23 -0
  201. package/dist/extraction/languages/rust.d.ts.map +1 -0
  202. package/dist/extraction/languages/rust.js +172 -0
  203. package/dist/extraction/languages/rust.js.map +1 -0
  204. package/dist/extraction/languages/scala.d.ts +3 -0
  205. package/dist/extraction/languages/scala.d.ts.map +1 -0
  206. package/dist/extraction/languages/scala.js +219 -0
  207. package/dist/extraction/languages/scala.js.map +1 -0
  208. package/dist/extraction/languages/solidity.d.ts +3 -0
  209. package/dist/extraction/languages/solidity.d.ts.map +1 -0
  210. package/dist/extraction/languages/solidity.js +293 -0
  211. package/dist/extraction/languages/solidity.js.map +1 -0
  212. package/dist/extraction/languages/swift.d.ts +3 -0
  213. package/dist/extraction/languages/swift.d.ts.map +1 -0
  214. package/dist/extraction/languages/swift.js +152 -0
  215. package/dist/extraction/languages/swift.js.map +1 -0
  216. package/dist/extraction/languages/terraform.d.ts +3 -0
  217. package/dist/extraction/languages/terraform.d.ts.map +1 -0
  218. package/dist/extraction/languages/terraform.js +641 -0
  219. package/dist/extraction/languages/terraform.js.map +1 -0
  220. package/dist/extraction/languages/typescript.d.ts +16 -0
  221. package/dist/extraction/languages/typescript.d.ts.map +1 -0
  222. package/dist/extraction/languages/typescript.js +174 -0
  223. package/dist/extraction/languages/typescript.js.map +1 -0
  224. package/dist/extraction/languages/vbnet.d.ts +11 -0
  225. package/dist/extraction/languages/vbnet.d.ts.map +1 -0
  226. package/dist/extraction/languages/vbnet.js +141 -0
  227. package/dist/extraction/languages/vbnet.js.map +1 -0
  228. package/dist/extraction/liquid-extractor.d.ts +59 -0
  229. package/dist/extraction/liquid-extractor.d.ts.map +1 -0
  230. package/dist/extraction/liquid-extractor.js +357 -0
  231. package/dist/extraction/liquid-extractor.js.map +1 -0
  232. package/dist/extraction/mybatis-extractor.d.ts +68 -0
  233. package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
  234. package/dist/extraction/mybatis-extractor.js +300 -0
  235. package/dist/extraction/mybatis-extractor.js.map +1 -0
  236. package/dist/extraction/parse-pool.d.ts +167 -0
  237. package/dist/extraction/parse-pool.d.ts.map +1 -0
  238. package/dist/extraction/parse-pool.js +421 -0
  239. package/dist/extraction/parse-pool.js.map +1 -0
  240. package/dist/extraction/parse-worker.d.ts +8 -0
  241. package/dist/extraction/parse-worker.d.ts.map +1 -0
  242. package/dist/extraction/parse-worker.js +138 -0
  243. package/dist/extraction/parse-worker.js.map +1 -0
  244. package/dist/extraction/razor-extractor.d.ts +42 -0
  245. package/dist/extraction/razor-extractor.d.ts.map +1 -0
  246. package/dist/extraction/razor-extractor.js +285 -0
  247. package/dist/extraction/razor-extractor.js.map +1 -0
  248. package/dist/extraction/store-worker.d.ts +24 -0
  249. package/dist/extraction/store-worker.d.ts.map +1 -0
  250. package/dist/extraction/store-worker.js +139 -0
  251. package/dist/extraction/store-worker.js.map +1 -0
  252. package/dist/extraction/store-writer.d.ts +63 -0
  253. package/dist/extraction/store-writer.d.ts.map +1 -0
  254. package/dist/extraction/store-writer.js +174 -0
  255. package/dist/extraction/store-writer.js.map +1 -0
  256. package/dist/extraction/svelte-extractor.d.ts +56 -0
  257. package/dist/extraction/svelte-extractor.d.ts.map +1 -0
  258. package/dist/extraction/svelte-extractor.js +275 -0
  259. package/dist/extraction/svelte-extractor.js.map +1 -0
  260. package/dist/extraction/syntax-tokens.d.ts +103 -0
  261. package/dist/extraction/syntax-tokens.d.ts.map +1 -0
  262. package/dist/extraction/syntax-tokens.js +381 -0
  263. package/dist/extraction/syntax-tokens.js.map +1 -0
  264. package/dist/extraction/tree-sitter-helpers.d.ts +28 -0
  265. package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
  266. package/dist/extraction/tree-sitter-helpers.js +153 -0
  267. package/dist/extraction/tree-sitter-helpers.js.map +1 -0
  268. package/dist/extraction/tree-sitter-types.d.ts +279 -0
  269. package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
  270. package/dist/extraction/tree-sitter-types.js +10 -0
  271. package/dist/extraction/tree-sitter-types.js.map +1 -0
  272. package/dist/extraction/tree-sitter.d.ts +766 -0
  273. package/dist/extraction/tree-sitter.d.ts.map +1 -0
  274. package/dist/extraction/tree-sitter.js +7138 -0
  275. package/dist/extraction/tree-sitter.js.map +1 -0
  276. package/dist/extraction/vue-extractor.d.ts +51 -0
  277. package/dist/extraction/vue-extractor.d.ts.map +1 -0
  278. package/dist/extraction/vue-extractor.js +254 -0
  279. package/dist/extraction/vue-extractor.js.map +1 -0
  280. package/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
  281. package/dist/extraction/wasm/tree-sitter-c.wasm +0 -0
  282. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  283. package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  284. package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  285. package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  286. package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  287. package/dist/extraction/wasm/tree-sitter-cpp.wasm +0 -0
  288. package/dist/extraction/wasm/tree-sitter-dart.wasm +0 -0
  289. package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  290. package/dist/extraction/wasm/tree-sitter-go.wasm +0 -0
  291. package/dist/extraction/wasm/tree-sitter-java.wasm +0 -0
  292. package/dist/extraction/wasm/tree-sitter-javascript.wasm +0 -0
  293. package/dist/extraction/wasm/tree-sitter-kotlin.wasm +0 -0
  294. package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
  295. package/dist/extraction/wasm/tree-sitter-luau.wasm +0 -0
  296. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  297. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  298. package/dist/extraction/wasm/tree-sitter-php.wasm +0 -0
  299. package/dist/extraction/wasm/tree-sitter-python.wasm +0 -0
  300. package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
  301. package/dist/extraction/wasm/tree-sitter-ruby.wasm +0 -0
  302. package/dist/extraction/wasm/tree-sitter-rust.wasm +0 -0
  303. package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  304. package/dist/extraction/wasm/tree-sitter-swift.wasm +0 -0
  305. package/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
  306. package/dist/extraction/wasm/tree-sitter-tsx.wasm +0 -0
  307. package/dist/extraction/wasm/tree-sitter-typescript.wasm +0 -0
  308. package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  309. package/dist/extraction/wasm-runtime-flags.d.ts +53 -0
  310. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
  311. package/dist/extraction/wasm-runtime-flags.js +130 -0
  312. package/dist/extraction/wasm-runtime-flags.js.map +1 -0
  313. package/dist/graph/branch-guards.d.ts +248 -0
  314. package/dist/graph/branch-guards.d.ts.map +1 -0
  315. package/dist/graph/branch-guards.js +2231 -0
  316. package/dist/graph/branch-guards.js.map +1 -0
  317. package/dist/graph/dead-code.d.ts +251 -0
  318. package/dist/graph/dead-code.d.ts.map +1 -0
  319. package/dist/graph/dead-code.js +756 -0
  320. package/dist/graph/dead-code.js.map +1 -0
  321. package/dist/graph/dynamic-boundary-report.d.ts +121 -0
  322. package/dist/graph/dynamic-boundary-report.d.ts.map +1 -0
  323. package/dist/graph/dynamic-boundary-report.js +283 -0
  324. package/dist/graph/dynamic-boundary-report.js.map +1 -0
  325. package/dist/graph/index.d.ts +12 -0
  326. package/dist/graph/index.d.ts.map +1 -0
  327. package/dist/graph/index.js +28 -0
  328. package/dist/graph/index.js.map +1 -0
  329. package/dist/graph/named-symbol-flow.d.ts +125 -0
  330. package/dist/graph/named-symbol-flow.d.ts.map +1 -0
  331. package/dist/graph/named-symbol-flow.js +552 -0
  332. package/dist/graph/named-symbol-flow.js.map +1 -0
  333. package/dist/graph/queries.d.ts +106 -0
  334. package/dist/graph/queries.d.ts.map +1 -0
  335. package/dist/graph/queries.js +341 -0
  336. package/dist/graph/queries.js.map +1 -0
  337. package/dist/graph/symbol-lookup.d.ts +83 -0
  338. package/dist/graph/symbol-lookup.d.ts.map +1 -0
  339. package/dist/graph/symbol-lookup.js +181 -0
  340. package/dist/graph/symbol-lookup.js.map +1 -0
  341. package/dist/graph/traversal.d.ts +127 -0
  342. package/dist/graph/traversal.d.ts.map +1 -0
  343. package/dist/graph/traversal.js +599 -0
  344. package/dist/graph/traversal.js.map +1 -0
  345. package/dist/graph/type-hierarchy.d.ts +155 -0
  346. package/dist/graph/type-hierarchy.d.ts.map +1 -0
  347. package/dist/graph/type-hierarchy.js +382 -0
  348. package/dist/graph/type-hierarchy.js.map +1 -0
  349. package/dist/index.d.ts +874 -0
  350. package/dist/index.d.ts.map +1 -0
  351. package/dist/index.js +2005 -0
  352. package/dist/index.js.map +1 -0
  353. package/dist/installer/config-writer.d.ts +28 -0
  354. package/dist/installer/config-writer.d.ts.map +1 -0
  355. package/dist/installer/config-writer.js +91 -0
  356. package/dist/installer/config-writer.js.map +1 -0
  357. package/dist/installer/index.d.ts +143 -0
  358. package/dist/installer/index.d.ts.map +1 -0
  359. package/dist/installer/index.js +621 -0
  360. package/dist/installer/index.js.map +1 -0
  361. package/dist/installer/instructions-template.d.ts +41 -0
  362. package/dist/installer/instructions-template.d.ts.map +1 -0
  363. package/dist/installer/instructions-template.js +53 -0
  364. package/dist/installer/instructions-template.js.map +1 -0
  365. package/dist/installer/targets/antigravity.d.ts +57 -0
  366. package/dist/installer/targets/antigravity.d.ts.map +1 -0
  367. package/dist/installer/targets/antigravity.js +308 -0
  368. package/dist/installer/targets/antigravity.js.map +1 -0
  369. package/dist/installer/targets/claude.d.ts +65 -0
  370. package/dist/installer/targets/claude.d.ts.map +1 -0
  371. package/dist/installer/targets/claude.js +514 -0
  372. package/dist/installer/targets/claude.js.map +1 -0
  373. package/dist/installer/targets/codex.d.ts +33 -0
  374. package/dist/installer/targets/codex.d.ts.map +1 -0
  375. package/dist/installer/targets/codex.js +212 -0
  376. package/dist/installer/targets/codex.js.map +1 -0
  377. package/dist/installer/targets/copilot-cli.d.ts +32 -0
  378. package/dist/installer/targets/copilot-cli.d.ts.map +1 -0
  379. package/dist/installer/targets/copilot-cli.js +215 -0
  380. package/dist/installer/targets/copilot-cli.js.map +1 -0
  381. package/dist/installer/targets/copilot-jetbrains.d.ts +42 -0
  382. package/dist/installer/targets/copilot-jetbrains.d.ts.map +1 -0
  383. package/dist/installer/targets/copilot-jetbrains.js +238 -0
  384. package/dist/installer/targets/copilot-jetbrains.js.map +1 -0
  385. package/dist/installer/targets/copilot-vscode.d.ts +47 -0
  386. package/dist/installer/targets/copilot-vscode.d.ts.map +1 -0
  387. package/dist/installer/targets/copilot-vscode.js +219 -0
  388. package/dist/installer/targets/copilot-vscode.js.map +1 -0
  389. package/dist/installer/targets/cursor.d.ts +35 -0
  390. package/dist/installer/targets/cursor.d.ts.map +1 -0
  391. package/dist/installer/targets/cursor.js +254 -0
  392. package/dist/installer/targets/cursor.js.map +1 -0
  393. package/dist/installer/targets/gemini.d.ts +26 -0
  394. package/dist/installer/targets/gemini.d.ts.map +1 -0
  395. package/dist/installer/targets/gemini.js +165 -0
  396. package/dist/installer/targets/gemini.js.map +1 -0
  397. package/dist/installer/targets/hermes.d.ts +18 -0
  398. package/dist/installer/targets/hermes.d.ts.map +1 -0
  399. package/dist/installer/targets/hermes.js +359 -0
  400. package/dist/installer/targets/hermes.js.map +1 -0
  401. package/dist/installer/targets/kiro.d.ts +27 -0
  402. package/dist/installer/targets/kiro.d.ts.map +1 -0
  403. package/dist/installer/targets/kiro.js +178 -0
  404. package/dist/installer/targets/kiro.js.map +1 -0
  405. package/dist/installer/targets/opencode.d.ts +49 -0
  406. package/dist/installer/targets/opencode.d.ts.map +1 -0
  407. package/dist/installer/targets/opencode.js +339 -0
  408. package/dist/installer/targets/opencode.js.map +1 -0
  409. package/dist/installer/targets/registry.d.ts +35 -0
  410. package/dist/installer/targets/registry.d.ts.map +1 -0
  411. package/dist/installer/targets/registry.js +97 -0
  412. package/dist/installer/targets/registry.js.map +1 -0
  413. package/dist/installer/targets/shared.d.ts +101 -0
  414. package/dist/installer/targets/shared.d.ts.map +1 -0
  415. package/dist/installer/targets/shared.js +264 -0
  416. package/dist/installer/targets/shared.js.map +1 -0
  417. package/dist/installer/targets/toml.d.ts +53 -0
  418. package/dist/installer/targets/toml.d.ts.map +1 -0
  419. package/dist/installer/targets/toml.js +226 -0
  420. package/dist/installer/targets/toml.js.map +1 -0
  421. package/dist/installer/targets/types.d.ts +108 -0
  422. package/dist/installer/targets/types.d.ts.map +1 -0
  423. package/dist/installer/targets/types.js +16 -0
  424. package/dist/installer/targets/types.js.map +1 -0
  425. package/dist/mcp/daemon-manager.d.ts +42 -0
  426. package/dist/mcp/daemon-manager.d.ts.map +1 -0
  427. package/dist/mcp/daemon-manager.js +141 -0
  428. package/dist/mcp/daemon-manager.js.map +1 -0
  429. package/dist/mcp/daemon-paths.d.ts +81 -0
  430. package/dist/mcp/daemon-paths.d.ts.map +1 -0
  431. package/dist/mcp/daemon-paths.js +228 -0
  432. package/dist/mcp/daemon-paths.js.map +1 -0
  433. package/dist/mcp/daemon-registry.d.ts +57 -0
  434. package/dist/mcp/daemon-registry.d.ts.map +1 -0
  435. package/dist/mcp/daemon-registry.js +323 -0
  436. package/dist/mcp/daemon-registry.js.map +1 -0
  437. package/dist/mcp/daemon.d.ts +294 -0
  438. package/dist/mcp/daemon.d.ts.map +1 -0
  439. package/dist/mcp/daemon.js +897 -0
  440. package/dist/mcp/daemon.js.map +1 -0
  441. package/dist/mcp/dynamic-boundaries.d.ts +32 -0
  442. package/dist/mcp/dynamic-boundaries.d.ts.map +1 -0
  443. package/dist/mcp/dynamic-boundaries.js +323 -0
  444. package/dist/mcp/dynamic-boundaries.js.map +1 -0
  445. package/dist/mcp/early-ppid.d.ts +26 -0
  446. package/dist/mcp/early-ppid.d.ts.map +1 -0
  447. package/dist/mcp/early-ppid.js +29 -0
  448. package/dist/mcp/early-ppid.js.map +1 -0
  449. package/dist/mcp/engine.d.ts +133 -0
  450. package/dist/mcp/engine.d.ts.map +1 -0
  451. package/dist/mcp/engine.js +421 -0
  452. package/dist/mcp/engine.js.map +1 -0
  453. package/dist/mcp/explore-dedup.d.ts +140 -0
  454. package/dist/mcp/explore-dedup.d.ts.map +1 -0
  455. package/dist/mcp/explore-dedup.js +239 -0
  456. package/dist/mcp/explore-dedup.js.map +1 -0
  457. package/dist/mcp/explore-diagnostics.d.ts +289 -0
  458. package/dist/mcp/explore-diagnostics.d.ts.map +1 -0
  459. package/dist/mcp/explore-diagnostics.js +558 -0
  460. package/dist/mcp/explore-diagnostics.js.map +1 -0
  461. package/dist/mcp/explore-session-state.d.ts +217 -0
  462. package/dist/mcp/explore-session-state.d.ts.map +1 -0
  463. package/dist/mcp/explore-session-state.js +322 -0
  464. package/dist/mcp/explore-session-state.js.map +1 -0
  465. package/dist/mcp/index.d.ts +139 -0
  466. package/dist/mcp/index.d.ts.map +1 -0
  467. package/dist/mcp/index.js +636 -0
  468. package/dist/mcp/index.js.map +1 -0
  469. package/dist/mcp/liveness-watchdog.d.ts +35 -0
  470. package/dist/mcp/liveness-watchdog.d.ts.map +1 -0
  471. package/dist/mcp/liveness-watchdog.js +269 -0
  472. package/dist/mcp/liveness-watchdog.js.map +1 -0
  473. package/dist/mcp/ppid-watchdog.d.ts +62 -0
  474. package/dist/mcp/ppid-watchdog.d.ts.map +1 -0
  475. package/dist/mcp/ppid-watchdog.js +64 -0
  476. package/dist/mcp/ppid-watchdog.js.map +1 -0
  477. package/dist/mcp/proxy.d.ts +87 -0
  478. package/dist/mcp/proxy.d.ts.map +1 -0
  479. package/dist/mcp/proxy.js +672 -0
  480. package/dist/mcp/proxy.js.map +1 -0
  481. package/dist/mcp/query-pool.d.ts +108 -0
  482. package/dist/mcp/query-pool.d.ts.map +1 -0
  483. package/dist/mcp/query-pool.js +315 -0
  484. package/dist/mcp/query-pool.js.map +1 -0
  485. package/dist/mcp/query-worker.d.ts +24 -0
  486. package/dist/mcp/query-worker.d.ts.map +1 -0
  487. package/dist/mcp/query-worker.js +87 -0
  488. package/dist/mcp/query-worker.js.map +1 -0
  489. package/dist/mcp/server-instructions.d.ts +34 -0
  490. package/dist/mcp/server-instructions.d.ts.map +1 -0
  491. package/dist/mcp/server-instructions.js +113 -0
  492. package/dist/mcp/server-instructions.js.map +1 -0
  493. package/dist/mcp/session.d.ts +109 -0
  494. package/dist/mcp/session.d.ts.map +1 -0
  495. package/dist/mcp/session.js +380 -0
  496. package/dist/mcp/session.js.map +1 -0
  497. package/dist/mcp/startup-handshake.d.ts +44 -0
  498. package/dist/mcp/startup-handshake.d.ts.map +1 -0
  499. package/dist/mcp/startup-handshake.js +73 -0
  500. package/dist/mcp/startup-handshake.js.map +1 -0
  501. package/dist/mcp/stdin-teardown.d.ts +27 -0
  502. package/dist/mcp/stdin-teardown.d.ts.map +1 -0
  503. package/dist/mcp/stdin-teardown.js +49 -0
  504. package/dist/mcp/stdin-teardown.js.map +1 -0
  505. package/dist/mcp/tools.d.ts +936 -0
  506. package/dist/mcp/tools.d.ts.map +1 -0
  507. package/dist/mcp/tools.js +6611 -0
  508. package/dist/mcp/tools.js.map +1 -0
  509. package/dist/mcp/transport.d.ts +188 -0
  510. package/dist/mcp/transport.d.ts.map +1 -0
  511. package/dist/mcp/transport.js +377 -0
  512. package/dist/mcp/transport.js.map +1 -0
  513. package/dist/mcp/version.d.ts +19 -0
  514. package/dist/mcp/version.d.ts.map +1 -0
  515. package/dist/mcp/version.js +71 -0
  516. package/dist/mcp/version.js.map +1 -0
  517. package/dist/mcp/writer-lock.d.ts +47 -0
  518. package/dist/mcp/writer-lock.d.ts.map +1 -0
  519. package/dist/mcp/writer-lock.js +218 -0
  520. package/dist/mcp/writer-lock.js.map +1 -0
  521. package/dist/project-config.d.ts +117 -0
  522. package/dist/project-config.d.ts.map +1 -0
  523. package/dist/project-config.js +409 -0
  524. package/dist/project-config.js.map +1 -0
  525. package/dist/resolution/alias-binding.d.ts +56 -0
  526. package/dist/resolution/alias-binding.d.ts.map +1 -0
  527. package/dist/resolution/alias-binding.js +118 -0
  528. package/dist/resolution/alias-binding.js.map +1 -0
  529. package/dist/resolution/c-fnptr-synthesizer.d.ts +6 -0
  530. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -0
  531. package/dist/resolution/c-fnptr-synthesizer.js +1506 -0
  532. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -0
  533. package/dist/resolution/callback-synthesizer.d.ts +78 -0
  534. package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
  535. package/dist/resolution/callback-synthesizer.js +4105 -0
  536. package/dist/resolution/callback-synthesizer.js.map +1 -0
  537. package/dist/resolution/cooperative-yield.d.ts +40 -0
  538. package/dist/resolution/cooperative-yield.d.ts.map +1 -0
  539. package/dist/resolution/cooperative-yield.js +44 -0
  540. package/dist/resolution/cooperative-yield.js.map +1 -0
  541. package/dist/resolution/expo-router-synthesizer.d.ts +32 -0
  542. package/dist/resolution/expo-router-synthesizer.d.ts.map +1 -0
  543. package/dist/resolution/expo-router-synthesizer.js +189 -0
  544. package/dist/resolution/expo-router-synthesizer.js.map +1 -0
  545. package/dist/resolution/frameworks/astro.d.ts +9 -0
  546. package/dist/resolution/frameworks/astro.d.ts.map +1 -0
  547. package/dist/resolution/frameworks/astro.js +169 -0
  548. package/dist/resolution/frameworks/astro.js.map +1 -0
  549. package/dist/resolution/frameworks/cargo-workspace.d.ts +18 -0
  550. package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
  551. package/dist/resolution/frameworks/cargo-workspace.js +225 -0
  552. package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
  553. package/dist/resolution/frameworks/cics.d.ts +20 -0
  554. package/dist/resolution/frameworks/cics.d.ts.map +1 -0
  555. package/dist/resolution/frameworks/cics.js +90 -0
  556. package/dist/resolution/frameworks/cics.js.map +1 -0
  557. package/dist/resolution/frameworks/csharp.d.ts +8 -0
  558. package/dist/resolution/frameworks/csharp.d.ts.map +1 -0
  559. package/dist/resolution/frameworks/csharp.js +335 -0
  560. package/dist/resolution/frameworks/csharp.js.map +1 -0
  561. package/dist/resolution/frameworks/drupal.d.ts +51 -0
  562. package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
  563. package/dist/resolution/frameworks/drupal.js +367 -0
  564. package/dist/resolution/frameworks/drupal.js.map +1 -0
  565. package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
  566. package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
  567. package/dist/resolution/frameworks/expo-modules.js +148 -0
  568. package/dist/resolution/frameworks/expo-modules.js.map +1 -0
  569. package/dist/resolution/frameworks/expo-router.d.ts +189 -0
  570. package/dist/resolution/frameworks/expo-router.d.ts.map +1 -0
  571. package/dist/resolution/frameworks/expo-router.js +785 -0
  572. package/dist/resolution/frameworks/expo-router.js.map +1 -0
  573. package/dist/resolution/frameworks/express.d.ts +8 -0
  574. package/dist/resolution/frameworks/express.d.ts.map +1 -0
  575. package/dist/resolution/frameworks/express.js +540 -0
  576. package/dist/resolution/frameworks/express.js.map +1 -0
  577. package/dist/resolution/frameworks/fabric.d.ts +3 -0
  578. package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
  579. package/dist/resolution/frameworks/fabric.js +354 -0
  580. package/dist/resolution/frameworks/fabric.js.map +1 -0
  581. package/dist/resolution/frameworks/go.d.ts +8 -0
  582. package/dist/resolution/frameworks/go.d.ts.map +1 -0
  583. package/dist/resolution/frameworks/go.js +184 -0
  584. package/dist/resolution/frameworks/go.js.map +1 -0
  585. package/dist/resolution/frameworks/goframe.d.ts +41 -0
  586. package/dist/resolution/frameworks/goframe.d.ts.map +1 -0
  587. package/dist/resolution/frameworks/goframe.js +112 -0
  588. package/dist/resolution/frameworks/goframe.js.map +1 -0
  589. package/dist/resolution/frameworks/index.d.ts +55 -0
  590. package/dist/resolution/frameworks/index.d.ts.map +1 -0
  591. package/dist/resolution/frameworks/index.js +203 -0
  592. package/dist/resolution/frameworks/index.js.map +1 -0
  593. package/dist/resolution/frameworks/java.d.ts +8 -0
  594. package/dist/resolution/frameworks/java.d.ts.map +1 -0
  595. package/dist/resolution/frameworks/java.js +539 -0
  596. package/dist/resolution/frameworks/java.js.map +1 -0
  597. package/dist/resolution/frameworks/laravel.d.ts +13 -0
  598. package/dist/resolution/frameworks/laravel.d.ts.map +1 -0
  599. package/dist/resolution/frameworks/laravel.js +257 -0
  600. package/dist/resolution/frameworks/laravel.js.map +1 -0
  601. package/dist/resolution/frameworks/nestjs.d.ts +26 -0
  602. package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
  603. package/dist/resolution/frameworks/nestjs.js +690 -0
  604. package/dist/resolution/frameworks/nestjs.js.map +1 -0
  605. package/dist/resolution/frameworks/nextjs.d.ts +76 -0
  606. package/dist/resolution/frameworks/nextjs.d.ts.map +1 -0
  607. package/dist/resolution/frameworks/nextjs.js +328 -0
  608. package/dist/resolution/frameworks/nextjs.js.map +1 -0
  609. package/dist/resolution/frameworks/object-literal.d.ts +32 -0
  610. package/dist/resolution/frameworks/object-literal.d.ts.map +1 -0
  611. package/dist/resolution/frameworks/object-literal.js +139 -0
  612. package/dist/resolution/frameworks/object-literal.js.map +1 -0
  613. package/dist/resolution/frameworks/package-deps.d.ts +14 -0
  614. package/dist/resolution/frameworks/package-deps.d.ts.map +1 -0
  615. package/dist/resolution/frameworks/package-deps.js +78 -0
  616. package/dist/resolution/frameworks/package-deps.js.map +1 -0
  617. package/dist/resolution/frameworks/play.d.ts +19 -0
  618. package/dist/resolution/frameworks/play.d.ts.map +1 -0
  619. package/dist/resolution/frameworks/play.js +111 -0
  620. package/dist/resolution/frameworks/play.js.map +1 -0
  621. package/dist/resolution/frameworks/python.d.ts +10 -0
  622. package/dist/resolution/frameworks/python.d.ts.map +1 -0
  623. package/dist/resolution/frameworks/python.js +566 -0
  624. package/dist/resolution/frameworks/python.js.map +1 -0
  625. package/dist/resolution/frameworks/react-native.d.ts +29 -0
  626. package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
  627. package/dist/resolution/frameworks/react-native.js +549 -0
  628. package/dist/resolution/frameworks/react-native.js.map +1 -0
  629. package/dist/resolution/frameworks/react-router.d.ts +46 -0
  630. package/dist/resolution/frameworks/react-router.d.ts.map +1 -0
  631. package/dist/resolution/frameworks/react-router.js +187 -0
  632. package/dist/resolution/frameworks/react-router.js.map +1 -0
  633. package/dist/resolution/frameworks/react.d.ts +9 -0
  634. package/dist/resolution/frameworks/react.d.ts.map +1 -0
  635. package/dist/resolution/frameworks/react.js +257 -0
  636. package/dist/resolution/frameworks/react.js.map +1 -0
  637. package/dist/resolution/frameworks/ruby.d.ts +8 -0
  638. package/dist/resolution/frameworks/ruby.d.ts.map +1 -0
  639. package/dist/resolution/frameworks/ruby.js +302 -0
  640. package/dist/resolution/frameworks/ruby.js.map +1 -0
  641. package/dist/resolution/frameworks/rust.d.ts +8 -0
  642. package/dist/resolution/frameworks/rust.d.ts.map +1 -0
  643. package/dist/resolution/frameworks/rust.js +304 -0
  644. package/dist/resolution/frameworks/rust.js.map +1 -0
  645. package/dist/resolution/frameworks/svelte.d.ts +9 -0
  646. package/dist/resolution/frameworks/svelte.d.ts.map +1 -0
  647. package/dist/resolution/frameworks/svelte.js +258 -0
  648. package/dist/resolution/frameworks/svelte.js.map +1 -0
  649. package/dist/resolution/frameworks/sveltekit-router.d.ts +36 -0
  650. package/dist/resolution/frameworks/sveltekit-router.d.ts.map +1 -0
  651. package/dist/resolution/frameworks/sveltekit-router.js +156 -0
  652. package/dist/resolution/frameworks/sveltekit-router.js.map +1 -0
  653. package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
  654. package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
  655. package/dist/resolution/frameworks/swift-objc.js +252 -0
  656. package/dist/resolution/frameworks/swift-objc.js.map +1 -0
  657. package/dist/resolution/frameworks/swift.d.ts +10 -0
  658. package/dist/resolution/frameworks/swift.d.ts.map +1 -0
  659. package/dist/resolution/frameworks/swift.js +410 -0
  660. package/dist/resolution/frameworks/swift.js.map +1 -0
  661. package/dist/resolution/frameworks/tanstack-router.d.ts +84 -0
  662. package/dist/resolution/frameworks/tanstack-router.d.ts.map +1 -0
  663. package/dist/resolution/frameworks/tanstack-router.js +437 -0
  664. package/dist/resolution/frameworks/tanstack-router.js.map +1 -0
  665. package/dist/resolution/frameworks/terraform.d.ts +38 -0
  666. package/dist/resolution/frameworks/terraform.d.ts.map +1 -0
  667. package/dist/resolution/frameworks/terraform.js +277 -0
  668. package/dist/resolution/frameworks/terraform.js.map +1 -0
  669. package/dist/resolution/frameworks/vue-router.d.ts +82 -0
  670. package/dist/resolution/frameworks/vue-router.d.ts.map +1 -0
  671. package/dist/resolution/frameworks/vue-router.js +377 -0
  672. package/dist/resolution/frameworks/vue-router.js.map +1 -0
  673. package/dist/resolution/frameworks/vue.d.ts +9 -0
  674. package/dist/resolution/frameworks/vue.d.ts.map +1 -0
  675. package/dist/resolution/frameworks/vue.js +303 -0
  676. package/dist/resolution/frameworks/vue.js.map +1 -0
  677. package/dist/resolution/go-module.d.ts +26 -0
  678. package/dist/resolution/go-module.d.ts.map +1 -0
  679. package/dist/resolution/go-module.js +78 -0
  680. package/dist/resolution/go-module.js.map +1 -0
  681. package/dist/resolution/goframe-synthesizer.d.ts +29 -0
  682. package/dist/resolution/goframe-synthesizer.d.ts.map +1 -0
  683. package/dist/resolution/goframe-synthesizer.js +163 -0
  684. package/dist/resolution/goframe-synthesizer.js.map +1 -0
  685. package/dist/resolution/import-resolver.d.ts +122 -0
  686. package/dist/resolution/import-resolver.d.ts.map +1 -0
  687. package/dist/resolution/import-resolver.js +2490 -0
  688. package/dist/resolution/import-resolver.js.map +1 -0
  689. package/dist/resolution/index.d.ts +402 -0
  690. package/dist/resolution/index.d.ts.map +1 -0
  691. package/dist/resolution/index.js +2581 -0
  692. package/dist/resolution/index.js.map +1 -0
  693. package/dist/resolution/js-builtins.d.ts +11 -0
  694. package/dist/resolution/js-builtins.d.ts.map +1 -0
  695. package/dist/resolution/js-builtins.js +23 -0
  696. package/dist/resolution/js-builtins.js.map +1 -0
  697. package/dist/resolution/lru-cache.d.ts +24 -0
  698. package/dist/resolution/lru-cache.d.ts.map +1 -0
  699. package/dist/resolution/lru-cache.js +62 -0
  700. package/dist/resolution/lru-cache.js.map +1 -0
  701. package/dist/resolution/memory-budget.d.ts +48 -0
  702. package/dist/resolution/memory-budget.d.ts.map +1 -0
  703. package/dist/resolution/memory-budget.js +162 -0
  704. package/dist/resolution/memory-budget.js.map +1 -0
  705. package/dist/resolution/name-matcher.d.ts +196 -0
  706. package/dist/resolution/name-matcher.d.ts.map +1 -0
  707. package/dist/resolution/name-matcher.js +3484 -0
  708. package/dist/resolution/name-matcher.js.map +1 -0
  709. package/dist/resolution/next-router-synthesizer.d.ts +27 -0
  710. package/dist/resolution/next-router-synthesizer.d.ts.map +1 -0
  711. package/dist/resolution/next-router-synthesizer.js +113 -0
  712. package/dist/resolution/next-router-synthesizer.js.map +1 -0
  713. package/dist/resolution/path-aliases.d.ts +70 -0
  714. package/dist/resolution/path-aliases.d.ts.map +1 -0
  715. package/dist/resolution/path-aliases.js +346 -0
  716. package/dist/resolution/path-aliases.js.map +1 -0
  717. package/dist/resolution/react-router-synthesizer.d.ts +33 -0
  718. package/dist/resolution/react-router-synthesizer.d.ts.map +1 -0
  719. package/dist/resolution/react-router-synthesizer.js +126 -0
  720. package/dist/resolution/react-router-synthesizer.js.map +1 -0
  721. package/dist/resolution/resolver-pool.d.ts +106 -0
  722. package/dist/resolution/resolver-pool.d.ts.map +1 -0
  723. package/dist/resolution/resolver-pool.js +344 -0
  724. package/dist/resolution/resolver-pool.js.map +1 -0
  725. package/dist/resolution/resolver-worker.d.ts +17 -0
  726. package/dist/resolution/resolver-worker.d.ts.map +1 -0
  727. package/dist/resolution/resolver-worker.js +141 -0
  728. package/dist/resolution/resolver-worker.js.map +1 -0
  729. package/dist/resolution/strip-comments.d.ts +33 -0
  730. package/dist/resolution/strip-comments.d.ts.map +1 -0
  731. package/dist/resolution/strip-comments.js +550 -0
  732. package/dist/resolution/strip-comments.js.map +1 -0
  733. package/dist/resolution/sveltekit-synthesizer.d.ts +58 -0
  734. package/dist/resolution/sveltekit-synthesizer.d.ts.map +1 -0
  735. package/dist/resolution/sveltekit-synthesizer.js +173 -0
  736. package/dist/resolution/sveltekit-synthesizer.js.map +1 -0
  737. package/dist/resolution/swift-objc-bridge.d.ts +134 -0
  738. package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
  739. package/dist/resolution/swift-objc-bridge.js +256 -0
  740. package/dist/resolution/swift-objc-bridge.js.map +1 -0
  741. package/dist/resolution/synth-utils.d.ts +26 -0
  742. package/dist/resolution/synth-utils.d.ts.map +1 -0
  743. package/dist/resolution/synth-utils.js +75 -0
  744. package/dist/resolution/synth-utils.js.map +1 -0
  745. package/dist/resolution/tanstack-router-synthesizer.d.ts +31 -0
  746. package/dist/resolution/tanstack-router-synthesizer.d.ts.map +1 -0
  747. package/dist/resolution/tanstack-router-synthesizer.js +114 -0
  748. package/dist/resolution/tanstack-router-synthesizer.js.map +1 -0
  749. package/dist/resolution/tier-synthesizer.d.ts +48 -0
  750. package/dist/resolution/tier-synthesizer.d.ts.map +1 -0
  751. package/dist/resolution/tier-synthesizer.js +907 -0
  752. package/dist/resolution/tier-synthesizer.js.map +1 -0
  753. package/dist/resolution/types.d.ts +323 -0
  754. package/dist/resolution/types.d.ts.map +1 -0
  755. package/dist/resolution/types.js +58 -0
  756. package/dist/resolution/types.js.map +1 -0
  757. package/dist/resolution/vue-router-synthesizer.d.ts +30 -0
  758. package/dist/resolution/vue-router-synthesizer.d.ts.map +1 -0
  759. package/dist/resolution/vue-router-synthesizer.js +115 -0
  760. package/dist/resolution/vue-router-synthesizer.js.map +1 -0
  761. package/dist/resolution/workspace-packages.d.ts +58 -0
  762. package/dist/resolution/workspace-packages.d.ts.map +1 -0
  763. package/dist/resolution/workspace-packages.js +346 -0
  764. package/dist/resolution/workspace-packages.js.map +1 -0
  765. package/dist/search/identifier-segments.d.ts +70 -0
  766. package/dist/search/identifier-segments.d.ts.map +1 -0
  767. package/dist/search/identifier-segments.js +205 -0
  768. package/dist/search/identifier-segments.js.map +1 -0
  769. package/dist/search/query-parser.d.ts +57 -0
  770. package/dist/search/query-parser.d.ts.map +1 -0
  771. package/dist/search/query-parser.js +177 -0
  772. package/dist/search/query-parser.js.map +1 -0
  773. package/dist/search/query-paths.d.ts +57 -0
  774. package/dist/search/query-paths.d.ts.map +1 -0
  775. package/dist/search/query-paths.js +298 -0
  776. package/dist/search/query-paths.js.map +1 -0
  777. package/dist/search/query-utils.d.ts +102 -0
  778. package/dist/search/query-utils.d.ts.map +1 -0
  779. package/dist/search/query-utils.js +487 -0
  780. package/dist/search/query-utils.js.map +1 -0
  781. package/dist/sync/git-hooks.d.ts +45 -0
  782. package/dist/sync/git-hooks.d.ts.map +1 -0
  783. package/dist/sync/git-hooks.js +227 -0
  784. package/dist/sync/git-hooks.js.map +1 -0
  785. package/dist/sync/index.d.ts +19 -0
  786. package/dist/sync/index.d.ts.map +1 -0
  787. package/dist/sync/index.js +35 -0
  788. package/dist/sync/index.js.map +1 -0
  789. package/dist/sync/watch-policy.d.ts +48 -0
  790. package/dist/sync/watch-policy.d.ts.map +1 -0
  791. package/dist/sync/watch-policy.js +124 -0
  792. package/dist/sync/watch-policy.js.map +1 -0
  793. package/dist/sync/watcher.d.ts +402 -0
  794. package/dist/sync/watcher.d.ts.map +1 -0
  795. package/dist/sync/watcher.js +978 -0
  796. package/dist/sync/watcher.js.map +1 -0
  797. package/dist/sync/worktree.d.ts +63 -0
  798. package/dist/sync/worktree.d.ts.map +1 -0
  799. package/dist/sync/worktree.js +182 -0
  800. package/dist/sync/worktree.js.map +1 -0
  801. package/dist/telemetry/index.d.ts +145 -0
  802. package/dist/telemetry/index.d.ts.map +1 -0
  803. package/dist/telemetry/index.js +592 -0
  804. package/dist/telemetry/index.js.map +1 -0
  805. package/dist/types.d.ts +473 -0
  806. package/dist/types.d.ts.map +1 -0
  807. package/dist/types.js +118 -0
  808. package/dist/types.js.map +1 -0
  809. package/dist/ui/color.d.ts +21 -0
  810. package/dist/ui/color.d.ts.map +1 -0
  811. package/dist/ui/color.js +42 -0
  812. package/dist/ui/color.js.map +1 -0
  813. package/dist/ui/glyphs.d.ts +67 -0
  814. package/dist/ui/glyphs.d.ts.map +1 -0
  815. package/dist/ui/glyphs.js +125 -0
  816. package/dist/ui/glyphs.js.map +1 -0
  817. package/dist/ui/shimmer-progress.d.ts +11 -0
  818. package/dist/ui/shimmer-progress.d.ts.map +1 -0
  819. package/dist/ui/shimmer-progress.js +164 -0
  820. package/dist/ui/shimmer-progress.js.map +1 -0
  821. package/dist/ui/shimmer-worker.d.ts +2 -0
  822. package/dist/ui/shimmer-worker.d.ts.map +1 -0
  823. package/dist/ui/shimmer-worker.js +126 -0
  824. package/dist/ui/shimmer-worker.js.map +1 -0
  825. package/dist/ui/types.d.ts +15 -0
  826. package/dist/ui/types.d.ts.map +1 -0
  827. package/dist/ui/types.js +3 -0
  828. package/dist/ui/types.js.map +1 -0
  829. package/dist/ui-server/api/deadcode.d.ts +84 -0
  830. package/dist/ui-server/api/deadcode.d.ts.map +1 -0
  831. package/dist/ui-server/api/deadcode.js +136 -0
  832. package/dist/ui-server/api/deadcode.js.map +1 -0
  833. package/dist/ui-server/api/effects.d.ts +87 -0
  834. package/dist/ui-server/api/effects.d.ts.map +1 -0
  835. package/dist/ui-server/api/effects.js +499 -0
  836. package/dist/ui-server/api/effects.js.map +1 -0
  837. package/dist/ui-server/api/entrypoints.d.ts +86 -0
  838. package/dist/ui-server/api/entrypoints.d.ts.map +1 -0
  839. package/dist/ui-server/api/entrypoints.js +279 -0
  840. package/dist/ui-server/api/entrypoints.js.map +1 -0
  841. package/dist/ui-server/api/events.d.ts +183 -0
  842. package/dist/ui-server/api/events.d.ts.map +1 -0
  843. package/dist/ui-server/api/events.js +430 -0
  844. package/dist/ui-server/api/events.js.map +1 -0
  845. package/dist/ui-server/api/file.d.ts +66 -0
  846. package/dist/ui-server/api/file.d.ts.map +1 -0
  847. package/dist/ui-server/api/file.js +235 -0
  848. package/dist/ui-server/api/file.js.map +1 -0
  849. package/dist/ui-server/api/filecode.d.ts +126 -0
  850. package/dist/ui-server/api/filecode.d.ts.map +1 -0
  851. package/dist/ui-server/api/filecode.js +205 -0
  852. package/dist/ui-server/api/filecode.js.map +1 -0
  853. package/dist/ui-server/api/flow.d.ts +226 -0
  854. package/dist/ui-server/api/flow.d.ts.map +1 -0
  855. package/dist/ui-server/api/flow.js +611 -0
  856. package/dist/ui-server/api/flow.js.map +1 -0
  857. package/dist/ui-server/api/hierarchy.d.ts +81 -0
  858. package/dist/ui-server/api/hierarchy.d.ts.map +1 -0
  859. package/dist/ui-server/api/hierarchy.js +92 -0
  860. package/dist/ui-server/api/hierarchy.js.map +1 -0
  861. package/dist/ui-server/api/index.d.ts +90 -0
  862. package/dist/ui-server/api/index.d.ts.map +1 -0
  863. package/dist/ui-server/api/index.js +332 -0
  864. package/dist/ui-server/api/index.js.map +1 -0
  865. package/dist/ui-server/api/map.d.ts +238 -0
  866. package/dist/ui-server/api/map.d.ts.map +1 -0
  867. package/dist/ui-server/api/map.js +681 -0
  868. package/dist/ui-server/api/map.js.map +1 -0
  869. package/dist/ui-server/api/node.d.ts +81 -0
  870. package/dist/ui-server/api/node.d.ts.map +1 -0
  871. package/dist/ui-server/api/node.js +388 -0
  872. package/dist/ui-server/api/node.js.map +1 -0
  873. package/dist/ui-server/api/nodes.d.ts +25 -0
  874. package/dist/ui-server/api/nodes.d.ts.map +1 -0
  875. package/dist/ui-server/api/nodes.js +45 -0
  876. package/dist/ui-server/api/nodes.js.map +1 -0
  877. package/dist/ui-server/api/program.d.ts +139 -0
  878. package/dist/ui-server/api/program.d.ts.map +1 -0
  879. package/dist/ui-server/api/program.js +315 -0
  880. package/dist/ui-server/api/program.js.map +1 -0
  881. package/dist/ui-server/api/respond.d.ts +76 -0
  882. package/dist/ui-server/api/respond.d.ts.map +1 -0
  883. package/dist/ui-server/api/respond.js +186 -0
  884. package/dist/ui-server/api/respond.js.map +1 -0
  885. package/dist/ui-server/api/route-roots.d.ts +39 -0
  886. package/dist/ui-server/api/route-roots.d.ts.map +1 -0
  887. package/dist/ui-server/api/route-roots.js +96 -0
  888. package/dist/ui-server/api/route-roots.js.map +1 -0
  889. package/dist/ui-server/api/routes.d.ts +59 -0
  890. package/dist/ui-server/api/routes.d.ts.map +1 -0
  891. package/dist/ui-server/api/routes.js +112 -0
  892. package/dist/ui-server/api/routes.js.map +1 -0
  893. package/dist/ui-server/api/screens.d.ts +117 -0
  894. package/dist/ui-server/api/screens.d.ts.map +1 -0
  895. package/dist/ui-server/api/screens.js +611 -0
  896. package/dist/ui-server/api/screens.js.map +1 -0
  897. package/dist/ui-server/api/search.d.ts +29 -0
  898. package/dist/ui-server/api/search.d.ts.map +1 -0
  899. package/dist/ui-server/api/search.js +232 -0
  900. package/dist/ui-server/api/search.js.map +1 -0
  901. package/dist/ui-server/api/session.d.ts +52 -0
  902. package/dist/ui-server/api/session.d.ts.map +1 -0
  903. package/dist/ui-server/api/session.js +199 -0
  904. package/dist/ui-server/api/session.js.map +1 -0
  905. package/dist/ui-server/api/source.d.ts +200 -0
  906. package/dist/ui-server/api/source.d.ts.map +1 -0
  907. package/dist/ui-server/api/source.js +419 -0
  908. package/dist/ui-server/api/source.js.map +1 -0
  909. package/dist/ui-server/api/stats.d.ts +27 -0
  910. package/dist/ui-server/api/stats.d.ts.map +1 -0
  911. package/dist/ui-server/api/stats.js +164 -0
  912. package/dist/ui-server/api/stats.js.map +1 -0
  913. package/dist/ui-server/api/steps.d.ts +274 -0
  914. package/dist/ui-server/api/steps.d.ts.map +1 -0
  915. package/dist/ui-server/api/steps.js +1446 -0
  916. package/dist/ui-server/api/steps.js.map +1 -0
  917. package/dist/ui-server/api/trail-store.d.ts +142 -0
  918. package/dist/ui-server/api/trail-store.d.ts.map +1 -0
  919. package/dist/ui-server/api/trail-store.js +323 -0
  920. package/dist/ui-server/api/trail-store.js.map +1 -0
  921. package/dist/ui-server/api/trails.d.ts +163 -0
  922. package/dist/ui-server/api/trails.d.ts.map +1 -0
  923. package/dist/ui-server/api/trails.js +369 -0
  924. package/dist/ui-server/api/trails.js.map +1 -0
  925. package/dist/ui-server/api/when.d.ts +125 -0
  926. package/dist/ui-server/api/when.d.ts.map +1 -0
  927. package/dist/ui-server/api/when.js +251 -0
  928. package/dist/ui-server/api/when.js.map +1 -0
  929. package/dist/ui-server/api/wire.d.ts +179 -0
  930. package/dist/ui-server/api/wire.d.ts.map +1 -0
  931. package/dist/ui-server/api/wire.js +231 -0
  932. package/dist/ui-server/api/wire.js.map +1 -0
  933. package/dist/ui-server/assets.d.ts +40 -0
  934. package/dist/ui-server/assets.d.ts.map +1 -0
  935. package/dist/ui-server/assets.js +110 -0
  936. package/dist/ui-server/assets.js.map +1 -0
  937. package/dist/ui-server/constants.d.ts +32 -0
  938. package/dist/ui-server/constants.d.ts.map +1 -0
  939. package/dist/ui-server/constants.js +35 -0
  940. package/dist/ui-server/constants.js.map +1 -0
  941. package/dist/ui-server/highlight/index.d.ts +113 -0
  942. package/dist/ui-server/highlight/index.d.ts.map +1 -0
  943. package/dist/ui-server/highlight/index.js +307 -0
  944. package/dist/ui-server/highlight/index.js.map +1 -0
  945. package/dist/ui-server/highlight/languages.d.ts +36 -0
  946. package/dist/ui-server/highlight/languages.d.ts.map +1 -0
  947. package/dist/ui-server/highlight/languages.js +50 -0
  948. package/dist/ui-server/highlight/languages.js.map +1 -0
  949. package/dist/ui-server/index.d.ts +92 -0
  950. package/dist/ui-server/index.d.ts.map +1 -0
  951. package/dist/ui-server/index.js +399 -0
  952. package/dist/ui-server/index.js.map +1 -0
  953. package/dist/ui-server/open-browser.d.ts +31 -0
  954. package/dist/ui-server/open-browser.d.ts.map +1 -0
  955. package/dist/ui-server/open-browser.js +79 -0
  956. package/dist/ui-server/open-browser.js.map +1 -0
  957. package/dist/ui-server/security.d.ts +127 -0
  958. package/dist/ui-server/security.d.ts.map +1 -0
  959. package/dist/ui-server/security.js +332 -0
  960. package/dist/ui-server/security.js.map +1 -0
  961. package/dist/ui-server/static.d.ts +45 -0
  962. package/dist/ui-server/static.d.ts.map +1 -0
  963. package/dist/ui-server/static.js +165 -0
  964. package/dist/ui-server/static.js.map +1 -0
  965. package/dist/upgrade/index.d.ts +164 -0
  966. package/dist/upgrade/index.d.ts.map +1 -0
  967. package/dist/upgrade/index.js +649 -0
  968. package/dist/upgrade/index.js.map +1 -0
  969. package/dist/upgrade/remove-binary.d.ts +87 -0
  970. package/dist/upgrade/remove-binary.d.ts.map +1 -0
  971. package/dist/upgrade/remove-binary.js +289 -0
  972. package/dist/upgrade/remove-binary.js.map +1 -0
  973. package/dist/upgrade/update-check.d.ts +92 -0
  974. package/dist/upgrade/update-check.d.ts.map +1 -0
  975. package/dist/upgrade/update-check.js +258 -0
  976. package/dist/upgrade/update-check.js.map +1 -0
  977. package/dist/utils.d.ts +238 -0
  978. package/dist/utils.d.ts.map +1 -0
  979. package/dist/utils.js +601 -0
  980. package/dist/utils.js.map +1 -0
  981. package/dist/viewer/assets/archivo-latin-ext-wght-normal-C4zznr8T.woff2 +0 -0
  982. package/dist/viewer/assets/archivo-latin-wght-normal-E0tuGl4L.woff2 +0 -0
  983. package/dist/viewer/assets/archivo-vietnamese-wght-normal-XAtsl5Q_.woff2 +0 -0
  984. package/dist/viewer/assets/ibm-plex-mono-cyrillic-400-italic-2syK4fUT.woff +0 -0
  985. package/dist/viewer/assets/ibm-plex-mono-cyrillic-400-italic-CBJ8pzag.woff2 +0 -0
  986. package/dist/viewer/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
  987. package/dist/viewer/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
  988. package/dist/viewer/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
  989. package/dist/viewer/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
  990. package/dist/viewer/assets/ibm-plex-mono-cyrillic-600-normal-CTOM6hUh.woff2 +0 -0
  991. package/dist/viewer/assets/ibm-plex-mono-cyrillic-600-normal-fLZuRloM.woff +0 -0
  992. package/dist/viewer/assets/ibm-plex-mono-cyrillic-ext-400-italic-B4oTjJdl.woff +0 -0
  993. package/dist/viewer/assets/ibm-plex-mono-cyrillic-ext-400-italic-CBjNughH.woff2 +0 -0
  994. package/dist/viewer/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
  995. package/dist/viewer/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
  996. package/dist/viewer/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
  997. package/dist/viewer/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
  998. package/dist/viewer/assets/ibm-plex-mono-cyrillic-ext-600-normal-9HEixskS.woff +0 -0
  999. package/dist/viewer/assets/ibm-plex-mono-cyrillic-ext-600-normal-V-xxqcpd.woff2 +0 -0
  1000. package/dist/viewer/assets/ibm-plex-mono-latin-400-italic-66oory27.woff +0 -0
  1001. package/dist/viewer/assets/ibm-plex-mono-latin-400-italic-BqAiT5Ww.woff2 +0 -0
  1002. package/dist/viewer/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  1003. package/dist/viewer/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  1004. package/dist/viewer/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  1005. package/dist/viewer/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  1006. package/dist/viewer/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
  1007. package/dist/viewer/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
  1008. package/dist/viewer/assets/ibm-plex-mono-latin-ext-400-italic-B7_fu1kp.woff2 +0 -0
  1009. package/dist/viewer/assets/ibm-plex-mono-latin-ext-400-italic-Bg0ZHwF4.woff +0 -0
  1010. package/dist/viewer/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
  1011. package/dist/viewer/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
  1012. package/dist/viewer/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
  1013. package/dist/viewer/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
  1014. package/dist/viewer/assets/ibm-plex-mono-latin-ext-600-normal-D38SheWl.woff2 +0 -0
  1015. package/dist/viewer/assets/ibm-plex-mono-latin-ext-600-normal-DmB0ttJJ.woff +0 -0
  1016. package/dist/viewer/assets/ibm-plex-mono-vietnamese-400-italic-D6eaYXMU.woff +0 -0
  1017. package/dist/viewer/assets/ibm-plex-mono-vietnamese-400-italic-DRuN92E5.woff2 +0 -0
  1018. package/dist/viewer/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
  1019. package/dist/viewer/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
  1020. package/dist/viewer/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
  1021. package/dist/viewer/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
  1022. package/dist/viewer/assets/ibm-plex-mono-vietnamese-600-normal-D2EvbN8M.woff2 +0 -0
  1023. package/dist/viewer/assets/ibm-plex-mono-vietnamese-600-normal-iLQfcSjf.woff +0 -0
  1024. package/dist/viewer/assets/index-2LG7iXtP.js +97 -0
  1025. package/dist/viewer/assets/index-AtMBttuU.css +1 -0
  1026. package/dist/viewer/index.html +16 -0
  1027. package/package.json +69 -0
  1028. package/scripts/add-lang/bench.sh +60 -0
  1029. package/scripts/add-lang/check-grammar.mjs +75 -0
  1030. package/scripts/add-lang/dump-ast.mjs +103 -0
  1031. package/scripts/add-lang/verify-extraction.mjs +70 -0
  1032. package/scripts/agent-eval/ab-adoption.sh +91 -0
  1033. package/scripts/agent-eval/ab-hook.sh +86 -0
  1034. package/scripts/agent-eval/ab-impl.sh +78 -0
  1035. package/scripts/agent-eval/ab-new-vs-baseline.sh +161 -0
  1036. package/scripts/agent-eval/ab-sufficiency.sh +78 -0
  1037. package/scripts/agent-eval/allocation-fixtures.json +344 -0
  1038. package/scripts/agent-eval/arms-F.sh +21 -0
  1039. package/scripts/agent-eval/arms-matrix.sh +37 -0
  1040. package/scripts/agent-eval/audit.sh +68 -0
  1041. package/scripts/agent-eval/bench-readme.sh +48 -0
  1042. package/scripts/agent-eval/bench-why-repo.sh +22 -0
  1043. package/scripts/agent-eval/block-read-hook.sh +19 -0
  1044. package/scripts/agent-eval/compare-arms.mjs +209 -0
  1045. package/scripts/agent-eval/diff-index-drift.mjs +102 -0
  1046. package/scripts/agent-eval/hook-settings.json +15 -0
  1047. package/scripts/agent-eval/itrun.sh +120 -0
  1048. package/scripts/agent-eval/no-cli-shim.sh +96 -0
  1049. package/scripts/agent-eval/offload-eval-3arm.sh +72 -0
  1050. package/scripts/agent-eval/offload-eval-cost.mjs +133 -0
  1051. package/scripts/agent-eval/offload-eval-effort.mjs +108 -0
  1052. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -0
  1053. package/scripts/agent-eval/offload-eval-frontload.sh +47 -0
  1054. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -0
  1055. package/scripts/agent-eval/offload-eval-hook.mjs +84 -0
  1056. package/scripts/agent-eval/offload-eval-judge.mjs +103 -0
  1057. package/scripts/agent-eval/offload-eval-matrix.sh +20 -0
  1058. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -0
  1059. package/scripts/agent-eval/offload-eval-refs1.sh +50 -0
  1060. package/scripts/agent-eval/offload-eval-setup.sh +24 -0
  1061. package/scripts/agent-eval/offload-eval-styles.sh +72 -0
  1062. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -0
  1063. package/scripts/agent-eval/offload-eval.md +76 -0
  1064. package/scripts/agent-eval/parse-arms.mjs +116 -0
  1065. package/scripts/agent-eval/parse-bench-readme.mjs +238 -0
  1066. package/scripts/agent-eval/parse-run.mjs +1401 -0
  1067. package/scripts/agent-eval/parse-session.mjs +130 -0
  1068. package/scripts/agent-eval/probe-allocation.mjs +335 -0
  1069. package/scripts/agent-eval/probe-context.mjs +21 -0
  1070. package/scripts/agent-eval/probe-decl-only.mjs +198 -0
  1071. package/scripts/agent-eval/probe-explore.mjs +40 -0
  1072. package/scripts/agent-eval/probe-factory-closure.mjs +147 -0
  1073. package/scripts/agent-eval/probe-file-spend.mjs +195 -0
  1074. package/scripts/agent-eval/probe-named-symbol.mjs +163 -0
  1075. package/scripts/agent-eval/probe-node.mjs +20 -0
  1076. package/scripts/agent-eval/probe-suite-envelope.mjs +124 -0
  1077. package/scripts/agent-eval/probe-sweep.mjs +119 -0
  1078. package/scripts/agent-eval/probe-trace.mjs +20 -0
  1079. package/scripts/agent-eval/redirect-read-hook.sh +38 -0
  1080. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
  1081. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
  1082. package/scripts/agent-eval/run-agent.sh +34 -0
  1083. package/scripts/agent-eval/run-all.sh +149 -0
  1084. package/scripts/agent-eval/run-arms.sh +56 -0
  1085. package/scripts/agent-eval/seq-matrix.mjs +137 -0
  1086. package/scripts/benchmarks/measure-index.cjs +128 -0
  1087. package/scripts/benchmarks/observe-index.py +91 -0
  1088. package/scripts/build-bundle.sh +154 -0
  1089. package/scripts/build-kernel.sh +87 -0
  1090. package/scripts/check-ui-build.mjs +157 -0
  1091. package/scripts/check-ui-package.mjs +192 -0
  1092. package/scripts/clean-remaining.mjs +243 -0
  1093. package/scripts/count-codegraph.mjs +26 -0
  1094. package/scripts/deep-clean.mjs +66 -0
  1095. package/scripts/dump-graph.mjs +57 -0
  1096. package/scripts/extract-release-notes.mjs +130 -0
  1097. package/scripts/final-codegraph-cleanup.mjs +57 -0
  1098. package/scripts/go-rebrand.mjs +114 -0
  1099. package/scripts/kernel-parity.mjs +283 -0
  1100. package/scripts/local-install.sh +41 -0
  1101. package/scripts/npm-sdk.js +75 -0
  1102. package/scripts/npm-shim.js +279 -0
  1103. package/scripts/pack-npm.sh +123 -0
  1104. package/scripts/prepare-release.mjs +270 -0
  1105. package/scripts/rebrand.mjs +129 -0
  1106. package/scripts/sync-ui-version.mjs +47 -0
  1107. package/scripts/try-repo.sh +112 -0
@@ -0,0 +1,3208 @@
1
+ "use strict";
2
+ /**
3
+ * Extraction Orchestrator
4
+ *
5
+ * Coordinates file scanning, parsing, and database storage.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.loadAllGrammars = exports.loadGrammarsForLanguages = exports.initGrammars = exports.getSupportedLanguages = exports.isGrammarLoaded = exports.isLanguageSupported = exports.isSourceFile = exports.detectLanguage = exports.extractFromSource = exports.ExtractionOrchestrator = exports.INDEXED_AT_COMMIT_KEY = exports.ScopeIgnore = void 0;
45
+ exports.hashContent = hashContent;
46
+ exports.buildDefaultIgnore = buildDefaultIgnore;
47
+ exports.preloadLanguagesForFiles = preloadLanguagesForFiles;
48
+ exports.buildScopeIgnore = buildScopeIgnore;
49
+ exports.discoverEmbeddedRepoRoots = discoverEmbeddedRepoRoots;
50
+ exports.findUnindexedIgnoredRepos = findUnindexedIgnoredRepos;
51
+ exports.getGitChangedFiles = getGitChangedFiles;
52
+ exports.getGitHeadSha = getGitHeadSha;
53
+ exports.canTrustGitFastPath = canTrustGitFastPath;
54
+ exports.scanDirectory = scanDirectory;
55
+ exports.scanDirectoryAsync = scanDirectoryAsync;
56
+ const fs = __importStar(require("fs"));
57
+ const fsp = __importStar(require("fs/promises"));
58
+ const path = __importStar(require("path"));
59
+ const os = __importStar(require("os"));
60
+ const crypto = __importStar(require("crypto"));
61
+ const child_process_1 = require("child_process");
62
+ const tree_sitter_1 = require("./tree-sitter");
63
+ const parse_pool_1 = require("./parse-pool");
64
+ const store_writer_1 = require("./store-writer");
65
+ const kernel_1 = require("./kernel");
66
+ const generated_detection_1 = require("./generated-detection");
67
+ const grammars_1 = require("./grammars");
68
+ const project_config_1 = require("../project-config");
69
+ const directory_1 = require("../directory");
70
+ const errors_1 = require("../errors");
71
+ const utils_1 = require("../utils");
72
+ const ignore_1 = __importDefault(require("ignore"));
73
+ const frameworks_1 = require("../resolution/frameworks");
74
+ const cooperative_yield_1 = require("../resolution/cooperative-yield");
75
+ /**
76
+ * Number of files to read in parallel during indexing.
77
+ * File reads are I/O-bound; batching overlaps I/O wait with CPU parse work.
78
+ */
79
+ const FILE_IO_BATCH_SIZE = 10;
80
+ /**
81
+ * How many files the `sync()` reconcile processes between cooperative yields to
82
+ * the event loop. The reconcile runs two O(files) loops of synchronous `fs`
83
+ * calls (existsSync for removals, statSync for adds/mods); on a very large repo
84
+ * (~100k files) an un-yielded run wedges the main thread for minutes, which both
85
+ * trips the liveness watchdog (it SIGKILLs a process whose loop stops turning)
86
+ * and blocks the first MCP tool call behind the catch-up gate (issue #905).
87
+ * Yielding every N files keeps the socket, the watchdog heartbeat, and any
88
+ * concurrent read query responsive while the reconcile runs.
89
+ */
90
+ const SYNC_RECONCILE_YIELD_INTERVAL = 1000;
91
+ // PARSER_RESET_INTERVAL moved to parse-worker.ts (runs in worker thread)
92
+ /**
93
+ * Maximum time (ms) to wait for a single file to parse in the worker thread.
94
+ * If tree-sitter hangs or WASM runs out of memory, this prevents the entire
95
+ * indexing run from freezing. The worker is restarted after a (hard) timeout.
96
+ * Env-overridable via CODEGRAPH_PARSE_TIMEOUT_MS for slow storage (#1231).
97
+ */
98
+ const PARSE_TIMEOUT_MS = (0, parse_pool_1.resolveParseTimeoutMs)(process.env.CODEGRAPH_PARSE_TIMEOUT_MS);
99
+ /**
100
+ * Number of files to parse before recycling the worker thread.
101
+ * WASM linear memory can grow but NEVER shrink (WebAssembly spec limitation).
102
+ * The only way to reclaim tree-sitter's WASM heap is to destroy the entire
103
+ * V8 isolate by terminating the worker thread and spawning a fresh one.
104
+ * This interval balances memory usage against the cost of reloading grammars.
105
+ */
106
+ const WORKER_RECYCLE_INTERVAL = 250;
107
+ /**
108
+ * Calculate SHA256 hash of file contents
109
+ */
110
+ function hashContent(content) {
111
+ return crypto.createHash('sha256').update(content).digest('hex');
112
+ }
113
+ /**
114
+ * Skip files larger than this (bytes). Generated bundles, minified JS, and
115
+ * vendored blobs blow the WASM heap and the worker-recycle budget for no useful
116
+ * symbols. 1 MB covers essentially all hand-written source.
117
+ */
118
+ const MAX_FILE_SIZE = 1024 * 1024;
119
+ /**
120
+ * Directory names that are dependency, build, cache, or tooling output across the
121
+ * languages/frameworks Alpha Code Sense supports — curated from the canonical
122
+ * github/gitignore templates. Excluded by default so the graph reflects your code,
123
+ * not third-party noise, without requiring a `.gitignore` (issue #407). The
124
+ * exclusion applies uniformly (git or not, tracked or not); the only opt-in is an
125
+ * explicit `.gitignore` negation (e.g. `!vendor/`). First-party-prone or generic
126
+ * names (`packages`, `lib`, `app`, `bin`, `src`, `deps`, `env`, `tmp`, `storage`,
127
+ * `Library`) are deliberately NOT listed, to avoid ever hiding real source.
128
+ *
129
+ * Only dirs that actually contain *indexable source* (or are enormous) earn a slot
130
+ * — IDE/state dirs like `.idea`/`.vs` are omitted because Alpha Code Sense indexes only
131
+ * recognized source extensions, so they produce no symbols regardless.
132
+ */
133
+ const DEFAULT_IGNORE_DIRS = new Set([
134
+ // JS / TS — dependency directories
135
+ 'node_modules', 'bower_components', 'jspm_packages', 'web_modules',
136
+ '.yarn', '.pnpm-store',
137
+ // JS / TS — framework & bundler build / cache / deploy output
138
+ '.next', '.nuxt', '.svelte-kit', '.turbo', '.vite', '.parcel-cache', '.angular',
139
+ '.docusaurus', 'storybook-static', '.vinxi', '.nitro', 'out-tsc',
140
+ '.vercel', '.netlify', '.wrangler',
141
+ // Build output (common across ecosystems)
142
+ 'dist', 'build', 'out', '.output',
143
+ // Test / coverage
144
+ 'coverage', '.nyc_output',
145
+ // Python
146
+ '__pycache__', '__pypackages__', '.venv', 'venv', '.pixi', '.pdm-build',
147
+ '.mypy_cache', '.pytest_cache', '.ruff_cache', '.tox', '.nox', '.hypothesis',
148
+ '.ipynb_checkpoints', '.eggs',
149
+ // Rust / JVM (Maven, Gradle, Scala)
150
+ 'target', '.gradle',
151
+ // .NET
152
+ 'obj',
153
+ // Vendored deps (Go, PHP/Composer, Ruby/Bundler)
154
+ 'vendor',
155
+ // Swift / iOS
156
+ '.build', 'Pods', 'Carthage', 'DerivedData', '.swiftpm',
157
+ // Dart / Flutter
158
+ '.dart_tool', '.pub-cache',
159
+ // Native (Android NDK, C/C++ deps)
160
+ '.cxx', '.externalNativeBuild', 'vcpkg_installed',
161
+ // Scala tooling
162
+ '.bloop', '.metals',
163
+ // Lua / Luau (LuaRocks)
164
+ 'lua_modules', '.luarocks',
165
+ // Delphi / RAD Studio IDE backups (duplicate .pas source — would double-count)
166
+ '__history', '__recovery',
167
+ // Generic cache
168
+ '.cache',
169
+ ]);
170
+ /**
171
+ * Android resource directory types. A `res/` tree holds ONLY non-code resources —
172
+ * layouts, drawables, value bags (strings/colors/styles), menus, navigation
173
+ * graphs — split into one typed subdirectory per kind, optionally density/locale/
174
+ * version-qualified (`values-es`, `drawable-hdpi`, `layout-v21`, …). None of it
175
+ * yields an extractable code symbol, yet on an Android app it DOMINATES the tree
176
+ * (one report: 26k XML files = 97% of the project, 0 symbols), bloating the DB,
177
+ * slowing indexing, and skewing both the file count and `codegraph_explore`
178
+ * results (#1047). So these are excluded by default. The structure is
179
+ * self-identifying — a non-Android project has no `res/layout/` etc., so it's
180
+ * untouched — and the only XML that DOES produce symbols (MyBatis mappers) lives
181
+ * under `src/main/resources/`, never `res/`, so nothing useful is dropped.
182
+ * `res/raw/` is deliberately NOT here: it holds arbitrary bundled assets that can
183
+ * be code-ish (a `.sql` schema, a `.js`), so we leave it indexed. Override any of
184
+ * these with a `.gitignore` negation (e.g. `!res/values/`).
185
+ */
186
+ const ANDROID_RES_TYPES = [
187
+ 'anim', 'animator', 'color', 'drawable', 'font', 'layout',
188
+ 'menu', 'mipmap', 'navigation', 'transition', 'values', 'xml',
189
+ ];
190
+ /** Gitignore-style patterns for the `ignore` matcher: the dirs above plus a few globs. */
191
+ const DEFAULT_IGNORE_PATTERNS = [
192
+ ...Array.from(DEFAULT_IGNORE_DIRS, (d) => `${d}/`),
193
+ '*.egg-info/', // Python packaging metadata
194
+ 'cmake-build-*/', // CLion / CMake build trees
195
+ 'bazel-*/', // Bazel output symlink trees
196
+ // Android resource dirs at any depth, with their qualifier variants (#1047).
197
+ ...ANDROID_RES_TYPES.map((t) => `**/res/${t}*/`),
198
+ ];
199
+ /** True if `buf` decodes as strict UTF-8 (no invalid byte sequences). */
200
+ function isValidUtf8(buf) {
201
+ try {
202
+ new TextDecoder('utf-8', { fatal: true }).decode(buf);
203
+ return true;
204
+ }
205
+ catch {
206
+ return false;
207
+ }
208
+ }
209
+ /**
210
+ * Read a `.gitignore` and return patterns safe to hand to the `ignore` matcher —
211
+ * never throwing, even when the file isn't real gitignore text. Two failure
212
+ * modes, both seen in the wild (issue #682):
213
+ *
214
+ * - The file isn't valid UTF-8 — e.g. transparently encrypted in place by
215
+ * corporate DLP / endpoint-security software, leaving a UTF-16 header plus
216
+ * ciphertext. None of it is meaningful patterns, so the whole file is skipped.
217
+ * - The file is text but a single line can't be compiled to a regex by the
218
+ * `ignore` library — `\\[` and friends throw "Unterminated character class".
219
+ * Crucially the throw is LAZY (at match time, not `.add()`), so it would
220
+ * otherwise escape mid-scan. That one pattern is dropped; the rest are kept.
221
+ *
222
+ * Either way a warning that NAMES the file is logged (the reporter couldn't tell
223
+ * which `.gitignore` was at fault) and indexing continues instead of aborting.
224
+ * Returns '' when there's nothing usable.
225
+ */
226
+ function readGitignorePatterns(giPath) {
227
+ let buf;
228
+ try {
229
+ buf = fs.readFileSync(giPath);
230
+ }
231
+ catch {
232
+ return ''; // unreadable (permissions / race) — treat as absent
233
+ }
234
+ // A NUL byte never appears in real gitignore text, and a fatal UTF-8 decode
235
+ // catches the rest. Such a file isn't ignore patterns at all.
236
+ if (buf.includes(0) || !isValidUtf8(buf)) {
237
+ (0, errors_1.logWarn)('Ignoring a .gitignore that is not valid UTF-8 text — it may have been encrypted ' +
238
+ 'in place by endpoint-security software. Indexing continues without it.', { file: giPath });
239
+ return '';
240
+ }
241
+ const content = buf.toString('utf-8');
242
+ // Fast path: one `.ignores()` call forces the library to compile EVERY rule,
243
+ // so if it doesn't throw, the whole file is safe to use verbatim.
244
+ try {
245
+ (0, ignore_1.default)().add(content).ignores('.codegraph-probe');
246
+ return content;
247
+ }
248
+ catch {
249
+ // Fall through: a line is uncompilable — keep the good ones, drop the bad.
250
+ }
251
+ const kept = [];
252
+ let dropped = 0;
253
+ for (const line of content.split(/\r?\n/)) {
254
+ try {
255
+ (0, ignore_1.default)().add(line).ignores('.codegraph-probe');
256
+ kept.push(line);
257
+ }
258
+ catch {
259
+ dropped++;
260
+ }
261
+ }
262
+ if (dropped > 0) {
263
+ (0, errors_1.logWarn)(`Skipped ${dropped} unparseable pattern(s) in a .gitignore; the rest are applied.`, { file: giPath });
264
+ }
265
+ return kept.join('\n');
266
+ }
267
+ /**
268
+ * Resolve the repository GIT_DIR for `repoRoot` (a `.git` directory, or the
269
+ * target of a `.git` file pointer). Null when this isn't a git checkout.
270
+ */
271
+ function resolveGitDir(repoRoot) {
272
+ const gitPath = path.join(repoRoot, '.git');
273
+ let st;
274
+ try {
275
+ st = fs.statSync(gitPath);
276
+ }
277
+ catch {
278
+ return null;
279
+ }
280
+ if (st.isDirectory())
281
+ return gitPath;
282
+ if (!st.isFile())
283
+ return null;
284
+ try {
285
+ const raw = fs.readFileSync(gitPath, 'utf8').match(/^gitdir:\s*(.+)$/m)?.[1]?.trim();
286
+ if (!raw)
287
+ return null;
288
+ return path.isAbsolute(raw) ? path.normalize(raw) : path.resolve(repoRoot, raw);
289
+ }
290
+ catch {
291
+ return null;
292
+ }
293
+ }
294
+ /** Expand a leading `~/` the way git does for `core.excludesFile`. */
295
+ function expandUserPath(p) {
296
+ if (p === '~')
297
+ return os.homedir();
298
+ if (p.startsWith('~/'))
299
+ return path.join(os.homedir(), p.slice(2));
300
+ return p;
301
+ }
302
+ /**
303
+ * Root-relative exclude patterns from git sources that are NOT the root
304
+ * `.gitignore`: `.git/info/exclude` and `core.excludesFile`. Same semantics as
305
+ * the root `.gitignore`, so they merge into {@link buildDefaultIgnore}. Without
306
+ * these, the watcher / FS-walk scope silently diverged from
307
+ * `git ls-files --exclude-standard` (#1728).
308
+ */
309
+ function readGitExcludeExtraPatterns(rootDir) {
310
+ const chunks = [];
311
+ const gitDir = resolveGitDir(rootDir);
312
+ if (gitDir) {
313
+ const excludePath = path.join(gitDir, 'info', 'exclude');
314
+ if (fs.existsSync(excludePath)) {
315
+ const patterns = readGitignorePatterns(excludePath);
316
+ if (patterns)
317
+ chunks.push(patterns);
318
+ }
319
+ }
320
+ try {
321
+ const configured = (0, child_process_1.execFileSync)('git', ['-C', rootDir, 'config', '--get', 'core.excludesFile'], { encoding: 'utf8', timeout: 5_000, stdio: ['ignore', 'pipe', 'ignore'] }).trim();
322
+ if (configured) {
323
+ const abs = expandUserPath(configured);
324
+ if (fs.existsSync(abs)) {
325
+ const patterns = readGitignorePatterns(abs);
326
+ if (patterns)
327
+ chunks.push(patterns);
328
+ }
329
+ }
330
+ }
331
+ catch {
332
+ // No git, unset, or timeout — leave extras empty.
333
+ }
334
+ return chunks.join('\n');
335
+ }
336
+ /**
337
+ * Directories `git ls-files -o -i --exclude-standard --directory` reports as
338
+ * ignored-untracked. Seeded into {@link ScopeIgnore} so nested `.gitignore`
339
+ * effects (and any exclude-standard rule the flat matcher might miss) prune the
340
+ * watcher the same way the indexer skips them (#1728).
341
+ */
342
+ function listGitIgnoredDirectories(rootDir) {
343
+ try {
344
+ const out = (0, child_process_1.execFileSync)('git', ['-C', rootDir, 'ls-files', '-z', '-o', '-i', '--exclude-standard', '--directory'], {
345
+ encoding: 'utf8',
346
+ timeout: 60_000,
347
+ maxBuffer: 50 * 1024 * 1024,
348
+ stdio: ['ignore', 'pipe', 'ignore'],
349
+ });
350
+ const dirs = [];
351
+ for (const entry of out.split('\0')) {
352
+ if (!entry)
353
+ continue;
354
+ dirs.push(entry.endsWith('/') ? entry : `${entry}/`);
355
+ }
356
+ return dirs;
357
+ }
358
+ catch {
359
+ return [];
360
+ }
361
+ }
362
+ /**
363
+ * An `ignore` matcher seeded with the built-in defaults, merged with the project's
364
+ * root .gitignore so a negation there (e.g. `!vendor/`) overrides a default, plus
365
+ * git's other root-relative exclude files (`.git/info/exclude`, `core.excludesFile`)
366
+ * so watcher / FS-walk scope matches `git ls-files --exclude-standard` (#1728).
367
+ * Shared by both enumeration paths so behavior is identical with or without git —
368
+ * and so the defaults apply to tracked files too (committing a dependency dir
369
+ * doesn't make it project code; the explicit `.gitignore` negation is the only
370
+ * opt-in).
371
+ */
372
+ function buildDefaultIgnore(rootDir) {
373
+ const ig = (0, ignore_1.default)().add(DEFAULT_IGNORE_PATTERNS);
374
+ const rootGitignore = path.join(rootDir, '.gitignore');
375
+ if (fs.existsSync(rootGitignore))
376
+ ig.add(readGitignorePatterns(rootGitignore));
377
+ const extra = readGitExcludeExtraPatterns(rootDir);
378
+ if (extra)
379
+ ig.add(extra);
380
+ return ig;
381
+ }
382
+ /**
383
+ * Defaults-only ignore matcher (no root `.gitignore` merged). Used wherever the
384
+ * parent repo's own ignore rules must NOT apply — inside embedded child repos,
385
+ * whose gitignore semantics their own `git ls-files` already enforced (#514).
386
+ */
387
+ function defaultsOnlyIgnore() {
388
+ return (0, ignore_1.default)().add(DEFAULT_IGNORE_PATTERNS);
389
+ }
390
+ /**
391
+ * Matcher for the project's `codegraph.json` `includeIgnored` patterns — the
392
+ * explicit opt-in to index embedded git repos living inside gitignored
393
+ * directories (#622, #699). Returns `null` when the project opted in nothing,
394
+ * which is the zero-config DEFAULT: `.gitignore` is then fully respected and a
395
+ * gitignored directory (even one holding nested repos) is never walked or
396
+ * indexed (#970, #976). Built once per scan/sync/scope operation from the scan
397
+ * root and threaded down — never global, so multi-project daemons stay isolated.
398
+ */
399
+ function loadIncludeIgnoredMatcher(rootDir) {
400
+ const patterns = (0, project_config_1.loadIncludeIgnoredPatterns)(rootDir);
401
+ return patterns.length > 0 ? (0, ignore_1.default)().add(patterns) : null;
402
+ }
403
+ /**
404
+ * Matcher for the project's `codegraph.json` `exclude` patterns — paths to keep
405
+ * OUT of the index even when git-tracked, which `.gitignore` cannot do (#999).
406
+ * The escape hatch for a committed vendor/theme/SDK directory. Returns `null`
407
+ * when nothing is excluded (the zero-config default → no overhead). Matched
408
+ * against project-root-relative paths, so it applies uniformly across the whole
409
+ * workspace, including inside embedded repos (excluding `static/` means gone
410
+ * everywhere). Built once per scan/sync/scope operation from the scan root.
411
+ */
412
+ function loadExcludeMatcher(rootDir) {
413
+ const patterns = (0, project_config_1.loadExcludePatterns)(rootDir);
414
+ return patterns.length > 0 ? (0, ignore_1.default)().add(patterns) : null;
415
+ }
416
+ /**
417
+ * Matcher for the project's `codegraph.json` `include` patterns — first-party
418
+ * source to force INTO the index even when `.gitignore` drops it (the general
419
+ * whitelist `includeIgnored` never was — that one only revives *embedded git
420
+ * repos*). The case it exists for: a project under a second VCS (SVN/Perforce)
421
+ * `.gitignore`s its own real source so it stays out of Git, yet we still want it
422
+ * indexed. Returns `null` when nothing is force-included (the zero-config
423
+ * default → no overhead, no extra walk). Built once per scan/sync/scope
424
+ * operation from the scan root.
425
+ */
426
+ function loadIncludeMatcher(rootDir) {
427
+ const patterns = (0, project_config_1.loadIncludePatterns)(rootDir);
428
+ return patterns.length > 0 ? (0, ignore_1.default)().add(patterns) : null;
429
+ }
430
+ /** Glob metacharacters that end the static (literal) prefix of an `include` pattern. */
431
+ const GLOB_META = /[*?[\]{}!]/;
432
+ /**
433
+ * The static directory prefix of each `include` pattern — the literal leading
434
+ * path up to the first glob segment — trailing-slashed, used to (a) walk only
435
+ * the opted-in subtrees in `collectIncludedFiles` and (b) let `ScopeIgnore` keep
436
+ * the watcher descending toward them. `Tools/` stays `Tools/`; a recursive
437
+ * `Tools/**` glob yields `Tools/`; `src/local/file.ts` yields `src/local/` (the
438
+ * file's dir); a pattern that starts with a glob (like a leading `**`) yields
439
+ * `''`, meaning "no static root — walk the whole tree". Duplicates and roots
440
+ * nested under a broader root are collapsed so each subtree is walked once.
441
+ */
442
+ function includeStaticRoots(patterns) {
443
+ const roots = new Set();
444
+ for (const pattern of patterns) {
445
+ let p = pattern.replace(/^\/+/, '');
446
+ const trailingSlash = p.endsWith('/');
447
+ if (trailingSlash)
448
+ p = p.slice(0, -1);
449
+ const segs = p.split('/').filter(Boolean);
450
+ const lead = [];
451
+ for (const s of segs) {
452
+ if (GLOB_META.test(s))
453
+ break;
454
+ lead.push(s);
455
+ }
456
+ const hadWildcard = lead.length < segs.length;
457
+ // A wholly-literal pattern with no trailing slash names a file (or a dir we
458
+ // can't tell apart) — drop its last segment so we walk the containing dir
459
+ // and let the matcher pick the file. A trailing slash or a glob means the
460
+ // remaining `lead` is already the directory to walk.
461
+ if (!hadWildcard && !trailingSlash && lead.length > 0)
462
+ lead.pop();
463
+ if (lead.length === 0) {
464
+ roots.clear();
465
+ roots.add('');
466
+ return ['']; // a top-level glob forces a whole-tree walk; nothing narrower matters
467
+ }
468
+ roots.add(lead.join('/') + '/');
469
+ }
470
+ // Collapse roots nested under a broader one (e.g. drop `a/b/` if `a/` is present).
471
+ const all = [...roots];
472
+ return all.filter((r) => !all.some((other) => other !== r && r.startsWith(other)));
473
+ }
474
+ /**
475
+ * Actively discover the source files an `include` whitelist forces in. `git
476
+ * ls-files` never lists gitignored files, so a filtered filesystem walk of just
477
+ * the opted-in subtrees (`includeStaticRoots`) is the only way to find them.
478
+ * Returns project-root-relative, normalized source-file paths.
479
+ *
480
+ * A file is collected when it MATCHES `include`, is NOT hit by `exclude` (an
481
+ * explicit exclude always wins), is a recognized source file, and does not live
482
+ * under a built-in default-ignored dir (`node_modules`, `dist`, …), `.git`, or
483
+ * Alpha Code Sense's data dir — those are never resurfaced, mirroring `ScopeIgnore`.
484
+ * `.gitignore` is deliberately NOT consulted: overriding it is the whole point.
485
+ */
486
+ function collectIncludedFiles(rootDir, include, exclude, roots, overrides) {
487
+ const out = new Set();
488
+ const defaults = defaultsOnlyIgnore();
489
+ const visited = new Set();
490
+ const consider = (abs, rel, isDir) => {
491
+ if (isDir) {
492
+ if (defaults.ignores(rel + '/'))
493
+ return; // never node_modules/dist/… via include
494
+ // An explicit `exclude` always wins over `include`; prune the whole subtree
495
+ // here so a large excluded dir (a committed frontend's own vendored deps,
496
+ // build output, …) is never walked — the per-file guard below still catches
497
+ // anything a directory pattern doesn't, so this is a pure efficiency win.
498
+ if (exclude && exclude.ignores(rel + '/'))
499
+ return;
500
+ walk(abs);
501
+ }
502
+ else {
503
+ if (defaults.ignores(rel))
504
+ return;
505
+ if (!include.ignores(rel))
506
+ return;
507
+ if (exclude && exclude.ignores(rel))
508
+ return;
509
+ if (!(0, grammars_1.isSourceFile)(rel, overrides))
510
+ return;
511
+ out.add(rel);
512
+ }
513
+ };
514
+ function walk(absDir) {
515
+ let realDir;
516
+ try {
517
+ realDir = fs.realpathSync(absDir);
518
+ }
519
+ catch {
520
+ return;
521
+ }
522
+ if (visited.has(realDir))
523
+ return; // symlink-cycle guard
524
+ visited.add(realDir);
525
+ let entries;
526
+ try {
527
+ entries = fs.readdirSync(absDir, { withFileTypes: true });
528
+ }
529
+ catch {
530
+ return;
531
+ }
532
+ for (const entry of entries) {
533
+ if (entry.name === '.git' || (0, directory_1.isAlphaCsDataDir)(entry.name))
534
+ continue;
535
+ const abs = path.join(absDir, entry.name);
536
+ const rel = (0, utils_1.normalizePath)(path.relative(rootDir, abs));
537
+ if (!rel || rel.startsWith('..'))
538
+ continue;
539
+ if (entry.isSymbolicLink()) {
540
+ try {
541
+ const st = fs.statSync(fs.realpathSync(abs));
542
+ consider(abs, rel, st.isDirectory());
543
+ }
544
+ catch {
545
+ // broken symlink — skip
546
+ }
547
+ continue;
548
+ }
549
+ consider(abs, rel, entry.isDirectory());
550
+ }
551
+ }
552
+ for (const root of roots) {
553
+ walk(root === '' ? rootDir : path.join(rootDir, root));
554
+ }
555
+ return out;
556
+ }
557
+ /**
558
+ * The included source files (`codegraph.json` `include`) for a scan root, or an
559
+ * empty set when nothing is force-included. Centralizes loading the matcher,
560
+ * roots, exclude, and overrides so both enumeration paths (git and filesystem
561
+ * walk) add the same files.
562
+ */
563
+ function collectIncludedFilesForRoot(rootDir) {
564
+ const include = loadIncludeMatcher(rootDir);
565
+ if (!include)
566
+ return new Set();
567
+ const roots = includeStaticRoots((0, project_config_1.loadIncludePatterns)(rootDir));
568
+ return collectIncludedFiles(rootDir, include, loadExcludeMatcher(rootDir), roots, (0, project_config_1.loadExtensionOverrides)(rootDir));
569
+ }
570
+ /**
571
+ * `git ls-files --directory` collapses a wholly-untracked/ignored directory into
572
+ * one entry — and when the command's own cwd is such a directory (the indexed
573
+ * root is itself a git-ignored subdir of an enclosing repo), git emits the
574
+ * literal `./` meaning "this entire directory". That sentinel is not a real
575
+ * nested path: feeding it to the `ignore` matcher throws ("path should be a
576
+ * `path.relative()`d string, but got "./""), which used to abort `buildScopeIgnore`
577
+ * and so break the MCP daemon's watcher/auto-sync on connect; and joining it back
578
+ * onto `repoDir` would just re-point at the cwd. Drop it wherever we consume
579
+ * `--directory` output. (#936)
580
+ */
581
+ function isWholeCwdEntry(entry) {
582
+ return entry === './' || entry === '.' || entry === '';
583
+ }
584
+ /**
585
+ * List the gitignored DIRECTORIES of a repo (collapsed, trailing-slash form),
586
+ * relative to `repoDir`. These are invisible to every other `git ls-files` /
587
+ * `git status` mode — and in a multi-repo workspace they are exactly where the
588
+ * nested project repos live (a super-repo `.gitignore`s its child repos to keep
589
+ * `git status` quiet; that does not make them third-party code). (#514)
590
+ */
591
+ function listIgnoredDirs(repoDir) {
592
+ try {
593
+ const out = (0, child_process_1.execFileSync)('git', ['ls-files', '-z', '-o', '-i', '--exclude-standard', '--directory'], { cwd: repoDir, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
594
+ return out.split('\0').filter((e) => e.endsWith('/') && !isWholeCwdEntry(e));
595
+ }
596
+ catch {
597
+ return [];
598
+ }
599
+ }
600
+ /** Max directory depth searched below an ignored dir for nested `.git` roots. */
601
+ const EMBEDDED_REPO_SEARCH_DEPTH = 4;
602
+ /** Max directories examined per search — a huge ignored data dir must never stall a scan/sync. */
603
+ const EMBEDDED_REPO_SEARCH_ENTRIES = 2000;
604
+ /**
605
+ * Classify a directory's `.git` entry for embedded-repo discovery.
606
+ *
607
+ * - A `.git` **directory** is an embedded clone — distinct first-party code a
608
+ * super-repo merely hides from git; index it (#193, #514).
609
+ * - A `.git` **file** is a pointer (`gitdir: …`). A git **worktree** points into
610
+ * the host repo's own `.git/worktrees/<name>`, so it is a second working view
611
+ * of a repo Alpha Code Sense already indexes — indexing it just duplicates the whole
612
+ * graph N times; skip it (#848). A **submodule worktree** points into
613
+ * `.git/modules/<module>/worktrees/<name>` — same duplication, so skip it too
614
+ * (#945). A **submodule** checkout points into `.git/modules/<module>` (no
615
+ * `worktrees/` segment) and is distinct code, so index it as before.
616
+ *
617
+ * Returns `'none'` when there is no `.git` entry here.
618
+ */
619
+ function classifyGitDir(absDir) {
620
+ let st;
621
+ try {
622
+ st = fs.statSync(path.join(absDir, '.git'));
623
+ }
624
+ catch {
625
+ return 'none';
626
+ }
627
+ if (st.isDirectory())
628
+ return 'embedded';
629
+ if (!st.isFile())
630
+ return 'none';
631
+ try {
632
+ const gitdir = fs.readFileSync(path.join(absDir, '.git'), 'utf8').match(/^gitdir:\s*(.+)$/m)?.[1]?.trim();
633
+ // A worktree's gitdir lives under some repo's `.git/worktrees/<name>` —
634
+ // either the top-level repo's (`.git/worktrees/`) or, for a worktree of a
635
+ // submodule, that submodule's gitdir (`.git/modules/<module>/worktrees/`).
636
+ // The optional `modules/<module>` segment covers the submodule case (#945).
637
+ // Match both separators so a Windows-style pointer is recognized too.
638
+ if (gitdir && /(^|[\\/])\.git[\\/](modules[\\/][^\\/]+[\\/])?worktrees[\\/]/.test(gitdir))
639
+ return 'worktree';
640
+ }
641
+ catch {
642
+ // Unreadable `.git` pointer — fall back to the prior "index it" behavior.
643
+ }
644
+ return 'embedded';
645
+ }
646
+ /**
647
+ * Find git repositories nested under `absDir` (inclusive), shallow bounded BFS.
648
+ * Stops descending at each repo root found — contents belong to that repo's own
649
+ * enumeration. Skips default-ignored dirs (`node_modules` can contain `.git`
650
+ * from npm git-dependencies — that never makes it project code) and Alpha Code Sense
651
+ * data dirs. Depth- and entry-capped so a huge ignored tree can't stall the scan.
652
+ */
653
+ function findNestedGitRepos(absDir, relPrefix) {
654
+ const found = [];
655
+ const defaults = defaultsOnlyIgnore();
656
+ const queue = [
657
+ { abs: absDir, rel: relPrefix, depth: 0 },
658
+ ];
659
+ let examined = 0;
660
+ while (queue.length > 0) {
661
+ const { abs, rel, depth } = queue.shift();
662
+ if (++examined > EMBEDDED_REPO_SEARCH_ENTRIES) {
663
+ (0, errors_1.logDebug)('Embedded-repo search entry cap hit — deeper repos (if any) not discovered', { under: relPrefix });
664
+ break;
665
+ }
666
+ const cls = classifyGitDir(abs);
667
+ if (cls === 'worktree') {
668
+ continue; // a git worktree duplicates an already-indexed repo (#848) — skip
669
+ }
670
+ if (cls === 'embedded') {
671
+ found.push(rel);
672
+ continue; // its own git handles everything below
673
+ }
674
+ if (depth >= EMBEDDED_REPO_SEARCH_DEPTH)
675
+ continue;
676
+ let entries;
677
+ try {
678
+ entries = fs.readdirSync(abs, { withFileTypes: true });
679
+ }
680
+ catch {
681
+ continue;
682
+ }
683
+ for (const entry of entries) {
684
+ if (!entry.isDirectory())
685
+ continue;
686
+ if (entry.name === '.git' || (0, directory_1.isAlphaCsDataDir)(entry.name))
687
+ continue;
688
+ const childRel = rel + entry.name + '/';
689
+ if (defaults.ignores(childRel))
690
+ continue;
691
+ queue.push({ abs: path.join(abs, entry.name), rel: childRel, depth: depth + 1 });
692
+ }
693
+ }
694
+ return found;
695
+ }
696
+ /**
697
+ * Workspace-scope ignore matcher. Ordinary paths get the root's matcher
698
+ * (built-in defaults + root `.gitignore` + `.git/info/exclude` +
699
+ * `core.excludesFile`, plus directories `git ls-files --exclude-standard`
700
+ * reports as ignored); paths inside an EMBEDDED repo get that repo's own
701
+ * matcher — the parent's `.gitignore` hides a child repo from git, not from
702
+ * the index (#514). A directory path (trailing slash) that is an ANCESTOR of
703
+ * an embedded root is never ignored, so directory-pruning callers (the Linux
704
+ * per-directory watcher) still descend to reach the embedded repos.
705
+ *
706
+ * Shared by the indexer (scoped sync / skip checks) and the watcher so their
707
+ * scope cannot diverge from each other or from `git ls-files --exclude-standard`
708
+ * (#1728).
709
+ */
710
+ /**
711
+ * The grammars to preload for a file set.
712
+ *
713
+ * Path-only detection calls every `.h` file C, but parse-time detection reads
714
+ * the source and can reclassify it as C++ or Objective-C (`detectLanguage`
715
+ * with a `source` argument). Workers only ever get the grammars named here, so
716
+ * a header that turns out to be Objective-C in a project with no `.m` file
717
+ * found no parser and failed with `Failed to get parser for language: objc`
718
+ * (#1628). C++ was already covered; Objective-C was not.
719
+ */
720
+ function preloadLanguagesForFiles(files, overrides) {
721
+ const languages = [...new Set(files.map((f) => (0, grammars_1.detectLanguage)(f, undefined, overrides)))];
722
+ if (languages.includes('c')) {
723
+ for (const ambiguous of ['cpp', 'objc']) {
724
+ if (!languages.includes(ambiguous))
725
+ languages.push(ambiguous);
726
+ }
727
+ }
728
+ return languages;
729
+ }
730
+ class ScopeIgnore {
731
+ rootMatcher;
732
+ exclude;
733
+ include;
734
+ includeRoots;
735
+ embedded;
736
+ defaults = defaultsOnlyIgnore();
737
+ constructor(rootMatcher, embedded,
738
+ /**
739
+ * Project `codegraph.json` `exclude` patterns (#999), matched against the
740
+ * full root-relative path. Wins over everything else — an explicit user
741
+ * exclude applies even to tracked files and even inside embedded repos.
742
+ */
743
+ exclude = null,
744
+ /**
745
+ * Project `codegraph.json` `include` patterns — first-party source forced
746
+ * INTO the index despite `.gitignore`. When a path matches, it is NOT
747
+ * ignored (so the watcher watches it), overriding `.gitignore`/`rootMatcher`
748
+ * — but never `exclude` (checked first) and never a built-in default-ignored
749
+ * dir. `includeRoots` are the static prefixes so a gitignored ANCESTOR
750
+ * directory of an included subtree still isn't pruned by the directory
751
+ * walker/watcher.
752
+ */
753
+ include = null, includeRoots = []) {
754
+ this.rootMatcher = rootMatcher;
755
+ this.exclude = exclude;
756
+ this.include = include;
757
+ this.includeRoots = includeRoots;
758
+ // Longest root first so paths in nested embedded repos hit the innermost matcher.
759
+ this.embedded = [...embedded].sort((a, b) => b.root.length - a.root.length);
760
+ }
761
+ ignores(rel) {
762
+ // User `exclude` (#999) is checked first and against the full root-relative
763
+ // path: it must drop git-TRACKED paths (which `.gitignore` can't) and apply
764
+ // everywhere, including ancestors of embedded repos.
765
+ if (this.exclude && this.exclude.ignores(rel))
766
+ return true;
767
+ // User `include`: force first-party source in despite `.gitignore`. Never
768
+ // resurfaces a built-in default-ignored dir (node_modules/dist/…), so an
769
+ // include pattern can't accidentally pull in dependency/build trees.
770
+ if (this.include && !this.defaults.ignores(rel)) {
771
+ if (rel.endsWith('/')) {
772
+ // A directory on (or leading to) an included subtree must stay walkable
773
+ // so the watcher/walker descends to reach the forced-in files.
774
+ if (this.includeRoots.some((r) => r.startsWith(rel) || rel.startsWith(r)))
775
+ return false;
776
+ }
777
+ else if (this.include.ignores(rel)) {
778
+ return false;
779
+ }
780
+ }
781
+ for (const { root, matcher } of this.embedded) {
782
+ if (rel.startsWith(root)) {
783
+ const inner = rel.slice(root.length);
784
+ if (inner === '')
785
+ return false;
786
+ // Built-in defaults apply to the FULL path uniformly (#407) — an
787
+ // embedded repo inside node_modules (an npm git-dependency) must stay
788
+ // excluded even though its own rules wouldn't ignore its files.
789
+ return this.defaults.ignores(rel) || matcher.ignores(inner);
790
+ }
791
+ }
792
+ // Never prune a directory that leads to an embedded repo.
793
+ if (rel.endsWith('/') && this.embedded.some(({ root }) => root.startsWith(rel))) {
794
+ return false;
795
+ }
796
+ return this.rootMatcher.ignores(rel);
797
+ }
798
+ }
799
+ exports.ScopeIgnore = ScopeIgnore;
800
+ /**
801
+ * Build the workspace-scope matcher. When the caller already knows the
802
+ * embedded roots (the scanner discovers them during collection), pass them to
803
+ * skip rediscovery; otherwise they're discovered here (the watcher path).
804
+ */
805
+ function buildScopeIgnore(rootDir, embeddedRoots) {
806
+ const roots = embeddedRoots ? [...embeddedRoots] : discoverEmbeddedRepoRoots(rootDir);
807
+ const include = loadIncludeMatcher(rootDir);
808
+ // Root matcher already has defaults + root `.gitignore` + info/exclude +
809
+ // core.excludesFile. Seed ignored-untracked directories from git so nested
810
+ // `.gitignore` effects prune the watcher identically to the indexer (#1728).
811
+ const rootMatcher = buildDefaultIgnore(rootDir);
812
+ for (const dir of listGitIgnoredDirectories(rootDir)) {
813
+ rootMatcher.add(dir);
814
+ }
815
+ return new ScopeIgnore(rootMatcher, roots.map((root) => ({ root, matcher: buildDefaultIgnore(path.join(rootDir, root)) })), loadExcludeMatcher(rootDir), include, include ? includeStaticRoots((0, project_config_1.loadIncludePatterns)(rootDir)) : []);
816
+ }
817
+ /**
818
+ * Whether an embedded repo found as a tracked gitlink (mode 160000, #1031/#1033)
819
+ * must be SKIPPED rather than indexed. A gitlink is tracked, so `.gitignore`
820
+ * can't untrack it — but the discovery passes for it must still honor the same
821
+ * scope rules as every other path, or a gitignored reference/data dir full of
822
+ * `git add`ed clones gets pulled into the index against the user's stated intent
823
+ * (#1065). Two reasons to skip:
824
+ * 1. It sits in a built-in default-ignored location — an npm git-dependency
825
+ * under `node_modules` is never project code; not even an explicit opt-in
826
+ * revives it (matches `findIgnoredEmbeddedRepos`).
827
+ * 2. The parent repo's own `.gitignore` covers its path and the project did
828
+ * NOT opt that path in via `codegraph.json` `includeIgnored`. The gitignore
829
+ * rule is the user's stated intent to keep that path out of scope, exactly
830
+ * as for an UNtracked embedded repo — respect it by default, opt back in
831
+ * with `includeIgnored` (#514, #970, #976).
832
+ * `relDir` is repoDir-relative (trailing-slashed); `prefix` is repoDir's
833
+ * scan-root-relative path so the `includeIgnored` pattern is matched on the full
834
+ * scan-root-relative path. `defaults` is `defaultsOnlyIgnore()` and `repoIgnore`
835
+ * is `buildDefaultIgnore(repoDir)` (defaults + the repo's own `.gitignore`),
836
+ * both passed in so they're built once per repo level rather than per gitlink.
837
+ */
838
+ function gitlinkEmbeddedRepoSkipped(relDir, prefix, defaults, repoIgnore, includeIgnored) {
839
+ if (defaults.ignores(relDir))
840
+ return true; // default-ignored — never index, opt-in can't revive
841
+ if (!repoIgnore.ignores(relDir))
842
+ return false; // not ignored at all — index as before (#1031/#1033)
843
+ // Gitignored by the repo's own rules — skip unless the project opted it in.
844
+ return !includeIgnored?.ignores((0, utils_1.normalizePath)(prefix + relDir));
845
+ }
846
+ /**
847
+ * Standalone discovery of every embedded repo root under `rootDir` (relative,
848
+ * trailing-slashed) — the untracked kind (#193) always, and the gitignored kind
849
+ * (#514) only for directories the project opted in via `codegraph.json`
850
+ * `includeIgnored` (#622, #699); otherwise `.gitignore` is respected and they
851
+ * are not discovered (#970, #976). Recursive (an embedded repo can embed further
852
+ * repos). Returns [] for non-git roots: the filesystem walk handles nested repos
853
+ * there already.
854
+ */
855
+ function discoverEmbeddedRepoRoots(rootDir) {
856
+ try {
857
+ (0, child_process_1.execFileSync)('git', ['rev-parse', '--git-dir'], { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
858
+ }
859
+ catch {
860
+ return [];
861
+ }
862
+ const out = [];
863
+ const defaults = defaultsOnlyIgnore();
864
+ const includeIgnored = loadIncludeIgnoredMatcher(rootDir);
865
+ const visit = (repoAbs, prefix) => {
866
+ const candidates = [];
867
+ try {
868
+ const o = (0, child_process_1.execFileSync)('git', ['ls-files', '-z', '-o', '--exclude-standard', '--directory'], { cwd: repoAbs, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
869
+ for (const e of o.split('\0')) {
870
+ if (e.endsWith('/') && !isWholeCwdEntry(e) && !defaults.ignores(e)) {
871
+ candidates.push(...findNestedGitRepos(path.join(repoAbs, e), e));
872
+ }
873
+ }
874
+ }
875
+ catch { /* untracked listing failed — ignored-side discovery still runs */ }
876
+ // Unexpanded gitlinks (mode 160000) with a real checkout on disk — embedded
877
+ // repos `git add`ed without `.gitmodules`, or submodules not active here. The
878
+ // untracked listing above can't see them (they're tracked), so find them the
879
+ // same way collectGitFiles does, keeping watcher scope == indexer scope.
880
+ // (#1031, #1033)
881
+ try {
882
+ const staged = lsFilesStaged({ cwd: repoAbs, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
883
+ const repoIgnore = buildDefaultIgnore(repoAbs);
884
+ for (const entry of staged.split('\0')) {
885
+ if (!entry || entry.slice(0, 6) !== '160000')
886
+ continue;
887
+ const tab = entry.indexOf('\t');
888
+ if (tab === -1)
889
+ continue;
890
+ const rel = entry.slice(tab + 1);
891
+ const relDir = rel.endsWith('/') ? rel : rel + '/';
892
+ // A gitlink under a gitignored path is respected (not indexed) unless the
893
+ // project opted it in — same rule as the untracked-ignored kind (#1065).
894
+ if (gitlinkEmbeddedRepoSkipped(relDir, prefix, defaults, repoIgnore, includeIgnored))
895
+ continue;
896
+ if (classifyGitDir(path.join(repoAbs, rel)) === 'embedded')
897
+ candidates.push(relDir);
898
+ }
899
+ }
900
+ catch { /* staged listing failed — other discovery still runs */ }
901
+ candidates.push(...findIgnoredEmbeddedRepos(repoAbs, includeIgnored, prefix));
902
+ for (const rel of candidates) {
903
+ const full = (0, utils_1.normalizePath)(prefix + rel);
904
+ out.push(full);
905
+ visit(path.join(repoAbs, rel), full);
906
+ }
907
+ };
908
+ visit(rootDir, '');
909
+ return out;
910
+ }
911
+ /**
912
+ * Cap on how many skipped gitignored repos the CLI hint enumerates — a huge
913
+ * gitignored data dir full of clones must never turn the hint scan into a long
914
+ * walk. Enough to make the point; the caller says "+N more" past this.
915
+ */
916
+ const UNINDEXED_IGNORED_REPO_HINT_CAP = 100;
917
+ /**
918
+ * The INVERSE of the gitignored side of {@link discoverEmbeddedRepoRoots}:
919
+ * nested git repositories under a gitignored directory that the project has NOT
920
+ * opted into via `codegraph.json` `includeIgnored`. These are real repos the
921
+ * default `init`/`index` deliberately skips because `.gitignore` excludes them
922
+ * (#970, #976) — most visibly the "super-repo `.gitignore`s its child repos"
923
+ * layout (#1156), where `init` at the parent correctly indexes ~nothing while
924
+ * `init` inside each child works. The CLI uses this to turn that silent empty
925
+ * index into an actionable hint: it names the skipped repos and offers to opt
926
+ * them in. Paths are `rootDir`-relative and trailing-slashed (valid
927
+ * `includeIgnored` patterns as-is). Returns `[]` for a non-git root (a
928
+ * filesystem walk already descends into nested repos there), skips built-in
929
+ * default-ignored dirs (`node_modules`, …), and is bounded so it never stalls
930
+ * on a giant ignored tree.
931
+ */
932
+ function findUnindexedIgnoredRepos(rootDir) {
933
+ try {
934
+ (0, child_process_1.execFileSync)('git', ['rev-parse', '--git-dir'], { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
935
+ }
936
+ catch {
937
+ return [];
938
+ }
939
+ const defaults = defaultsOnlyIgnore();
940
+ const includeIgnored = loadIncludeIgnoredMatcher(rootDir);
941
+ const repos = [];
942
+ for (const dir of listIgnoredDirs(rootDir)) {
943
+ if (defaults.ignores(dir))
944
+ continue; // node_modules etc. — never project code
945
+ if (includeIgnored?.ignores((0, utils_1.normalizePath)(dir)))
946
+ continue; // already opted in — nothing to nag about
947
+ for (const repo of findNestedGitRepos(path.join(rootDir, dir), dir)) {
948
+ // Per-repo opt-in check, mirroring findIgnoredEmbeddedRepos: a child
949
+ // pattern (`repos/a/`) doesn't match the parent dir above but DOES
950
+ // cover this repo — it's indexed, so don't nag about it (#1295).
951
+ if (includeIgnored?.ignores((0, utils_1.normalizePath)(repo)))
952
+ continue;
953
+ repos.push(repo);
954
+ if (repos.length >= UNINDEXED_IGNORED_REPO_HINT_CAP)
955
+ return repos;
956
+ }
957
+ }
958
+ return repos;
959
+ }
960
+ /**
961
+ * Discover embedded repos hidden by `repoDir`'s OWN gitignore rules: for each
962
+ * gitignored directory, search for nested `.git` roots. Returns repo paths
963
+ * relative to `repoDir`, trailing-slashed.
964
+ *
965
+ * OPT-IN ONLY. Walking into a gitignored directory contradicts what every other
966
+ * tool (and Alpha Code Sense's own `git ls-files` foundation) does — `.gitignore`
967
+ * excludes. So this returns `[]` unless the project opted the directory in via
968
+ * `codegraph.json` `includeIgnored`; without that, a gitignored dir — including
969
+ * a huge reference/data dir full of nested clones — is left untouched (#970,
970
+ * #976). When opted in, it restores the super-repo-of-clones behavior (#622,
971
+ * #699). `prefix` is the scan-root-relative path of `repoDir`, so a pattern like
972
+ * `services/` opts that whole subtree in at any recursion depth. Built-in
973
+ * default excludes (`node_modules`, …) are always skipped.
974
+ */
975
+ function findIgnoredEmbeddedRepos(repoDir, includeIgnored, prefix) {
976
+ if (!includeIgnored)
977
+ return [];
978
+ const defaults = defaultsOnlyIgnore();
979
+ const repos = [];
980
+ for (const dir of listIgnoredDirs(repoDir)) {
981
+ if (defaults.ignores(dir))
982
+ continue;
983
+ const nested = findNestedGitRepos(path.join(repoDir, dir), dir);
984
+ if (includeIgnored.ignores((0, utils_1.normalizePath)(prefix + dir))) {
985
+ // The whole ignored dir is opted in — every nested repo under it counts.
986
+ repos.push(...nested);
987
+ }
988
+ else {
989
+ // A single gitignore rule often covers the PARENT of the opted-in
990
+ // repos: `.gitignore: /repos/` lists `repos/` as ONE ignored entry,
991
+ // while `includeIgnored: ["repos/a/"]` (the CLI hint's own suggested
992
+ // spelling) names the child — which never matches the parent path, so
993
+ // the opt-in silently did nothing (#1295). Match each nested repo
994
+ // root individually so both spellings work. The walk is bounded
995
+ // (depth/entry caps in findNestedGitRepos) and only runs when
996
+ // includeIgnored is configured at all.
997
+ repos.push(...nested.filter((r) => includeIgnored.ignores((0, utils_1.normalizePath)(prefix + r))));
998
+ }
999
+ }
1000
+ return repos;
1001
+ }
1002
+ /**
1003
+ * `git ls-files -z -s`, expanding submodules where git allows it.
1004
+ *
1005
+ * `--recurse-submodules` could not be combined with `-s` before git 2.36:
1006
+ * `builtin/ls-files.c` listed `show_stage` among the modes that die, and the
1007
+ * check is unconditional — it does not look at whether the repo actually has
1008
+ * submodules, so every call fails on older git. Ubuntu 22.04 LTS (2.34.1) and
1009
+ * Debian 11 (2.30.2) are both below that line.
1010
+ *
1011
+ * Letting the throw escape cost far more than submodule expansion: it unwound
1012
+ * the whole git-visible pass, so `includeIgnored`, gitlink recursion and the
1013
+ * `codegraph.json` include allowlist silently stopped applying and files went
1014
+ * missing from the index with no error (#1549). Retry without the flag instead
1015
+ * — `-s` is the part that matters here, since gitlink detection reads the mode
1016
+ * bits, and embedded repos are reached through the gitlink recursion anyway.
1017
+ */
1018
+ function lsFilesStaged(gitOpts) {
1019
+ try {
1020
+ return (0, child_process_1.execFileSync)('git', ['ls-files', '-z', '-s', '--recurse-submodules'], gitOpts);
1021
+ }
1022
+ catch {
1023
+ return (0, child_process_1.execFileSync)('git', ['ls-files', '-z', '-s'], gitOpts);
1024
+ }
1025
+ }
1026
+ /**
1027
+ * Collect git-visible files (tracked + untracked, .gitignore-respected) from the
1028
+ * git repository rooted at `repoDir`, adding each to `files` with `prefix`
1029
+ * prepended so paths stay relative to the original scan root.
1030
+ *
1031
+ * Recurses into embedded git repositories — nested repos that are NOT submodules
1032
+ * (independent clones living inside the workspace, common in CMake "super-repo"
1033
+ * layouts). The parent repo's `git ls-files` cannot see into them: tracked output
1034
+ * skips them entirely, and untracked output reports them only as an opaque
1035
+ * "subdir/" entry (trailing slash) rather than expanding their files. Each
1036
+ * embedded repo is its own git boundary, so we re-run `git ls-files` inside it.
1037
+ * (See issue #193.) GITIGNORED embedded repos are invisible even to that; they
1038
+ * are discovered separately via `findIgnoredEmbeddedRepos` (#514) but ONLY for
1039
+ * directories the project opted in through `codegraph.json` `includeIgnored`
1040
+ * (`includeIgnored` here, threaded from the scan root) — by default `.gitignore`
1041
+ * is respected and they stay out (#970, #976). Every embedded repo root (however
1042
+ * found) is recorded in `embeddedRoots` so callers can exempt its files from the
1043
+ * parent's own gitignore rules.
1044
+ */
1045
+ function collectGitFiles(repoDir, prefix, files, embeddedRoots, includeIgnored = null) {
1046
+ const gitOpts = { cwd: repoDir, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true };
1047
+ // Tracked files. --recurse-submodules pulls in files from active submodules,
1048
+ // which the index would otherwise represent only as a commit pointer.
1049
+ // Without this, monorepos using submodules index 0 files. (See issue #147.)
1050
+ // Note: --recurse-submodules only supports -c/--cached and --stage modes — it
1051
+ // can't be combined with -o, so untracked files are gathered separately below.
1052
+ //
1053
+ // We use --stage (-s) rather than -c so each entry carries its file mode. That
1054
+ // lets us spot gitlink entries (mode 160000) that --recurse-submodules did NOT
1055
+ // expand: a nested repo `git add`ed without a `.gitmodules` entry, or a
1056
+ // submodule that isn't active/initialized in this checkout. Such a gitlink
1057
+ // falls through every pass — it's tracked, so the untracked `-o` listing below
1058
+ // never reports it, and --recurse-submodules only expands ACTIVE submodules —
1059
+ // so its source would be silently skipped, leaving only the super-repo's own
1060
+ // files indexed. We collect those gitlinks here and recurse into them below.
1061
+ // (An active submodule is expanded inline by --recurse-submodules and so never
1062
+ // surfaces as a 160000 entry — only the unhandled gitlinks do.) (#1031, #1033)
1063
+ //
1064
+ // -z gives NUL-separated, unquoted output so non-ASCII (e.g. CJK) paths
1065
+ // survive verbatim. Without it git octal-escapes and double-quotes such paths
1066
+ // (the core.quotepath default), and the quoted form never matches a real file
1067
+ // on disk → those files are silently dropped from the index. (#541) With -s the
1068
+ // path follows a TAB after the `<mode> <object> <stage>` prefix.
1069
+ const gitlinkRels = [];
1070
+ const tracked = lsFilesStaged(gitOpts);
1071
+ for (const entry of tracked.split('\0')) {
1072
+ if (!entry)
1073
+ continue;
1074
+ const tab = entry.indexOf('\t');
1075
+ if (tab === -1)
1076
+ continue; // --stage always emits "<mode> <object> <stage>\t<path>"
1077
+ const rel = entry.slice(tab + 1);
1078
+ if (entry.slice(0, 6) === '160000') {
1079
+ gitlinkRels.push(rel); // an unexpanded gitlink — recursed into below, not a source file itself
1080
+ continue;
1081
+ }
1082
+ files.add((0, utils_1.normalizePath)(prefix + rel));
1083
+ }
1084
+ // Untracked files (submodules manage their own untracked state). Embedded git
1085
+ // repos surface here as a single "subdir/" entry that git refuses to descend
1086
+ // into — recurse into those as their own repos so their source gets indexed.
1087
+ const untracked = (0, child_process_1.execFileSync)('git', ['ls-files', '-z', '-o', '--exclude-standard'], gitOpts);
1088
+ for (const rel of untracked.split('\0')) {
1089
+ if (!rel)
1090
+ continue;
1091
+ if (rel.endsWith('/')) {
1092
+ // git only emits a trailing-slash directory entry for an embedded repo.
1093
+ // Guard with a .git check anyway, and skip anything else exactly as git
1094
+ // itself skips it (we never descend into a non-repo opaque dir). Never
1095
+ // descend into default-ignored locations — an embedded repo inside
1096
+ // node_modules is an npm git-dependency, not project code.
1097
+ const childDir = path.join(repoDir, rel);
1098
+ // A git worktree surfaces here as an opaque untracked dir too — skip it,
1099
+ // it's a duplicate working view of an already-indexed repo (#848).
1100
+ if (classifyGitDir(childDir) === 'embedded' && !defaultsOnlyIgnore().ignores(rel)) {
1101
+ embeddedRoots?.add((0, utils_1.normalizePath)(prefix + rel));
1102
+ collectGitFiles(childDir, prefix + rel, files, embeddedRoots, includeIgnored);
1103
+ }
1104
+ continue;
1105
+ }
1106
+ files.add((0, utils_1.normalizePath)(prefix + rel));
1107
+ }
1108
+ // Gitlink entries (mode 160000) that --recurse-submodules left unexpanded —
1109
+ // an embedded repo `git add`ed without `.gitmodules`, or a submodule not
1110
+ // active/initialized in this checkout. When such a gitlink has a real working
1111
+ // tree on disk it is distinct first-party code we must index as its own
1112
+ // embedded repo: the tracked pass skipped its contents and the untracked pass
1113
+ // never sees it (it's tracked, not "other"). A gitlink with no checkout on disk
1114
+ // (an uninitialized submodule — empty dir, no `.git`) has nothing to index and
1115
+ // is left alone, as is a submodule worktree (a duplicate view, #945). (#1031, #1033)
1116
+ if (gitlinkRels.length > 0) {
1117
+ const defaults = defaultsOnlyIgnore();
1118
+ const repoIgnore = buildDefaultIgnore(repoDir);
1119
+ for (const rel of gitlinkRels) {
1120
+ const relDir = rel.endsWith('/') ? rel : rel + '/';
1121
+ // A gitlink under a gitignored path is respected (not indexed) unless the
1122
+ // project opted it in via `includeIgnored` — keep tracked gitlinks under
1123
+ // the same scope rule as the untracked-ignored kind below (#1065).
1124
+ if (gitlinkEmbeddedRepoSkipped(relDir, prefix, defaults, repoIgnore, includeIgnored))
1125
+ continue;
1126
+ const childDir = path.join(repoDir, rel);
1127
+ // 'embedded' = a real .git checkout on disk; 'worktree' and 'none' are skipped.
1128
+ if (classifyGitDir(childDir) !== 'embedded')
1129
+ continue;
1130
+ embeddedRoots?.add((0, utils_1.normalizePath)(prefix + relDir));
1131
+ collectGitFiles(childDir, prefix + relDir, files, embeddedRoots, includeIgnored);
1132
+ }
1133
+ }
1134
+ // Embedded repos hidden by THIS repo's ignore rules (`/packages/` in a
1135
+ // super-repo .gitignore) never appear in any listing above. By default they
1136
+ // stay hidden — `.gitignore` is respected (#970, #976). They are recursed into
1137
+ // only when the project opted the directory in via `codegraph.json`
1138
+ // `includeIgnored` (#622, #699), which `findIgnoredEmbeddedRepos` enforces.
1139
+ for (const rel of findIgnoredEmbeddedRepos(repoDir, includeIgnored, prefix)) {
1140
+ embeddedRoots?.add((0, utils_1.normalizePath)(prefix + rel));
1141
+ collectGitFiles(path.join(repoDir, rel), prefix + rel, files, embeddedRoots, includeIgnored);
1142
+ }
1143
+ }
1144
+ /**
1145
+ * Get all files visible to git (tracked + untracked but not ignored).
1146
+ * Respects .gitignore at all levels (root, subdirectories) and descends into
1147
+ * embedded (nested, non-submodule) git repos. Returns null on failure
1148
+ * (non-git project) so callers can fall back to a filesystem walk.
1149
+ */
1150
+ function getGitVisibleFiles(rootDir) {
1151
+ try {
1152
+ // Check if the project directory is gitignored by a parent repo.
1153
+ // When rootDir lives inside a parent git repo that ignores it,
1154
+ // `git ls-files` returns nothing — fall back to filesystem walk.
1155
+ const gitRoot = (0, child_process_1.execFileSync)('git', ['rev-parse', '--show-toplevel'], { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true }).trim();
1156
+ if (path.resolve(gitRoot) !== path.resolve(rootDir)) {
1157
+ try {
1158
+ // git check-ignore exits 0 if the path IS ignored, 1 if not
1159
+ (0, child_process_1.execFileSync)('git', ['check-ignore', '-q', path.resolve(rootDir)], { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
1160
+ // Directory is gitignored by parent repo — fall back to filesystem walk
1161
+ (0, errors_1.logDebug)('project root is gitignored by a parent repo — falling back to filesystem walk', {
1162
+ rootDir,
1163
+ gitRoot,
1164
+ });
1165
+ return null;
1166
+ }
1167
+ catch {
1168
+ // Not ignored — safe to use git ls-files
1169
+ }
1170
+ }
1171
+ const files = new Set();
1172
+ const embeddedRoots = new Set();
1173
+ collectGitFiles(rootDir, '', files, embeddedRoots, loadIncludeIgnoredMatcher(rootDir));
1174
+ // Apply built-in default ignores uniformly — to tracked files too, since
1175
+ // committing a dependency/build dir doesn't make it project code. A
1176
+ // `.gitignore` negation (e.g. `!vendor/`) is the explicit opt-in. (issue #407)
1177
+ // Files inside an EMBEDDED repo are matched against that repo's own rules,
1178
+ // not the parent's: the parent's .gitignore hides the child repo from git,
1179
+ // not from the index. (#514)
1180
+ const ig = buildScopeIgnore(rootDir, embeddedRoots);
1181
+ const visible = new Set([...files].filter((f) => !ig.ignores(f)));
1182
+ // Force-include first-party source the project whitelisted in
1183
+ // `codegraph.json` `include`. These are gitignored, so `git ls-files` never
1184
+ // listed them above — discover them directly off disk and add them. (The
1185
+ // common SVN+Git dual-VCS case: source committed to SVN, gitignored out of
1186
+ // Git, but still wanted in the graph.)
1187
+ for (const f of collectIncludedFilesForRoot(rootDir))
1188
+ visible.add(f);
1189
+ return visible;
1190
+ }
1191
+ catch (error) {
1192
+ // Any failure here (git missing, a `git rev-parse`/`ls-files` timeout or
1193
+ // buffer overrun under load, an unreadable repo, unsupported flag combo on
1194
+ // older git, etc.) silently sent every caller to `scanDirectoryWalk` with
1195
+ // zero signal that the fast git-delegated path was skipped — making reports
1196
+ // like #1567 (nested-`.gitignore`-excluded `node_modules` walked into)
1197
+ // hard to triage, since both ignore implementations look correct in
1198
+ // isolation but there was no way to tell which one ran. Log it under the
1199
+ // existing CODEGRAPH_DEBUG gate so a future report can confirm or rule out
1200
+ // the fallback in one step.
1201
+ (0, errors_1.logDebug)('git-based file listing unavailable — falling back to filesystem walk', {
1202
+ rootDir,
1203
+ error: error instanceof Error ? error.message : String(error),
1204
+ });
1205
+ return null;
1206
+ }
1207
+ }
1208
+ /**
1209
+ * Use `git status` to detect changed files instead of scanning every file.
1210
+ * Returns null on failure so callers fall back to full scan.
1211
+ *
1212
+ * Recurses into embedded repos — the untracked kind (#193: the parent's status
1213
+ * collapses them to an opaque `?? subdir/` entry) always, and the gitignored
1214
+ * kind (#514: they never appear in the parent's status at all) only for
1215
+ * directories opted in via `codegraph.json` `includeIgnored` (#622, #699) —
1216
+ * running `git status` inside each, so changes in a multi-repo workspace sync
1217
+ * without a full rescan. By default a gitignored dir is left alone, matching the
1218
+ * full-index scan (#970, #976). Deleting an ENTIRE embedded repo dir is the one
1219
+ * case this cannot see (the child status that would report the deletions is gone
1220
+ * with it); a full `codegraph index` reconciles that.
1221
+ */
1222
+ function getGitChangedFiles(rootDir, sinceCommit) {
1223
+ try {
1224
+ // `git status` only ever describes the WORKING TREE, so a change that has
1225
+ // been committed leaves no entry and never enters the candidate set — the
1226
+ // hash comparison in getChangedFiles is correct but is never reached for
1227
+ // it, and `pendingChanges` reads 0 while the index is genuinely behind
1228
+ // (#1829). `sinceCommit` — the commit the index was last brought up to
1229
+ // date at — adds the other half: what has been committed since. Callers
1230
+ // that hold no such stamp still get exactly what they always did, the
1231
+ // working-tree changes.
1232
+ const changes = { modified: [], added: [], deleted: [] };
1233
+ // Custom extension → language overrides from the project's codegraph.json,
1234
+ // so change detection sees the same custom-extension files the full index does.
1235
+ const overrides = (0, project_config_1.loadExtensionOverrides)(rootDir);
1236
+ collectGitStatus(rootDir, '', changes, overrides, loadIncludeIgnoredMatcher(rootDir), loadExcludeMatcher(rootDir), sinceCommit ?? undefined);
1237
+ return changes;
1238
+ }
1239
+ catch {
1240
+ return null;
1241
+ }
1242
+ }
1243
+ /**
1244
+ * Metadata key: the commit the index was last brought up to date at. Written by
1245
+ * a full index AND by every successful sync — unlike the extraction stamp, which
1246
+ * a sync must not advance because it only touches a subset of files. This one is
1247
+ * about the tree; failed file paths remain explicit retry candidates. (#1829)
1248
+ */
1249
+ exports.INDEXED_AT_COMMIT_KEY = 'indexed_at_commit';
1250
+ /** HEAD's commit sha, or null in a non-git repo or one with no commits yet. */
1251
+ function getGitHeadSha(rootDir) {
1252
+ try {
1253
+ return (0, child_process_1.execFileSync)('git', ['rev-parse', 'HEAD'], {
1254
+ cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true,
1255
+ }).trim() || null;
1256
+ }
1257
+ catch {
1258
+ return null;
1259
+ }
1260
+ }
1261
+ /**
1262
+ * NUL-delimited status/path pairs for every path committed
1263
+ * between `sinceCommit` and HEAD. Empty when the stamp IS HEAD, which is the
1264
+ * common case — one cheap git call on the hot path.
1265
+ */
1266
+ function gitCommittedChangesSince(repoDir, sinceCommit) {
1267
+ // NUL framing preserves Unicode, quotes, tabs and newlines in Git paths.
1268
+ // Let command failures reach getGitChangedFiles: [] would falsely mean clean.
1269
+ const out = (0, child_process_1.execFileSync)('git', ['diff', '--relative', '--name-status', '--no-renames', '-z', sinceCommit, 'HEAD', '--', '.'], {
1270
+ cwd: repoDir, encoding: 'utf-8', timeout: 10000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true,
1271
+ });
1272
+ return out.split('\0');
1273
+ }
1274
+ /**
1275
+ * Can an INDEX trust the git fast path, given the commit it was built at?
1276
+ *
1277
+ * False means "fall back to the full scan" — the expensive path that compares
1278
+ * every file on disk against the DB, and the only correct read when git cannot
1279
+ * say what happened between the stamp and now:
1280
+ *
1281
+ * - stamp present but unknown to this repo (rebase, gc, shallow clone, a stamp
1282
+ * from a different checkout) — history moved under the index.
1283
+ * - stamp absent while the repo HAS commits — an index built before stamping
1284
+ * existed. One full scan; the next sync stamps it and the fast path returns.
1285
+ *
1286
+ * A repo with NO commits keeps the fast path with or without a stamp: every
1287
+ * file is untracked, so `git status` already sees all of them. Callers with no
1288
+ * index behind them (the exported `getGitChangedFiles`) never ask this — a
1289
+ * working-tree diff is the whole of what they wanted. (#1829)
1290
+ */
1291
+ function canTrustGitFastPath(rootDir, sinceCommit) {
1292
+ const head = getGitHeadSha(rootDir);
1293
+ if (head == null)
1294
+ return true; // no commits (or not a git repo — caller handles that)
1295
+ if (!sinceCommit)
1296
+ return false;
1297
+ if (sinceCommit === head)
1298
+ return true;
1299
+ try {
1300
+ (0, child_process_1.execFileSync)('git', ['cat-file', '-e', `${sinceCommit}^{commit}`], {
1301
+ cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true,
1302
+ });
1303
+ return true;
1304
+ }
1305
+ catch {
1306
+ return false;
1307
+ }
1308
+ }
1309
+ function collectGitStatus(repoDir, prefix, out, overrides, includeIgnored = null, exclude = null, sinceCommit) {
1310
+ const output = (0, child_process_1.execFileSync)('git',
1311
+ // `-uall` lists individual untracked files instead of collapsing an
1312
+ // entirely-untracked directory into one `?? dir/` entry, which would
1313
+ // otherwise be dropped here (only embedded git repos are recursed into
1314
+ // below). Nested untracked git repos still collapse to `?? repo/` even
1315
+ // with `-uall` — git never crosses a repo boundary — so the recursion
1316
+ // still handles them. (#1213)
1317
+ ['status', '--porcelain', '--no-renames', '-z', '-uall'], { cwd: repoDir, encoding: 'utf-8', timeout: 10000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });
1318
+ // This repo's own ignore rules — built-in defaults (#407) plus its .gitignore.
1319
+ // Change detection must exclude the SAME files the full index does, but git
1320
+ // status hides neither: it ignores nothing for *tracked* paths, and the
1321
+ // built-in defaults aren't gitignore at all. Without this filter a committed
1322
+ // vendor/ dir, or a tracked file under a .gitignored dir, surfaces here as a
1323
+ // change — so `ltm-alpha-cs status` (which reads getChangedFiles) reports a
1324
+ // pending edit the full index never tracks and `sync` never clears. Matching
1325
+ // repo-relative `rel` at each recursion level mirrors getGitVisibleFiles'
1326
+ // ScopeIgnore: every embedded repo is judged by ITS OWN rules, never the
1327
+ // parent's. (#766)
1328
+ const ig = buildDefaultIgnore(repoDir);
1329
+ // One classifier for both candidate sources below, so a committed change is
1330
+ // filtered by exactly the rules a working-tree change is (#766, #999, #1829).
1331
+ const classify = (statusCode, rel) => {
1332
+ const filePath = (0, utils_1.normalizePath)(prefix + rel);
1333
+ if (!(0, grammars_1.isSourceFile)(filePath, overrides))
1334
+ return;
1335
+ if (statusCode.includes('D')) {
1336
+ // Deletions stay unfiltered: getChangedFiles acts on one only when the
1337
+ // path is already tracked in the DB, where removal is always correct — and
1338
+ // that lets a newly-excluded dir's stale rows clean themselves up. (#766)
1339
+ out.deleted.push(filePath);
1340
+ return;
1341
+ }
1342
+ // Added (`??`) / modified files inside an excluded dir must not enter the
1343
+ // index — match against the repo-relative path, same as the full scan. (#766)
1344
+ if (ig.ignores(rel))
1345
+ return;
1346
+ // User `codegraph.json` `exclude` (#999) is project-root-relative, so it's
1347
+ // matched against the full path — sync must not re-add a tracked file the
1348
+ // full index now keeps out. Deletions above stay unfiltered so a file that
1349
+ // WAS indexed before an exclude was added still cleans itself out.
1350
+ if (exclude && exclude.ignores(filePath))
1351
+ return;
1352
+ if (statusCode === '??') {
1353
+ out.added.push(filePath);
1354
+ }
1355
+ else {
1356
+ // M, MM, AM, A (staged), etc. — treat as modified. getChangedFiles
1357
+ // re-decides added-vs-modified from the DB, so a committed `A` that the
1358
+ // index never saw still lands in `added`.
1359
+ out.modified.push(filePath);
1360
+ }
1361
+ };
1362
+ const untrackedDirs = [];
1363
+ for (const line of output.split('\0')) {
1364
+ if (line.length < 4)
1365
+ continue; // Minimum: "XY file"
1366
+ const statusCode = line.substring(0, 2);
1367
+ const rel = (0, utils_1.normalizePath)(line.substring(3));
1368
+ // Untracked directory entries (trailing slash) may hide an embedded repo —
1369
+ // collect for the recursion below instead of treating as a file.
1370
+ if (statusCode === '??' && rel.endsWith('/')) {
1371
+ untrackedDirs.push(rel);
1372
+ continue;
1373
+ }
1374
+ classify(statusCode, rel);
1375
+ }
1376
+ // Committed but unindexed: everything between the commit this index was last
1377
+ // brought up to date at and HEAD. `git status` cannot see these — committing
1378
+ // is precisely what removes a file from its output — so without this pass a
1379
+ // `git commit` makes a real pending change read as zero (#1829). The stamp
1380
+ // belongs to the ROOT repo, so the embedded-repo recursion below passes none.
1381
+ if (sinceCommit) {
1382
+ const fields = gitCommittedChangesSince(repoDir, sinceCommit);
1383
+ for (let i = 0; i + 1 < fields.length; i += 2) {
1384
+ classify(`${fields[i].charAt(0)} `, (0, utils_1.normalizePath)(fields[i + 1]));
1385
+ }
1386
+ }
1387
+ // Recurse embedded repos found under untracked dirs (at the dir itself or
1388
+ // nested deeper). Gitignored dirs are walked only for the directories the
1389
+ // project opted in via `includeIgnored`; by default `.gitignore` is respected
1390
+ // and they are left alone (#970, #976), mirroring the full-index scan.
1391
+ for (const rel of untrackedDirs) {
1392
+ for (const repoRel of findNestedGitRepos(path.join(repoDir, rel), rel)) {
1393
+ collectGitStatus(path.join(repoDir, repoRel), prefix + repoRel, out, overrides, includeIgnored, exclude);
1394
+ }
1395
+ }
1396
+ for (const rel of findIgnoredEmbeddedRepos(repoDir, includeIgnored, prefix)) {
1397
+ collectGitStatus(path.join(repoDir, rel), prefix + rel, out, overrides, includeIgnored, exclude);
1398
+ }
1399
+ }
1400
+ /**
1401
+ * Recursively scan a directory for source files.
1402
+ *
1403
+ * In git repos, uses `git ls-files` (inherently respects .gitignore at all
1404
+ * levels), then keeps files with a supported source extension. For non-git
1405
+ * projects, falls back to a filesystem walk that parses .gitignore itself.
1406
+ */
1407
+ function scanDirectory(rootDir, onProgress) {
1408
+ // Custom extension → language overrides from the project's codegraph.json.
1409
+ const overrides = (0, project_config_1.loadExtensionOverrides)(rootDir);
1410
+ // Fast path: use git to get all visible files (respects .gitignore everywhere)
1411
+ const gitFiles = getGitVisibleFiles(rootDir);
1412
+ if (gitFiles) {
1413
+ const files = [];
1414
+ let count = 0;
1415
+ for (const filePath of gitFiles) {
1416
+ if ((0, grammars_1.isSourceFile)(filePath, overrides)) {
1417
+ files.push(filePath);
1418
+ count++;
1419
+ onProgress?.(count, filePath);
1420
+ }
1421
+ }
1422
+ return files;
1423
+ }
1424
+ // Fallback: walk filesystem for non-git projects
1425
+ return scanDirectoryWalk(rootDir, onProgress);
1426
+ }
1427
+ /** Record one file the scan declined to index. */
1428
+ function tallySkip(stats, rel) {
1429
+ if (!stats)
1430
+ return;
1431
+ const ext = path.extname(rel).toLowerCase();
1432
+ if (!ext)
1433
+ return;
1434
+ stats.unsupportedByExtension.set(ext, (stats.unsupportedByExtension.get(ext) ?? 0) + 1);
1435
+ }
1436
+ async function scanDirectoryAsync(rootDir, onProgress, stats) {
1437
+ // Custom extension → language overrides from the project's codegraph.json.
1438
+ const overrides = (0, project_config_1.loadExtensionOverrides)(rootDir);
1439
+ const gitFiles = getGitVisibleFiles(rootDir);
1440
+ if (gitFiles) {
1441
+ const files = [];
1442
+ let count = 0;
1443
+ for (const filePath of gitFiles) {
1444
+ if ((0, grammars_1.isSourceFile)(filePath, overrides)) {
1445
+ files.push(filePath);
1446
+ count++;
1447
+ onProgress?.(count, filePath);
1448
+ // Yield every 100 files so worker threads can render progress
1449
+ if (count % 100 === 0) {
1450
+ await new Promise(r => setImmediate(r));
1451
+ }
1452
+ }
1453
+ else {
1454
+ tallySkip(stats, filePath);
1455
+ }
1456
+ }
1457
+ return files;
1458
+ }
1459
+ return scanDirectoryWalk(rootDir, onProgress, stats);
1460
+ }
1461
+ /**
1462
+ * Filesystem walk fallback for non-git projects.
1463
+ */
1464
+ function scanDirectoryWalk(rootDir, onProgress, stats) {
1465
+ const files = [];
1466
+ let count = 0;
1467
+ const visitedDirs = new Set();
1468
+ // Custom extension → language overrides from the project's codegraph.json.
1469
+ const overrides = (0, project_config_1.loadExtensionOverrides)(rootDir);
1470
+ const loadIgnore = (dir) => {
1471
+ const giPath = path.join(dir, '.gitignore');
1472
+ if (!fs.existsSync(giPath))
1473
+ return null;
1474
+ // readGitignorePatterns is defensive: a non-UTF-8 (DLP-encrypted) or
1475
+ // uncompilable .gitignore is skipped/filtered with a warning, never thrown
1476
+ // (issue #682) — so the per-file `.ignores()` calls below can't crash.
1477
+ const patterns = readGitignorePatterns(giPath);
1478
+ return patterns ? { dir, ig: (0, ignore_1.default)().add(patterns) } : null;
1479
+ };
1480
+ const isIgnored = (fullPath, isDir, matchers) => {
1481
+ for (const { dir, ig } of matchers) {
1482
+ let rel = (0, utils_1.normalizePath)(path.relative(dir, fullPath));
1483
+ if (!rel || rel.startsWith('..'))
1484
+ continue; // not under this matcher's dir
1485
+ if (isDir)
1486
+ rel += '/'; // dir-only rules (e.g. `build/`) only match with the slash
1487
+ if (ig.ignores(rel))
1488
+ return true;
1489
+ }
1490
+ return false;
1491
+ };
1492
+ function walk(dir, matchers) {
1493
+ let realDir;
1494
+ try {
1495
+ realDir = fs.realpathSync(dir);
1496
+ }
1497
+ catch {
1498
+ (0, errors_1.logDebug)('Skipping unresolvable directory', { dir });
1499
+ return;
1500
+ }
1501
+ if (visitedDirs.has(realDir)) {
1502
+ (0, errors_1.logDebug)('Skipping already-visited directory (symlink cycle)', { dir, realDir });
1503
+ return;
1504
+ }
1505
+ visitedDirs.add(realDir);
1506
+ // This directory's own .gitignore (if present) applies to everything below it.
1507
+ // The root's .gitignore is already merged into the seeded base matcher (so a
1508
+ // negation there can override a built-in default), so skip it here.
1509
+ const own = dir === rootDir ? null : loadIgnore(dir);
1510
+ const active = own ? [...matchers, own] : matchers;
1511
+ let entries;
1512
+ try {
1513
+ entries = fs.readdirSync(dir, { withFileTypes: true });
1514
+ }
1515
+ catch (error) {
1516
+ (0, errors_1.logDebug)('Skipping unreadable directory', { dir, error: String(error) });
1517
+ return;
1518
+ }
1519
+ for (const entry of entries) {
1520
+ // Never descend into git internals or any Alpha Code Sense data directory
1521
+ // (the active one or a sibling another environment created — #636).
1522
+ if (entry.name === '.git' || (0, directory_1.isAlphaCsDataDir)(entry.name))
1523
+ continue;
1524
+ const fullPath = path.join(dir, entry.name);
1525
+ const relativePath = (0, utils_1.normalizePath)(path.relative(rootDir, fullPath));
1526
+ if (entry.isSymbolicLink()) {
1527
+ try {
1528
+ const realTarget = fs.realpathSync(fullPath);
1529
+ const stat = fs.statSync(realTarget);
1530
+ if (stat.isDirectory()) {
1531
+ if (!isIgnored(fullPath, true, active)) {
1532
+ walk(fullPath, active);
1533
+ }
1534
+ }
1535
+ else if (stat.isFile()) {
1536
+ if (!isIgnored(fullPath, false, active)) {
1537
+ if ((0, grammars_1.isSourceFile)(relativePath, overrides)) {
1538
+ files.push(relativePath);
1539
+ count++;
1540
+ onProgress?.(count, relativePath);
1541
+ }
1542
+ else {
1543
+ tallySkip(stats, relativePath);
1544
+ }
1545
+ }
1546
+ }
1547
+ }
1548
+ catch {
1549
+ (0, errors_1.logDebug)('Skipping broken symlink', { path: fullPath });
1550
+ }
1551
+ continue;
1552
+ }
1553
+ if (entry.isDirectory()) {
1554
+ if (!isIgnored(fullPath, true, active)) {
1555
+ walk(fullPath, active);
1556
+ }
1557
+ }
1558
+ else if (entry.isFile()) {
1559
+ if (!isIgnored(fullPath, false, active)) {
1560
+ if ((0, grammars_1.isSourceFile)(relativePath, overrides)) {
1561
+ files.push(relativePath);
1562
+ count++;
1563
+ onProgress?.(count, relativePath);
1564
+ }
1565
+ else {
1566
+ tallySkip(stats, relativePath);
1567
+ }
1568
+ }
1569
+ }
1570
+ }
1571
+ }
1572
+ // Seed a base matcher with the built-in default ignores (merged with the root
1573
+ // .gitignore so a negation can override). Nested .gitignores still layer per-dir.
1574
+ const baseMatchers = [{ dir: rootDir, ig: buildDefaultIgnore(rootDir) }];
1575
+ // Project `codegraph.json` `exclude` patterns (#999), rooted at the project so
1576
+ // `isIgnored` matches them against root-relative paths — same coverage the
1577
+ // git path gets via ScopeIgnore, for non-git projects.
1578
+ const exclude = loadExcludeMatcher(rootDir);
1579
+ if (exclude)
1580
+ baseMatchers.push({ dir: rootDir, ig: exclude });
1581
+ walk(rootDir, baseMatchers);
1582
+ // Force-include first-party source whitelisted in `codegraph.json` `include`
1583
+ // — the walk above honours `.gitignore`, so anything gitignored was dropped;
1584
+ // add it back here (deduped). Mirrors the git path's union.
1585
+ const included = collectIncludedFilesForRoot(rootDir);
1586
+ if (included.size > 0) {
1587
+ const seen = new Set(files);
1588
+ for (const f of included) {
1589
+ if (!seen.has(f)) {
1590
+ files.push(f);
1591
+ seen.add(f);
1592
+ }
1593
+ }
1594
+ }
1595
+ return files;
1596
+ }
1597
+ /**
1598
+ * Resurrect a resolution edge that is about to be dropped (its target symbol
1599
+ * was removed, renamed, or its whole file deleted) as the ORIGINAL unresolved
1600
+ * reference that created it, read from the refName/refKind stamp
1601
+ * `createEdges` writes into edge metadata. Inserted as status='pending', the
1602
+ * ref is consumed by the same sync's resolution sweep: it rebinds to an
1603
+ * alternative definition if one exists, or parks as status='failed' where the
1604
+ * #1240 retry finds it if the symbol later reappears.
1605
+ *
1606
+ * Returns null — drop silently, the pre-#1240 behavior — for edges without a
1607
+ * refName stamp (created before the stamp existed, or synthesized): rebuilding
1608
+ * a ref from the target's plain node name would strip the receiver/qualifier
1609
+ * context the original text carried (`h.greet` → `greet`) and could rebind
1610
+ * somewhere a full re-index never would. Silent beats wrong.
1611
+ */
1612
+ function resurrectRefFromDroppedEdge(e) {
1613
+ const refName = e.metadata?.refName;
1614
+ if (typeof refName !== 'string' || refName.length === 0)
1615
+ return null;
1616
+ const refKind = typeof e.metadata?.refKind === 'string' ? e.metadata.refKind : e.kind;
1617
+ return {
1618
+ fromNodeId: e.source,
1619
+ referenceName: refName,
1620
+ referenceKind: refKind,
1621
+ line: e.line ?? 0,
1622
+ column: e.column ?? 0,
1623
+ filePath: e.sourceFilePath,
1624
+ language: e.sourceLanguage,
1625
+ };
1626
+ }
1627
+ /**
1628
+ * Extraction orchestrator
1629
+ */
1630
+ class ExtractionOrchestrator {
1631
+ rootDir;
1632
+ queries;
1633
+ /**
1634
+ * Names of frameworks detected for this project, populated by indexAll().
1635
+ * Passed to extractFromSource so framework-specific extractors (route nodes,
1636
+ * middleware, etc.) run after the tree-sitter pass. Cleared if detection
1637
+ * hasn't run yet so single-file re-index paths can detect on the spot.
1638
+ */
1639
+ detectedFrameworkNames = null;
1640
+ /**
1641
+ * Scope matcher for SCOPED syncs, memoized on the mtimes of the two root
1642
+ * files it is derived from (`codegraph.json`, `.gitignore`). See
1643
+ * {@link scopedSyncMatcher}.
1644
+ */
1645
+ scopedMatcher = null;
1646
+ constructor(rootDir, queries) {
1647
+ this.rootDir = rootDir;
1648
+ this.queries = queries;
1649
+ }
1650
+ /**
1651
+ * The scope matcher a scoped sync applies to the paths it was handed — the
1652
+ * same `buildScopeIgnore` the full scan uses, so an explicitly-passed path
1653
+ * that is OUT of scope (a user `exclude` in `codegraph.json`, a `.gitignore`
1654
+ * rule, a built-in default) is treated exactly as the full walk would treat
1655
+ * it: absent, hence removed if tracked, never parsed (#1590).
1656
+ *
1657
+ * Memoized on the root config + root `.gitignore` mtimes: building the
1658
+ * matcher runs embedded-repo discovery (`git ls-files`), which would defeat
1659
+ * the scoped path's whole point (skipping O(repo) work) if paid per sync.
1660
+ * Two `stat`s per sync while nothing changed. An embedded repo created
1661
+ * between config edits joins the scoped matcher on the next full sync, the
1662
+ * same lifecycle the watcher's own matcher already has.
1663
+ */
1664
+ scopedSyncMatcher() {
1665
+ // Bust when any root-level exclude source the matcher reads may have
1666
+ // changed. Nested `.gitignore` edits force a full watcher sync, which
1667
+ // clears this cache (see the full-reconcile branch in sync()).
1668
+ const gitDir = resolveGitDir(this.rootDir);
1669
+ const key = [
1670
+ project_config_1.PROJECT_CONFIG_FILENAME,
1671
+ '.gitignore',
1672
+ gitDir ? path.join(gitDir, 'info', 'exclude') : '',
1673
+ ]
1674
+ .map((name) => {
1675
+ if (!name)
1676
+ return '-';
1677
+ try {
1678
+ return String(fs.statSync(path.isAbsolute(name) ? name : path.join(this.rootDir, name)).mtimeMs);
1679
+ }
1680
+ catch {
1681
+ return '-';
1682
+ }
1683
+ })
1684
+ .join('|');
1685
+ if (this.scopedMatcher && this.scopedMatcher.key === key)
1686
+ return this.scopedMatcher.matcher;
1687
+ const matcher = buildScopeIgnore(this.rootDir);
1688
+ this.scopedMatcher = { key, matcher };
1689
+ return matcher;
1690
+ }
1691
+ /**
1692
+ * Build a filesystem-backed ResolutionContext sufficient for framework
1693
+ * detection. Graph-query methods (getNodesByName etc.) return empty because
1694
+ * the DB hasn't been populated yet, but detect() only uses readFile,
1695
+ * fileExists, and getAllFiles, so that's fine.
1696
+ */
1697
+ buildDetectionContext(files) {
1698
+ const rootDir = this.rootDir;
1699
+ return {
1700
+ getNodesInFile: () => [],
1701
+ getNodesByName: () => [],
1702
+ getNodesByQualifiedName: () => [],
1703
+ getNodesByKind: () => [],
1704
+ getNodesByLowerName: () => [],
1705
+ getImportMappings: () => [],
1706
+ getAllFiles: () => files,
1707
+ getProjectRoot: () => rootDir,
1708
+ fileExists: (relativePath) => {
1709
+ const full = (0, utils_1.validatePathWithinRoot)(rootDir, relativePath);
1710
+ if (!full)
1711
+ return false;
1712
+ try {
1713
+ return fs.existsSync(full);
1714
+ }
1715
+ catch {
1716
+ return false;
1717
+ }
1718
+ },
1719
+ readFile: (relativePath) => {
1720
+ const full = (0, utils_1.validatePathWithinRoot)(rootDir, relativePath);
1721
+ if (!full)
1722
+ return null;
1723
+ try {
1724
+ return fs.readFileSync(full, 'utf-8');
1725
+ }
1726
+ catch {
1727
+ return null;
1728
+ }
1729
+ },
1730
+ // Monorepo support — needed by framework detect()s that probe
1731
+ // subpackage manifests (e.g. fabric-view looking at
1732
+ // packages/<sub>/package.json when the root manifest is just a
1733
+ // workspace declaration). Matches the resolver-context shape.
1734
+ listDirectories: (relativePath) => {
1735
+ const target = relativePath === '.' || relativePath === ''
1736
+ ? rootDir
1737
+ : path.join(rootDir, relativePath);
1738
+ try {
1739
+ return fs
1740
+ .readdirSync(target, { withFileTypes: true })
1741
+ .filter((entry) => entry.isDirectory())
1742
+ .map((entry) => entry.name);
1743
+ }
1744
+ catch {
1745
+ return [];
1746
+ }
1747
+ },
1748
+ };
1749
+ }
1750
+ /**
1751
+ * Detect frameworks on demand using the current scanned files (or a fresh
1752
+ * scan if none are provided). Cached on the orchestrator so repeat calls
1753
+ * inside a single run don't re-scan.
1754
+ */
1755
+ ensureDetectedFrameworks(files) {
1756
+ if (this.detectedFrameworkNames !== null)
1757
+ return this.detectedFrameworkNames;
1758
+ const fileList = files ?? scanDirectory(this.rootDir);
1759
+ const context = this.buildDetectionContext(fileList);
1760
+ this.detectedFrameworkNames = (0, frameworks_1.detectFrameworks)(context).map((r) => r.name);
1761
+ return this.detectedFrameworkNames;
1762
+ }
1763
+ /**
1764
+ * Index all files in the project
1765
+ */
1766
+ async indexAll(onProgress, signal, verbose,
1767
+ // Writer-side backstop for deferred WAL checkpointing (#1231): returns
1768
+ // null in the normal case, or a promise to await (at this safe,
1769
+ // between-transactions boundary) when the WAL has outrun the off-thread
1770
+ // checkpointer past its hard cap. See db/wal-valve.ts.
1771
+ walBackpressure,
1772
+ // Fresh-DB store offload (perf): when set, per-file store bundles are
1773
+ // applied by a dedicated writer thread instead of the main thread. Only
1774
+ // passed for a COMPLETELY fresh database, where the main thread performs
1775
+ // no reads/writes during the parse loop, so one writer applying bundles
1776
+ // in file order preserves the #1015 determinism exactly.
1777
+ storeWriterOpts) {
1778
+ const tGrammar = Date.now();
1779
+ await (0, grammars_1.initGrammars)();
1780
+ if (process.env.CODEGRAPH_SYNTH_TIMINGS)
1781
+ console.error(`[phase-timing] grammar-init: ${Date.now() - tGrammar}ms`);
1782
+ const startTime = Date.now();
1783
+ const errors = [];
1784
+ let filesIndexed = 0;
1785
+ let filesSkipped = 0;
1786
+ let filesErrored = 0;
1787
+ let totalNodes = 0;
1788
+ let totalEdges = 0;
1789
+ // Custom extension → language overrides from the project's codegraph.json.
1790
+ // Threaded into language detection so custom-extension files load the right
1791
+ // grammar and store under the mapped language.
1792
+ const overrides = (0, project_config_1.loadExtensionOverrides)(this.rootDir);
1793
+ const log = verbose
1794
+ ? (msg) => { console.log(`[worker] ${msg}`); }
1795
+ : (_msg) => { };
1796
+ // Phase 1: Scan for files
1797
+ onProgress?.({
1798
+ phase: 'scanning',
1799
+ current: 0,
1800
+ total: 0,
1801
+ });
1802
+ // Phase attribution to stderr (same opt-in as the synthesis timings):
1803
+ // early-run 5-10s single stalls were observed on 95k-file repos but never
1804
+ // attributed — these labels settle scan vs framework-detect vs grammars.
1805
+ const tScan = Date.now();
1806
+ const skipStats = { unsupportedByExtension: new Map() };
1807
+ const files = await scanDirectoryAsync(this.rootDir, (current, file) => {
1808
+ onProgress?.({
1809
+ phase: 'scanning',
1810
+ current,
1811
+ total: 0,
1812
+ currentFile: file,
1813
+ });
1814
+ }, skipStats);
1815
+ if (process.env.CODEGRAPH_SYNTH_TIMINGS)
1816
+ console.error(`[phase-timing] scan: ${Date.now() - tScan}ms (${files.length} files)`);
1817
+ /** Only meaningful when nothing was indexable — see IndexResult (#1502). */
1818
+ const skipSummary = () => {
1819
+ let total = 0;
1820
+ for (const n of skipStats.unsupportedByExtension.values())
1821
+ total += n;
1822
+ if (total === 0)
1823
+ return {};
1824
+ const top = [...skipStats.unsupportedByExtension.entries()]
1825
+ .map(([ext, count]) => ({ ext, count }))
1826
+ .sort((a, b) => b.count - a.count || a.ext.localeCompare(b.ext))
1827
+ .slice(0, 5);
1828
+ return { filesSkippedUnsupported: total, topUnsupportedExtensions: top };
1829
+ };
1830
+ // A re-index over an existing DB skips unchanged-hash files at the store,
1831
+ // which would preserve wiped zero-node rows (#1541) — drop them first so
1832
+ // this run stores their files fresh. No-op on a fresh DB.
1833
+ this.healZeroNodeRows();
1834
+ // Detect frameworks once per indexAll run using the scanned file list.
1835
+ // Names are passed to each parse call so framework-specific extractors
1836
+ // (route nodes, middleware, etc.) run after the tree-sitter pass.
1837
+ // Framework detection is reset each run so adding e.g. requirements.txt
1838
+ // between runs is picked up without restarting the process.
1839
+ this.detectedFrameworkNames = null;
1840
+ const tFw = Date.now();
1841
+ const frameworkNames = this.ensureDetectedFrameworks(files);
1842
+ if (process.env.CODEGRAPH_SYNTH_TIMINGS)
1843
+ console.error(`[phase-timing] framework-detect: ${Date.now() - tFw}ms`);
1844
+ if (signal?.aborted) {
1845
+ return {
1846
+ success: false,
1847
+ filesIndexed: 0,
1848
+ filesSkipped: 0,
1849
+ filesErrored: 0,
1850
+ nodesCreated: 0,
1851
+ edgesCreated: 0,
1852
+ errors: [{ message: 'Aborted', severity: 'error' }],
1853
+ durationMs: Date.now() - startTime,
1854
+ };
1855
+ }
1856
+ // Phase 2: Parse files in a worker thread (keeps main thread unblocked for UI)
1857
+ const total = files.length;
1858
+ let processed = 0;
1859
+ // Emit parsing phase immediately so the progress bar appears during worker setup.
1860
+ // The yield lets the shimmer worker flush the phase transition to stdout before
1861
+ // the main thread starts synchronous grammar detection work.
1862
+ onProgress?.({
1863
+ phase: 'parsing',
1864
+ current: 0,
1865
+ total,
1866
+ });
1867
+ await new Promise(resolve => setImmediate(resolve));
1868
+ // Detect needed languages and load grammars in the parse worker
1869
+ const neededLanguages = preloadLanguagesForFiles(files, overrides);
1870
+ // Parse files on a pool of worker threads (keeps the main thread free for UI
1871
+ // and uses every core). Falls back to in-process parsing when the compiled
1872
+ // worker is unavailable (e.g. running from source in tests).
1873
+ const parseWorkerPath = path.join(__dirname, 'parse-worker.js');
1874
+ const useWorker = fs.existsSync(parseWorkerPath);
1875
+ let pool = null;
1876
+ if (useWorker) {
1877
+ // CODEGRAPH_PARSE_WORKERS: explicit worker count; 1 = the old single-worker
1878
+ // behaviour (the conservative rollback). Unset → clamp(cores-1, 1, 8),
1879
+ // with cores from availableParallelism — cpuset/affinity-honest, where
1880
+ // os.cpus() enumerates the host's CPUs and spawned 8 wasm workers (and
1881
+ // their grammar heaps) inside a 2-CPU container for zero extra
1882
+ // throughput (§7a.1). Floored so a 2-core box still gets 2 workers:
1883
+ // parse is worker-side CPU, and 1 worker measured 34% slower than the
1884
+ // old oversubscribed pool on the kernel-scale 2-cpuset envelope
1885
+ // (493s vs 369s) — main + store-worker don't fill the second core.
1886
+ const poolSize = (0, parse_pool_1.resolveParsePoolSize)(process.env.CODEGRAPH_PARSE_WORKERS, Math.max(3, os.availableParallelism()));
1887
+ // Read each needed grammar's WASM ONCE here and hand the bytes to every
1888
+ // worker, so spawns/respawns load grammars from memory instead of
1889
+ // re-reading them from disk (#1231: on an HDD, respawn re-reads amplify
1890
+ // the very I/O contention that caused the respawn).
1891
+ const grammarBuffers = await (0, grammars_1.readGrammarWasmBytes)(neededLanguages);
1892
+ pool = new parse_pool_1.ParseWorkerPool({
1893
+ languages: neededLanguages,
1894
+ size: poolSize,
1895
+ workerScriptPath: parseWorkerPath,
1896
+ recycleInterval: WORKER_RECYCLE_INTERVAL,
1897
+ parseTimeoutMs: PARSE_TIMEOUT_MS,
1898
+ log,
1899
+ grammarBuffers,
1900
+ });
1901
+ log(`Parse worker pool: ${poolSize} worker(s)`);
1902
+ // Bulk index: every core will be needed — spawn the whole pool now so
1903
+ // worker boot overlaps the first read batches instead of trickling in
1904
+ // behind queue-pressure growth.
1905
+ pool.prewarm();
1906
+ }
1907
+ else {
1908
+ // In-process fallback: load grammars locally and parse on the main thread.
1909
+ await (0, grammars_1.loadGrammarsForLanguages)(neededLanguages);
1910
+ }
1911
+ // Dedicated store writer thread (fresh DB only — see the parameter doc).
1912
+ // Same availability rule as the parse pool: needs the compiled worker
1913
+ // (absent when running from source in tests → main-thread fallback).
1914
+ const storeWorkerPath = path.join(__dirname, 'store-worker.js');
1915
+ let storeWriter = null;
1916
+ if (storeWriterOpts &&
1917
+ process.env.CODEGRAPH_NO_STORE_WORKER !== '1' &&
1918
+ fs.existsSync(storeWorkerPath)) {
1919
+ // Deliberately NOT awaiting ready(): worker_threads delivers messages in
1920
+ // order, so bundles posted while the worker is still booting queue
1921
+ // behind 'open'. A boot failure surfaces at the first drain() — same
1922
+ // propagation point as a store error.
1923
+ storeWriter = new store_writer_1.StoreWriter(storeWorkerPath, storeWriterOpts.dbPath, storeWriterOpts.fastInit);
1924
+ log('Store writer thread active');
1925
+ }
1926
+ /** Queue-depth bound for un-acked bundles (bundles hold whole node/edge arrays). */
1927
+ const STORE_WRITER_WINDOW = 64;
1928
+ /**
1929
+ * Parse one file: on the pool when available (the promise REJECTS on a worker
1930
+ * crash/timeout — the caller records it and the retry pass re-attempts), or
1931
+ * in-process synchronously as the no-worker fallback. The language is resolved
1932
+ * here on the main thread, where the codegraph.json overrides are loaded.
1933
+ */
1934
+ const parseFile = (filePath, content) => {
1935
+ const language = (0, grammars_1.detectLanguage)(filePath, content, overrides);
1936
+ if (!pool)
1937
+ return Promise.resolve((0, tree_sitter_1.extractFromSource)(filePath, content, language, frameworkNames));
1938
+ return pool.requestParse({ filePath, content, language, frameworkNames });
1939
+ };
1940
+ // --- Bounded rolling-window dispatch, ordered commit ---
1941
+ // Reads stay batched/parallel; parses run concurrently across the pool; the
1942
+ // SQLite store stays on the main thread (it isn't thread-safe). Crucially we
1943
+ // COMMIT results in original file order, not parse-completion order: the
1944
+ // resolution phase (run after indexing) resolves an ambiguous reference to one
1945
+ // of several same-named candidates by the nodes' DB insertion order, so a
1946
+ // stable commit order keeps the resulting graph deterministic — byte-identical
1947
+ // to the single-worker path — instead of drifting with parse timing. The
1948
+ // `completed` buffer holds at most ~windowSize out-of-order results, so memory
1949
+ // stays bounded.
1950
+ const windowSize = pool ? Math.max(4, pool.size * 2) : 1;
1951
+ const inFlight = new Set();
1952
+ const completed = new Map();
1953
+ let nextSeq = 0; // file-order sequence assigned at dispatch
1954
+ let nextToStore = 0; // cursor: next sequence to commit
1955
+ let aborted = false;
1956
+ // Yielder for the in-order commit path: a single giant generated file's
1957
+ // store is otherwise one unyielding multi-second transaction span on the
1958
+ // main thread (5–14s single stalls measured on llvm-project), starving
1959
+ // the #850 watchdog heartbeat on slow hardware.
1960
+ const commitYield = (0, cooperative_yield_1.createYielder)();
1961
+ const storeResult = async (filePath, content, stats, result) => {
1962
+ processed++;
1963
+ // WAL hard-cap backstop: between files (never mid-transaction), pause
1964
+ // the store until the off-thread checkpoint catches up. Resolves to
1965
+ // null in the normal case — a single size check, no cost.
1966
+ const bp = walBackpressure?.();
1967
+ if (bp)
1968
+ await bp;
1969
+ // Kernel deferred-decode results carry table sizes in kernelCounts
1970
+ // (their object arrays are empty — decode happens at the store).
1971
+ const nodeCount = result.kernelCounts?.nodes ?? result.nodes.length;
1972
+ const edgeCount = result.kernelCounts?.edges ?? result.edges.length;
1973
+ // Store: on the writer thread when active (fresh DB — bundles applied
1974
+ // in the same file order this chain dispatches them), else on the main
1975
+ // thread (SQLite connections are per-thread).
1976
+ const language = (0, grammars_1.detectLanguage)(filePath, content, overrides);
1977
+ if (storeWriter) {
1978
+ if (result.kernelBuffers) {
1979
+ // Buffers go to the writer as-is; the worker decodes + finalizes.
1980
+ // The main thread's only per-file work stays O(1) + the content hash.
1981
+ storeWriter.send({
1982
+ kernel: true,
1983
+ filePath,
1984
+ language,
1985
+ buffers: result.kernelBuffers,
1986
+ file: this.buildFileRecord(filePath, content, language, stats, nodeCount, result.errors),
1987
+ });
1988
+ }
1989
+ else {
1990
+ storeWriter.send(this.buildFreshStoreBundle(filePath, content, language, stats, result));
1991
+ }
1992
+ await storeWriter.waitBelow(STORE_WRITER_WINDOW);
1993
+ }
1994
+ else {
1995
+ const materialized = (0, kernel_1.materializeKernelResult)(result, filePath, language);
1996
+ await this.storeExtractionResult(filePath, content, language, stats, materialized, commitYield);
1997
+ }
1998
+ if (result.errors.length > 0) {
1999
+ for (const err of result.errors) {
2000
+ if (!err.filePath)
2001
+ err.filePath = filePath;
2002
+ }
2003
+ errors.push(...result.errors);
2004
+ }
2005
+ if (nodeCount > 0) {
2006
+ filesIndexed++;
2007
+ totalNodes += nodeCount;
2008
+ totalEdges += edgeCount;
2009
+ }
2010
+ else if (result.errors.some((e) => e.severity === 'error')) {
2011
+ filesErrored++;
2012
+ }
2013
+ else {
2014
+ // Files with no symbols but no errors (yaml, twig, properties) are
2015
+ // tracked at the file level — count them as indexed so the CLI doesn't
2016
+ // misleadingly report "No files found to index".
2017
+ const lang = (0, grammars_1.detectLanguage)(filePath, content, overrides);
2018
+ if ((0, grammars_1.isFileLevelOnlyLanguage)(lang)) {
2019
+ filesIndexed++;
2020
+ }
2021
+ else {
2022
+ filesSkipped++;
2023
+ }
2024
+ }
2025
+ onProgress?.({ phase: 'parsing', current: processed, total, currentFile: filePath });
2026
+ };
2027
+ const recordParseFailure = async (filePath, content, stats, err) => {
2028
+ await storeResult(filePath, content, stats, {
2029
+ nodes: [],
2030
+ edges: [],
2031
+ unresolvedReferences: [],
2032
+ errors: [{
2033
+ message: err instanceof Error ? err.message : String(err),
2034
+ filePath,
2035
+ severity: 'error',
2036
+ code: 'parse_error',
2037
+ }],
2038
+ durationMs: 0,
2039
+ });
2040
+ };
2041
+ // Commit buffered parses to the DB in file order, advancing the cursor over
2042
+ // contiguous completed results. Runs after each parse settles (and once more
2043
+ // after the drain). storeResult is now async (it yields between chunked
2044
+ // inserts), so commits are SERIALIZED on a promise chain — concurrent parse
2045
+ // completions append to the chain instead of interleaving mid-store, which
2046
+ // preserves both the file-order commit invariant (#1015: resolution
2047
+ // disambiguates same-named candidates by insertion order) and the
2048
+ // single-writer discipline for SQLite. Errors are recorded and re-thrown
2049
+ // at the drain, matching the old synchronous propagation.
2050
+ let flushChain = Promise.resolve();
2051
+ let flushError = null;
2052
+ const flushOrdered = () => {
2053
+ flushChain = flushChain.then(async () => {
2054
+ if (aborted || flushError)
2055
+ return;
2056
+ try {
2057
+ while (completed.has(nextToStore)) {
2058
+ const item = completed.get(nextToStore);
2059
+ completed.delete(nextToStore);
2060
+ nextToStore++;
2061
+ if (item.ok)
2062
+ await storeResult(item.filePath, item.content, item.stats, item.result);
2063
+ else
2064
+ await recordParseFailure(item.filePath, item.content, item.stats, item.err);
2065
+ }
2066
+ }
2067
+ catch (err) {
2068
+ flushError = err;
2069
+ }
2070
+ });
2071
+ return flushChain;
2072
+ };
2073
+ // Dispatch one file's parse (parses run concurrently across the pool), tagged
2074
+ // with its file-order sequence so flushOrdered commits results in order. The
2075
+ // backpressure below bounds how far parsing runs ahead of the in-order commit.
2076
+ const feed = async (filePath, content, stats) => {
2077
+ const seq = nextSeq++;
2078
+ const p = (async () => {
2079
+ try {
2080
+ const result = await parseFile(filePath, content);
2081
+ completed.set(seq, { ok: true, filePath, content, stats, result });
2082
+ }
2083
+ catch (parseErr) {
2084
+ completed.set(seq, { ok: false, filePath, content, stats, err: parseErr });
2085
+ }
2086
+ flushOrdered();
2087
+ })();
2088
+ const tracked = p.finally(() => { inFlight.delete(tracked); });
2089
+ inFlight.add(tracked);
2090
+ // Backpressure on the dispatched-but-not-yet-committed count (in-flight +
2091
+ // buffered), not just in-flight: a slow file sitting at the commit cursor
2092
+ // lets later parses finish and buffer, which would otherwise grow without
2093
+ // bound. Wait for parses to settle (each may advance the cursor) until the
2094
+ // window has room. When nothing is in flight but the window is still full,
2095
+ // the async commit chain is what's behind — await it so the cursor
2096
+ // advances (buffered items hold whole file contents, so this bound is
2097
+ // load-bearing for memory).
2098
+ while (nextSeq - nextToStore >= windowSize) {
2099
+ if (inFlight.size > 0)
2100
+ await Promise.race(inFlight);
2101
+ else
2102
+ await flushOrdered();
2103
+ }
2104
+ };
2105
+ const tParseLoop = Date.now();
2106
+ for (let i = 0; i < files.length; i += FILE_IO_BATCH_SIZE) {
2107
+ if (signal?.aborted) {
2108
+ aborted = true;
2109
+ break;
2110
+ }
2111
+ const batch = files.slice(i, i + FILE_IO_BATCH_SIZE);
2112
+ // Read files in parallel (with path validation before any I/O)
2113
+ const fileContents = await Promise.all(batch.map(async (fp) => {
2114
+ try {
2115
+ // Indexing read: follow in-root symlinks the directory walk already
2116
+ // descended into (the `../` guard still applies) so files reached
2117
+ // via an in-root symlink-to-outside still index (#935).
2118
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, fp, { allowSymlinkEscape: true });
2119
+ if (!fullPath) {
2120
+ (0, errors_1.logWarn)('Path traversal blocked in batch reader', { filePath: fp });
2121
+ return { filePath: fp, content: null, stats: null, error: new Error('Path traversal blocked') };
2122
+ }
2123
+ const content = await fsp.readFile(fullPath, 'utf-8');
2124
+ const stats = await fsp.stat(fullPath);
2125
+ return { filePath: fp, content, stats, error: null };
2126
+ }
2127
+ catch (err) {
2128
+ return { filePath: fp, content: null, stats: null, error: err };
2129
+ }
2130
+ }));
2131
+ // Dispatch each readable file into the bounded parse window; the window
2132
+ // stores results on the main thread as they arrive.
2133
+ for (const { filePath, content, stats, error } of fileContents) {
2134
+ if (signal?.aborted) {
2135
+ aborted = true;
2136
+ break;
2137
+ }
2138
+ if (error || content === null || stats === null) {
2139
+ processed++;
2140
+ filesErrored++;
2141
+ errors.push({
2142
+ message: `Failed to read file: ${error instanceof Error ? error.message : String(error)}`,
2143
+ filePath,
2144
+ severity: 'error',
2145
+ code: 'read_error',
2146
+ });
2147
+ onProgress?.({ phase: 'parsing', current: processed, total });
2148
+ continue;
2149
+ }
2150
+ // Honour MAX_FILE_SIZE. Without this check, vendored generated
2151
+ // headers, minified bundles, and other multi-MB files get indexed,
2152
+ // wasting WASM heap and the worker recycle budget on inputs with no
2153
+ // useful symbols. The single-file extractFile path already enforces
2154
+ // this; the bulk path used to silently skip the check.
2155
+ if (stats.size > MAX_FILE_SIZE) {
2156
+ await storeResult(filePath, content, stats, {
2157
+ nodes: [],
2158
+ edges: [],
2159
+ unresolvedReferences: [],
2160
+ errors: [{
2161
+ message: `File exceeds max size (${stats.size} > ${MAX_FILE_SIZE})`,
2162
+ filePath,
2163
+ severity: 'warning',
2164
+ code: 'size_exceeded',
2165
+ }],
2166
+ durationMs: 0,
2167
+ });
2168
+ continue;
2169
+ }
2170
+ // Parse on the pool (main thread stays unblocked). Errors/timeouts are
2171
+ // handled inside feed() → recordParseFailure, feeding the retry pass.
2172
+ await feed(filePath, content, stats);
2173
+ }
2174
+ if (aborted)
2175
+ break;
2176
+ }
2177
+ // Drain parses still in flight (skip on abort — we tear down below instead),
2178
+ // then commit any results the cursor hasn't reached yet.
2179
+ if (!aborted) {
2180
+ await Promise.all(inFlight);
2181
+ await flushOrdered();
2182
+ if (flushError) {
2183
+ if (storeWriter)
2184
+ await storeWriter.close();
2185
+ throw flushError;
2186
+ }
2187
+ // All bundles are posted; wait for the writer to apply them, then close
2188
+ // its connection BEFORE any main-thread DB work below (retry pass,
2189
+ // resolution) so exactly one connection writes at a time.
2190
+ if (storeWriter) {
2191
+ try {
2192
+ await storeWriter.drain();
2193
+ }
2194
+ finally {
2195
+ await storeWriter.close();
2196
+ storeWriter = null;
2197
+ }
2198
+ }
2199
+ }
2200
+ if (process.env.CODEGRAPH_SYNTH_TIMINGS)
2201
+ console.error(`[phase-timing] parse-loop: ${Date.now() - tParseLoop}ms`);
2202
+ if (signal?.aborted || aborted) {
2203
+ if (storeWriter)
2204
+ await storeWriter.close();
2205
+ if (pool)
2206
+ await pool.destroy();
2207
+ return {
2208
+ success: false,
2209
+ filesIndexed,
2210
+ filesSkipped,
2211
+ filesErrored,
2212
+ filesDiscovered: total,
2213
+ ...skipSummary(),
2214
+ nodesCreated: totalNodes,
2215
+ edgesCreated: totalEdges,
2216
+ errors: [{ message: 'Aborted', severity: 'error' }, ...errors],
2217
+ durationMs: Date.now() - startTime,
2218
+ };
2219
+ }
2220
+ // Report 100% so the progress bar doesn't hang at 99%
2221
+ onProgress?.({
2222
+ phase: 'parsing',
2223
+ current: total,
2224
+ total,
2225
+ });
2226
+ // Yield so the shimmer worker's buffered stdout writes can flush.
2227
+ // Worker thread stdout is proxied through the main thread's event loop,
2228
+ // so synchronous work here blocks the animation from rendering.
2229
+ await new Promise(resolve => setImmediate(resolve));
2230
+ // Retry pass: files that failed due to WASM memory corruption may succeed
2231
+ // on a fresh worker with a clean heap. Recycle before each attempt so
2232
+ // every file gets the absolute cleanest WASM state possible. Timeouts are
2233
+ // retried too (#1231): most are main-thread-stall artifacts, not slow
2234
+ // parses, and this pass parses one file at a time with the store strictly
2235
+ // after each parse resolves, so the stall window can't recur here.
2236
+ const retryableErrors = errors.filter((e) => e.code === 'parse_error' && e.filePath &&
2237
+ (e.message.includes('Worker exited') ||
2238
+ e.message.includes('memory access out of bounds') ||
2239
+ e.message.includes('timed out')));
2240
+ if (retryableErrors.length > 0 && pool) {
2241
+ log(`Retrying ${retryableErrors.length} files that failed due to WASM memory errors or timeouts...`);
2242
+ // Fresh WASM heaps for the retry phase. A retry that still crashes its
2243
+ // worker makes the pool respawn it, so later retries keep landing on clean
2244
+ // workers too.
2245
+ pool.recycleAll();
2246
+ const stillFailing = [];
2247
+ for (const errEntry of retryableErrors) {
2248
+ const filePath = errEntry.filePath;
2249
+ if (signal?.aborted)
2250
+ break;
2251
+ let content;
2252
+ try {
2253
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, filePath);
2254
+ if (!fullPath)
2255
+ continue;
2256
+ content = await fsp.readFile(fullPath, 'utf-8');
2257
+ }
2258
+ catch {
2259
+ continue;
2260
+ }
2261
+ let result;
2262
+ try {
2263
+ result = await parseFile(filePath, content);
2264
+ }
2265
+ catch {
2266
+ stillFailing.push(errEntry);
2267
+ continue;
2268
+ }
2269
+ // The pool hands kernel results back as an undecoded buffer transport
2270
+ // (`nodes`/`edges` EMPTY, tables in kernelBuffers). The main loop
2271
+ // decodes or forwards to the store worker; this path stores directly,
2272
+ // so decode here — otherwise a kernel-language retry passes the gate
2273
+ // below via `errors.length === 0`, stores nothing, and the file is
2274
+ // permanently recorded as "(0 symbols)" with the error erased (#1541).
2275
+ const language = (0, grammars_1.detectLanguage)(filePath, content, overrides);
2276
+ result = (0, kernel_1.materializeKernelResult)(result, filePath, language);
2277
+ if (result.nodes.length > 0 || result.errors.length === 0) {
2278
+ const stats = await fsp.stat(path.join(this.rootDir, filePath));
2279
+ await this.storeExtractionResult(filePath, content, language, stats, result, commitYield);
2280
+ const idx = errors.indexOf(errEntry);
2281
+ if (idx >= 0)
2282
+ errors.splice(idx, 1);
2283
+ filesErrored--;
2284
+ filesIndexed++;
2285
+ totalNodes += result.nodes.length;
2286
+ totalEdges += result.edges.length;
2287
+ log(`Retry OK: ${filePath} (${result.nodes.length} nodes)`);
2288
+ }
2289
+ }
2290
+ // Last resort: for files that still crash on a clean worker, strip
2291
+ // comment-only lines to reduce WASM memory pressure. Many compiler
2292
+ // test files are 90%+ comments (CHECK directives) that don't contribute
2293
+ // code nodes but consume parser memory.
2294
+ if (stillFailing.length > 0) {
2295
+ log(`${stillFailing.length} files still failing — retrying with comments stripped...`);
2296
+ pool.recycleAll();
2297
+ for (const errEntry of stillFailing) {
2298
+ const filePath = errEntry.filePath;
2299
+ if (signal?.aborted)
2300
+ break;
2301
+ let fullContent;
2302
+ try {
2303
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, filePath);
2304
+ if (!fullPath)
2305
+ continue;
2306
+ fullContent = await fsp.readFile(fullPath, 'utf-8');
2307
+ }
2308
+ catch {
2309
+ continue;
2310
+ }
2311
+ // Strip lines that are entirely comments (preserving line numbers
2312
+ // by replacing with empty lines so node positions stay correct)
2313
+ const stripped = fullContent
2314
+ .split('\n')
2315
+ .map(line => /^\s*\/\//.test(line) ? '' : line)
2316
+ .join('\n');
2317
+ let result;
2318
+ try {
2319
+ result = await parseFile(filePath, stripped);
2320
+ }
2321
+ catch {
2322
+ continue;
2323
+ }
2324
+ // Same undecoded-transport hazard as the first retry pass (#1541).
2325
+ const language = (0, grammars_1.detectLanguage)(filePath, fullContent, overrides);
2326
+ result = (0, kernel_1.materializeKernelResult)(result, filePath, language);
2327
+ if (result.nodes.length > 0 || result.errors.length === 0) {
2328
+ const stats = await fsp.stat(path.join(this.rootDir, filePath));
2329
+ await this.storeExtractionResult(filePath, fullContent, language, stats, result, commitYield);
2330
+ // Salvaged from comment-stripped source: keep a visible trace in
2331
+ // the summary instead of erasing the failure outright — the
2332
+ // stored result may be missing whatever the failing parse choked
2333
+ // on, and a silently "clean" file here is how an index quietly
2334
+ // disagrees with a later per-file sync of the same bytes (#1565).
2335
+ errEntry.severity = 'warning';
2336
+ errEntry.code = 'salvaged_stripped';
2337
+ errEntry.message = `Indexed from comment-stripped source after repeated parse failures (symbols may be incomplete until the file is re-indexed): ${errEntry.message}`;
2338
+ filesErrored--;
2339
+ filesIndexed++;
2340
+ totalNodes += result.nodes.length;
2341
+ totalEdges += result.edges.length;
2342
+ log(`Retry (stripped) OK: ${filePath} (${result.nodes.length} nodes)`);
2343
+ }
2344
+ }
2345
+ }
2346
+ }
2347
+ // Shut down the parse worker pool.
2348
+ if (pool)
2349
+ await pool.destroy();
2350
+ return {
2351
+ success: filesIndexed > 0 || errors.filter((e) => e.severity === 'error').length === 0,
2352
+ filesIndexed,
2353
+ filesSkipped,
2354
+ filesErrored,
2355
+ filesDiscovered: total,
2356
+ ...skipSummary(),
2357
+ nodesCreated: totalNodes,
2358
+ edgesCreated: totalEdges,
2359
+ errors,
2360
+ durationMs: Date.now() - startTime,
2361
+ };
2362
+ }
2363
+ /**
2364
+ * Index specific files
2365
+ */
2366
+ async indexFiles(filePaths) {
2367
+ const startTime = Date.now();
2368
+ const errors = [];
2369
+ let filesIndexed = 0;
2370
+ let filesSkipped = 0;
2371
+ let filesErrored = 0;
2372
+ let totalNodes = 0;
2373
+ let totalEdges = 0;
2374
+ for (const filePath of filePaths) {
2375
+ const result = await this.indexFile(filePath);
2376
+ if (result.errors.length > 0) {
2377
+ errors.push(...result.errors);
2378
+ }
2379
+ if (result.nodes.length > 0) {
2380
+ filesIndexed++;
2381
+ totalNodes += result.nodes.length;
2382
+ totalEdges += result.edges.length;
2383
+ }
2384
+ else if (result.errors.some((e) => e.severity === 'error')) {
2385
+ filesErrored++;
2386
+ }
2387
+ else {
2388
+ const tracked = this.queries.getFileByPath(filePath);
2389
+ if (tracked && (0, grammars_1.isFileLevelOnlyLanguage)(tracked.language)) {
2390
+ filesIndexed++;
2391
+ }
2392
+ else {
2393
+ filesSkipped++;
2394
+ }
2395
+ }
2396
+ }
2397
+ return {
2398
+ success: filesIndexed > 0 || errors.filter((e) => e.severity === 'error').length === 0,
2399
+ filesIndexed,
2400
+ filesSkipped,
2401
+ filesErrored,
2402
+ nodesCreated: totalNodes,
2403
+ edgesCreated: totalEdges,
2404
+ errors,
2405
+ durationMs: Date.now() - startTime,
2406
+ };
2407
+ }
2408
+ /**
2409
+ * Index a single file
2410
+ */
2411
+ async indexFile(relativePath) {
2412
+ // Indexing read: follow in-root symlinks (the `../` guard still applies), #935.
2413
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, relativePath, { allowSymlinkEscape: true });
2414
+ if (!fullPath) {
2415
+ return {
2416
+ nodes: [],
2417
+ edges: [],
2418
+ unresolvedReferences: [],
2419
+ errors: [{ message: `Path traversal blocked: ${relativePath}`, filePath: relativePath, severity: 'error', code: 'path_traversal' }],
2420
+ durationMs: 0,
2421
+ };
2422
+ }
2423
+ // Read file content and stats
2424
+ let content;
2425
+ let stats;
2426
+ try {
2427
+ stats = await fsp.stat(fullPath);
2428
+ content = await fsp.readFile(fullPath, 'utf-8');
2429
+ }
2430
+ catch (error) {
2431
+ return {
2432
+ nodes: [],
2433
+ edges: [],
2434
+ unresolvedReferences: [],
2435
+ errors: [
2436
+ {
2437
+ message: `Failed to read file: ${error instanceof Error ? error.message : String(error)}`,
2438
+ filePath: relativePath,
2439
+ severity: 'error',
2440
+ code: 'read_error',
2441
+ },
2442
+ ],
2443
+ durationMs: 0,
2444
+ };
2445
+ }
2446
+ return this.indexFileWithContent(relativePath, content, stats);
2447
+ }
2448
+ /**
2449
+ * Index a single file with pre-read content and stats.
2450
+ * Used by the parallel batch reader to avoid redundant file I/O.
2451
+ */
2452
+ async indexFileWithContent(relativePath, content, stats) {
2453
+ // Prevent `../` traversal; follow in-root symlinks like the directory walk (#935).
2454
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, relativePath, { allowSymlinkEscape: true });
2455
+ if (!fullPath) {
2456
+ (0, errors_1.logWarn)('Path traversal blocked in indexFileWithContent', { relativePath });
2457
+ return {
2458
+ nodes: [],
2459
+ edges: [],
2460
+ unresolvedReferences: [],
2461
+ errors: [{ message: 'Path traversal blocked', filePath: relativePath, severity: 'error', code: 'path_traversal' }],
2462
+ durationMs: 0,
2463
+ };
2464
+ }
2465
+ const language = (0, grammars_1.detectLanguage)(relativePath, content, (0, project_config_1.loadExtensionOverrides)(this.rootDir));
2466
+ // Check file size
2467
+ if (stats.size > MAX_FILE_SIZE) {
2468
+ const result = {
2469
+ nodes: [],
2470
+ edges: [],
2471
+ unresolvedReferences: [],
2472
+ errors: [
2473
+ {
2474
+ message: `File exceeds max size (${stats.size} > ${MAX_FILE_SIZE})`,
2475
+ filePath: relativePath,
2476
+ severity: 'warning',
2477
+ code: 'size_exceeded',
2478
+ },
2479
+ ],
2480
+ durationMs: 0,
2481
+ };
2482
+ await this.storeExtractionResult(relativePath, content, language, stats, result, (0, cooperative_yield_1.createYielder)());
2483
+ return result;
2484
+ }
2485
+ // Detect language (honoring the project's codegraph.json extension overrides)
2486
+ if (!(0, grammars_1.isLanguageSupported)(language)) {
2487
+ return {
2488
+ nodes: [],
2489
+ edges: [],
2490
+ unresolvedReferences: [],
2491
+ errors: [],
2492
+ durationMs: 0,
2493
+ };
2494
+ }
2495
+ // Extract from source. Use cached framework names if indexAll has run,
2496
+ // otherwise detect on the spot so single-file re-index paths still emit
2497
+ // route nodes / middleware / etc.
2498
+ const frameworkNames = this.ensureDetectedFrameworks();
2499
+ const result = (0, tree_sitter_1.extractFromSource)(relativePath, content, language, frameworkNames);
2500
+ // Store in database
2501
+ await this.storeExtractionResult(relativePath, content, language, stats, result, (0, cooperative_yield_1.createYielder)());
2502
+ return result;
2503
+ }
2504
+ /**
2505
+ * Store extraction result in database
2506
+ */
2507
+ /**
2508
+ * Delete file rows recorded with ZERO nodes so their files re-index.
2509
+ *
2510
+ * No extraction path stores an empty, error-free result for a
2511
+ * symbol-bearing language — even an empty file keeps its file node — so a
2512
+ * zero-node row is a wiped one (#1541: an interrupted parse's retry stored
2513
+ * an undecoded kernel transport). The wiped row's content hash matches the
2514
+ * on-disk bytes, so every hash-based reconcile skips the file forever;
2515
+ * deleting the row lets the normal add path repair it. File-level-only
2516
+ * languages (yaml, twig, properties) are left alone. Deleting a zero-node
2517
+ * row cascades nothing: it has no nodes, so no edges or refs either.
2518
+ */
2519
+ healZeroNodeRows() {
2520
+ for (const f of this.queries.getAllFiles()) {
2521
+ // A zero-node row WITH recorded errors is a deliberate skip marker
2522
+ // (#1557: oversized / repeatedly-unparseable files are persisted with
2523
+ // their reason so syncs stop retrying them) — leave those alone. The
2524
+ // #1541 wipe rows are the error-FREE zero-node rows.
2525
+ if (f.nodeCount === 0 &&
2526
+ !(0, grammars_1.isFileLevelOnlyLanguage)(f.language) &&
2527
+ (f.errors === undefined || f.errors.length === 0)) {
2528
+ this.queries.deleteFile(f.path);
2529
+ }
2530
+ }
2531
+ }
2532
+ async storeExtractionResult(filePath, content, language, stats, result, onYield) {
2533
+ // A kernel result can arrive as an undecoded buffer transport (empty
2534
+ // node/edge arrays, tables riding in kernelBuffers). Decode it before
2535
+ // storing — persisting the transport as-is records the file as having no
2536
+ // symbols at all (#1541). No-op for already-decoded results.
2537
+ result = (0, kernel_1.materializeKernelResult)(result, filePath, language);
2538
+ // Bulk inserts run in bounded sub-transactions with a yield between, so a
2539
+ // giant generated file (tens of thousands of symbols) can't block the
2540
+ // event loop — and the #850 watchdog heartbeat — for the whole store.
2541
+ // The file was NEVER one atomic transaction (each insert call has its
2542
+ // own), and the files-table record still lands last, so crash recovery
2543
+ // is unchanged: a partially-stored file has no record and re-indexes.
2544
+ const STORE_CHUNK = 2000;
2545
+ const contentHash = hashContent(content);
2546
+ // Check if file already exists and hasn't changed. A skip/failure MARKER
2547
+ // row (zero nodes + recorded errors, #1557) never blocks a store carrying
2548
+ // real content: markers are written BEFORE the retry pass under the same
2549
+ // content hash, so treating them as "no changes" would silently discard a
2550
+ // successful retry's symbols — a permanent empty file presented as
2551
+ // recovered (the #1541 wipe, reintroduced through the marker path).
2552
+ const existingFile = this.queries.getFileByPath(filePath);
2553
+ if (existingFile && existingFile.contentHash === contentHash) {
2554
+ const existingIsMarker = existingFile.nodeCount === 0 && (existingFile.errors?.length ?? 0) > 0;
2555
+ const incomingHasContent = result.nodes.length > 0;
2556
+ if (!existingIsMarker || !incomingHasContent) {
2557
+ return; // No changes
2558
+ }
2559
+ }
2560
+ // Re-decided on every re-index of a changed file, so a banner added (or
2561
+ // removed) by an edit is reflected on the next sync (#1500). Computed after
2562
+ // the unchanged-file early return so untouched files pay nothing.
2563
+ const generated = (0, generated_detection_1.detectGeneratedFile)(filePath, content);
2564
+ // Snapshot incoming cross-file edges BEFORE deleting this file's nodes.
2565
+ // `deleteFile` cascades to delete every edge whose source OR target is a
2566
+ // node in this file (edges.FK ... ON DELETE CASCADE). Edges whose SOURCE is
2567
+ // in this file are re-emitted by the extractor below, but edges whose SOURCE
2568
+ // is in a *different* (unchanged) file are not — they would be silently
2569
+ // dropped, which is issue #899: re-indexing a callee file severs `calls`/
2570
+ // `references` edges from callers that import it via module-attribute
2571
+ // access (`pkg.mod.fn(...)`).
2572
+ //
2573
+ // We snapshot the edge plus the target node's (name, kind) so we can
2574
+ // re-resolve to the re-indexed target's NEW id. Node ids are
2575
+ // `sha256(filePath:kind:name:line)`, so any line shift in the callee file
2576
+ // (e.g. a docstring-only edit above the symbol) changes every target id and
2577
+ // a naive re-insert by old id would silently drop every edge. Matching by
2578
+ // (filePath, kind, name) is stable across line shifts; if the symbol was
2579
+ // renamed/removed, no match is found and the edge stays dropped (correct).
2580
+ const crossFileIncomingEdges = existingFile
2581
+ ? this.queries.getCrossFileIncomingEdgesWithTarget(filePath)
2582
+ : [];
2583
+ // Delete existing data for this file
2584
+ if (existingFile) {
2585
+ this.queries.deleteFile(filePath);
2586
+ }
2587
+ // Filter out nodes with missing required fields before insertion.
2588
+ // This prevents FK violations when edges reference nodes that would
2589
+ // be silently skipped by insertNode() (see issue #42).
2590
+ const validNodes = result.nodes.filter((n) => n.id && n.kind && n.name && n.filePath && n.language);
2591
+ const insertedIds = new Set(validNodes.map((n) => n.id));
2592
+ const validEdges = result.edges.filter((e) => insertedIds.has(e.source) && insertedIds.has(e.target));
2593
+ const validRefs = result.unresolvedReferences
2594
+ .filter((ref) => insertedIds.has(ref.fromNodeId))
2595
+ .map((ref) => ({
2596
+ ...ref,
2597
+ filePath: ref.filePath ?? filePath,
2598
+ language: ref.language ?? language,
2599
+ }));
2600
+ // Fast path for the common case (everything fits one chunk): the whole
2601
+ // file — nodes, edges, refs, file record — lands in ONE transaction with
2602
+ // no event-loop yields in between. Giant generated files keep the chunked
2603
+ // + yielding path below so the #850 watchdog heartbeat stays serviced.
2604
+ const fitsOneChunk = validNodes.length <= STORE_CHUNK &&
2605
+ validEdges.length <= STORE_CHUNK &&
2606
+ validRefs.length <= STORE_CHUNK;
2607
+ if (fitsOneChunk) {
2608
+ // Snapshot/re-resolution of cross-file incoming edges (below) still runs
2609
+ // for the sync path; on a fresh bulk index crossFileIncomingEdges is [].
2610
+ this.queries.storeFileBundle({
2611
+ nodes: validNodes,
2612
+ edges: validEdges,
2613
+ refs: validRefs,
2614
+ file: {
2615
+ path: filePath,
2616
+ contentHash,
2617
+ language,
2618
+ size: stats.size,
2619
+ modifiedAt: stats.mtimeMs,
2620
+ indexedAt: Date.now(),
2621
+ nodeCount: result.nodes.length,
2622
+ errors: result.errors.length > 0 ? result.errors : undefined,
2623
+ generated,
2624
+ },
2625
+ });
2626
+ if (crossFileIncomingEdges.length > 0) {
2627
+ this.reattachCrossFileEdges(crossFileIncomingEdges, validNodes);
2628
+ }
2629
+ return;
2630
+ }
2631
+ // Insert nodes (chunked — see STORE_CHUNK above)
2632
+ for (let i = 0; i < validNodes.length; i += STORE_CHUNK) {
2633
+ this.queries.insertNodes(validNodes.slice(i, i + STORE_CHUNK));
2634
+ await onYield?.();
2635
+ }
2636
+ // Filter edges to only reference nodes that were actually inserted
2637
+ if (validEdges.length > 0) {
2638
+ for (let i = 0; i < validEdges.length; i += STORE_CHUNK) {
2639
+ this.queries.insertEdges(validEdges.slice(i, i + STORE_CHUNK));
2640
+ await onYield?.();
2641
+ }
2642
+ }
2643
+ // Re-insert cross-file incoming edges snapshotted before the delete,
2644
+ // re-resolving each edge's target to the re-indexed node's new id by
2645
+ // (filePath, kind, name). Node ids include the source line, so any line
2646
+ // shift in the callee file (e.g. a docstring-only edit above the symbol)
2647
+ // changes every target id and a naive re-insert by old id would drop them
2648
+ // all. `insertEdges` still filters to endpoints that exist. This closes
2649
+ // the #899 edge-drop on `sync`.
2650
+ //
2651
+ // Edges whose callee (target) was renamed/removed during the re-index (no
2652
+ // match in `newNodesByKindName`) are not silently dropped anymore: each is
2653
+ // resurrected as its ORIGINAL unresolved ref (stamped on the edge as
2654
+ // metadata.refName/refKind at creation) so the same sync's resolution
2655
+ // sweep can rebind it to an alternative definition elsewhere, or park it
2656
+ // as status='failed' to be retried when the symbol reappears — the
2657
+ // removal-side counterpart of #1240. Edges without refName (built before
2658
+ // the stamp existed, or synthesized) still drop silently: reconstructing
2659
+ // a ref from the target's plain name would strip receiver/qualifier
2660
+ // context and risk a rebind a full re-index would never make.
2661
+ if (crossFileIncomingEdges.length > 0) {
2662
+ this.reattachCrossFileEdges(crossFileIncomingEdges, validNodes);
2663
+ }
2664
+ // Insert unresolved references in batch with denormalized filePath/language
2665
+ for (let i = 0; i < validRefs.length; i += STORE_CHUNK) {
2666
+ this.queries.insertUnresolvedRefsBatch(validRefs.slice(i, i + STORE_CHUNK));
2667
+ await onYield?.();
2668
+ }
2669
+ // Insert file record
2670
+ const fileRecord = {
2671
+ path: filePath,
2672
+ contentHash,
2673
+ language,
2674
+ size: stats.size,
2675
+ modifiedAt: stats.mtimeMs,
2676
+ indexedAt: Date.now(),
2677
+ nodeCount: result.nodes.length,
2678
+ errors: result.errors.length > 0 ? result.errors : undefined,
2679
+ generated,
2680
+ };
2681
+ this.queries.upsertFile(fileRecord);
2682
+ }
2683
+ /**
2684
+ * Build one file's store bundle for the FRESH-DB path: no existing-file
2685
+ * check, no cross-file edge snapshot (both are re-index concerns — a fresh
2686
+ * database has neither). Filters mirror storeExtractionResult exactly.
2687
+ */
2688
+ /** The FileRecord for a fresh-index store (nodeCount is the PRE-filter count). */
2689
+ buildFileRecord(filePath, content, language, stats, nodeCount, resultErrors) {
2690
+ return {
2691
+ path: filePath,
2692
+ contentHash: hashContent(content),
2693
+ language,
2694
+ size: stats.size,
2695
+ modifiedAt: stats.mtimeMs,
2696
+ indexedAt: Date.now(),
2697
+ nodeCount,
2698
+ errors: resultErrors.length > 0 ? resultErrors : undefined,
2699
+ // Decided here, once, while the content is already in memory — never at
2700
+ // query time (#1500). The header scan short-circuits on a single
2701
+ // substring test for ~every hand-written file.
2702
+ generated: (0, generated_detection_1.detectGeneratedFile)(filePath, content),
2703
+ };
2704
+ }
2705
+ buildFreshStoreBundle(filePath, content, language, stats, result) {
2706
+ return (0, store_writer_1.finalizeStoreBundle)(result, filePath, language, this.buildFileRecord(filePath, content, language, stats, result.nodes.length, result.errors));
2707
+ }
2708
+ /**
2709
+ * Re-attach cross-file incoming edges snapshotted before a re-index delete
2710
+ * (#899): re-resolve each edge's target to the re-indexed node's new id by
2711
+ * (kind, name); targets that vanished are resurrected as their original
2712
+ * unresolved ref (#1240's removal-side counterpart) when the edge carries
2713
+ * its refName stamp.
2714
+ */
2715
+ reattachCrossFileEdges(crossFileIncomingEdges, validNodes) {
2716
+ const newNodesByKindName = new Map();
2717
+ for (const n of validNodes) {
2718
+ newNodesByKindName.set(`${n.kind}\0${n.name}`, n.id);
2719
+ }
2720
+ const reinserted = [];
2721
+ const resurrected = [];
2722
+ for (const e of crossFileIncomingEdges) {
2723
+ const newTargetId = newNodesByKindName.get(`${e.targetKind}\0${e.targetName}`);
2724
+ if (newTargetId) {
2725
+ reinserted.push({ source: e.source, target: newTargetId, kind: e.kind, metadata: e.metadata, line: e.line, column: e.column, provenance: e.provenance });
2726
+ }
2727
+ else {
2728
+ const ref = resurrectRefFromDroppedEdge(e);
2729
+ if (ref)
2730
+ resurrected.push(ref);
2731
+ }
2732
+ }
2733
+ if (reinserted.length > 0) {
2734
+ this.queries.insertEdges(reinserted);
2735
+ }
2736
+ if (resurrected.length > 0) {
2737
+ this.queries.insertUnresolvedRefsBatch(resurrected);
2738
+ }
2739
+ }
2740
+ /**
2741
+ * Re-open, for re-resolution, every resolution edge whose answer this sync
2742
+ * may have changed — the fix for index drift (CG-33).
2743
+ *
2744
+ * Incremental sync re-resolves only the references IN the changed files, but
2745
+ * resolution's answer is a function of the WHOLE graph: a reference binds to
2746
+ * one of the same-named definitions project-wide, so adding or removing a
2747
+ * definition of `pct` can change which `pct` every other file's `pct(...)`
2748
+ * should bind to. Those other files are never revisited, and their references
2749
+ * resolved successfully once and were deleted from `unresolved_refs`, so
2750
+ * nothing existed to revisit them with — the index kept an answer that was
2751
+ * correct against an older graph. Measured on codegraph's own long-lived
2752
+ * index: 4.3% of distinct edges differed from a clean rebuild, in BOTH
2753
+ * directions, overwhelmingly `calls`. See docs/benchmarks/index-drift-cg33.md.
2754
+ *
2755
+ * This deletes each affected edge and re-inserts it as the reference that
2756
+ * created it (the refName/refKind stamp), status='pending', for the sync's
2757
+ * resolution sweep to bind against the post-sync graph — the same input a
2758
+ * full rebuild resolves from, which is what makes the two converge.
2759
+ *
2760
+ * Deliberately conservative in three ways, because a wrong deletion is a
2761
+ * permanent edge loss while a missed rebind is only residual drift:
2762
+ * - an edge with no refName stamp (synthesized, or built by an engine older
2763
+ * than the stamp) is left ALONE rather than reconstructed from the target's
2764
+ * plain name, same rule as `resurrectRefFromDroppedEdge`;
2765
+ * - edges whose source is in a file this sync already re-extracted are
2766
+ * skipped — their references were re-resolved from scratch moments ago;
2767
+ * - very common names are skipped by the per-name ceiling in
2768
+ * `getResolutionEdgesByTargetName`.
2769
+ *
2770
+ * Returns the number of references resurrected.
2771
+ */
2772
+ resurrectStaleResolutionEdges(definitionDelta, changedFilePaths) {
2773
+ if (definitionDelta.length === 0)
2774
+ return 0;
2775
+ const alreadyFresh = new Set(changedFilePaths);
2776
+ const candidates = this.queries.getResolutionEdgesByTargetName(definitionDelta);
2777
+ const edgeIds = [];
2778
+ const refs = [];
2779
+ for (const e of candidates) {
2780
+ if (alreadyFresh.has(e.sourceFilePath))
2781
+ continue;
2782
+ const ref = resurrectRefFromDroppedEdge(e);
2783
+ if (!ref)
2784
+ continue; // no stamp — never delete what we cannot restore
2785
+ edgeIds.push(e.edgeId);
2786
+ refs.push(ref);
2787
+ }
2788
+ if (refs.length === 0)
2789
+ return 0;
2790
+ // Delete first. The sweep re-inserts whichever edge resolution now picks,
2791
+ // and `insertEdges` is INSERT OR IGNORE against idx_edges_identity — so a
2792
+ // rebind to the same target is a clean no-op, but leaving the old row in
2793
+ // place for a rebind ELSEWHERE would keep both, turning drift into
2794
+ // duplication.
2795
+ this.queries.replaceResolutionEdgesWithUnresolvedRefs(edgeIds, refs);
2796
+ return refs.length;
2797
+ }
2798
+ /**
2799
+ * Sync the index with the current file state.
2800
+ *
2801
+ * Change detection is filesystem-based, never git: a (size, mtime) stat
2802
+ * pre-filter skips unchanged files, then a content-hash compare confirms real
2803
+ * changes. This works in non-git projects and catches committed changes from
2804
+ * `git pull`/`checkout`/`merge`/`rebase` that `git status` cannot see.
2805
+ */
2806
+ async sync(onProgress,
2807
+ /**
2808
+ * Watcher fast path: the exact project-relative paths the OS reported as
2809
+ * changed. When provided, reconciliation runs over ONLY these paths —
2810
+ * per-path logic identical to the full walk (stat pre-filter, hash
2811
+ * confirm, the #1240 removal/resurrection flow) — skipping the O(repo)
2812
+ * scan and tracked-load. Callers must pass undefined whenever the change
2813
+ * set is not exactly known (directory removals, event overflow): the full
2814
+ * scan-diff remains the ground truth those cases need (#1285).
2815
+ */
2816
+ scopedPaths,
2817
+ /**
2818
+ * Writer-side WAL pressure valve (#1539). Called after every changed file
2819
+ * is stored, when no extraction transaction is open, so a checkpoint can
2820
+ * safely catch up before the next file grows the WAL further.
2821
+ */
2822
+ backpressure) {
2823
+ await (0, grammars_1.initGrammars)(); // Initialize WASM runtime (grammars loaded lazily below)
2824
+ const startTime = Date.now();
2825
+ let filesChecked = 0;
2826
+ let filesAdded = 0;
2827
+ let filesModified = 0;
2828
+ let filesRemoved = 0;
2829
+ let nodesUpdated = 0;
2830
+ const changedFilePaths = [];
2831
+ // `file\0name` definition pairs for the files this sync touches, sampled
2832
+ // BEFORE their nodes are replaced/deleted. Compared against the post-store
2833
+ // pairs below to derive `definitionDelta` (CG-33).
2834
+ const pairsBefore = new Set();
2835
+ onProgress?.({
2836
+ phase: 'scanning',
2837
+ current: 0,
2838
+ total: 0,
2839
+ });
2840
+ const filesToIndex = [];
2841
+ const failedFilePaths = [];
2842
+ // === Filesystem reconcile (git-independent) ===
2843
+ // The source of truth for "what changed" is the filesystem vs the indexed
2844
+ // state — never git. We enumerate the current source files and reconcile
2845
+ // each against the DB. A cheap (size, mtime) stat pre-filter skips unchanged
2846
+ // files without reading or hashing them, so the expensive read+hash+parse
2847
+ // only runs for files that actually changed. This catches edits/adds/deletes
2848
+ // whether or not the project uses git, and crucially also catches committed
2849
+ // changes from `git pull`/`checkout`/`merge`/`rebase` — which `git status`
2850
+ // cannot see, because the working tree is clean afterward.
2851
+ const tSyncScan = Date.now();
2852
+ let currentFiles;
2853
+ let trackedFiles;
2854
+ if (scopedPaths && scopedPaths.length > 0) {
2855
+ // Scoped reconcile: stat only the reported paths. filesChecked counts
2856
+ // the PATHS examined (not the files found) — it must stay non-zero even
2857
+ // when every scoped path was a deletion, because Alpha Code Sense.watch()
2858
+ // reads `filesChecked === 0 && durationMs === 0` as the
2859
+ // lock-unavailable signature (#449).
2860
+ const unique = [...new Set(scopedPaths)];
2861
+ // A scoped path is "present" only if it exists AND is in scope — the
2862
+ // same two gates the full walk applies (source extension, scope
2863
+ // matcher). Without the scope gate a caller's stale view of scope
2864
+ // leaked straight into the index: the watcher re-parsed a file the
2865
+ // user had just excluded in `codegraph.json` while `codegraph sync`
2866
+ // removed it (#1590). Out-of-scope paths fall out of `currentFiles`,
2867
+ // so a tracked one takes the removal branch below, exactly as a full
2868
+ // sync would treat it. (`include`-forced paths pass: ScopeIgnore
2869
+ // applies the include precedence itself.)
2870
+ const scope = this.scopedSyncMatcher();
2871
+ const overrides = (0, project_config_1.loadExtensionOverrides)(this.rootDir);
2872
+ currentFiles = unique.filter((p) => (0, grammars_1.isSourceFile)(p, overrides) &&
2873
+ !scope.ignores(p) &&
2874
+ fs.existsSync(path.join(this.rootDir, p)));
2875
+ trackedFiles = [];
2876
+ for (const p of unique) {
2877
+ const rec = this.queries.getFileByPath(p);
2878
+ if (rec)
2879
+ trackedFiles.push(rec);
2880
+ }
2881
+ filesChecked = unique.length;
2882
+ if (process.env.CODEGRAPH_SYNTH_TIMINGS)
2883
+ console.error(`[phase-timing] sync-scoped: ${Date.now() - tSyncScan}ms (${unique.length} paths, ${trackedFiles.length} tracked)`);
2884
+ }
2885
+ else {
2886
+ // Full reconcile: drop the memoized scope matcher so a nested
2887
+ // `.gitignore` / exclude-standard change that forced this full sync is
2888
+ // visible to the next scoped sync (#1728).
2889
+ this.scopedMatcher = null;
2890
+ currentFiles = await scanDirectoryAsync(this.rootDir);
2891
+ if (process.env.CODEGRAPH_SYNTH_TIMINGS)
2892
+ console.error(`[phase-timing] sync-scan: ${Date.now() - tSyncScan}ms (${currentFiles.length} files)`);
2893
+ filesChecked = currentFiles.length;
2894
+ // Full reconcile only (scoped syncs must not touch rows outside their
2895
+ // scope): drop zero-node rows so the wiped files re-index as adds below.
2896
+ this.healZeroNodeRows();
2897
+ const tTracked = Date.now();
2898
+ trackedFiles = this.queries.getAllFiles();
2899
+ if (process.env.CODEGRAPH_SYNTH_TIMINGS)
2900
+ console.error(`[phase-timing] sync-tracked-load: ${Date.now() - tTracked}ms (${trackedFiles.length} tracked)`);
2901
+ }
2902
+ const currentSet = new Set(currentFiles);
2903
+ const trackedMap = new Map();
2904
+ for (const f of trackedFiles) {
2905
+ trackedMap.set(f.path, f);
2906
+ }
2907
+ // Removals: tracked in the DB but no longer a present source file. Check the
2908
+ // filesystem directly — `scanDirectory` (via `git ls-files`) still lists a
2909
+ // file deleted from disk but not yet staged, so set membership alone misses it.
2910
+ // `reconcileChecks` drives the cooperative yield shared with the adds/mods loop
2911
+ // below (see SYNC_RECONCILE_YIELD_INTERVAL / issue #905).
2912
+ let reconcileChecks = 0;
2913
+ for (const tracked of trackedFiles) {
2914
+ if (!currentSet.has(tracked.path) || !fs.existsSync(path.join(this.rootDir, tracked.path))) {
2915
+ // Before the cascade deletes them, resurrect incoming cross-file
2916
+ // resolution edges as their original refs (#1240 removal case): the
2917
+ // callers live in files this sync will NOT revisit, so this is their
2918
+ // only chance to rebind to an alternative definition — or to park as
2919
+ // failed until the symbol reappears somewhere. (A deleted file whose
2920
+ // CALLERS are also being deleted is fine: their nodes cascade later
2921
+ // in this loop and take the resurrected rows with them.)
2922
+ // Every name this file defined is about to stop existing here, which
2923
+ // narrows the candidate set for that name repo-wide (CG-33).
2924
+ for (const pair of this.queries.getNodeNamePairsByFiles([tracked.path]))
2925
+ pairsBefore.add(pair);
2926
+ const incoming = this.queries.getCrossFileIncomingEdgesWithTarget(tracked.path);
2927
+ if (incoming.length > 0) {
2928
+ const resurrected = incoming
2929
+ .map((e) => resurrectRefFromDroppedEdge(e))
2930
+ .filter((r) => r !== null);
2931
+ if (resurrected.length > 0) {
2932
+ this.queries.insertUnresolvedRefsBatch(resurrected);
2933
+ }
2934
+ }
2935
+ this.queries.deleteFile(tracked.path);
2936
+ filesRemoved++;
2937
+ }
2938
+ if (++reconcileChecks % SYNC_RECONCILE_YIELD_INTERVAL === 0) {
2939
+ await new Promise((resolve) => setImmediate(resolve));
2940
+ }
2941
+ }
2942
+ // Adds / modifications.
2943
+ for (const filePath of currentFiles) {
2944
+ // Same cooperative yield as the removals loop — this is the other O(files)
2945
+ // synchronous-stat loop that wedges the main thread on a large repo (#905).
2946
+ // Yield at the top of the body so the `continue` fast-paths below still hit it.
2947
+ if (++reconcileChecks % SYNC_RECONCILE_YIELD_INTERVAL === 0) {
2948
+ await new Promise((resolve) => setImmediate(resolve));
2949
+ }
2950
+ const fullPath = path.join(this.rootDir, filePath);
2951
+ const tracked = trackedMap.get(filePath);
2952
+ // Cheap pre-filter: an already-indexed file whose size AND mtime both match
2953
+ // the DB is unchanged — skip it without reading or hashing. (A content
2954
+ // change that preserves both exactly is the blind spot every mtime-based
2955
+ // incremental tool accepts; `index --force` is the escape hatch. Git bumps
2956
+ // mtime on every file it writes during checkout/merge, so pulls are caught.)
2957
+ if (tracked) {
2958
+ try {
2959
+ const stat = fs.statSync(fullPath);
2960
+ if (stat.size === tracked.size && Math.floor(stat.mtimeMs) === Math.floor(tracked.modifiedAt)) {
2961
+ continue;
2962
+ }
2963
+ }
2964
+ catch (error) {
2965
+ (0, errors_1.logDebug)('Skipping unstattable file during sync', { filePath, error: String(error) });
2966
+ failedFilePaths.push(filePath);
2967
+ continue;
2968
+ }
2969
+ }
2970
+ // New, or size/mtime changed — read + hash to confirm a real content change.
2971
+ let content;
2972
+ try {
2973
+ content = fs.readFileSync(fullPath, 'utf-8');
2974
+ }
2975
+ catch (error) {
2976
+ (0, errors_1.logDebug)('Skipping unreadable file during sync', { filePath, error: String(error) });
2977
+ failedFilePaths.push(filePath);
2978
+ continue;
2979
+ }
2980
+ const contentHash = hashContent(content);
2981
+ if (!tracked) {
2982
+ filesToIndex.push(filePath);
2983
+ changedFilePaths.push(filePath);
2984
+ filesAdded++;
2985
+ }
2986
+ else if (tracked.contentHash !== contentHash) {
2987
+ filesToIndex.push(filePath);
2988
+ changedFilePaths.push(filePath);
2989
+ filesModified++;
2990
+ }
2991
+ }
2992
+ // Sampled here — after the add/modify classification, before any file is
2993
+ // re-extracted — because `storeExtractionResult` deletes a file's nodes
2994
+ // before inserting the new ones, so this is the last point the pre-edit
2995
+ // definition set is readable (CG-33).
2996
+ if (filesToIndex.length > 0) {
2997
+ for (const pair of this.queries.getNodeNamePairsByFiles(filesToIndex))
2998
+ pairsBefore.add(pair);
2999
+ }
3000
+ // Load only grammars needed for changed files
3001
+ if (filesToIndex.length > 0) {
3002
+ const overrides = (0, project_config_1.loadExtensionOverrides)(this.rootDir);
3003
+ await (0, grammars_1.loadGrammarsForLanguages)(preloadLanguagesForFiles(filesToIndex, overrides));
3004
+ }
3005
+ // Index changed files
3006
+ const total = filesToIndex.length;
3007
+ for (let i = 0; i < filesToIndex.length; i++) {
3008
+ const filePath = filesToIndex[i];
3009
+ onProgress?.({
3010
+ phase: 'parsing',
3011
+ current: i + 1,
3012
+ total,
3013
+ currentFile: filePath,
3014
+ });
3015
+ const result = await this.indexFile(filePath);
3016
+ if (result.errors.some(e => e.severity === 'error'))
3017
+ failedFilePaths.push(filePath);
3018
+ nodesUpdated += result.nodes.length;
3019
+ const pause = backpressure?.();
3020
+ if (pause)
3021
+ await pause;
3022
+ }
3023
+ // Names whose definition set this sync changed: a `file\0name` pair present
3024
+ // before but not after (removed/renamed away) or after but not before
3025
+ // (added). A pair on both sides is untouched as far as resolution's
3026
+ // candidate set is concerned — only its node id moved, which
3027
+ // reattachCrossFileEdges already follows — so an edit that only changes
3028
+ // bodies yields an empty delta and no downstream rebind work (CG-33).
3029
+ //
3030
+ // Compared per FILE, not as one name set over the whole batch: a commit
3031
+ // that adds `collect` to a new file while an unrelated changed file already
3032
+ // defined `collect` must still flag the name, and a bare name set cancels
3033
+ // exactly that case out. That miss left the largest residual class in the
3034
+ // first measurement of this fix.
3035
+ const pairsAfter = this.queries.getNodeNamePairsByFiles(filesToIndex);
3036
+ const deltaNames = new Set();
3037
+ const nameOf = (pair) => pair.slice(pair.indexOf('\0') + 1);
3038
+ for (const pair of pairsBefore)
3039
+ if (!pairsAfter.has(pair))
3040
+ deltaNames.add(nameOf(pair));
3041
+ for (const pair of pairsAfter)
3042
+ if (!pairsBefore.has(pair))
3043
+ deltaNames.add(nameOf(pair));
3044
+ const definitionDelta = [...deltaNames];
3045
+ return {
3046
+ filesChecked,
3047
+ filesAdded,
3048
+ filesModified,
3049
+ filesRemoved,
3050
+ nodesUpdated,
3051
+ durationMs: Date.now() - startTime,
3052
+ changedFilePaths: changedFilePaths.length > 0 ? changedFilePaths : undefined,
3053
+ ...(failedFilePaths.length > 0 ? { failedFilePaths } : {}),
3054
+ definitionDelta: definitionDelta.length > 0 ? definitionDelta : undefined,
3055
+ };
3056
+ }
3057
+ indexedDirtyPaths(stamp) {
3058
+ try {
3059
+ const state = JSON.parse(this.queries.getMetadata('indexed_dirty_paths') ?? 'null');
3060
+ if (!state || state.commit !== (stamp ?? '') || !Array.isArray(state.paths))
3061
+ return null;
3062
+ if (!state.paths.every((p) => typeof p === 'string' && p.length > 0 &&
3063
+ !path.isAbsolute(p) && !p.split('/').includes('..')))
3064
+ return null;
3065
+ return state.paths;
3066
+ }
3067
+ catch {
3068
+ return null;
3069
+ }
3070
+ }
3071
+ /** Capture before file reads. In-flight/failed full writes must not claim freshness. */
3072
+ beginGitIndexState(full) {
3073
+ const head = getGitHeadSha(this.rootDir) ?? '';
3074
+ const stamp = this.queries.getMetadata(exports.INDEXED_AT_COMMIT_KEY) ?? '';
3075
+ const prior = this.indexedDirtyPaths(stamp);
3076
+ const status = getGitChangedFiles(this.rootDir);
3077
+ const dirty = status ? [...new Set([
3078
+ ...(full ? [] : prior ?? []), ...status.added, ...status.modified, ...status.deleted,
3079
+ ])] : null;
3080
+ if (full || prior === null || dirty === null) {
3081
+ this.queries.setMetadata(exports.INDEXED_AT_COMMIT_KEY, '');
3082
+ this.queries.setMetadata('indexed_dirty_paths', '');
3083
+ }
3084
+ else {
3085
+ // Scoped writes leave the commit alone and retain dirty paths before the
3086
+ // first write, so a crash cannot forget an indexed uncommitted edit.
3087
+ this.queries.setMetadata('indexed_dirty_paths', JSON.stringify({ commit: stamp, paths: dirty }));
3088
+ }
3089
+ return { head, stamp, dirty };
3090
+ }
3091
+ finishGitIndexState(snapshot, full, retries = []) {
3092
+ const after = getGitChangedFiles(this.rootDir);
3093
+ if (!snapshot.dirty || !after)
3094
+ return;
3095
+ const commit = full ? snapshot.head : snapshot.stamp;
3096
+ const paths = [...new Set([...snapshot.dirty, ...after.added, ...after.modified, ...after.deleted, ...retries])].sort();
3097
+ // The embedded commit makes a torn pair fail closed: readers reject a dirty
3098
+ // set that doesn't match the separately stored commit. Write the set first.
3099
+ this.queries.setMetadata('indexed_dirty_paths', JSON.stringify({ commit, paths }));
3100
+ if (full)
3101
+ this.queries.setMetadata(exports.INDEXED_AT_COMMIT_KEY, commit);
3102
+ }
3103
+ /**
3104
+ * Get files that have changed since last index.
3105
+ * Uses git status as a fast path when available, falling back to full scan.
3106
+ */
3107
+ getChangedFiles() {
3108
+ // The commit this index was last brought up to date at. Absent on an index
3109
+ // built before stamping existed — getGitChangedFiles then declines the fast
3110
+ // path and the full scan below answers correctly, once, until a sync or a
3111
+ // full index writes the stamp. (#1829)
3112
+ let sinceCommit = null;
3113
+ try {
3114
+ sinceCommit = this.queries.getMetadata(exports.INDEXED_AT_COMMIT_KEY) ?? null;
3115
+ }
3116
+ catch { /* advisory */ }
3117
+ const dirtyPaths = this.indexedDirtyPaths(sinceCommit);
3118
+ const gitChanges = dirtyPaths !== null && canTrustGitFastPath(this.rootDir, sinceCommit)
3119
+ ? getGitChangedFiles(this.rootDir, sinceCommit)
3120
+ : null;
3121
+ if (gitChanges) {
3122
+ // === Git fast path ===
3123
+ const added = [];
3124
+ const modified = [];
3125
+ const removed = [];
3126
+ // Git supplies candidates, never the verdict. A committed deletion may
3127
+ // have been recreated locally; a previously indexed dirty path may have
3128
+ // vanished from git status after restore. Classify current disk vs DB once.
3129
+ const candidates = new Set([...gitChanges.deleted, ...gitChanges.modified, ...gitChanges.added, ...dirtyPaths]);
3130
+ const scope = this.scopedSyncMatcher();
3131
+ const overrides = (0, project_config_1.loadExtensionOverrides)(this.rootDir);
3132
+ for (const filePath of candidates) {
3133
+ const tracked = this.queries.getFileByPath(filePath);
3134
+ const fullPath = path.join(this.rootDir, filePath);
3135
+ if (!(0, grammars_1.isSourceFile)(filePath, overrides) || scope.ignores(filePath) || !fs.existsSync(fullPath)) {
3136
+ if (tracked)
3137
+ removed.push(filePath);
3138
+ continue;
3139
+ }
3140
+ let content;
3141
+ try {
3142
+ content = fs.readFileSync(fullPath, 'utf-8');
3143
+ }
3144
+ catch (error) {
3145
+ (0, errors_1.logDebug)('Skipping unreadable file while detecting changes', { filePath, error: String(error) });
3146
+ continue;
3147
+ }
3148
+ if (!tracked)
3149
+ added.push(filePath);
3150
+ else if (tracked.contentHash !== hashContent(content))
3151
+ modified.push(filePath);
3152
+ }
3153
+ return { added, modified, removed };
3154
+ }
3155
+ // === Fallback: full scan (non-git project or git failure) ===
3156
+ const currentFiles = new Set(scanDirectory(this.rootDir));
3157
+ const trackedFiles = this.queries.getAllFiles();
3158
+ // Build Map for O(1) lookups
3159
+ const trackedMap = new Map();
3160
+ for (const f of trackedFiles) {
3161
+ trackedMap.set(f.path, f);
3162
+ }
3163
+ const added = [];
3164
+ const modified = [];
3165
+ const removed = [];
3166
+ // Find removed files
3167
+ for (const tracked of trackedFiles) {
3168
+ if (!currentFiles.has(tracked.path)) {
3169
+ removed.push(tracked.path);
3170
+ }
3171
+ }
3172
+ // Find added and modified files
3173
+ for (const filePath of currentFiles) {
3174
+ const fullPath = path.join(this.rootDir, filePath);
3175
+ let content;
3176
+ try {
3177
+ content = fs.readFileSync(fullPath, 'utf-8');
3178
+ }
3179
+ catch (error) {
3180
+ (0, errors_1.logDebug)('Skipping unreadable file while detecting changes', { filePath, error: String(error) });
3181
+ continue;
3182
+ }
3183
+ const contentHash = hashContent(content);
3184
+ const tracked = trackedMap.get(filePath);
3185
+ if (!tracked) {
3186
+ added.push(filePath);
3187
+ }
3188
+ else if (tracked.contentHash !== contentHash) {
3189
+ modified.push(filePath);
3190
+ }
3191
+ }
3192
+ return { added, modified, removed };
3193
+ }
3194
+ }
3195
+ exports.ExtractionOrchestrator = ExtractionOrchestrator;
3196
+ // Re-export useful types and functions
3197
+ var tree_sitter_2 = require("./tree-sitter");
3198
+ Object.defineProperty(exports, "extractFromSource", { enumerable: true, get: function () { return tree_sitter_2.extractFromSource; } });
3199
+ var grammars_2 = require("./grammars");
3200
+ Object.defineProperty(exports, "detectLanguage", { enumerable: true, get: function () { return grammars_2.detectLanguage; } });
3201
+ Object.defineProperty(exports, "isSourceFile", { enumerable: true, get: function () { return grammars_2.isSourceFile; } });
3202
+ Object.defineProperty(exports, "isLanguageSupported", { enumerable: true, get: function () { return grammars_2.isLanguageSupported; } });
3203
+ Object.defineProperty(exports, "isGrammarLoaded", { enumerable: true, get: function () { return grammars_2.isGrammarLoaded; } });
3204
+ Object.defineProperty(exports, "getSupportedLanguages", { enumerable: true, get: function () { return grammars_2.getSupportedLanguages; } });
3205
+ Object.defineProperty(exports, "initGrammars", { enumerable: true, get: function () { return grammars_2.initGrammars; } });
3206
+ Object.defineProperty(exports, "loadGrammarsForLanguages", { enumerable: true, get: function () { return grammars_2.loadGrammarsForLanguages; } });
3207
+ Object.defineProperty(exports, "loadAllGrammars", { enumerable: true, get: function () { return grammars_2.loadAllGrammars; } });
3208
+ //# sourceMappingURL=index.js.map