@kkvcrobatz107/codegraph 0.9.6-pkm.1

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 (501) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +595 -0
  3. package/dist/bin/codegraph.d.ts +25 -0
  4. package/dist/bin/codegraph.d.ts.map +1 -0
  5. package/dist/bin/codegraph.js +1563 -0
  6. package/dist/bin/codegraph.js.map +1 -0
  7. package/dist/bin/node-version-check.d.ts +37 -0
  8. package/dist/bin/node-version-check.d.ts.map +1 -0
  9. package/dist/bin/node-version-check.js +79 -0
  10. package/dist/bin/node-version-check.js.map +1 -0
  11. package/dist/bin/uninstall.d.ts +14 -0
  12. package/dist/bin/uninstall.d.ts.map +1 -0
  13. package/dist/bin/uninstall.js +36 -0
  14. package/dist/bin/uninstall.js.map +1 -0
  15. package/dist/context/formatter.d.ts +30 -0
  16. package/dist/context/formatter.d.ts.map +1 -0
  17. package/dist/context/formatter.js +244 -0
  18. package/dist/context/formatter.js.map +1 -0
  19. package/dist/context/index.d.ts +110 -0
  20. package/dist/context/index.d.ts.map +1 -0
  21. package/dist/context/index.js +1169 -0
  22. package/dist/context/index.js.map +1 -0
  23. package/dist/db/index.d.ts +101 -0
  24. package/dist/db/index.d.ts.map +1 -0
  25. package/dist/db/index.js +251 -0
  26. package/dist/db/index.js.map +1 -0
  27. package/dist/db/migrations.d.ts +44 -0
  28. package/dist/db/migrations.d.ts.map +1 -0
  29. package/dist/db/migrations.js +131 -0
  30. package/dist/db/migrations.js.map +1 -0
  31. package/dist/db/queries.d.ts +281 -0
  32. package/dist/db/queries.d.ts.map +1 -0
  33. package/dist/db/queries.js +1300 -0
  34. package/dist/db/queries.js.map +1 -0
  35. package/dist/db/schema.sql +151 -0
  36. package/dist/db/sqlite-adapter.d.ts +46 -0
  37. package/dist/db/sqlite-adapter.d.ts.map +1 -0
  38. package/dist/db/sqlite-adapter.js +114 -0
  39. package/dist/db/sqlite-adapter.js.map +1 -0
  40. package/dist/directory.d.ts +57 -0
  41. package/dist/directory.d.ts.map +1 -0
  42. package/dist/directory.js +264 -0
  43. package/dist/directory.js.map +1 -0
  44. package/dist/errors.d.ts +136 -0
  45. package/dist/errors.d.ts.map +1 -0
  46. package/dist/errors.js +219 -0
  47. package/dist/errors.js.map +1 -0
  48. package/dist/extraction/dfm-extractor.d.ts +31 -0
  49. package/dist/extraction/dfm-extractor.d.ts.map +1 -0
  50. package/dist/extraction/dfm-extractor.js +151 -0
  51. package/dist/extraction/dfm-extractor.js.map +1 -0
  52. package/dist/extraction/grammars.d.ts +90 -0
  53. package/dist/extraction/grammars.d.ts.map +1 -0
  54. package/dist/extraction/grammars.js +407 -0
  55. package/dist/extraction/grammars.js.map +1 -0
  56. package/dist/extraction/index.d.ts +138 -0
  57. package/dist/extraction/index.d.ts.map +1 -0
  58. package/dist/extraction/index.js +1378 -0
  59. package/dist/extraction/index.js.map +1 -0
  60. package/dist/extraction/languages/c-cpp.d.ts +4 -0
  61. package/dist/extraction/languages/c-cpp.d.ts.map +1 -0
  62. package/dist/extraction/languages/c-cpp.js +171 -0
  63. package/dist/extraction/languages/c-cpp.js.map +1 -0
  64. package/dist/extraction/languages/csharp.d.ts +3 -0
  65. package/dist/extraction/languages/csharp.d.ts.map +1 -0
  66. package/dist/extraction/languages/csharp.js +73 -0
  67. package/dist/extraction/languages/csharp.js.map +1 -0
  68. package/dist/extraction/languages/dart.d.ts +3 -0
  69. package/dist/extraction/languages/dart.d.ts.map +1 -0
  70. package/dist/extraction/languages/dart.js +192 -0
  71. package/dist/extraction/languages/dart.js.map +1 -0
  72. package/dist/extraction/languages/go.d.ts +3 -0
  73. package/dist/extraction/languages/go.d.ts.map +1 -0
  74. package/dist/extraction/languages/go.js +70 -0
  75. package/dist/extraction/languages/go.js.map +1 -0
  76. package/dist/extraction/languages/index.d.ts +10 -0
  77. package/dist/extraction/languages/index.d.ts.map +1 -0
  78. package/dist/extraction/languages/index.js +51 -0
  79. package/dist/extraction/languages/index.js.map +1 -0
  80. package/dist/extraction/languages/java.d.ts +3 -0
  81. package/dist/extraction/languages/java.d.ts.map +1 -0
  82. package/dist/extraction/languages/java.js +70 -0
  83. package/dist/extraction/languages/java.js.map +1 -0
  84. package/dist/extraction/languages/javascript.d.ts +3 -0
  85. package/dist/extraction/languages/javascript.d.ts.map +1 -0
  86. package/dist/extraction/languages/javascript.js +90 -0
  87. package/dist/extraction/languages/javascript.js.map +1 -0
  88. package/dist/extraction/languages/kotlin.d.ts +3 -0
  89. package/dist/extraction/languages/kotlin.d.ts.map +1 -0
  90. package/dist/extraction/languages/kotlin.js +259 -0
  91. package/dist/extraction/languages/kotlin.js.map +1 -0
  92. package/dist/extraction/languages/lua.d.ts +3 -0
  93. package/dist/extraction/languages/lua.d.ts.map +1 -0
  94. package/dist/extraction/languages/lua.js +150 -0
  95. package/dist/extraction/languages/lua.js.map +1 -0
  96. package/dist/extraction/languages/luau.d.ts +3 -0
  97. package/dist/extraction/languages/luau.d.ts.map +1 -0
  98. package/dist/extraction/languages/luau.js +37 -0
  99. package/dist/extraction/languages/luau.js.map +1 -0
  100. package/dist/extraction/languages/objc.d.ts +3 -0
  101. package/dist/extraction/languages/objc.d.ts.map +1 -0
  102. package/dist/extraction/languages/objc.js +133 -0
  103. package/dist/extraction/languages/objc.js.map +1 -0
  104. package/dist/extraction/languages/pascal.d.ts +3 -0
  105. package/dist/extraction/languages/pascal.d.ts.map +1 -0
  106. package/dist/extraction/languages/pascal.js +66 -0
  107. package/dist/extraction/languages/pascal.js.map +1 -0
  108. package/dist/extraction/languages/php.d.ts +3 -0
  109. package/dist/extraction/languages/php.d.ts.map +1 -0
  110. package/dist/extraction/languages/php.js +107 -0
  111. package/dist/extraction/languages/php.js.map +1 -0
  112. package/dist/extraction/languages/python.d.ts +3 -0
  113. package/dist/extraction/languages/python.d.ts.map +1 -0
  114. package/dist/extraction/languages/python.js +56 -0
  115. package/dist/extraction/languages/python.js.map +1 -0
  116. package/dist/extraction/languages/ruby.d.ts +3 -0
  117. package/dist/extraction/languages/ruby.d.ts.map +1 -0
  118. package/dist/extraction/languages/ruby.js +114 -0
  119. package/dist/extraction/languages/ruby.js.map +1 -0
  120. package/dist/extraction/languages/rust.d.ts +3 -0
  121. package/dist/extraction/languages/rust.d.ts.map +1 -0
  122. package/dist/extraction/languages/rust.js +109 -0
  123. package/dist/extraction/languages/rust.js.map +1 -0
  124. package/dist/extraction/languages/scala.d.ts +3 -0
  125. package/dist/extraction/languages/scala.d.ts.map +1 -0
  126. package/dist/extraction/languages/scala.js +139 -0
  127. package/dist/extraction/languages/scala.js.map +1 -0
  128. package/dist/extraction/languages/swift.d.ts +3 -0
  129. package/dist/extraction/languages/swift.d.ts.map +1 -0
  130. package/dist/extraction/languages/swift.js +91 -0
  131. package/dist/extraction/languages/swift.js.map +1 -0
  132. package/dist/extraction/languages/typescript.d.ts +3 -0
  133. package/dist/extraction/languages/typescript.d.ts.map +1 -0
  134. package/dist/extraction/languages/typescript.js +129 -0
  135. package/dist/extraction/languages/typescript.js.map +1 -0
  136. package/dist/extraction/liquid-extractor.d.ts +52 -0
  137. package/dist/extraction/liquid-extractor.d.ts.map +1 -0
  138. package/dist/extraction/liquid-extractor.js +313 -0
  139. package/dist/extraction/liquid-extractor.js.map +1 -0
  140. package/dist/extraction/mybatis-extractor.d.ts +48 -0
  141. package/dist/extraction/mybatis-extractor.d.ts.map +1 -0
  142. package/dist/extraction/mybatis-extractor.js +198 -0
  143. package/dist/extraction/mybatis-extractor.js.map +1 -0
  144. package/dist/extraction/parse-worker.d.ts +8 -0
  145. package/dist/extraction/parse-worker.d.ts.map +1 -0
  146. package/dist/extraction/parse-worker.js +94 -0
  147. package/dist/extraction/parse-worker.js.map +1 -0
  148. package/dist/extraction/svelte-extractor.d.ts +56 -0
  149. package/dist/extraction/svelte-extractor.d.ts.map +1 -0
  150. package/dist/extraction/svelte-extractor.js +272 -0
  151. package/dist/extraction/svelte-extractor.js.map +1 -0
  152. package/dist/extraction/tree-sitter-helpers.d.ts +28 -0
  153. package/dist/extraction/tree-sitter-helpers.d.ts.map +1 -0
  154. package/dist/extraction/tree-sitter-helpers.js +103 -0
  155. package/dist/extraction/tree-sitter-helpers.js.map +1 -0
  156. package/dist/extraction/tree-sitter-types.d.ts +193 -0
  157. package/dist/extraction/tree-sitter-types.d.ts.map +1 -0
  158. package/dist/extraction/tree-sitter-types.js +10 -0
  159. package/dist/extraction/tree-sitter-types.js.map +1 -0
  160. package/dist/extraction/tree-sitter.d.ts +291 -0
  161. package/dist/extraction/tree-sitter.d.ts.map +1 -0
  162. package/dist/extraction/tree-sitter.js +2961 -0
  163. package/dist/extraction/tree-sitter.js.map +1 -0
  164. package/dist/extraction/vue-extractor.d.ts +36 -0
  165. package/dist/extraction/vue-extractor.d.ts.map +1 -0
  166. package/dist/extraction/vue-extractor.js +163 -0
  167. package/dist/extraction/vue-extractor.js.map +1 -0
  168. package/dist/extraction/wasm/tree-sitter-lua.wasm +0 -0
  169. package/dist/extraction/wasm/tree-sitter-luau.wasm +0 -0
  170. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  171. package/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
  172. package/dist/extraction/wasm-runtime-flags.d.ts +38 -0
  173. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -0
  174. package/dist/extraction/wasm-runtime-flags.js +105 -0
  175. package/dist/extraction/wasm-runtime-flags.js.map +1 -0
  176. package/dist/graph/index.d.ts +8 -0
  177. package/dist/graph/index.d.ts.map +1 -0
  178. package/dist/graph/index.js +13 -0
  179. package/dist/graph/index.js.map +1 -0
  180. package/dist/graph/queries.d.ts +106 -0
  181. package/dist/graph/queries.d.ts.map +1 -0
  182. package/dist/graph/queries.js +366 -0
  183. package/dist/graph/queries.js.map +1 -0
  184. package/dist/graph/traversal.d.ts +127 -0
  185. package/dist/graph/traversal.d.ts.map +1 -0
  186. package/dist/graph/traversal.js +528 -0
  187. package/dist/graph/traversal.js.map +1 -0
  188. package/dist/index.d.ts +460 -0
  189. package/dist/index.d.ts.map +1 -0
  190. package/dist/index.js +863 -0
  191. package/dist/index.js.map +1 -0
  192. package/dist/installer/claude-md-template.d.ts +14 -0
  193. package/dist/installer/claude-md-template.d.ts.map +1 -0
  194. package/dist/installer/claude-md-template.js +21 -0
  195. package/dist/installer/claude-md-template.js.map +1 -0
  196. package/dist/installer/config-writer.d.ts +29 -0
  197. package/dist/installer/config-writer.d.ts.map +1 -0
  198. package/dist/installer/config-writer.js +111 -0
  199. package/dist/installer/config-writer.js.map +1 -0
  200. package/dist/installer/index.d.ts +117 -0
  201. package/dist/installer/index.d.ts.map +1 -0
  202. package/dist/installer/index.js +528 -0
  203. package/dist/installer/index.js.map +1 -0
  204. package/dist/installer/instructions-template.d.ts +28 -0
  205. package/dist/installer/instructions-template.d.ts.map +1 -0
  206. package/dist/installer/instructions-template.js +65 -0
  207. package/dist/installer/instructions-template.js.map +1 -0
  208. package/dist/installer/targets/antigravity.d.ts +57 -0
  209. package/dist/installer/targets/antigravity.d.ts.map +1 -0
  210. package/dist/installer/targets/antigravity.js +307 -0
  211. package/dist/installer/targets/antigravity.js.map +1 -0
  212. package/dist/installer/targets/claude.d.ts +47 -0
  213. package/dist/installer/targets/claude.d.ts.map +1 -0
  214. package/dist/installer/targets/claude.js +401 -0
  215. package/dist/installer/targets/claude.js.map +1 -0
  216. package/dist/installer/targets/codex.d.ts +18 -0
  217. package/dist/installer/targets/codex.d.ts.map +1 -0
  218. package/dist/installer/targets/codex.js +185 -0
  219. package/dist/installer/targets/codex.js.map +1 -0
  220. package/dist/installer/targets/cursor.d.ts +35 -0
  221. package/dist/installer/targets/cursor.d.ts.map +1 -0
  222. package/dist/installer/targets/cursor.js +283 -0
  223. package/dist/installer/targets/cursor.js.map +1 -0
  224. package/dist/installer/targets/gemini.d.ts +26 -0
  225. package/dist/installer/targets/gemini.d.ts.map +1 -0
  226. package/dist/installer/targets/gemini.js +165 -0
  227. package/dist/installer/targets/gemini.js.map +1 -0
  228. package/dist/installer/targets/hermes.d.ts +18 -0
  229. package/dist/installer/targets/hermes.d.ts.map +1 -0
  230. package/dist/installer/targets/hermes.js +359 -0
  231. package/dist/installer/targets/hermes.js.map +1 -0
  232. package/dist/installer/targets/kiro.d.ts +27 -0
  233. package/dist/installer/targets/kiro.d.ts.map +1 -0
  234. package/dist/installer/targets/kiro.js +196 -0
  235. package/dist/installer/targets/kiro.js.map +1 -0
  236. package/dist/installer/targets/opencode.d.ts +30 -0
  237. package/dist/installer/targets/opencode.d.ts.map +1 -0
  238. package/dist/installer/targets/opencode.js +235 -0
  239. package/dist/installer/targets/opencode.js.map +1 -0
  240. package/dist/installer/targets/registry.d.ts +35 -0
  241. package/dist/installer/targets/registry.d.ts.map +1 -0
  242. package/dist/installer/targets/registry.js +91 -0
  243. package/dist/installer/targets/registry.js.map +1 -0
  244. package/dist/installer/targets/shared.d.ts +77 -0
  245. package/dist/installer/targets/shared.d.ts.map +1 -0
  246. package/dist/installer/targets/shared.js +246 -0
  247. package/dist/installer/targets/shared.js.map +1 -0
  248. package/dist/installer/targets/toml.d.ts +52 -0
  249. package/dist/installer/targets/toml.d.ts.map +1 -0
  250. package/dist/installer/targets/toml.js +147 -0
  251. package/dist/installer/targets/toml.js.map +1 -0
  252. package/dist/installer/targets/types.d.ts +116 -0
  253. package/dist/installer/targets/types.d.ts.map +1 -0
  254. package/dist/installer/targets/types.js +16 -0
  255. package/dist/installer/targets/types.js.map +1 -0
  256. package/dist/mcp/daemon-paths.d.ts +46 -0
  257. package/dist/mcp/daemon-paths.d.ts.map +1 -0
  258. package/dist/mcp/daemon-paths.js +125 -0
  259. package/dist/mcp/daemon-paths.js.map +1 -0
  260. package/dist/mcp/daemon.d.ts +161 -0
  261. package/dist/mcp/daemon.d.ts.map +1 -0
  262. package/dist/mcp/daemon.js +403 -0
  263. package/dist/mcp/daemon.js.map +1 -0
  264. package/dist/mcp/engine.d.ts +100 -0
  265. package/dist/mcp/engine.d.ts.map +1 -0
  266. package/dist/mcp/engine.js +291 -0
  267. package/dist/mcp/engine.js.map +1 -0
  268. package/dist/mcp/index.d.ts +109 -0
  269. package/dist/mcp/index.d.ts.map +1 -0
  270. package/dist/mcp/index.js +470 -0
  271. package/dist/mcp/index.js.map +1 -0
  272. package/dist/mcp/proxy.d.ts +46 -0
  273. package/dist/mcp/proxy.d.ts.map +1 -0
  274. package/dist/mcp/proxy.js +276 -0
  275. package/dist/mcp/proxy.js.map +1 -0
  276. package/dist/mcp/server-instructions.d.ts +19 -0
  277. package/dist/mcp/server-instructions.d.ts.map +1 -0
  278. package/dist/mcp/server-instructions.js +73 -0
  279. package/dist/mcp/server-instructions.js.map +1 -0
  280. package/dist/mcp/session.d.ts +67 -0
  281. package/dist/mcp/session.d.ts.map +1 -0
  282. package/dist/mcp/session.js +276 -0
  283. package/dist/mcp/session.js.map +1 -0
  284. package/dist/mcp/tools.d.ts +385 -0
  285. package/dist/mcp/tools.d.ts.map +1 -0
  286. package/dist/mcp/tools.js +2545 -0
  287. package/dist/mcp/tools.js.map +1 -0
  288. package/dist/mcp/transport.d.ts +188 -0
  289. package/dist/mcp/transport.d.ts.map +1 -0
  290. package/dist/mcp/transport.js +343 -0
  291. package/dist/mcp/transport.js.map +1 -0
  292. package/dist/mcp/version.d.ts +19 -0
  293. package/dist/mcp/version.d.ts.map +1 -0
  294. package/dist/mcp/version.js +71 -0
  295. package/dist/mcp/version.js.map +1 -0
  296. package/dist/resolution/callback-synthesizer.d.ts +10 -0
  297. package/dist/resolution/callback-synthesizer.d.ts.map +1 -0
  298. package/dist/resolution/callback-synthesizer.js +924 -0
  299. package/dist/resolution/callback-synthesizer.js.map +1 -0
  300. package/dist/resolution/frameworks/cargo-workspace.d.ts +18 -0
  301. package/dist/resolution/frameworks/cargo-workspace.d.ts.map +1 -0
  302. package/dist/resolution/frameworks/cargo-workspace.js +225 -0
  303. package/dist/resolution/frameworks/cargo-workspace.js.map +1 -0
  304. package/dist/resolution/frameworks/csharp.d.ts +8 -0
  305. package/dist/resolution/frameworks/csharp.d.ts.map +1 -0
  306. package/dist/resolution/frameworks/csharp.js +241 -0
  307. package/dist/resolution/frameworks/csharp.js.map +1 -0
  308. package/dist/resolution/frameworks/drupal.d.ts +51 -0
  309. package/dist/resolution/frameworks/drupal.d.ts.map +1 -0
  310. package/dist/resolution/frameworks/drupal.js +367 -0
  311. package/dist/resolution/frameworks/drupal.js.map +1 -0
  312. package/dist/resolution/frameworks/expo-modules.d.ts +3 -0
  313. package/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
  314. package/dist/resolution/frameworks/expo-modules.js +143 -0
  315. package/dist/resolution/frameworks/expo-modules.js.map +1 -0
  316. package/dist/resolution/frameworks/express.d.ts +8 -0
  317. package/dist/resolution/frameworks/express.d.ts.map +1 -0
  318. package/dist/resolution/frameworks/express.js +308 -0
  319. package/dist/resolution/frameworks/express.js.map +1 -0
  320. package/dist/resolution/frameworks/fabric.d.ts +3 -0
  321. package/dist/resolution/frameworks/fabric.d.ts.map +1 -0
  322. package/dist/resolution/frameworks/fabric.js +354 -0
  323. package/dist/resolution/frameworks/fabric.js.map +1 -0
  324. package/dist/resolution/frameworks/go.d.ts +8 -0
  325. package/dist/resolution/frameworks/go.d.ts.map +1 -0
  326. package/dist/resolution/frameworks/go.js +161 -0
  327. package/dist/resolution/frameworks/go.js.map +1 -0
  328. package/dist/resolution/frameworks/index.d.ts +48 -0
  329. package/dist/resolution/frameworks/index.d.ts.map +1 -0
  330. package/dist/resolution/frameworks/index.js +161 -0
  331. package/dist/resolution/frameworks/index.js.map +1 -0
  332. package/dist/resolution/frameworks/java.d.ts +8 -0
  333. package/dist/resolution/frameworks/java.d.ts.map +1 -0
  334. package/dist/resolution/frameworks/java.js +504 -0
  335. package/dist/resolution/frameworks/java.js.map +1 -0
  336. package/dist/resolution/frameworks/laravel.d.ts +13 -0
  337. package/dist/resolution/frameworks/laravel.d.ts.map +1 -0
  338. package/dist/resolution/frameworks/laravel.js +257 -0
  339. package/dist/resolution/frameworks/laravel.js.map +1 -0
  340. package/dist/resolution/frameworks/nestjs.d.ts +26 -0
  341. package/dist/resolution/frameworks/nestjs.d.ts.map +1 -0
  342. package/dist/resolution/frameworks/nestjs.js +698 -0
  343. package/dist/resolution/frameworks/nestjs.js.map +1 -0
  344. package/dist/resolution/frameworks/play.d.ts +19 -0
  345. package/dist/resolution/frameworks/play.d.ts.map +1 -0
  346. package/dist/resolution/frameworks/play.js +111 -0
  347. package/dist/resolution/frameworks/play.js.map +1 -0
  348. package/dist/resolution/frameworks/python.d.ts +10 -0
  349. package/dist/resolution/frameworks/python.d.ts.map +1 -0
  350. package/dist/resolution/frameworks/python.js +396 -0
  351. package/dist/resolution/frameworks/python.js.map +1 -0
  352. package/dist/resolution/frameworks/react-native.d.ts +3 -0
  353. package/dist/resolution/frameworks/react-native.d.ts.map +1 -0
  354. package/dist/resolution/frameworks/react-native.js +360 -0
  355. package/dist/resolution/frameworks/react-native.js.map +1 -0
  356. package/dist/resolution/frameworks/react.d.ts +8 -0
  357. package/dist/resolution/frameworks/react.d.ts.map +1 -0
  358. package/dist/resolution/frameworks/react.js +365 -0
  359. package/dist/resolution/frameworks/react.js.map +1 -0
  360. package/dist/resolution/frameworks/ruby.d.ts +8 -0
  361. package/dist/resolution/frameworks/ruby.d.ts.map +1 -0
  362. package/dist/resolution/frameworks/ruby.js +302 -0
  363. package/dist/resolution/frameworks/ruby.js.map +1 -0
  364. package/dist/resolution/frameworks/rust.d.ts +8 -0
  365. package/dist/resolution/frameworks/rust.d.ts.map +1 -0
  366. package/dist/resolution/frameworks/rust.js +304 -0
  367. package/dist/resolution/frameworks/rust.js.map +1 -0
  368. package/dist/resolution/frameworks/svelte.d.ts +9 -0
  369. package/dist/resolution/frameworks/svelte.d.ts.map +1 -0
  370. package/dist/resolution/frameworks/svelte.js +249 -0
  371. package/dist/resolution/frameworks/svelte.js.map +1 -0
  372. package/dist/resolution/frameworks/swift-objc.d.ts +37 -0
  373. package/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
  374. package/dist/resolution/frameworks/swift-objc.js +252 -0
  375. package/dist/resolution/frameworks/swift-objc.js.map +1 -0
  376. package/dist/resolution/frameworks/swift.d.ts +10 -0
  377. package/dist/resolution/frameworks/swift.d.ts.map +1 -0
  378. package/dist/resolution/frameworks/swift.js +400 -0
  379. package/dist/resolution/frameworks/swift.js.map +1 -0
  380. package/dist/resolution/frameworks/vue.d.ts +9 -0
  381. package/dist/resolution/frameworks/vue.d.ts.map +1 -0
  382. package/dist/resolution/frameworks/vue.js +306 -0
  383. package/dist/resolution/frameworks/vue.js.map +1 -0
  384. package/dist/resolution/go-module.d.ts +26 -0
  385. package/dist/resolution/go-module.d.ts.map +1 -0
  386. package/dist/resolution/go-module.js +78 -0
  387. package/dist/resolution/go-module.js.map +1 -0
  388. package/dist/resolution/import-resolver.d.ts +68 -0
  389. package/dist/resolution/import-resolver.d.ts.map +1 -0
  390. package/dist/resolution/import-resolver.js +1231 -0
  391. package/dist/resolution/import-resolver.js.map +1 -0
  392. package/dist/resolution/index.d.ts +116 -0
  393. package/dist/resolution/index.d.ts.map +1 -0
  394. package/dist/resolution/index.js +878 -0
  395. package/dist/resolution/index.js.map +1 -0
  396. package/dist/resolution/lru-cache.d.ts +24 -0
  397. package/dist/resolution/lru-cache.d.ts.map +1 -0
  398. package/dist/resolution/lru-cache.js +62 -0
  399. package/dist/resolution/lru-cache.js.map +1 -0
  400. package/dist/resolution/name-matcher.d.ts +32 -0
  401. package/dist/resolution/name-matcher.d.ts.map +1 -0
  402. package/dist/resolution/name-matcher.js +596 -0
  403. package/dist/resolution/name-matcher.js.map +1 -0
  404. package/dist/resolution/path-aliases.d.ts +68 -0
  405. package/dist/resolution/path-aliases.d.ts.map +1 -0
  406. package/dist/resolution/path-aliases.js +238 -0
  407. package/dist/resolution/path-aliases.js.map +1 -0
  408. package/dist/resolution/strip-comments.d.ts +27 -0
  409. package/dist/resolution/strip-comments.d.ts.map +1 -0
  410. package/dist/resolution/strip-comments.js +441 -0
  411. package/dist/resolution/strip-comments.js.map +1 -0
  412. package/dist/resolution/swift-objc-bridge.d.ts +134 -0
  413. package/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
  414. package/dist/resolution/swift-objc-bridge.js +256 -0
  415. package/dist/resolution/swift-objc-bridge.js.map +1 -0
  416. package/dist/resolution/types.d.ts +209 -0
  417. package/dist/resolution/types.d.ts.map +1 -0
  418. package/dist/resolution/types.js +8 -0
  419. package/dist/resolution/types.js.map +1 -0
  420. package/dist/search/query-parser.d.ts +57 -0
  421. package/dist/search/query-parser.d.ts.map +1 -0
  422. package/dist/search/query-parser.js +177 -0
  423. package/dist/search/query-parser.js.map +1 -0
  424. package/dist/search/query-utils.d.ts +53 -0
  425. package/dist/search/query-utils.d.ts.map +1 -0
  426. package/dist/search/query-utils.js +350 -0
  427. package/dist/search/query-utils.js.map +1 -0
  428. package/dist/sync/git-hooks.d.ts +45 -0
  429. package/dist/sync/git-hooks.d.ts.map +1 -0
  430. package/dist/sync/git-hooks.js +223 -0
  431. package/dist/sync/git-hooks.js.map +1 -0
  432. package/dist/sync/index.d.ts +19 -0
  433. package/dist/sync/index.d.ts.map +1 -0
  434. package/dist/sync/index.js +35 -0
  435. package/dist/sync/index.js.map +1 -0
  436. package/dist/sync/watch-policy.d.ts +48 -0
  437. package/dist/sync/watch-policy.d.ts.map +1 -0
  438. package/dist/sync/watch-policy.js +124 -0
  439. package/dist/sync/watch-policy.js.map +1 -0
  440. package/dist/sync/watcher.d.ts +191 -0
  441. package/dist/sync/watcher.d.ts.map +1 -0
  442. package/dist/sync/watcher.js +398 -0
  443. package/dist/sync/watcher.js.map +1 -0
  444. package/dist/sync/worktree.d.ts +54 -0
  445. package/dist/sync/worktree.d.ts.map +1 -0
  446. package/dist/sync/worktree.js +136 -0
  447. package/dist/sync/worktree.js.map +1 -0
  448. package/dist/types.d.ts +369 -0
  449. package/dist/types.d.ts.map +1 -0
  450. package/dist/types.js +78 -0
  451. package/dist/types.js.map +1 -0
  452. package/dist/ui/glyphs.d.ts +42 -0
  453. package/dist/ui/glyphs.d.ts.map +1 -0
  454. package/dist/ui/glyphs.js +78 -0
  455. package/dist/ui/glyphs.js.map +1 -0
  456. package/dist/ui/shimmer-progress.d.ts +11 -0
  457. package/dist/ui/shimmer-progress.d.ts.map +1 -0
  458. package/dist/ui/shimmer-progress.js +90 -0
  459. package/dist/ui/shimmer-progress.js.map +1 -0
  460. package/dist/ui/shimmer-worker.d.ts +2 -0
  461. package/dist/ui/shimmer-worker.d.ts.map +1 -0
  462. package/dist/ui/shimmer-worker.js +118 -0
  463. package/dist/ui/shimmer-worker.js.map +1 -0
  464. package/dist/ui/types.d.ts +17 -0
  465. package/dist/ui/types.d.ts.map +1 -0
  466. package/dist/ui/types.js +3 -0
  467. package/dist/ui/types.js.map +1 -0
  468. package/dist/utils.d.ts +205 -0
  469. package/dist/utils.d.ts.map +1 -0
  470. package/dist/utils.js +549 -0
  471. package/dist/utils.js.map +1 -0
  472. package/package.json +59 -0
  473. package/scripts/add-lang/bench.sh +60 -0
  474. package/scripts/add-lang/check-grammar.mjs +75 -0
  475. package/scripts/add-lang/dump-ast.mjs +103 -0
  476. package/scripts/add-lang/verify-extraction.mjs +70 -0
  477. package/scripts/agent-eval/arms-F.sh +21 -0
  478. package/scripts/agent-eval/arms-matrix.sh +37 -0
  479. package/scripts/agent-eval/audit.sh +68 -0
  480. package/scripts/agent-eval/bench-readme.sh +28 -0
  481. package/scripts/agent-eval/block-read-hook.sh +19 -0
  482. package/scripts/agent-eval/hook-settings.json +15 -0
  483. package/scripts/agent-eval/itrun.sh +107 -0
  484. package/scripts/agent-eval/parse-arms.mjs +116 -0
  485. package/scripts/agent-eval/parse-bench-readme.mjs +67 -0
  486. package/scripts/agent-eval/parse-run.mjs +45 -0
  487. package/scripts/agent-eval/parse-session.mjs +93 -0
  488. package/scripts/agent-eval/probe-context.mjs +21 -0
  489. package/scripts/agent-eval/probe-explore.mjs +40 -0
  490. package/scripts/agent-eval/probe-node.mjs +20 -0
  491. package/scripts/agent-eval/probe-trace.mjs +20 -0
  492. package/scripts/agent-eval/run-agent.sh +34 -0
  493. package/scripts/agent-eval/run-all.sh +67 -0
  494. package/scripts/agent-eval/run-arms.sh +56 -0
  495. package/scripts/agent-eval/seq-matrix.mjs +137 -0
  496. package/scripts/build-bundle.sh +118 -0
  497. package/scripts/extract-release-notes.mjs +130 -0
  498. package/scripts/local-install.sh +41 -0
  499. package/scripts/npm-shim.js +246 -0
  500. package/scripts/pack-npm.sh +95 -0
  501. package/scripts/prepare-release.mjs +270 -0
@@ -0,0 +1,1378 @@
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 = void 0;
45
+ exports.hashContent = hashContent;
46
+ exports.buildDefaultIgnore = buildDefaultIgnore;
47
+ exports.scanDirectory = scanDirectory;
48
+ exports.scanDirectoryAsync = scanDirectoryAsync;
49
+ const fs = __importStar(require("fs"));
50
+ const fsp = __importStar(require("fs/promises"));
51
+ const path = __importStar(require("path"));
52
+ const crypto = __importStar(require("crypto"));
53
+ const child_process_1 = require("child_process");
54
+ const tree_sitter_1 = require("./tree-sitter");
55
+ const grammars_1 = require("./grammars");
56
+ const errors_1 = require("../errors");
57
+ const utils_1 = require("../utils");
58
+ const ignore_1 = __importDefault(require("ignore"));
59
+ const frameworks_1 = require("../resolution/frameworks");
60
+ /**
61
+ * Number of files to read in parallel during indexing.
62
+ * File reads are I/O-bound; batching overlaps I/O wait with CPU parse work.
63
+ */
64
+ const FILE_IO_BATCH_SIZE = 10;
65
+ // PARSER_RESET_INTERVAL moved to parse-worker.ts (runs in worker thread)
66
+ /**
67
+ * Maximum time (ms) to wait for a single file to parse in the worker thread.
68
+ * If tree-sitter hangs or WASM runs out of memory, this prevents the entire
69
+ * indexing run from freezing. The worker is restarted after a timeout.
70
+ */
71
+ const PARSE_TIMEOUT_MS = 10_000;
72
+ /**
73
+ * Number of files to parse before recycling the worker thread.
74
+ * WASM linear memory can grow but NEVER shrink (WebAssembly spec limitation).
75
+ * The only way to reclaim tree-sitter's WASM heap is to destroy the entire
76
+ * V8 isolate by terminating the worker thread and spawning a fresh one.
77
+ * This interval balances memory usage against the cost of reloading grammars.
78
+ */
79
+ const WORKER_RECYCLE_INTERVAL = 250;
80
+ /**
81
+ * Calculate SHA256 hash of file contents
82
+ */
83
+ function hashContent(content) {
84
+ return crypto.createHash('sha256').update(content).digest('hex');
85
+ }
86
+ /**
87
+ * Skip files larger than this (bytes). Generated bundles, minified JS, and
88
+ * vendored blobs blow the WASM heap and the worker-recycle budget for no useful
89
+ * symbols. 1 MB covers essentially all hand-written source.
90
+ */
91
+ const MAX_FILE_SIZE = 1024 * 1024;
92
+ /**
93
+ * Directory names that are dependency, build, cache, or tooling output across the
94
+ * languages/frameworks CodeGraph supports — curated from the canonical
95
+ * github/gitignore templates. Excluded by default so the graph reflects your code,
96
+ * not third-party noise, without requiring a `.gitignore` (issue #407). The
97
+ * exclusion applies uniformly (git or not, tracked or not); the only opt-in is an
98
+ * explicit `.gitignore` negation (e.g. `!vendor/`). First-party-prone or generic
99
+ * names (`packages`, `lib`, `app`, `bin`, `src`, `deps`, `env`, `tmp`, `storage`,
100
+ * `Library`) are deliberately NOT listed, to avoid ever hiding real source.
101
+ *
102
+ * Only dirs that actually contain *indexable source* (or are enormous) earn a slot
103
+ * — IDE/state dirs like `.idea`/`.vs` are omitted because CodeGraph indexes only
104
+ * recognized source extensions, so they produce no symbols regardless.
105
+ */
106
+ const DEFAULT_IGNORE_DIRS = new Set([
107
+ // JS / TS — dependency directories
108
+ 'node_modules', 'bower_components', 'jspm_packages', 'web_modules',
109
+ '.yarn', '.pnpm-store',
110
+ // JS / TS — framework & bundler build / cache / deploy output
111
+ '.next', '.nuxt', '.svelte-kit', '.turbo', '.vite', '.parcel-cache', '.angular',
112
+ '.docusaurus', 'storybook-static', '.vinxi', '.nitro', 'out-tsc',
113
+ '.vercel', '.netlify', '.wrangler',
114
+ // Build output (common across ecosystems)
115
+ 'dist', 'build', 'out', '.output',
116
+ // Test / coverage
117
+ 'coverage', '.nyc_output',
118
+ // Python
119
+ '__pycache__', '__pypackages__', '.venv', 'venv', '.pixi', '.pdm-build',
120
+ '.mypy_cache', '.pytest_cache', '.ruff_cache', '.tox', '.nox', '.hypothesis',
121
+ '.ipynb_checkpoints', '.eggs',
122
+ // Rust / JVM (Maven, Gradle, Scala)
123
+ 'target', '.gradle',
124
+ // .NET
125
+ 'obj',
126
+ // Vendored deps (Go, PHP/Composer, Ruby/Bundler)
127
+ 'vendor',
128
+ // Swift / iOS
129
+ '.build', 'Pods', 'Carthage', 'DerivedData', '.swiftpm',
130
+ // Dart / Flutter
131
+ '.dart_tool', '.pub-cache',
132
+ // Native (Android NDK, C/C++ deps)
133
+ '.cxx', '.externalNativeBuild', 'vcpkg_installed',
134
+ // Scala tooling
135
+ '.bloop', '.metals',
136
+ // Lua / Luau (LuaRocks)
137
+ 'lua_modules', '.luarocks',
138
+ // Delphi / RAD Studio IDE backups (duplicate .pas source — would double-count)
139
+ '__history', '__recovery',
140
+ // Generic cache
141
+ '.cache',
142
+ ]);
143
+ /** Gitignore-style patterns for the `ignore` matcher: the dirs above plus a few globs. */
144
+ const DEFAULT_IGNORE_PATTERNS = [
145
+ ...Array.from(DEFAULT_IGNORE_DIRS, (d) => `${d}/`),
146
+ '*.egg-info/', // Python packaging metadata
147
+ 'cmake-build-*/', // CLion / CMake build trees
148
+ 'bazel-*/', // Bazel output symlink trees
149
+ ];
150
+ /**
151
+ * An `ignore` matcher seeded with the built-in defaults, merged with the project's
152
+ * root .gitignore so a negation there (e.g. `!vendor/`) overrides a default. Shared
153
+ * by both enumeration paths so behavior is identical with or without git — and so
154
+ * the defaults apply to tracked files too (committing a dependency dir doesn't make
155
+ * it project code; the explicit `.gitignore` negation is the only opt-in).
156
+ */
157
+ function buildDefaultIgnore(rootDir) {
158
+ const ig = (0, ignore_1.default)().add(DEFAULT_IGNORE_PATTERNS);
159
+ try {
160
+ const rootGitignore = path.join(rootDir, '.gitignore');
161
+ if (fs.existsSync(rootGitignore))
162
+ ig.add(fs.readFileSync(rootGitignore, 'utf-8'));
163
+ }
164
+ catch {
165
+ // Unreadable root .gitignore — the built-in defaults still apply.
166
+ }
167
+ return ig;
168
+ }
169
+ /**
170
+ * Collect git-visible files (tracked + untracked, .gitignore-respected) from the
171
+ * git repository rooted at `repoDir`, adding each to `files` with `prefix`
172
+ * prepended so paths stay relative to the original scan root.
173
+ *
174
+ * Recurses into embedded git repositories — nested repos that are NOT submodules
175
+ * (independent clones living inside the workspace, common in CMake "super-repo"
176
+ * layouts). The parent repo's `git ls-files` cannot see into them: tracked output
177
+ * skips them entirely, and untracked output reports them only as an opaque
178
+ * "subdir/" entry (trailing slash) rather than expanding their files. Each
179
+ * embedded repo is its own git boundary, so we re-run `git ls-files` inside it.
180
+ * (See issue #193.)
181
+ */
182
+ function collectGitFiles(repoDir, prefix, files) {
183
+ const gitOpts = { cwd: repoDir, encoding: 'utf-8', timeout: 30000, maxBuffer: 50 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'] };
184
+ // Tracked files. --recurse-submodules pulls in files from active submodules,
185
+ // which the index would otherwise represent only as a commit pointer.
186
+ // Without this, monorepos using submodules index 0 files. (See issue #147.)
187
+ // Note: --recurse-submodules only supports -c/--cached and --stage modes — it
188
+ // can't be combined with -o, so untracked files are gathered separately below.
189
+ const tracked = (0, child_process_1.execFileSync)('git', ['ls-files', '-c', '--recurse-submodules'], gitOpts);
190
+ for (const line of tracked.split('\n')) {
191
+ const trimmed = line.trim();
192
+ if (trimmed) {
193
+ files.add((0, utils_1.normalizePath)(prefix + trimmed));
194
+ }
195
+ }
196
+ // Untracked files (submodules manage their own untracked state). Embedded git
197
+ // repos surface here as a single "subdir/" entry that git refuses to descend
198
+ // into — recurse into those as their own repos so their source gets indexed.
199
+ const untracked = (0, child_process_1.execFileSync)('git', ['ls-files', '-o', '--exclude-standard'], gitOpts);
200
+ for (const line of untracked.split('\n')) {
201
+ const trimmed = line.trim();
202
+ if (!trimmed)
203
+ continue;
204
+ if (trimmed.endsWith('/')) {
205
+ // git only emits a trailing-slash directory entry for an embedded repo.
206
+ // Guard with a .git check anyway, and skip anything else exactly as git
207
+ // itself skips it (we never descend into a non-repo opaque dir).
208
+ const childDir = path.join(repoDir, trimmed);
209
+ if (fs.existsSync(path.join(childDir, '.git'))) {
210
+ collectGitFiles(childDir, prefix + trimmed, files);
211
+ }
212
+ continue;
213
+ }
214
+ files.add((0, utils_1.normalizePath)(prefix + trimmed));
215
+ }
216
+ }
217
+ /**
218
+ * Get all files visible to git (tracked + untracked but not ignored).
219
+ * Respects .gitignore at all levels (root, subdirectories) and descends into
220
+ * embedded (nested, non-submodule) git repos. Returns null on failure
221
+ * (non-git project) so callers can fall back to a filesystem walk.
222
+ */
223
+ function getGitVisibleFiles(rootDir) {
224
+ try {
225
+ // Check if the project directory is gitignored by a parent repo.
226
+ // When rootDir lives inside a parent git repo that ignores it,
227
+ // `git ls-files` returns nothing — fall back to filesystem walk.
228
+ const gitRoot = (0, child_process_1.execFileSync)('git', ['rev-parse', '--show-toplevel'], { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
229
+ if (path.resolve(gitRoot) !== path.resolve(rootDir)) {
230
+ try {
231
+ // git check-ignore exits 0 if the path IS ignored, 1 if not
232
+ (0, child_process_1.execFileSync)('git', ['check-ignore', '-q', path.resolve(rootDir)], { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] });
233
+ // Directory is gitignored by parent repo — fall back to filesystem walk
234
+ return null;
235
+ }
236
+ catch {
237
+ // Not ignored — safe to use git ls-files
238
+ }
239
+ }
240
+ const files = new Set();
241
+ collectGitFiles(rootDir, '', files);
242
+ // Apply built-in default ignores uniformly — to tracked files too, since
243
+ // committing a dependency/build dir doesn't make it project code. A
244
+ // `.gitignore` negation (e.g. `!vendor/`) is the explicit opt-in. (issue #407)
245
+ const ig = buildDefaultIgnore(rootDir);
246
+ return new Set([...files].filter((f) => !ig.ignores(f)));
247
+ }
248
+ catch {
249
+ return null;
250
+ }
251
+ }
252
+ /**
253
+ * Use `git status` to detect changed files instead of scanning every file.
254
+ * Returns null on failure so callers fall back to full scan.
255
+ */
256
+ function getGitChangedFiles(rootDir) {
257
+ try {
258
+ const output = (0, child_process_1.execFileSync)('git', ['status', '--porcelain', '--no-renames'], { cwd: rootDir, encoding: 'utf-8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] });
259
+ const modified = [];
260
+ const added = [];
261
+ const deleted = [];
262
+ for (const line of output.split('\n')) {
263
+ if (line.length < 4)
264
+ continue; // Minimum: "XY file"
265
+ const statusCode = line.substring(0, 2);
266
+ const filePath = (0, utils_1.normalizePath)(line.substring(3));
267
+ // Skip non-source files (git status already omits .gitignored paths).
268
+ if (!(0, grammars_1.isSourceFile)(filePath))
269
+ continue;
270
+ if (statusCode === '??') {
271
+ added.push(filePath);
272
+ }
273
+ else if (statusCode.includes('D')) {
274
+ deleted.push(filePath);
275
+ }
276
+ else {
277
+ // M, MM, AM, A (staged), etc. — treat as modified
278
+ modified.push(filePath);
279
+ }
280
+ }
281
+ return { modified, added, deleted };
282
+ }
283
+ catch {
284
+ return null;
285
+ }
286
+ }
287
+ /**
288
+ * Recursively scan a directory for source files.
289
+ *
290
+ * In git repos, uses `git ls-files` (inherently respects .gitignore at all
291
+ * levels), then keeps files with a supported source extension. For non-git
292
+ * projects, falls back to a filesystem walk that parses .gitignore itself.
293
+ */
294
+ function scanDirectory(rootDir, onProgress) {
295
+ // Fast path: use git to get all visible files (respects .gitignore everywhere)
296
+ const gitFiles = getGitVisibleFiles(rootDir);
297
+ if (gitFiles) {
298
+ const files = [];
299
+ let count = 0;
300
+ for (const filePath of gitFiles) {
301
+ if ((0, grammars_1.isSourceFile)(filePath)) {
302
+ files.push(filePath);
303
+ count++;
304
+ onProgress?.(count, filePath);
305
+ }
306
+ }
307
+ return files;
308
+ }
309
+ // Fallback: walk filesystem for non-git projects
310
+ return scanDirectoryWalk(rootDir, onProgress);
311
+ }
312
+ /**
313
+ * Async variant of scanDirectory that yields to the event loop periodically,
314
+ * allowing worker threads to receive and render progress messages.
315
+ */
316
+ async function scanDirectoryAsync(rootDir, onProgress) {
317
+ const gitFiles = getGitVisibleFiles(rootDir);
318
+ if (gitFiles) {
319
+ const files = [];
320
+ let count = 0;
321
+ for (const filePath of gitFiles) {
322
+ if ((0, grammars_1.isSourceFile)(filePath)) {
323
+ files.push(filePath);
324
+ count++;
325
+ onProgress?.(count, filePath);
326
+ // Yield every 100 files so worker threads can render progress
327
+ if (count % 100 === 0) {
328
+ await new Promise(r => setImmediate(r));
329
+ }
330
+ }
331
+ }
332
+ return files;
333
+ }
334
+ return scanDirectoryWalk(rootDir, onProgress);
335
+ }
336
+ /**
337
+ * Filesystem walk fallback for non-git projects.
338
+ */
339
+ function scanDirectoryWalk(rootDir, onProgress) {
340
+ const files = [];
341
+ let count = 0;
342
+ const visitedDirs = new Set();
343
+ const loadIgnore = (dir) => {
344
+ try {
345
+ const giPath = path.join(dir, '.gitignore');
346
+ if (fs.existsSync(giPath)) {
347
+ return { dir, ig: (0, ignore_1.default)().add(fs.readFileSync(giPath, 'utf-8')) };
348
+ }
349
+ }
350
+ catch {
351
+ // Unreadable .gitignore — treat as absent.
352
+ }
353
+ return null;
354
+ };
355
+ const isIgnored = (fullPath, isDir, matchers) => {
356
+ for (const { dir, ig } of matchers) {
357
+ let rel = (0, utils_1.normalizePath)(path.relative(dir, fullPath));
358
+ if (!rel || rel.startsWith('..'))
359
+ continue; // not under this matcher's dir
360
+ if (isDir)
361
+ rel += '/'; // dir-only rules (e.g. `build/`) only match with the slash
362
+ if (ig.ignores(rel))
363
+ return true;
364
+ }
365
+ return false;
366
+ };
367
+ function walk(dir, matchers) {
368
+ let realDir;
369
+ try {
370
+ realDir = fs.realpathSync(dir);
371
+ }
372
+ catch {
373
+ (0, errors_1.logDebug)('Skipping unresolvable directory', { dir });
374
+ return;
375
+ }
376
+ if (visitedDirs.has(realDir)) {
377
+ (0, errors_1.logDebug)('Skipping already-visited directory (symlink cycle)', { dir, realDir });
378
+ return;
379
+ }
380
+ visitedDirs.add(realDir);
381
+ // This directory's own .gitignore (if present) applies to everything below it.
382
+ // The root's .gitignore is already merged into the seeded base matcher (so a
383
+ // negation there can override a built-in default), so skip it here.
384
+ const own = dir === rootDir ? null : loadIgnore(dir);
385
+ const active = own ? [...matchers, own] : matchers;
386
+ let entries;
387
+ try {
388
+ entries = fs.readdirSync(dir, { withFileTypes: true });
389
+ }
390
+ catch (error) {
391
+ (0, errors_1.logDebug)('Skipping unreadable directory', { dir, error: String(error) });
392
+ return;
393
+ }
394
+ for (const entry of entries) {
395
+ // Never descend into git internals or our own data directory.
396
+ if (entry.name === '.git' || entry.name === '.codegraph')
397
+ continue;
398
+ const fullPath = path.join(dir, entry.name);
399
+ const relativePath = (0, utils_1.normalizePath)(path.relative(rootDir, fullPath));
400
+ if (entry.isSymbolicLink()) {
401
+ try {
402
+ const realTarget = fs.realpathSync(fullPath);
403
+ const stat = fs.statSync(realTarget);
404
+ if (stat.isDirectory()) {
405
+ if (!isIgnored(fullPath, true, active)) {
406
+ walk(fullPath, active);
407
+ }
408
+ }
409
+ else if (stat.isFile()) {
410
+ if (!isIgnored(fullPath, false, active) && (0, grammars_1.isSourceFile)(relativePath)) {
411
+ files.push(relativePath);
412
+ count++;
413
+ onProgress?.(count, relativePath);
414
+ }
415
+ }
416
+ }
417
+ catch {
418
+ (0, errors_1.logDebug)('Skipping broken symlink', { path: fullPath });
419
+ }
420
+ continue;
421
+ }
422
+ if (entry.isDirectory()) {
423
+ if (!isIgnored(fullPath, true, active)) {
424
+ walk(fullPath, active);
425
+ }
426
+ }
427
+ else if (entry.isFile()) {
428
+ if (!isIgnored(fullPath, false, active) && (0, grammars_1.isSourceFile)(relativePath)) {
429
+ files.push(relativePath);
430
+ count++;
431
+ onProgress?.(count, relativePath);
432
+ }
433
+ }
434
+ }
435
+ }
436
+ // Seed a base matcher with the built-in default ignores (merged with the root
437
+ // .gitignore so a negation can override). Nested .gitignores still layer per-dir.
438
+ walk(rootDir, [{ dir: rootDir, ig: buildDefaultIgnore(rootDir) }]);
439
+ return files;
440
+ }
441
+ /**
442
+ * Extraction orchestrator
443
+ */
444
+ class ExtractionOrchestrator {
445
+ rootDir;
446
+ queries;
447
+ /**
448
+ * Names of frameworks detected for this project, populated by indexAll().
449
+ * Passed to extractFromSource so framework-specific extractors (route nodes,
450
+ * middleware, etc.) run after the tree-sitter pass. Cleared if detection
451
+ * hasn't run yet so single-file re-index paths can detect on the spot.
452
+ */
453
+ detectedFrameworkNames = null;
454
+ constructor(rootDir, queries) {
455
+ this.rootDir = rootDir;
456
+ this.queries = queries;
457
+ }
458
+ /**
459
+ * Build a filesystem-backed ResolutionContext sufficient for framework
460
+ * detection. Graph-query methods (getNodesByName etc.) return empty because
461
+ * the DB hasn't been populated yet, but detect() only uses readFile,
462
+ * fileExists, and getAllFiles, so that's fine.
463
+ */
464
+ buildDetectionContext(files) {
465
+ const rootDir = this.rootDir;
466
+ return {
467
+ getNodesInFile: () => [],
468
+ getNodesByName: () => [],
469
+ getNodesByQualifiedName: () => [],
470
+ getNodesByKind: () => [],
471
+ getNodesByLowerName: () => [],
472
+ getImportMappings: () => [],
473
+ getAllFiles: () => files,
474
+ getProjectRoot: () => rootDir,
475
+ fileExists: (relativePath) => {
476
+ const full = (0, utils_1.validatePathWithinRoot)(rootDir, relativePath);
477
+ if (!full)
478
+ return false;
479
+ try {
480
+ return fs.existsSync(full);
481
+ }
482
+ catch {
483
+ return false;
484
+ }
485
+ },
486
+ readFile: (relativePath) => {
487
+ const full = (0, utils_1.validatePathWithinRoot)(rootDir, relativePath);
488
+ if (!full)
489
+ return null;
490
+ try {
491
+ return fs.readFileSync(full, 'utf-8');
492
+ }
493
+ catch {
494
+ return null;
495
+ }
496
+ },
497
+ // Monorepo support — needed by framework detect()s that probe
498
+ // subpackage manifests (e.g. fabric-view looking at
499
+ // packages/<sub>/package.json when the root manifest is just a
500
+ // workspace declaration). Matches the resolver-context shape.
501
+ listDirectories: (relativePath) => {
502
+ const target = relativePath === '.' || relativePath === ''
503
+ ? rootDir
504
+ : path.join(rootDir, relativePath);
505
+ try {
506
+ return fs
507
+ .readdirSync(target, { withFileTypes: true })
508
+ .filter((entry) => entry.isDirectory())
509
+ .map((entry) => entry.name);
510
+ }
511
+ catch {
512
+ return [];
513
+ }
514
+ },
515
+ };
516
+ }
517
+ /**
518
+ * Detect frameworks on demand using the current scanned files (or a fresh
519
+ * scan if none are provided). Cached on the orchestrator so repeat calls
520
+ * inside a single run don't re-scan.
521
+ */
522
+ ensureDetectedFrameworks(files) {
523
+ if (this.detectedFrameworkNames !== null)
524
+ return this.detectedFrameworkNames;
525
+ const fileList = files ?? scanDirectory(this.rootDir);
526
+ const context = this.buildDetectionContext(fileList);
527
+ this.detectedFrameworkNames = (0, frameworks_1.detectFrameworks)(context).map((r) => r.name);
528
+ return this.detectedFrameworkNames;
529
+ }
530
+ /**
531
+ * Index all files in the project
532
+ */
533
+ async indexAll(onProgress, signal, verbose) {
534
+ await (0, grammars_1.initGrammars)();
535
+ const startTime = Date.now();
536
+ const errors = [];
537
+ let filesIndexed = 0;
538
+ let filesSkipped = 0;
539
+ let filesErrored = 0;
540
+ let totalNodes = 0;
541
+ let totalEdges = 0;
542
+ const log = verbose
543
+ ? (msg) => { console.log(`[worker] ${msg}`); }
544
+ : (_msg) => { };
545
+ // Phase 1: Scan for files
546
+ onProgress?.({
547
+ phase: 'scanning',
548
+ current: 0,
549
+ total: 0,
550
+ });
551
+ const files = await scanDirectoryAsync(this.rootDir, (current, file) => {
552
+ onProgress?.({
553
+ phase: 'scanning',
554
+ current,
555
+ total: 0,
556
+ currentFile: file,
557
+ });
558
+ });
559
+ // Detect frameworks once per indexAll run using the scanned file list.
560
+ // Names are passed to each parse call so framework-specific extractors
561
+ // (route nodes, middleware, etc.) run after the tree-sitter pass.
562
+ // Framework detection is reset each run so adding e.g. requirements.txt
563
+ // between runs is picked up without restarting the process.
564
+ this.detectedFrameworkNames = null;
565
+ const frameworkNames = this.ensureDetectedFrameworks(files);
566
+ if (signal?.aborted) {
567
+ return {
568
+ success: false,
569
+ filesIndexed: 0,
570
+ filesSkipped: 0,
571
+ filesErrored: 0,
572
+ nodesCreated: 0,
573
+ edgesCreated: 0,
574
+ errors: [{ message: 'Aborted', severity: 'error' }],
575
+ durationMs: Date.now() - startTime,
576
+ };
577
+ }
578
+ // Phase 2: Parse files in a worker thread (keeps main thread unblocked for UI)
579
+ const total = files.length;
580
+ let processed = 0;
581
+ // Emit parsing phase immediately so the progress bar appears during worker setup.
582
+ // The yield lets the shimmer worker flush the phase transition to stdout before
583
+ // the main thread starts synchronous grammar detection work.
584
+ onProgress?.({
585
+ phase: 'parsing',
586
+ current: 0,
587
+ total,
588
+ });
589
+ await new Promise(resolve => setImmediate(resolve));
590
+ // Detect needed languages and load grammars in the parse worker
591
+ const neededLanguages = [...new Set(files.map((f) => (0, grammars_1.detectLanguage)(f)))];
592
+ // .h files default to 'c' but may be C++ — ensure cpp grammar is loaded when c is needed
593
+ if (neededLanguages.includes('c') && !neededLanguages.includes('cpp')) {
594
+ neededLanguages.push('cpp');
595
+ }
596
+ // Try to use a worker thread for parsing (keeps main thread unblocked for UI).
597
+ // Falls back to in-process parsing if the compiled worker is unavailable (e.g. tests).
598
+ const parseWorkerPath = path.join(__dirname, 'parse-worker.js');
599
+ const useWorker = fs.existsSync(parseWorkerPath);
600
+ let WorkerClass = null;
601
+ if (useWorker) {
602
+ const { Worker } = await Promise.resolve().then(() => __importStar(require('worker_threads')));
603
+ WorkerClass = Worker;
604
+ }
605
+ else {
606
+ // In-process fallback: load grammars locally
607
+ await (0, grammars_1.loadGrammarsForLanguages)(neededLanguages);
608
+ }
609
+ // --- Worker lifecycle management ---
610
+ // The worker can crash (OOM in WASM) or hang on pathological files.
611
+ // We track pending parse promises and handle both cases:
612
+ // - Timeout: terminate + restart the worker, reject the timed-out request
613
+ // - Crash: reject all pending promises, restart for remaining files
614
+ let parseWorker = null;
615
+ let nextId = 0;
616
+ let workerParseCount = 0;
617
+ const pendingParses = new Map();
618
+ function rejectAllPending(reason) {
619
+ for (const [id, pending] of pendingParses) {
620
+ clearTimeout(pending.timer);
621
+ pendingParses.delete(id);
622
+ pending.reject(new Error(reason));
623
+ }
624
+ }
625
+ function attachWorkerHandlers(w) {
626
+ w.on('message', (msg) => {
627
+ if (msg.type === 'parse-result' && msg.id !== undefined) {
628
+ const pending = pendingParses.get(msg.id);
629
+ if (pending) {
630
+ clearTimeout(pending.timer);
631
+ pendingParses.delete(msg.id);
632
+ pending.resolve(msg.result);
633
+ }
634
+ }
635
+ });
636
+ w.on('error', (err) => {
637
+ (0, errors_1.logWarn)('Parse worker error', { error: err.message });
638
+ rejectAllPending(`Worker error: ${err.message}`);
639
+ });
640
+ w.on('exit', (code) => {
641
+ if (code !== 0 && pendingParses.size > 0) {
642
+ (0, errors_1.logWarn)('Parse worker exited unexpectedly', { code });
643
+ rejectAllPending(`Worker exited with code ${code}`);
644
+ }
645
+ // Clear reference so we know to respawn, reset count so
646
+ // the fresh worker gets a full cycle before recycling.
647
+ if (parseWorker === w) {
648
+ parseWorker = null;
649
+ workerParseCount = 0;
650
+ }
651
+ });
652
+ }
653
+ async function ensureWorker() {
654
+ if (parseWorker)
655
+ return parseWorker;
656
+ log('Spawning new parse worker...');
657
+ parseWorker = new WorkerClass(parseWorkerPath);
658
+ attachWorkerHandlers(parseWorker);
659
+ // Load grammars in the new worker
660
+ await new Promise((resolve, reject) => {
661
+ parseWorker.once('message', (msg) => {
662
+ if (msg.type === 'grammars-loaded')
663
+ resolve();
664
+ else
665
+ reject(new Error(`Unexpected message: ${msg.type}`));
666
+ });
667
+ parseWorker.postMessage({ type: 'load-grammars', languages: neededLanguages });
668
+ });
669
+ return parseWorker;
670
+ }
671
+ if (WorkerClass) {
672
+ await ensureWorker();
673
+ }
674
+ /**
675
+ * Recycle the worker thread to reclaim WASM memory.
676
+ * Terminates the current worker and clears the reference so
677
+ * ensureWorker() will spawn a fresh one on the next call.
678
+ */
679
+ function recycleWorker() {
680
+ if (!parseWorker)
681
+ return;
682
+ log(`Recycling worker after ${workerParseCount} parses (heap: ${Math.round(process.memoryUsage().rss / 1024 / 1024)}MB RSS)`);
683
+ const w = parseWorker;
684
+ parseWorker = null;
685
+ workerParseCount = 0;
686
+ // Fire-and-forget: worker.terminate() can hang if WASM is stuck
687
+ w.terminate().catch(() => { });
688
+ }
689
+ async function requestParse(filePath, content) {
690
+ if (!WorkerClass) {
691
+ // In-process fallback
692
+ return (0, tree_sitter_1.extractFromSource)(filePath, content, (0, grammars_1.detectLanguage)(filePath, content), frameworkNames);
693
+ }
694
+ // Recycle the worker before the next parse if we've hit the threshold.
695
+ // This destroys the WASM linear memory (which can grow but never shrink)
696
+ // and starts a fresh worker with a clean heap.
697
+ if (workerParseCount >= WORKER_RECYCLE_INTERVAL) {
698
+ await recycleWorker();
699
+ }
700
+ const worker = await ensureWorker();
701
+ const id = nextId++;
702
+ workerParseCount++;
703
+ // Scale timeout for large files: base 10s + 10s per 100KB
704
+ const timeoutMs = PARSE_TIMEOUT_MS + Math.floor(content.length / 100_000) * 10_000;
705
+ return new Promise((resolve, reject) => {
706
+ const timer = setTimeout(() => {
707
+ pendingParses.delete(id);
708
+ log(`TIMEOUT: ${filePath} exceeded ${timeoutMs}ms — killing worker`);
709
+ // Reject FIRST — worker.terminate() can hang if WASM is stuck
710
+ parseWorker = null;
711
+ workerParseCount = 0;
712
+ reject(new Error(`Parse timed out after ${timeoutMs}ms`));
713
+ // Fire-and-forget: kill the stuck worker in the background
714
+ worker.terminate().catch(() => { });
715
+ }, timeoutMs);
716
+ pendingParses.set(id, { resolve, reject, timer });
717
+ worker.postMessage({ type: 'parse', id, filePath, content, frameworkNames });
718
+ });
719
+ }
720
+ for (let i = 0; i < files.length; i += FILE_IO_BATCH_SIZE) {
721
+ if (signal?.aborted) {
722
+ if (parseWorker)
723
+ parseWorker.terminate().catch(() => { });
724
+ return {
725
+ success: false,
726
+ filesIndexed,
727
+ filesSkipped,
728
+ filesErrored,
729
+ nodesCreated: totalNodes,
730
+ edgesCreated: totalEdges,
731
+ errors: [{ message: 'Aborted', severity: 'error' }, ...errors],
732
+ durationMs: Date.now() - startTime,
733
+ };
734
+ }
735
+ const batch = files.slice(i, i + FILE_IO_BATCH_SIZE);
736
+ // Read files in parallel (with path validation before any I/O)
737
+ const fileContents = await Promise.all(batch.map(async (fp) => {
738
+ try {
739
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, fp);
740
+ if (!fullPath) {
741
+ (0, errors_1.logWarn)('Path traversal blocked in batch reader', { filePath: fp });
742
+ return { filePath: fp, content: null, stats: null, error: new Error('Path traversal blocked') };
743
+ }
744
+ const content = await fsp.readFile(fullPath, 'utf-8');
745
+ const stats = await fsp.stat(fullPath);
746
+ return { filePath: fp, content, stats, error: null };
747
+ }
748
+ catch (err) {
749
+ return { filePath: fp, content: null, stats: null, error: err };
750
+ }
751
+ }));
752
+ // Send to worker for parsing, store results on main thread
753
+ for (const { filePath, content, stats, error } of fileContents) {
754
+ if (signal?.aborted) {
755
+ if (parseWorker)
756
+ parseWorker.terminate().catch(() => { });
757
+ return {
758
+ success: false,
759
+ filesIndexed,
760
+ filesSkipped,
761
+ filesErrored,
762
+ nodesCreated: totalNodes,
763
+ edgesCreated: totalEdges,
764
+ errors: [{ message: 'Aborted', severity: 'error' }, ...errors],
765
+ durationMs: Date.now() - startTime,
766
+ };
767
+ }
768
+ // Report progress before parsing (show current file being worked on)
769
+ onProgress?.({
770
+ phase: 'parsing',
771
+ current: processed,
772
+ total,
773
+ currentFile: filePath,
774
+ });
775
+ if (error || content === null || stats === null) {
776
+ processed++;
777
+ filesErrored++;
778
+ errors.push({
779
+ message: `Failed to read file: ${error instanceof Error ? error.message : String(error)}`,
780
+ filePath,
781
+ severity: 'error',
782
+ code: 'read_error',
783
+ });
784
+ continue;
785
+ }
786
+ // Honour MAX_FILE_SIZE. Without this check, vendored generated
787
+ // headers, minified bundles, and other multi-MB files get indexed,
788
+ // wasting WASM heap and the worker recycle budget on inputs with no
789
+ // useful symbols. The single-file extractFile path already enforces
790
+ // this; the bulk path used to silently skip the check.
791
+ if (stats.size > MAX_FILE_SIZE) {
792
+ processed++;
793
+ filesSkipped++;
794
+ errors.push({
795
+ message: `File exceeds max size (${stats.size} > ${MAX_FILE_SIZE})`,
796
+ filePath,
797
+ severity: 'warning',
798
+ code: 'size_exceeded',
799
+ });
800
+ onProgress?.({ phase: 'parsing', current: processed, total });
801
+ continue;
802
+ }
803
+ // Parse in worker thread (main thread stays unblocked).
804
+ // Wrapped in try/catch to handle worker timeouts and crashes gracefully.
805
+ let result;
806
+ try {
807
+ result = await requestParse(filePath, content);
808
+ }
809
+ catch (parseErr) {
810
+ processed++;
811
+ filesErrored++;
812
+ errors.push({
813
+ message: parseErr instanceof Error ? parseErr.message : String(parseErr),
814
+ filePath,
815
+ severity: 'error',
816
+ code: 'parse_error',
817
+ });
818
+ continue;
819
+ }
820
+ processed++;
821
+ // Store in database on main thread (SQLite is not thread-safe)
822
+ if (result.nodes.length > 0 || result.errors.length === 0) {
823
+ const language = (0, grammars_1.detectLanguage)(filePath, content);
824
+ this.storeExtractionResult(filePath, content, language, stats, result);
825
+ }
826
+ if (result.errors.length > 0) {
827
+ for (const err of result.errors) {
828
+ if (!err.filePath)
829
+ err.filePath = filePath;
830
+ }
831
+ errors.push(...result.errors);
832
+ }
833
+ if (result.nodes.length > 0) {
834
+ filesIndexed++;
835
+ totalNodes += result.nodes.length;
836
+ totalEdges += result.edges.length;
837
+ }
838
+ else if (result.errors.some((e) => e.severity === 'error')) {
839
+ filesErrored++;
840
+ }
841
+ else {
842
+ filesSkipped++;
843
+ }
844
+ }
845
+ }
846
+ // Report 100% so the progress bar doesn't hang at 99%
847
+ onProgress?.({
848
+ phase: 'parsing',
849
+ current: total,
850
+ total,
851
+ });
852
+ // Yield so the shimmer worker's buffered stdout writes can flush.
853
+ // Worker thread stdout is proxied through the main thread's event loop,
854
+ // so synchronous work here blocks the animation from rendering.
855
+ await new Promise(resolve => setImmediate(resolve));
856
+ // Retry pass: files that failed due to WASM memory corruption may succeed
857
+ // on a fresh worker with a clean heap. Recycle before each attempt so
858
+ // every file gets the absolute cleanest WASM state possible.
859
+ const retryableErrors = errors.filter((e) => e.code === 'parse_error' && e.filePath &&
860
+ (e.message.includes('Worker exited') || e.message.includes('memory access out of bounds')));
861
+ if (retryableErrors.length > 0 && WorkerClass) {
862
+ log(`Retrying ${retryableErrors.length} files that failed due to WASM memory errors...`);
863
+ const stillFailing = [];
864
+ for (const errEntry of retryableErrors) {
865
+ const filePath = errEntry.filePath;
866
+ if (signal?.aborted)
867
+ break;
868
+ // Fresh worker for every retry — maximum WASM headroom
869
+ recycleWorker();
870
+ let content;
871
+ try {
872
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, filePath);
873
+ if (!fullPath)
874
+ continue;
875
+ content = await fsp.readFile(fullPath, 'utf-8');
876
+ }
877
+ catch {
878
+ continue;
879
+ }
880
+ let result;
881
+ try {
882
+ result = await requestParse(filePath, content);
883
+ }
884
+ catch {
885
+ stillFailing.push(errEntry);
886
+ continue;
887
+ }
888
+ if (result.nodes.length > 0 || result.errors.length === 0) {
889
+ const language = (0, grammars_1.detectLanguage)(filePath, content);
890
+ const stats = await fsp.stat(path.join(this.rootDir, filePath));
891
+ this.storeExtractionResult(filePath, content, language, stats, result);
892
+ const idx = errors.indexOf(errEntry);
893
+ if (idx >= 0)
894
+ errors.splice(idx, 1);
895
+ filesErrored--;
896
+ filesIndexed++;
897
+ totalNodes += result.nodes.length;
898
+ totalEdges += result.edges.length;
899
+ log(`Retry OK: ${filePath} (${result.nodes.length} nodes)`);
900
+ }
901
+ }
902
+ // Last resort: for files that still crash on a clean worker, strip
903
+ // comment-only lines to reduce WASM memory pressure. Many compiler
904
+ // test files are 90%+ comments (CHECK directives) that don't contribute
905
+ // code nodes but consume parser memory.
906
+ if (stillFailing.length > 0) {
907
+ log(`${stillFailing.length} files still failing — retrying with comments stripped...`);
908
+ for (const errEntry of stillFailing) {
909
+ const filePath = errEntry.filePath;
910
+ if (signal?.aborted)
911
+ break;
912
+ recycleWorker();
913
+ let fullContent;
914
+ try {
915
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, filePath);
916
+ if (!fullPath)
917
+ continue;
918
+ fullContent = await fsp.readFile(fullPath, 'utf-8');
919
+ }
920
+ catch {
921
+ continue;
922
+ }
923
+ // Strip lines that are entirely comments (preserving line numbers
924
+ // by replacing with empty lines so node positions stay correct)
925
+ const stripped = fullContent
926
+ .split('\n')
927
+ .map(line => /^\s*\/\//.test(line) ? '' : line)
928
+ .join('\n');
929
+ let result;
930
+ try {
931
+ result = await requestParse(filePath, stripped);
932
+ }
933
+ catch {
934
+ continue;
935
+ }
936
+ if (result.nodes.length > 0 || result.errors.length === 0) {
937
+ const language = (0, grammars_1.detectLanguage)(filePath, fullContent);
938
+ const stats = await fsp.stat(path.join(this.rootDir, filePath));
939
+ this.storeExtractionResult(filePath, fullContent, language, stats, result);
940
+ const idx = errors.indexOf(errEntry);
941
+ if (idx >= 0)
942
+ errors.splice(idx, 1);
943
+ filesErrored--;
944
+ filesIndexed++;
945
+ totalNodes += result.nodes.length;
946
+ totalEdges += result.edges.length;
947
+ log(`Retry (stripped) OK: ${filePath} (${result.nodes.length} nodes)`);
948
+ }
949
+ }
950
+ }
951
+ }
952
+ // Shut down parse worker and clear any pending timers
953
+ rejectAllPending('Indexing complete');
954
+ if (parseWorker) {
955
+ parseWorker.terminate().catch(() => { });
956
+ }
957
+ return {
958
+ success: filesIndexed > 0 || errors.filter((e) => e.severity === 'error').length === 0,
959
+ filesIndexed,
960
+ filesSkipped,
961
+ filesErrored,
962
+ nodesCreated: totalNodes,
963
+ edgesCreated: totalEdges,
964
+ errors,
965
+ durationMs: Date.now() - startTime,
966
+ };
967
+ }
968
+ /**
969
+ * Index specific files
970
+ */
971
+ async indexFiles(filePaths) {
972
+ const startTime = Date.now();
973
+ const errors = [];
974
+ let filesIndexed = 0;
975
+ let filesSkipped = 0;
976
+ let filesErrored = 0;
977
+ let totalNodes = 0;
978
+ let totalEdges = 0;
979
+ for (const filePath of filePaths) {
980
+ const result = await this.indexFile(filePath);
981
+ if (result.errors.length > 0) {
982
+ errors.push(...result.errors);
983
+ }
984
+ if (result.nodes.length > 0) {
985
+ filesIndexed++;
986
+ totalNodes += result.nodes.length;
987
+ totalEdges += result.edges.length;
988
+ }
989
+ else if (result.errors.some((e) => e.severity === 'error')) {
990
+ filesErrored++;
991
+ }
992
+ else {
993
+ filesSkipped++;
994
+ }
995
+ }
996
+ return {
997
+ success: filesIndexed > 0 || errors.filter((e) => e.severity === 'error').length === 0,
998
+ filesIndexed,
999
+ filesSkipped,
1000
+ filesErrored,
1001
+ nodesCreated: totalNodes,
1002
+ edgesCreated: totalEdges,
1003
+ errors,
1004
+ durationMs: Date.now() - startTime,
1005
+ };
1006
+ }
1007
+ /**
1008
+ * Index a single file
1009
+ */
1010
+ async indexFile(relativePath) {
1011
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, relativePath);
1012
+ if (!fullPath) {
1013
+ return {
1014
+ nodes: [],
1015
+ edges: [],
1016
+ unresolvedReferences: [],
1017
+ errors: [{ message: `Path traversal blocked: ${relativePath}`, filePath: relativePath, severity: 'error', code: 'path_traversal' }],
1018
+ durationMs: 0,
1019
+ };
1020
+ }
1021
+ // Read file content and stats
1022
+ let content;
1023
+ let stats;
1024
+ try {
1025
+ stats = await fsp.stat(fullPath);
1026
+ content = await fsp.readFile(fullPath, 'utf-8');
1027
+ }
1028
+ catch (error) {
1029
+ return {
1030
+ nodes: [],
1031
+ edges: [],
1032
+ unresolvedReferences: [],
1033
+ errors: [
1034
+ {
1035
+ message: `Failed to read file: ${error instanceof Error ? error.message : String(error)}`,
1036
+ filePath: relativePath,
1037
+ severity: 'error',
1038
+ code: 'read_error',
1039
+ },
1040
+ ],
1041
+ durationMs: 0,
1042
+ };
1043
+ }
1044
+ return this.indexFileWithContent(relativePath, content, stats);
1045
+ }
1046
+ /**
1047
+ * Index a single file with pre-read content and stats.
1048
+ * Used by the parallel batch reader to avoid redundant file I/O.
1049
+ */
1050
+ async indexFileWithContent(relativePath, content, stats) {
1051
+ // Prevent path traversal
1052
+ const fullPath = (0, utils_1.validatePathWithinRoot)(this.rootDir, relativePath);
1053
+ if (!fullPath) {
1054
+ (0, errors_1.logWarn)('Path traversal blocked in indexFileWithContent', { relativePath });
1055
+ return {
1056
+ nodes: [],
1057
+ edges: [],
1058
+ unresolvedReferences: [],
1059
+ errors: [{ message: 'Path traversal blocked', filePath: relativePath, severity: 'error', code: 'path_traversal' }],
1060
+ durationMs: 0,
1061
+ };
1062
+ }
1063
+ // Check file size
1064
+ if (stats.size > MAX_FILE_SIZE) {
1065
+ return {
1066
+ nodes: [],
1067
+ edges: [],
1068
+ unresolvedReferences: [],
1069
+ errors: [
1070
+ {
1071
+ message: `File exceeds max size (${stats.size} > ${MAX_FILE_SIZE})`,
1072
+ filePath: relativePath,
1073
+ severity: 'warning',
1074
+ code: 'size_exceeded',
1075
+ },
1076
+ ],
1077
+ durationMs: 0,
1078
+ };
1079
+ }
1080
+ // Detect language
1081
+ const language = (0, grammars_1.detectLanguage)(relativePath, content);
1082
+ if (!(0, grammars_1.isLanguageSupported)(language)) {
1083
+ return {
1084
+ nodes: [],
1085
+ edges: [],
1086
+ unresolvedReferences: [],
1087
+ errors: [],
1088
+ durationMs: 0,
1089
+ };
1090
+ }
1091
+ // Extract from source. Use cached framework names if indexAll has run,
1092
+ // otherwise detect on the spot so single-file re-index paths still emit
1093
+ // route nodes / middleware / etc.
1094
+ const frameworkNames = this.ensureDetectedFrameworks();
1095
+ const result = (0, tree_sitter_1.extractFromSource)(relativePath, content, language, frameworkNames);
1096
+ // Store in database
1097
+ if (result.nodes.length > 0 || result.errors.length === 0) {
1098
+ this.storeExtractionResult(relativePath, content, language, stats, result);
1099
+ }
1100
+ return result;
1101
+ }
1102
+ /**
1103
+ * Store extraction result in database
1104
+ */
1105
+ storeExtractionResult(filePath, content, language, stats, result) {
1106
+ const contentHash = hashContent(content);
1107
+ // Check if file already exists and hasn't changed
1108
+ const existingFile = this.queries.getFileByPath(filePath);
1109
+ if (existingFile && existingFile.contentHash === contentHash) {
1110
+ return; // No changes
1111
+ }
1112
+ // Delete existing data for this file
1113
+ if (existingFile) {
1114
+ this.queries.deleteFile(filePath);
1115
+ }
1116
+ // Filter out nodes with missing required fields before insertion.
1117
+ // This prevents FK violations when edges reference nodes that would
1118
+ // be silently skipped by insertNode() (see issue #42).
1119
+ const validNodes = result.nodes.filter((n) => n.id && n.kind && n.name && n.filePath && n.language);
1120
+ // Insert nodes
1121
+ if (validNodes.length > 0) {
1122
+ this.queries.insertNodes(validNodes);
1123
+ }
1124
+ // Filter edges to only reference nodes that were actually inserted
1125
+ if (result.edges.length > 0) {
1126
+ const insertedIds = new Set(validNodes.map((n) => n.id));
1127
+ const validEdges = result.edges.filter((e) => insertedIds.has(e.source) && insertedIds.has(e.target));
1128
+ if (validEdges.length > 0) {
1129
+ this.queries.insertEdges(validEdges);
1130
+ }
1131
+ }
1132
+ // Insert unresolved references in batch with denormalized filePath/language
1133
+ if (result.unresolvedReferences.length > 0) {
1134
+ const insertedIds = new Set(validNodes.map((n) => n.id));
1135
+ const refsWithContext = result.unresolvedReferences
1136
+ .filter((ref) => insertedIds.has(ref.fromNodeId))
1137
+ .map((ref) => ({
1138
+ ...ref,
1139
+ filePath: ref.filePath ?? filePath,
1140
+ language: ref.language ?? language,
1141
+ }));
1142
+ if (refsWithContext.length > 0) {
1143
+ this.queries.insertUnresolvedRefsBatch(refsWithContext);
1144
+ }
1145
+ }
1146
+ // Insert file record
1147
+ const fileRecord = {
1148
+ path: filePath,
1149
+ contentHash,
1150
+ language,
1151
+ size: stats.size,
1152
+ modifiedAt: stats.mtimeMs,
1153
+ indexedAt: Date.now(),
1154
+ nodeCount: result.nodes.length,
1155
+ errors: result.errors.length > 0 ? result.errors : undefined,
1156
+ };
1157
+ this.queries.upsertFile(fileRecord);
1158
+ }
1159
+ /**
1160
+ * Sync the index with the current file state.
1161
+ *
1162
+ * Change detection is filesystem-based, never git: a (size, mtime) stat
1163
+ * pre-filter skips unchanged files, then a content-hash compare confirms real
1164
+ * changes. This works in non-git projects and catches committed changes from
1165
+ * `git pull`/`checkout`/`merge`/`rebase` that `git status` cannot see.
1166
+ */
1167
+ async sync(onProgress) {
1168
+ await (0, grammars_1.initGrammars)(); // Initialize WASM runtime (grammars loaded lazily below)
1169
+ const startTime = Date.now();
1170
+ let filesChecked = 0;
1171
+ let filesAdded = 0;
1172
+ let filesModified = 0;
1173
+ let filesRemoved = 0;
1174
+ let nodesUpdated = 0;
1175
+ const changedFilePaths = [];
1176
+ onProgress?.({
1177
+ phase: 'scanning',
1178
+ current: 0,
1179
+ total: 0,
1180
+ });
1181
+ const filesToIndex = [];
1182
+ // === Filesystem reconcile (git-independent) ===
1183
+ // The source of truth for "what changed" is the filesystem vs the indexed
1184
+ // state — never git. We enumerate the current source files and reconcile
1185
+ // each against the DB. A cheap (size, mtime) stat pre-filter skips unchanged
1186
+ // files without reading or hashing them, so the expensive read+hash+parse
1187
+ // only runs for files that actually changed. This catches edits/adds/deletes
1188
+ // whether or not the project uses git, and crucially also catches committed
1189
+ // changes from `git pull`/`checkout`/`merge`/`rebase` — which `git status`
1190
+ // cannot see, because the working tree is clean afterward.
1191
+ const currentFiles = scanDirectory(this.rootDir);
1192
+ filesChecked = currentFiles.length;
1193
+ const currentSet = new Set(currentFiles);
1194
+ const trackedFiles = this.queries.getAllFiles();
1195
+ const trackedMap = new Map();
1196
+ for (const f of trackedFiles) {
1197
+ trackedMap.set(f.path, f);
1198
+ }
1199
+ // Removals: tracked in the DB but no longer a present source file. Check the
1200
+ // filesystem directly — `scanDirectory` (via `git ls-files`) still lists a
1201
+ // file deleted from disk but not yet staged, so set membership alone misses it.
1202
+ for (const tracked of trackedFiles) {
1203
+ if (!currentSet.has(tracked.path) || !fs.existsSync(path.join(this.rootDir, tracked.path))) {
1204
+ this.queries.deleteFile(tracked.path);
1205
+ filesRemoved++;
1206
+ }
1207
+ }
1208
+ // Adds / modifications.
1209
+ for (const filePath of currentFiles) {
1210
+ const fullPath = path.join(this.rootDir, filePath);
1211
+ const tracked = trackedMap.get(filePath);
1212
+ // Cheap pre-filter: an already-indexed file whose size AND mtime both match
1213
+ // the DB is unchanged — skip it without reading or hashing. (A content
1214
+ // change that preserves both exactly is the blind spot every mtime-based
1215
+ // incremental tool accepts; `index --force` is the escape hatch. Git bumps
1216
+ // mtime on every file it writes during checkout/merge, so pulls are caught.)
1217
+ if (tracked) {
1218
+ try {
1219
+ const stat = fs.statSync(fullPath);
1220
+ if (stat.size === tracked.size && Math.floor(stat.mtimeMs) === Math.floor(tracked.modifiedAt)) {
1221
+ continue;
1222
+ }
1223
+ }
1224
+ catch (error) {
1225
+ (0, errors_1.logDebug)('Skipping unstattable file during sync', { filePath, error: String(error) });
1226
+ continue;
1227
+ }
1228
+ }
1229
+ // New, or size/mtime changed — read + hash to confirm a real content change.
1230
+ let content;
1231
+ try {
1232
+ content = fs.readFileSync(fullPath, 'utf-8');
1233
+ }
1234
+ catch (error) {
1235
+ (0, errors_1.logDebug)('Skipping unreadable file during sync', { filePath, error: String(error) });
1236
+ continue;
1237
+ }
1238
+ const contentHash = hashContent(content);
1239
+ if (!tracked) {
1240
+ filesToIndex.push(filePath);
1241
+ changedFilePaths.push(filePath);
1242
+ filesAdded++;
1243
+ }
1244
+ else if (tracked.contentHash !== contentHash) {
1245
+ filesToIndex.push(filePath);
1246
+ changedFilePaths.push(filePath);
1247
+ filesModified++;
1248
+ }
1249
+ }
1250
+ // Load only grammars needed for changed files
1251
+ if (filesToIndex.length > 0) {
1252
+ const neededLanguages = [...new Set(filesToIndex.map((f) => (0, grammars_1.detectLanguage)(f)))];
1253
+ // .h files default to 'c' but may be C++ — ensure cpp grammar is loaded
1254
+ if (neededLanguages.includes('c') && !neededLanguages.includes('cpp')) {
1255
+ neededLanguages.push('cpp');
1256
+ }
1257
+ await (0, grammars_1.loadGrammarsForLanguages)(neededLanguages);
1258
+ }
1259
+ // Index changed files
1260
+ const total = filesToIndex.length;
1261
+ for (let i = 0; i < filesToIndex.length; i++) {
1262
+ const filePath = filesToIndex[i];
1263
+ onProgress?.({
1264
+ phase: 'parsing',
1265
+ current: i + 1,
1266
+ total,
1267
+ currentFile: filePath,
1268
+ });
1269
+ const result = await this.indexFile(filePath);
1270
+ nodesUpdated += result.nodes.length;
1271
+ }
1272
+ return {
1273
+ filesChecked,
1274
+ filesAdded,
1275
+ filesModified,
1276
+ filesRemoved,
1277
+ nodesUpdated,
1278
+ durationMs: Date.now() - startTime,
1279
+ changedFilePaths: changedFilePaths.length > 0 ? changedFilePaths : undefined,
1280
+ };
1281
+ }
1282
+ /**
1283
+ * Get files that have changed since last index.
1284
+ * Uses git status as a fast path when available, falling back to full scan.
1285
+ */
1286
+ getChangedFiles() {
1287
+ const gitChanges = getGitChangedFiles(this.rootDir);
1288
+ if (gitChanges) {
1289
+ // === Git fast path ===
1290
+ const added = [];
1291
+ const modified = [];
1292
+ const removed = [];
1293
+ // Deleted files — only report if tracked in DB
1294
+ for (const filePath of gitChanges.deleted) {
1295
+ const tracked = this.queries.getFileByPath(filePath);
1296
+ if (tracked) {
1297
+ removed.push(filePath);
1298
+ }
1299
+ }
1300
+ // Modified + added files — read + hash, compare with DB. Untracked (`??`)
1301
+ // files stay untracked in git even after indexing, so they must be
1302
+ // hash-compared like modified files instead of always counting as added —
1303
+ // otherwise status reports them as pending forever. (See issue #206.)
1304
+ for (const filePath of [...gitChanges.modified, ...gitChanges.added]) {
1305
+ const fullPath = path.join(this.rootDir, filePath);
1306
+ let content;
1307
+ try {
1308
+ content = fs.readFileSync(fullPath, 'utf-8');
1309
+ }
1310
+ catch (error) {
1311
+ (0, errors_1.logDebug)('Skipping unreadable file while detecting changes', { filePath, error: String(error) });
1312
+ continue;
1313
+ }
1314
+ const contentHash = hashContent(content);
1315
+ const tracked = this.queries.getFileByPath(filePath);
1316
+ if (!tracked) {
1317
+ added.push(filePath);
1318
+ }
1319
+ else if (tracked.contentHash !== contentHash) {
1320
+ modified.push(filePath);
1321
+ }
1322
+ }
1323
+ return { added, modified, removed };
1324
+ }
1325
+ // === Fallback: full scan (non-git project or git failure) ===
1326
+ const currentFiles = new Set(scanDirectory(this.rootDir));
1327
+ const trackedFiles = this.queries.getAllFiles();
1328
+ // Build Map for O(1) lookups
1329
+ const trackedMap = new Map();
1330
+ for (const f of trackedFiles) {
1331
+ trackedMap.set(f.path, f);
1332
+ }
1333
+ const added = [];
1334
+ const modified = [];
1335
+ const removed = [];
1336
+ // Find removed files
1337
+ for (const tracked of trackedFiles) {
1338
+ if (!currentFiles.has(tracked.path)) {
1339
+ removed.push(tracked.path);
1340
+ }
1341
+ }
1342
+ // Find added and modified files
1343
+ for (const filePath of currentFiles) {
1344
+ const fullPath = path.join(this.rootDir, filePath);
1345
+ let content;
1346
+ try {
1347
+ content = fs.readFileSync(fullPath, 'utf-8');
1348
+ }
1349
+ catch (error) {
1350
+ (0, errors_1.logDebug)('Skipping unreadable file while detecting changes', { filePath, error: String(error) });
1351
+ continue;
1352
+ }
1353
+ const contentHash = hashContent(content);
1354
+ const tracked = trackedMap.get(filePath);
1355
+ if (!tracked) {
1356
+ added.push(filePath);
1357
+ }
1358
+ else if (tracked.contentHash !== contentHash) {
1359
+ modified.push(filePath);
1360
+ }
1361
+ }
1362
+ return { added, modified, removed };
1363
+ }
1364
+ }
1365
+ exports.ExtractionOrchestrator = ExtractionOrchestrator;
1366
+ // Re-export useful types and functions
1367
+ var tree_sitter_2 = require("./tree-sitter");
1368
+ Object.defineProperty(exports, "extractFromSource", { enumerable: true, get: function () { return tree_sitter_2.extractFromSource; } });
1369
+ var grammars_2 = require("./grammars");
1370
+ Object.defineProperty(exports, "detectLanguage", { enumerable: true, get: function () { return grammars_2.detectLanguage; } });
1371
+ Object.defineProperty(exports, "isSourceFile", { enumerable: true, get: function () { return grammars_2.isSourceFile; } });
1372
+ Object.defineProperty(exports, "isLanguageSupported", { enumerable: true, get: function () { return grammars_2.isLanguageSupported; } });
1373
+ Object.defineProperty(exports, "isGrammarLoaded", { enumerable: true, get: function () { return grammars_2.isGrammarLoaded; } });
1374
+ Object.defineProperty(exports, "getSupportedLanguages", { enumerable: true, get: function () { return grammars_2.getSupportedLanguages; } });
1375
+ Object.defineProperty(exports, "initGrammars", { enumerable: true, get: function () { return grammars_2.initGrammars; } });
1376
+ Object.defineProperty(exports, "loadGrammarsForLanguages", { enumerable: true, get: function () { return grammars_2.loadGrammarsForLanguages; } });
1377
+ Object.defineProperty(exports, "loadAllGrammars", { enumerable: true, get: function () { return grammars_2.loadAllGrammars; } });
1378
+ //# sourceMappingURL=index.js.map