kirograph 0.12.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 (434) hide show
  1. package/README.md +1171 -0
  2. package/dist/architecture/index.d.ts +11 -0
  3. package/dist/architecture/index.d.ts.map +1 -0
  4. package/dist/architecture/index.js +207 -0
  5. package/dist/architecture/index.js.map +7 -0
  6. package/dist/architecture/layers/csharp.d.ts +6 -0
  7. package/dist/architecture/layers/csharp.d.ts.map +1 -0
  8. package/dist/architecture/layers/csharp.js +100 -0
  9. package/dist/architecture/layers/csharp.js.map +7 -0
  10. package/dist/architecture/layers/elixir.js +116 -0
  11. package/dist/architecture/layers/elixir.js.map +7 -0
  12. package/dist/architecture/layers/go.d.ts +7 -0
  13. package/dist/architecture/layers/go.d.ts.map +1 -0
  14. package/dist/architecture/layers/go.js +117 -0
  15. package/dist/architecture/layers/go.js.map +7 -0
  16. package/dist/architecture/layers/index.d.ts +30 -0
  17. package/dist/architecture/layers/index.d.ts.map +1 -0
  18. package/dist/architecture/layers/index.js +100 -0
  19. package/dist/architecture/layers/index.js.map +7 -0
  20. package/dist/architecture/layers/java.d.ts +7 -0
  21. package/dist/architecture/layers/java.d.ts.map +1 -0
  22. package/dist/architecture/layers/java.js +119 -0
  23. package/dist/architecture/layers/java.js.map +7 -0
  24. package/dist/architecture/layers/python.d.ts +7 -0
  25. package/dist/architecture/layers/python.d.ts.map +1 -0
  26. package/dist/architecture/layers/python.js +111 -0
  27. package/dist/architecture/layers/python.js.map +7 -0
  28. package/dist/architecture/layers/ruby.d.ts +6 -0
  29. package/dist/architecture/layers/ruby.d.ts.map +1 -0
  30. package/dist/architecture/layers/ruby.js +95 -0
  31. package/dist/architecture/layers/ruby.js.map +7 -0
  32. package/dist/architecture/layers/rust.d.ts +6 -0
  33. package/dist/architecture/layers/rust.d.ts.map +1 -0
  34. package/dist/architecture/layers/rust.js +98 -0
  35. package/dist/architecture/layers/rust.js.map +7 -0
  36. package/dist/architecture/layers/types.d.ts +2 -0
  37. package/dist/architecture/layers/types.d.ts.map +1 -0
  38. package/dist/architecture/layers/types.js +17 -0
  39. package/dist/architecture/layers/types.js.map +7 -0
  40. package/dist/architecture/layers/typescript.d.ts +9 -0
  41. package/dist/architecture/layers/typescript.d.ts.map +1 -0
  42. package/dist/architecture/layers/typescript.js +143 -0
  43. package/dist/architecture/layers/typescript.js.map +7 -0
  44. package/dist/architecture/manifest/cargo.d.ts +3 -0
  45. package/dist/architecture/manifest/cargo.d.ts.map +1 -0
  46. package/dist/architecture/manifest/cargo.js +94 -0
  47. package/dist/architecture/manifest/cargo.js.map +7 -0
  48. package/dist/architecture/manifest/csproj.d.ts +3 -0
  49. package/dist/architecture/manifest/csproj.d.ts.map +1 -0
  50. package/dist/architecture/manifest/csproj.js +75 -0
  51. package/dist/architecture/manifest/csproj.js.map +7 -0
  52. package/dist/architecture/manifest/go.d.ts +3 -0
  53. package/dist/architecture/manifest/go.d.ts.map +1 -0
  54. package/dist/architecture/manifest/go.js +85 -0
  55. package/dist/architecture/manifest/go.js.map +7 -0
  56. package/dist/architecture/manifest/gradle.d.ts +3 -0
  57. package/dist/architecture/manifest/gradle.d.ts.map +1 -0
  58. package/dist/architecture/manifest/gradle.js +80 -0
  59. package/dist/architecture/manifest/gradle.js.map +7 -0
  60. package/dist/architecture/manifest/index.d.ts +12 -0
  61. package/dist/architecture/manifest/index.d.ts.map +1 -0
  62. package/dist/architecture/manifest/index.js +130 -0
  63. package/dist/architecture/manifest/index.js.map +7 -0
  64. package/dist/architecture/manifest/maven.d.ts +3 -0
  65. package/dist/architecture/manifest/maven.d.ts.map +1 -0
  66. package/dist/architecture/manifest/maven.js +76 -0
  67. package/dist/architecture/manifest/maven.js.map +7 -0
  68. package/dist/architecture/manifest/npm.d.ts +3 -0
  69. package/dist/architecture/manifest/npm.d.ts.map +1 -0
  70. package/dist/architecture/manifest/npm.js +103 -0
  71. package/dist/architecture/manifest/npm.js.map +7 -0
  72. package/dist/architecture/manifest/python.d.ts +3 -0
  73. package/dist/architecture/manifest/python.d.ts.map +1 -0
  74. package/dist/architecture/manifest/python.js +105 -0
  75. package/dist/architecture/manifest/python.js.map +7 -0
  76. package/dist/architecture/manifest/types.d.ts +2 -0
  77. package/dist/architecture/manifest/types.d.ts.map +1 -0
  78. package/dist/architecture/manifest/types.js +17 -0
  79. package/dist/architecture/manifest/types.js.map +7 -0
  80. package/dist/architecture/types.d.ts +91 -0
  81. package/dist/architecture/types.d.ts.map +1 -0
  82. package/dist/architecture/types.js +17 -0
  83. package/dist/architecture/types.js.map +7 -0
  84. package/dist/assets/logo.png +0 -0
  85. package/dist/banner.d.ts +6 -0
  86. package/dist/banner.d.ts.map +1 -0
  87. package/dist/banner.js +67 -0
  88. package/dist/banner.js.map +1 -0
  89. package/dist/bin/banner.d.ts +6 -0
  90. package/dist/bin/banner.d.ts.map +1 -0
  91. package/dist/bin/banner.js +88 -0
  92. package/dist/bin/banner.js.map +7 -0
  93. package/dist/bin/commands/affected.d.ts +3 -0
  94. package/dist/bin/commands/affected.d.ts.map +1 -0
  95. package/dist/bin/commands/affected.js +78 -0
  96. package/dist/bin/commands/affected.js.map +7 -0
  97. package/dist/bin/commands/architecture.d.ts +3 -0
  98. package/dist/bin/commands/architecture.d.ts.map +1 -0
  99. package/dist/bin/commands/architecture.js +125 -0
  100. package/dist/bin/commands/architecture.js.map +7 -0
  101. package/dist/bin/commands/caveman.js +136 -0
  102. package/dist/bin/commands/caveman.js.map +7 -0
  103. package/dist/bin/commands/context.d.ts +3 -0
  104. package/dist/bin/commands/context.d.ts.map +1 -0
  105. package/dist/bin/commands/context.js +81 -0
  106. package/dist/bin/commands/context.js.map +7 -0
  107. package/dist/bin/commands/coupling.d.ts +3 -0
  108. package/dist/bin/commands/coupling.d.ts.map +1 -0
  109. package/dist/bin/commands/coupling.js +164 -0
  110. package/dist/bin/commands/coupling.js.map +7 -0
  111. package/dist/bin/commands/dashboard.d.ts +3 -0
  112. package/dist/bin/commands/dashboard.d.ts.map +1 -0
  113. package/dist/bin/commands/dashboard.js +209 -0
  114. package/dist/bin/commands/dashboard.js.map +7 -0
  115. package/dist/bin/commands/dead-code.js +77 -0
  116. package/dist/bin/commands/dead-code.js.map +7 -0
  117. package/dist/bin/commands/export.js +2620 -0
  118. package/dist/bin/commands/export.js.map +7 -0
  119. package/dist/bin/commands/files.d.ts +3 -0
  120. package/dist/bin/commands/files.d.ts.map +1 -0
  121. package/dist/bin/commands/files.js +104 -0
  122. package/dist/bin/commands/files.js.map +7 -0
  123. package/dist/bin/commands/help.d.ts +4 -0
  124. package/dist/bin/commands/help.d.ts.map +1 -0
  125. package/dist/bin/commands/help.js +212 -0
  126. package/dist/bin/commands/help.js.map +7 -0
  127. package/dist/bin/commands/hotspots.js +77 -0
  128. package/dist/bin/commands/hotspots.js.map +7 -0
  129. package/dist/bin/commands/index.d.ts +3 -0
  130. package/dist/bin/commands/index.d.ts.map +1 -0
  131. package/dist/bin/commands/index.js +58 -0
  132. package/dist/bin/commands/index.js.map +7 -0
  133. package/dist/bin/commands/init.d.ts +3 -0
  134. package/dist/bin/commands/init.d.ts.map +1 -0
  135. package/dist/bin/commands/init.js +68 -0
  136. package/dist/bin/commands/init.js.map +7 -0
  137. package/dist/bin/commands/install.d.ts +3 -0
  138. package/dist/bin/commands/install.d.ts.map +1 -0
  139. package/dist/bin/commands/install.js +34 -0
  140. package/dist/bin/commands/install.js.map +7 -0
  141. package/dist/bin/commands/mark-dirty.d.ts +3 -0
  142. package/dist/bin/commands/mark-dirty.d.ts.map +1 -0
  143. package/dist/bin/commands/mark-dirty.js +51 -0
  144. package/dist/bin/commands/mark-dirty.js.map +7 -0
  145. package/dist/bin/commands/package.d.ts +3 -0
  146. package/dist/bin/commands/package.d.ts.map +1 -0
  147. package/dist/bin/commands/package.js +139 -0
  148. package/dist/bin/commands/package.js.map +7 -0
  149. package/dist/bin/commands/path.js +93 -0
  150. package/dist/bin/commands/path.js.map +7 -0
  151. package/dist/bin/commands/qdrant.d.ts +3 -0
  152. package/dist/bin/commands/qdrant.d.ts.map +1 -0
  153. package/dist/bin/commands/qdrant.js +159 -0
  154. package/dist/bin/commands/qdrant.js.map +1 -0
  155. package/dist/bin/commands/query.d.ts +3 -0
  156. package/dist/bin/commands/query.d.ts.map +1 -0
  157. package/dist/bin/commands/query.js +47 -0
  158. package/dist/bin/commands/query.js.map +7 -0
  159. package/dist/bin/commands/serve.d.ts +3 -0
  160. package/dist/bin/commands/serve.d.ts.map +1 -0
  161. package/dist/bin/commands/serve.js +59 -0
  162. package/dist/bin/commands/serve.js.map +7 -0
  163. package/dist/bin/commands/snapshot.js +122 -0
  164. package/dist/bin/commands/snapshot.js.map +7 -0
  165. package/dist/bin/commands/status.d.ts +3 -0
  166. package/dist/bin/commands/status.d.ts.map +1 -0
  167. package/dist/bin/commands/status.js +107 -0
  168. package/dist/bin/commands/status.js.map +7 -0
  169. package/dist/bin/commands/stop.d.ts +3 -0
  170. package/dist/bin/commands/stop.d.ts.map +1 -0
  171. package/dist/bin/commands/stop.js +81 -0
  172. package/dist/bin/commands/stop.js.map +1 -0
  173. package/dist/bin/commands/surprising.js +79 -0
  174. package/dist/bin/commands/surprising.js.map +7 -0
  175. package/dist/bin/commands/sync-if-dirty.d.ts +3 -0
  176. package/dist/bin/commands/sync-if-dirty.d.ts.map +1 -0
  177. package/dist/bin/commands/sync-if-dirty.js +67 -0
  178. package/dist/bin/commands/sync-if-dirty.js.map +7 -0
  179. package/dist/bin/commands/sync.d.ts +3 -0
  180. package/dist/bin/commands/sync.d.ts.map +1 -0
  181. package/dist/bin/commands/sync.js +81 -0
  182. package/dist/bin/commands/sync.js.map +7 -0
  183. package/dist/bin/commands/typesense.d.ts +3 -0
  184. package/dist/bin/commands/typesense.d.ts.map +1 -0
  185. package/dist/bin/commands/typesense.js +126 -0
  186. package/dist/bin/commands/typesense.js.map +1 -0
  187. package/dist/bin/commands/uninit.d.ts +4 -0
  188. package/dist/bin/commands/uninit.d.ts.map +1 -0
  189. package/dist/bin/commands/uninit.js +123 -0
  190. package/dist/bin/commands/uninit.js.map +7 -0
  191. package/dist/bin/commands/unlock.d.ts +3 -0
  192. package/dist/bin/commands/unlock.d.ts.map +1 -0
  193. package/dist/bin/commands/unlock.js +53 -0
  194. package/dist/bin/commands/unlock.js.map +7 -0
  195. package/dist/bin/commands/utils.d.ts +12 -0
  196. package/dist/bin/commands/utils.d.ts.map +1 -0
  197. package/dist/bin/commands/utils.js +56 -0
  198. package/dist/bin/commands/utils.js.map +7 -0
  199. package/dist/bin/installer/archive.js +230 -0
  200. package/dist/bin/installer/archive.js.map +7 -0
  201. package/dist/bin/installer/caveman.js +57 -0
  202. package/dist/bin/installer/caveman.js.map +7 -0
  203. package/dist/bin/installer/cli-agent.d.ts +15 -0
  204. package/dist/bin/installer/cli-agent.d.ts.map +1 -0
  205. package/dist/bin/installer/cli-agent.js +89 -0
  206. package/dist/bin/installer/cli-agent.js.map +7 -0
  207. package/dist/bin/installer/config-prompt.d.ts +13 -0
  208. package/dist/bin/installer/config-prompt.d.ts.map +1 -0
  209. package/dist/bin/installer/config-prompt.js +158 -0
  210. package/dist/bin/installer/config-prompt.js.map +7 -0
  211. package/dist/bin/installer/dashboard.d.ts +3 -0
  212. package/dist/bin/installer/dashboard.d.ts.map +1 -0
  213. package/dist/bin/installer/dashboard.js +149 -0
  214. package/dist/bin/installer/dashboard.js.map +7 -0
  215. package/dist/bin/installer/hooks.d.ts +5 -0
  216. package/dist/bin/installer/hooks.d.ts.map +1 -0
  217. package/dist/bin/installer/hooks.js +155 -0
  218. package/dist/bin/installer/hooks.js.map +7 -0
  219. package/dist/bin/installer/index.d.ts +11 -0
  220. package/dist/bin/installer/index.d.ts.map +1 -0
  221. package/dist/bin/installer/index.js +228 -0
  222. package/dist/bin/installer/index.js.map +7 -0
  223. package/dist/bin/installer/mcp.d.ts +5 -0
  224. package/dist/bin/installer/mcp.d.ts.map +1 -0
  225. package/dist/bin/installer/mcp.js +80 -0
  226. package/dist/bin/installer/mcp.js.map +7 -0
  227. package/dist/bin/installer/prompts.d.ts +28 -0
  228. package/dist/bin/installer/prompts.d.ts.map +1 -0
  229. package/dist/bin/installer/prompts.js +134 -0
  230. package/dist/bin/installer/prompts.js.map +7 -0
  231. package/dist/bin/installer/qdrant-dashboard.d.ts +4 -0
  232. package/dist/bin/installer/qdrant-dashboard.d.ts.map +1 -0
  233. package/dist/bin/installer/qdrant-dashboard.js +115 -0
  234. package/dist/bin/installer/qdrant-dashboard.js.map +7 -0
  235. package/dist/bin/installer/steering.d.ts +5 -0
  236. package/dist/bin/installer/steering.d.ts.map +1 -0
  237. package/dist/bin/installer/steering.js +283 -0
  238. package/dist/bin/installer/steering.js.map +7 -0
  239. package/dist/bin/kirograph.d.ts +6 -0
  240. package/dist/bin/kirograph.d.ts.map +1 -0
  241. package/dist/bin/kirograph.js +95 -0
  242. package/dist/bin/kirograph.js.map +7 -0
  243. package/dist/bin/progress.d.ts +14 -0
  244. package/dist/bin/progress.d.ts.map +1 -0
  245. package/dist/bin/progress.js +201 -0
  246. package/dist/bin/progress.js.map +7 -0
  247. package/dist/bin/ui.d.ts +11 -0
  248. package/dist/bin/ui.d.ts.map +1 -0
  249. package/dist/bin/ui.js +71 -0
  250. package/dist/bin/ui.js.map +7 -0
  251. package/dist/config.d.ts +48 -0
  252. package/dist/config.d.ts.map +1 -0
  253. package/dist/config.js +273 -0
  254. package/dist/config.js.map +7 -0
  255. package/dist/context/index.d.ts +61 -0
  256. package/dist/context/index.d.ts.map +1 -0
  257. package/dist/context/index.js +224 -0
  258. package/dist/context/index.js.map +7 -0
  259. package/dist/core/file-tree.d.ts +15 -0
  260. package/dist/core/file-tree.d.ts.map +1 -0
  261. package/dist/core/file-tree.js +69 -0
  262. package/dist/core/file-tree.js.map +7 -0
  263. package/dist/core/lock-manager.d.ts +20 -0
  264. package/dist/core/lock-manager.d.ts.map +1 -0
  265. package/dist/core/lock-manager.js +120 -0
  266. package/dist/core/lock-manager.js.map +7 -0
  267. package/dist/core/pipeline.d.ts +37 -0
  268. package/dist/core/pipeline.d.ts.map +1 -0
  269. package/dist/core/pipeline.js +375 -0
  270. package/dist/core/pipeline.js.map +7 -0
  271. package/dist/core/snapshot.js +141 -0
  272. package/dist/core/snapshot.js.map +7 -0
  273. package/dist/db/database.d.ts +133 -0
  274. package/dist/db/database.d.ts.map +1 -0
  275. package/dist/db/database.js +929 -0
  276. package/dist/db/database.js.map +7 -0
  277. package/dist/db/schema.sql +174 -0
  278. package/dist/errors.d.ts +49 -0
  279. package/dist/errors.d.ts.map +1 -0
  280. package/dist/errors.js +160 -0
  281. package/dist/errors.js.map +7 -0
  282. package/dist/extraction/extractor.d.ts +29 -0
  283. package/dist/extraction/extractor.d.ts.map +1 -0
  284. package/dist/extraction/extractor.js +764 -0
  285. package/dist/extraction/extractor.js.map +7 -0
  286. package/dist/extraction/grammars.d.ts +48 -0
  287. package/dist/extraction/grammars.d.ts.map +1 -0
  288. package/dist/extraction/grammars.js +166 -0
  289. package/dist/extraction/grammars.js.map +7 -0
  290. package/dist/extraction/languages.d.ts +9 -0
  291. package/dist/extraction/languages.d.ts.map +1 -0
  292. package/dist/extraction/languages.js +103 -0
  293. package/dist/extraction/languages.js.map +7 -0
  294. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  295. package/dist/frameworks/csharp.d.ts +8 -0
  296. package/dist/frameworks/csharp.d.ts.map +1 -0
  297. package/dist/frameworks/csharp.js +93 -0
  298. package/dist/frameworks/csharp.js.map +7 -0
  299. package/dist/frameworks/elixir.js +142 -0
  300. package/dist/frameworks/elixir.js.map +7 -0
  301. package/dist/frameworks/express.d.ts +8 -0
  302. package/dist/frameworks/express.d.ts.map +1 -0
  303. package/dist/frameworks/express.js +143 -0
  304. package/dist/frameworks/express.js.map +7 -0
  305. package/dist/frameworks/go.d.ts +8 -0
  306. package/dist/frameworks/go.d.ts.map +1 -0
  307. package/dist/frameworks/go.js +85 -0
  308. package/dist/frameworks/go.js.map +7 -0
  309. package/dist/frameworks/index.d.ts +30 -0
  310. package/dist/frameworks/index.d.ts.map +1 -0
  311. package/dist/frameworks/index.js +243 -0
  312. package/dist/frameworks/index.js.map +7 -0
  313. package/dist/frameworks/java.d.ts +8 -0
  314. package/dist/frameworks/java.d.ts.map +1 -0
  315. package/dist/frameworks/java.js +87 -0
  316. package/dist/frameworks/java.js.map +7 -0
  317. package/dist/frameworks/laravel.d.ts +9 -0
  318. package/dist/frameworks/laravel.d.ts.map +1 -0
  319. package/dist/frameworks/laravel.js +115 -0
  320. package/dist/frameworks/laravel.js.map +7 -0
  321. package/dist/frameworks/python.d.ts +10 -0
  322. package/dist/frameworks/python.d.ts.map +1 -0
  323. package/dist/frameworks/python.js +158 -0
  324. package/dist/frameworks/python.js.map +7 -0
  325. package/dist/frameworks/react.d.ts +9 -0
  326. package/dist/frameworks/react.d.ts.map +1 -0
  327. package/dist/frameworks/react.js +230 -0
  328. package/dist/frameworks/react.js.map +7 -0
  329. package/dist/frameworks/ruby.d.ts +8 -0
  330. package/dist/frameworks/ruby.d.ts.map +1 -0
  331. package/dist/frameworks/ruby.js +136 -0
  332. package/dist/frameworks/ruby.js.map +7 -0
  333. package/dist/frameworks/rust.d.ts +8 -0
  334. package/dist/frameworks/rust.d.ts.map +1 -0
  335. package/dist/frameworks/rust.js +82 -0
  336. package/dist/frameworks/rust.js.map +7 -0
  337. package/dist/frameworks/svelte.d.ts +8 -0
  338. package/dist/frameworks/svelte.d.ts.map +1 -0
  339. package/dist/frameworks/svelte.js +174 -0
  340. package/dist/frameworks/svelte.js.map +7 -0
  341. package/dist/frameworks/swift.d.ts +10 -0
  342. package/dist/frameworks/swift.d.ts.map +1 -0
  343. package/dist/frameworks/swift.js +151 -0
  344. package/dist/frameworks/swift.js.map +7 -0
  345. package/dist/frameworks/types.d.ts +37 -0
  346. package/dist/frameworks/types.d.ts.map +1 -0
  347. package/dist/frameworks/types.js +17 -0
  348. package/dist/frameworks/types.js.map +7 -0
  349. package/dist/graph/queries.d.ts +53 -0
  350. package/dist/graph/queries.d.ts.map +1 -0
  351. package/dist/graph/queries.js +224 -0
  352. package/dist/graph/queries.js.map +7 -0
  353. package/dist/graph/traversal.d.ts +35 -0
  354. package/dist/graph/traversal.d.ts.map +1 -0
  355. package/dist/graph/traversal.js +148 -0
  356. package/dist/graph/traversal.js.map +7 -0
  357. package/dist/index.d.ts +102 -0
  358. package/dist/index.d.ts.map +1 -0
  359. package/dist/index.js +303 -0
  360. package/dist/index.js.map +7 -0
  361. package/dist/installer/index.d.ts +10 -0
  362. package/dist/installer/index.d.ts.map +1 -0
  363. package/dist/installer/index.js +526 -0
  364. package/dist/installer/index.js.map +1 -0
  365. package/dist/mcp/server.d.ts +16 -0
  366. package/dist/mcp/server.d.ts.map +1 -0
  367. package/dist/mcp/server.js +116 -0
  368. package/dist/mcp/server.js.map +7 -0
  369. package/dist/mcp/tools.d.ts +37 -0
  370. package/dist/mcp/tools.d.ts.map +1 -0
  371. package/dist/mcp/tools.js +779 -0
  372. package/dist/mcp/tools.js.map +7 -0
  373. package/dist/mcp/transport.d.ts +29 -0
  374. package/dist/mcp/transport.d.ts.map +1 -0
  375. package/dist/mcp/transport.js +70 -0
  376. package/dist/mcp/transport.js.map +7 -0
  377. package/dist/resolution/index.d.ts +56 -0
  378. package/dist/resolution/index.d.ts.map +1 -0
  379. package/dist/resolution/index.js +384 -0
  380. package/dist/resolution/index.js.map +7 -0
  381. package/dist/resolution/name-matcher.d.ts +25 -0
  382. package/dist/resolution/name-matcher.d.ts.map +1 -0
  383. package/dist/resolution/name-matcher.js +60 -0
  384. package/dist/resolution/name-matcher.js.map +7 -0
  385. package/dist/scripts/postinstall.js +64 -0
  386. package/dist/search/query-utils.d.ts +21 -0
  387. package/dist/search/query-utils.d.ts.map +1 -0
  388. package/dist/search/query-utils.js +219 -0
  389. package/dist/search/query-utils.js.map +7 -0
  390. package/dist/search/searcher.d.ts +15 -0
  391. package/dist/search/searcher.d.ts.map +1 -0
  392. package/dist/search/searcher.js +49 -0
  393. package/dist/search/searcher.js.map +7 -0
  394. package/dist/sync/index.d.ts +33 -0
  395. package/dist/sync/index.d.ts.map +1 -0
  396. package/dist/sync/index.js +200 -0
  397. package/dist/sync/index.js.map +7 -0
  398. package/dist/types.d.ts +131 -0
  399. package/dist/types.d.ts.map +1 -0
  400. package/dist/types.js +37 -0
  401. package/dist/types.js.map +7 -0
  402. package/dist/utils.d.ts +52 -0
  403. package/dist/utils.d.ts.map +1 -0
  404. package/dist/utils.js +254 -0
  405. package/dist/utils.js.map +7 -0
  406. package/dist/vectors/index.d.ts +71 -0
  407. package/dist/vectors/index.d.ts.map +1 -0
  408. package/dist/vectors/index.js +480 -0
  409. package/dist/vectors/index.js.map +7 -0
  410. package/dist/vectors/lancedb-index.d.ts +50 -0
  411. package/dist/vectors/lancedb-index.d.ts.map +1 -0
  412. package/dist/vectors/lancedb-index.js +153 -0
  413. package/dist/vectors/lancedb-index.js.map +7 -0
  414. package/dist/vectors/orama-index.d.ts +54 -0
  415. package/dist/vectors/orama-index.d.ts.map +1 -0
  416. package/dist/vectors/orama-index.js +213 -0
  417. package/dist/vectors/orama-index.js.map +7 -0
  418. package/dist/vectors/pglite-index.d.ts +53 -0
  419. package/dist/vectors/pglite-index.d.ts.map +1 -0
  420. package/dist/vectors/pglite-index.js +194 -0
  421. package/dist/vectors/pglite-index.js.map +7 -0
  422. package/dist/vectors/qdrant-index.d.ts +70 -0
  423. package/dist/vectors/qdrant-index.d.ts.map +1 -0
  424. package/dist/vectors/qdrant-index.js +364 -0
  425. package/dist/vectors/qdrant-index.js.map +7 -0
  426. package/dist/vectors/typesense-index.d.ts +75 -0
  427. package/dist/vectors/typesense-index.d.ts.map +1 -0
  428. package/dist/vectors/typesense-index.js +453 -0
  429. package/dist/vectors/typesense-index.js.map +7 -0
  430. package/dist/vectors/vec-index.d.ts +52 -0
  431. package/dist/vectors/vec-index.d.ts.map +1 -0
  432. package/dist/vectors/vec-index.js +198 -0
  433. package/dist/vectors/vec-index.js.map +7 -0
  434. package/package.json +67 -0
@@ -0,0 +1,480 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var vectors_exports = {};
30
+ __export(vectors_exports, {
31
+ VectorManager: () => VectorManager
32
+ });
33
+ module.exports = __toCommonJS(vectors_exports);
34
+ var path = __toESM(require("path"));
35
+ var fs = __toESM(require("fs"));
36
+ var import_os = require("os");
37
+ var import_errors = require("../errors");
38
+ var import_vec_index = require("./vec-index");
39
+ var import_orama_index = require("./orama-index");
40
+ var import_pglite_index = require("./pglite-index");
41
+ var import_lancedb_index = require("./lancedb-index");
42
+ var import_qdrant_index = require("./qdrant-index");
43
+ var import_typesense_index = require("./typesense-index");
44
+ const DEFAULT_MODEL = "nomic-ai/nomic-embed-text-v1.5";
45
+ const DEFAULT_EMBEDDING_DIM = 768;
46
+ const GLOBAL_MODELS_DIR = path.join((0, import_os.homedir)(), ".kirograph", "models");
47
+ const BATCH_SIZE = 32;
48
+ const MIN_BATCH_SIZE = 4;
49
+ const MAX_TOKEN_CHARS = 2e3;
50
+ const EMBEDDABLE_KINDS = /* @__PURE__ */ new Set([
51
+ "function",
52
+ "method",
53
+ "class",
54
+ "interface",
55
+ "type_alias",
56
+ "component",
57
+ "module"
58
+ ]);
59
+ let transformers = null;
60
+ async function getTransformers() {
61
+ if (!transformers) {
62
+ transformers = await import("@huggingface/transformers");
63
+ }
64
+ return transformers;
65
+ }
66
+ function nodeToText(node) {
67
+ const parts = [`${node.kind}: ${node.name}`];
68
+ if (node.qualifiedName && node.qualifiedName !== node.name) {
69
+ parts.push(`path: ${node.qualifiedName}`);
70
+ }
71
+ parts.push(`file: ${node.filePath}`);
72
+ if (node.signature) parts.push(`signature: ${node.signature}`);
73
+ if (node.docstring) parts.push(`documentation: ${node.docstring}`);
74
+ const text = parts.join("\n");
75
+ if (text.length > MAX_TOKEN_CHARS) {
76
+ (0, import_errors.logDebug)(`nodeToText: truncated ${node.id} from ${text.length} to ${MAX_TOKEN_CHARS} chars`);
77
+ return text.slice(0, MAX_TOKEN_CHARS);
78
+ }
79
+ return text;
80
+ }
81
+ function cosine(a, b) {
82
+ let dot = 0, na = 0, nb = 0;
83
+ for (let i = 0; i < a.length; i++) {
84
+ dot += a[i] * b[i];
85
+ na += a[i] * a[i];
86
+ nb += b[i] * b[i];
87
+ }
88
+ const denom = Math.sqrt(na) * Math.sqrt(nb);
89
+ return denom === 0 ? 0 : dot / denom;
90
+ }
91
+ function toFloat32Array(data) {
92
+ if (data instanceof Float32Array) return data;
93
+ if (Array.isArray(data)) return new Float32Array(data);
94
+ if (data && typeof data === "object" && "length" in data) {
95
+ return Float32Array.from(Array.from(data));
96
+ }
97
+ throw new Error("Unsupported embedding data format");
98
+ }
99
+ class VectorManager {
100
+ constructor(db, config, projectRoot) {
101
+ this.db = db;
102
+ this.config = config;
103
+ this.projectRoot = projectRoot;
104
+ this.pipeline = null;
105
+ this._initialized = false;
106
+ this.vecIndex = null;
107
+ this.oramaIndex = null;
108
+ this.pgliteIndex = null;
109
+ this.lancedbIndex = null;
110
+ this.qdrantIndex = null;
111
+ this.typesenseIndex = null;
112
+ this._engineFallback = null;
113
+ }
114
+ isInitialized() {
115
+ return this.config.enableEmbeddings === true && this._initialized;
116
+ }
117
+ /** Non-null when the configured engine failed to load and cosine is being used instead. */
118
+ getEngineFallback() {
119
+ return this._engineFallback;
120
+ }
121
+ /**
122
+ * Load the embedding model. No-op when embeddings are disabled.
123
+ * Fails silently so callers can continue without semantic search.
124
+ * When config.useVecIndex is true, also initializes the sqlite-vec ANN index.
125
+ */
126
+ async initialize(onProgress) {
127
+ if (!this.config.enableEmbeddings) {
128
+ (0, import_errors.logDebug)("VectorManager: embeddings disabled");
129
+ return;
130
+ }
131
+ if (this._initialized) return;
132
+ const rawModel = this.config.embeddingModel || DEFAULT_MODEL;
133
+ const modelId = rawModel.includes("/") ? rawModel : DEFAULT_MODEL;
134
+ if (rawModel !== modelId) {
135
+ (0, import_errors.logWarn)(`VectorManager: invalid embeddingModel "${rawModel}", using default instead`, { default: DEFAULT_MODEL });
136
+ }
137
+ const cacheDir = GLOBAL_MODELS_DIR;
138
+ try {
139
+ const { pipeline, env } = await getTransformers();
140
+ env.cacheDir = cacheDir;
141
+ if (!fs.existsSync(cacheDir)) {
142
+ fs.mkdirSync(cacheDir, { recursive: true });
143
+ }
144
+ const cached = fs.existsSync(path.join(cacheDir, modelId));
145
+ if (cached) env.allowRemoteModels = false;
146
+ let lastFile = "";
147
+ this.pipeline = await pipeline("feature-extraction", modelId, {
148
+ dtype: "auto",
149
+ ...!cached && onProgress ? {
150
+ progress_callback: (p) => {
151
+ if (p.status === "progress" && p.file) {
152
+ lastFile = p.file;
153
+ onProgress(p.file, p.loaded ?? 0, p.total ?? 0, false);
154
+ } else if (p.status === "done" && lastFile) {
155
+ onProgress(lastFile, 1, 1, true);
156
+ lastFile = "";
157
+ }
158
+ }
159
+ } : {}
160
+ });
161
+ try {
162
+ const testOut = await this.pipeline("test", { pooling: "mean", normalize: true });
163
+ const actualDim = testOut.dims?.[1] ?? testOut.data?.length;
164
+ const configuredDim = this.config.embeddingDim ?? DEFAULT_EMBEDDING_DIM;
165
+ if (actualDim && actualDim !== configuredDim) {
166
+ (0, import_errors.logWarn)(
167
+ `VectorManager: embeddingDim mismatch \u2014 config says ${configuredDim} but model outputs ${actualDim}. Using actual dim.`,
168
+ { model: modelId, configuredDim, actualDim }
169
+ );
170
+ this.config.embeddingDim = actualDim;
171
+ }
172
+ } catch {
173
+ }
174
+ this._initialized = true;
175
+ (0, import_errors.logDebug)("VectorManager: model loaded", { modelId, embeddingDim: this.config.embeddingDim ?? DEFAULT_EMBEDDING_DIM });
176
+ } catch (err) {
177
+ (0, import_errors.logError)("VectorManager: failed to load embedding model", {
178
+ model: modelId,
179
+ error: String(err)
180
+ });
181
+ this._initialized = false;
182
+ return;
183
+ }
184
+ const engine = this.config.semanticEngine ?? (this.config.useVecIndex ? "sqlite-vec" : "cosine");
185
+ if (this.projectRoot && engine !== "cosine") {
186
+ const kirographDir = path.join(this.projectRoot, ".kirograph");
187
+ const embeddingDim = this.config.embeddingDim ?? DEFAULT_EMBEDDING_DIM;
188
+ if (engine === "sqlite-vec") {
189
+ this.vecIndex = new import_vec_index.VecIndex(kirographDir, embeddingDim);
190
+ await this.vecIndex.initialize();
191
+ if (this.vecIndex.isAvailable()) {
192
+ (0, import_errors.logDebug)("VectorManager: sqlite-vec ANN index ready");
193
+ } else {
194
+ this._engineFallback = "sqlite-vec unavailable \u2014 run: npm install better-sqlite3 sqlite-vec";
195
+ (0, import_errors.logDebug)("VectorManager: sqlite-vec unavailable, falling back to in-process cosine");
196
+ }
197
+ } else if (engine === "orama") {
198
+ this.oramaIndex = new import_orama_index.OramaIndex(kirographDir, embeddingDim);
199
+ await this.oramaIndex.initialize();
200
+ if (this.oramaIndex.isAvailable()) {
201
+ (0, import_errors.logDebug)("VectorManager: Orama hybrid index ready");
202
+ } else {
203
+ this._engineFallback = "orama unavailable \u2014 run: npm install @orama/orama @orama/plugin-data-persistence";
204
+ (0, import_errors.logDebug)("VectorManager: Orama unavailable, falling back to in-process cosine");
205
+ }
206
+ } else if (engine === "pglite") {
207
+ this.pgliteIndex = new import_pglite_index.PGliteIndex(kirographDir, embeddingDim);
208
+ await this.pgliteIndex.initialize();
209
+ if (this.pgliteIndex.isAvailable()) {
210
+ (0, import_errors.logDebug)("VectorManager: PGlite+pgvector hybrid index ready");
211
+ } else {
212
+ this._engineFallback = "pglite unavailable \u2014 run: npm install @electric-sql/pglite";
213
+ (0, import_errors.logDebug)("VectorManager: PGlite unavailable, falling back to in-process cosine");
214
+ }
215
+ } else if (engine === "lancedb") {
216
+ this.lancedbIndex = new import_lancedb_index.LanceDBIndex(kirographDir, embeddingDim);
217
+ await this.lancedbIndex.initialize();
218
+ if (this.lancedbIndex.isAvailable()) {
219
+ (0, import_errors.logDebug)("VectorManager: LanceDB ANN index ready");
220
+ } else {
221
+ this._engineFallback = "lancedb unavailable \u2014 run: npm install @lancedb/lancedb";
222
+ (0, import_errors.logDebug)("VectorManager: LanceDB unavailable, falling back to in-process cosine");
223
+ }
224
+ } else if (engine === "qdrant") {
225
+ this.qdrantIndex = new import_qdrant_index.QdrantIndex(kirographDir, embeddingDim);
226
+ await this.qdrantIndex.initialize();
227
+ if (this.qdrantIndex.isAvailable()) {
228
+ (0, import_errors.logDebug)("VectorManager: Qdrant ANN index ready");
229
+ } else {
230
+ this._engineFallback = "qdrant unavailable \u2014 run: npm install qdrant-local";
231
+ (0, import_errors.logDebug)("VectorManager: Qdrant unavailable, falling back to in-process cosine");
232
+ }
233
+ } else if (engine === "typesense") {
234
+ this.typesenseIndex = new import_typesense_index.TypesenseIndex(kirographDir, embeddingDim);
235
+ await this.typesenseIndex.initialize();
236
+ if (this.typesenseIndex.isAvailable()) {
237
+ (0, import_errors.logDebug)("VectorManager: Typesense ANN index ready");
238
+ } else {
239
+ const reason = this.typesenseIndex.getFailReason();
240
+ this._engineFallback = reason ? `typesense initialization failed: ${reason}` : "typesense unavailable \u2014 run: npm install typesense";
241
+ (0, import_errors.logDebug)("VectorManager: Typesense unavailable, falling back to in-process cosine");
242
+ }
243
+ }
244
+ }
245
+ }
246
+ /**
247
+ * Embed a single node and persist to the vectors table.
248
+ * Skips silently when disabled; logs on failure without throwing.
249
+ */
250
+ async embedNode(node) {
251
+ if (!this.config.enableEmbeddings) return;
252
+ if (!this._initialized || !this.pipeline) {
253
+ (0, import_errors.logError)("Embedding model unavailable", { model: this.config.embeddingModel });
254
+ return;
255
+ }
256
+ if (!EMBEDDABLE_KINDS.has(node.kind)) return;
257
+ try {
258
+ const text = `search_document: ${nodeToText(node)}`;
259
+ const output = await this.pipeline(text, { pooling: "mean", normalize: true });
260
+ const embedding = toFloat32Array(output.data);
261
+ if (!this.vecIndex?.isAvailable() && !this.oramaIndex?.isAvailable() && !this.pgliteIndex?.isAvailable() && !this.lancedbIndex?.isAvailable() && !this.qdrantIndex?.isAvailable() && !this.typesenseIndex?.isAvailable()) {
262
+ this.db.storeEmbedding(node.id, embedding, this.config.embeddingModel || DEFAULT_MODEL);
263
+ }
264
+ this.vecIndex?.upsert(node.id, embedding);
265
+ if (this.oramaIndex?.isAvailable()) await this.oramaIndex.upsert(node, embedding);
266
+ if (this.pgliteIndex?.isAvailable()) await this.pgliteIndex.upsert(node, embedding);
267
+ if (this.lancedbIndex?.isAvailable()) await this.lancedbIndex.upsert(node, embedding);
268
+ if (this.qdrantIndex?.isAvailable()) await this.qdrantIndex.upsert(node, embedding);
269
+ if (this.typesenseIndex?.isAvailable()) await this.typesenseIndex.upsert(node, embedding);
270
+ } catch (err) {
271
+ (0, import_errors.logWarn)("Failed to embed node", { nodeId: node.id, error: String(err) });
272
+ }
273
+ }
274
+ /** Number of entries currently in the active ANN/hybrid index (0 when not in use). */
275
+ async vecIndexCount() {
276
+ if (this.vecIndex?.isAvailable()) return this.vecIndex.count();
277
+ if (this.oramaIndex?.isAvailable()) return this.oramaIndex.count();
278
+ if (this.pgliteIndex?.isAvailable()) return this.pgliteIndex.count();
279
+ if (this.lancedbIndex?.isAvailable()) return this.lancedbIndex.count();
280
+ if (this.qdrantIndex?.isAvailable()) return this.qdrantIndex.count();
281
+ if (this.typesenseIndex?.isAvailable()) return this.typesenseIndex.count();
282
+ return 0;
283
+ }
284
+ /**
285
+ * Remove embeddings for the given node IDs from the active index.
286
+ * For cosine the `vectors` SQLite table is cleaned up automatically via FK cascade
287
+ * when nodes are deleted. For sqlite-vec, orama, and pglite the engine itself is
288
+ * the sole store of record, so we delete from it explicitly here.
289
+ */
290
+ async deleteEmbeddings(nodeIds) {
291
+ for (const id of nodeIds) {
292
+ this.vecIndex?.delete(id);
293
+ if (this.oramaIndex?.isAvailable()) await this.oramaIndex.delete(id);
294
+ if (this.pgliteIndex?.isAvailable()) await this.pgliteIndex.delete(id);
295
+ if (this.lancedbIndex?.isAvailable()) await this.lancedbIndex.delete(id);
296
+ if (this.qdrantIndex?.isAvailable()) await this.qdrantIndex.delete(id);
297
+ if (this.typesenseIndex?.isAvailable()) await this.typesenseIndex.delete(id);
298
+ }
299
+ }
300
+ /**
301
+ * Embed all eligible nodes in the database that don't yet have embeddings.
302
+ * Streams nodes in pages to avoid loading the entire node set into memory —
303
+ * critical for large codebases (100K+ symbols) where a single getAllNodes()
304
+ * call can exhaust the Node.js heap or the WASM linear memory.
305
+ *
306
+ * Uses dynamic batch sizing: starts at BATCH_SIZE, halves on OOM errors,
307
+ * and recovers back to full size after successful batches.
308
+ *
309
+ * Emits a pre-flight warning via onProgress when the embeddable node count
310
+ * exceeds LARGE_CODEBASE_THRESHOLD so the CLI can surface it to the user.
311
+ */
312
+ async embedAll(onProgress) {
313
+ if (!this.isInitialized() || !this.pipeline) return 0;
314
+ const modelId = this.config.embeddingModel || DEFAULT_MODEL;
315
+ const EMBEDDABLE_KINDS_ARRAY = [...EMBEDDABLE_KINDS];
316
+ const totalEmbeddable = this.db.countEmbeddableNodes(EMBEDDABLE_KINDS_ARRAY);
317
+ const LARGE_CODEBASE_THRESHOLD = 1e5;
318
+ if (totalEmbeddable > LARGE_CODEBASE_THRESHOLD) {
319
+ onProgress?.(-1, totalEmbeddable);
320
+ }
321
+ const existingIds = new Set(
322
+ this.typesenseIndex?.isAvailable() ? await this.typesenseIndex.getEmbeddedNodeIds() : this.qdrantIndex?.isAvailable() ? await this.qdrantIndex.getEmbeddedNodeIds() : this.lancedbIndex?.isAvailable() ? await this.lancedbIndex.getEmbeddedNodeIds() : this.pgliteIndex?.isAvailable() ? await this.pgliteIndex.getEmbeddedNodeIds() : this.oramaIndex?.isAvailable() ? await this.oramaIndex.getEmbeddedNodeIds() : this.vecIndex?.isAvailable() ? this.vecIndex.getEmbeddedNodeIds() : this.db.getEmbeddedNodeIds()
323
+ );
324
+ const PAGE_SIZE = 2e3;
325
+ let pageOffset = 0;
326
+ let processed = 0;
327
+ let currentBatchSize = BATCH_SIZE;
328
+ let consecutiveSuccesses = 0;
329
+ const totalPending = Math.max(0, totalEmbeddable - existingIds.size);
330
+ if (totalPending === 0) {
331
+ if (this.oramaIndex?.isAvailable()) await this.oramaIndex.save();
332
+ return 0;
333
+ }
334
+ (0, import_errors.logDebug)(`VectorManager: embedding ~${totalPending} nodes (${existingIds.size} already embedded, streaming in pages of ${PAGE_SIZE})`);
335
+ let pageBuffer = [];
336
+ let pageBufferOffset = 0;
337
+ let pageExhausted = false;
338
+ const fetchNextPage = () => {
339
+ const page = this.db.getEmbeddableNodesPaged(EMBEDDABLE_KINDS_ARRAY, PAGE_SIZE, pageOffset);
340
+ pageOffset += page.length;
341
+ pageBuffer = page.filter((n) => !existingIds.has(n.id));
342
+ pageBufferOffset = 0;
343
+ if (page.length < PAGE_SIZE) pageExhausted = true;
344
+ };
345
+ fetchNextPage();
346
+ while (pageBuffer.length > 0 || !pageExhausted && pageBufferOffset >= pageBuffer.length) {
347
+ if (pageBufferOffset >= pageBuffer.length) {
348
+ if (pageExhausted) break;
349
+ fetchNextPage();
350
+ if (pageBuffer.length === 0) break;
351
+ }
352
+ const batch = pageBuffer.slice(pageBufferOffset, pageBufferOffset + currentBatchSize);
353
+ if (batch.length === 0) break;
354
+ const texts = batch.map((n) => `search_document: ${nodeToText(n)}`);
355
+ try {
356
+ const outputs = await this.pipeline(texts, { pooling: "mean", normalize: true });
357
+ const dims = outputs.dims;
358
+ const dim = dims[1] ?? (this.config.embeddingDim ?? DEFAULT_EMBEDDING_DIM);
359
+ const flat = toFloat32Array(outputs.data);
360
+ const tsNodes = [];
361
+ const tsEmbeddings = [];
362
+ const qdNodes = [];
363
+ const qdEmbeddings = [];
364
+ for (let j = 0; j < batch.length; j++) {
365
+ const node = batch[j];
366
+ const embedding = flat.slice(j * dim, (j + 1) * dim);
367
+ if (!this.vecIndex?.isAvailable() && !this.oramaIndex?.isAvailable() && !this.pgliteIndex?.isAvailable() && !this.lancedbIndex?.isAvailable() && !this.qdrantIndex?.isAvailable() && !this.typesenseIndex?.isAvailable()) {
368
+ this.db.storeEmbedding(node.id, embedding, modelId);
369
+ }
370
+ this.vecIndex?.upsert(node.id, embedding);
371
+ if (this.oramaIndex?.isAvailable()) await this.oramaIndex.upsert(node, embedding);
372
+ if (this.pgliteIndex?.isAvailable()) await this.pgliteIndex.upsert(node, embedding);
373
+ if (this.lancedbIndex?.isAvailable()) await this.lancedbIndex.upsert(node, embedding);
374
+ if (this.qdrantIndex?.isAvailable()) {
375
+ qdNodes.push(node);
376
+ qdEmbeddings.push(embedding);
377
+ }
378
+ if (this.typesenseIndex?.isAvailable()) {
379
+ tsNodes.push(node);
380
+ tsEmbeddings.push(embedding);
381
+ }
382
+ }
383
+ if (qdNodes.length > 0) await this.qdrantIndex.bulkUpsert(qdNodes, qdEmbeddings);
384
+ if (tsNodes.length > 0) await this.typesenseIndex.bulkUpsert(tsNodes, tsEmbeddings);
385
+ pageBufferOffset += batch.length;
386
+ processed += batch.length;
387
+ consecutiveSuccesses++;
388
+ if (currentBatchSize < BATCH_SIZE && consecutiveSuccesses >= 5) {
389
+ currentBatchSize = Math.min(currentBatchSize * 2, BATCH_SIZE);
390
+ (0, import_errors.logDebug)(`VectorManager: batch size recovered to ${currentBatchSize}`);
391
+ consecutiveSuccesses = 0;
392
+ }
393
+ } catch (err) {
394
+ const errMsg = String(err);
395
+ const isOOM = errMsg.includes("bad allocation") || errMsg.includes("OOM") || errMsg.includes("out of memory");
396
+ if (isOOM && currentBatchSize > MIN_BATCH_SIZE) {
397
+ currentBatchSize = Math.max(Math.floor(currentBatchSize / 2), MIN_BATCH_SIZE);
398
+ consecutiveSuccesses = 0;
399
+ (0, import_errors.logWarn)(`VectorManager: OOM at batch offset ${pageBufferOffset} \u2014 reducing batch size to ${currentBatchSize} and retrying`, {
400
+ batchSize: currentBatchSize,
401
+ nodeIds: batch.slice(0, 3).map((n) => n.id)
402
+ });
403
+ } else if (isOOM && currentBatchSize <= MIN_BATCH_SIZE) {
404
+ (0, import_errors.logError)(`VectorManager: OOM even at minimum batch size ${MIN_BATCH_SIZE} \u2014 skipping ${batch.length} nodes`, {
405
+ batchStart: pageBufferOffset,
406
+ skippedNodes: batch.map((n) => `${n.kind}:${n.name} (${n.filePath})`).slice(0, 5)
407
+ });
408
+ pageBufferOffset += batch.length;
409
+ processed += batch.length;
410
+ consecutiveSuccesses = 0;
411
+ } else {
412
+ (0, import_errors.logWarn)(`VectorManager: batch embedding failed at offset ${pageBufferOffset}`, {
413
+ batchSize: currentBatchSize,
414
+ error: errMsg
415
+ });
416
+ pageBufferOffset += batch.length;
417
+ processed += batch.length;
418
+ consecutiveSuccesses = 0;
419
+ }
420
+ }
421
+ onProgress?.(processed, totalPending);
422
+ }
423
+ if (this.oramaIndex?.isAvailable()) await this.oramaIndex.save();
424
+ (0, import_errors.logDebug)(`VectorManager: embedding complete \u2014 ${processed} processed, final batch size: ${currentBatchSize}`);
425
+ return processed;
426
+ }
427
+ /**
428
+ * Semantic search: embed the query and return top-N nodes by similarity.
429
+ *
430
+ * When sqlite-vec is available (useVecIndex: true), delegates ANN search to
431
+ * VecIndex (fast, sub-linear). Otherwise falls back to in-process cosine
432
+ * similarity over all stored embeddings (linear scan, no extra deps).
433
+ *
434
+ * Returns empty array when not initialized.
435
+ */
436
+ async search(query, topN = 10) {
437
+ if (!this.isInitialized() || !this.pipeline) return [];
438
+ try {
439
+ const text = `search_query: ${query}`;
440
+ const output = await this.pipeline(text, { pooling: "mean", normalize: true });
441
+ const queryVec = toFloat32Array(output.data);
442
+ let nodeIds;
443
+ if (this.pgliteIndex?.isAvailable()) {
444
+ nodeIds = await this.pgliteIndex.search(query, queryVec, topN);
445
+ } else if (this.oramaIndex?.isAvailable()) {
446
+ nodeIds = await this.oramaIndex.search(query, queryVec, topN);
447
+ } else if (this.lancedbIndex?.isAvailable()) {
448
+ nodeIds = await this.lancedbIndex.search(queryVec, topN);
449
+ } else if (this.qdrantIndex?.isAvailable()) {
450
+ nodeIds = await this.qdrantIndex.search(queryVec, topN);
451
+ } else if (this.typesenseIndex?.isAvailable()) {
452
+ nodeIds = await this.typesenseIndex.search(queryVec, topN);
453
+ } else if (this.vecIndex?.isAvailable()) {
454
+ nodeIds = this.vecIndex.search(queryVec, topN);
455
+ } else {
456
+ const allEmbeddings = this.db.getAllEmbeddings();
457
+ nodeIds = allEmbeddings.map(({ nodeId, embedding }) => ({ nodeId, score: cosine(queryVec, embedding) })).filter((r) => r.score >= 0.3).sort((a, b) => b.score - a.score).slice(0, topN).map((r) => r.nodeId);
458
+ }
459
+ const results = [];
460
+ for (const nodeId of nodeIds) {
461
+ const node = this.db.getNode(nodeId);
462
+ if (node) results.push(node);
463
+ }
464
+ return results;
465
+ } catch (err) {
466
+ (0, import_errors.logWarn)("VectorManager: search failed", { error: String(err) });
467
+ return [];
468
+ }
469
+ }
470
+ /** Release engine resources (e.g. kill Qdrant child process). */
471
+ close() {
472
+ this.qdrantIndex?.close();
473
+ this.typesenseIndex?.close();
474
+ }
475
+ }
476
+ // Annotate the CommonJS export names for ESM import in node:
477
+ 0 && (module.exports = {
478
+ VectorManager
479
+ });
480
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/vectors/index.ts"],
4
+ "sourcesContent": ["/**\n * KiroGraph Vector Manager\n *\n * Semantic search via configurable local embedding models using @huggingface/transformers v3.\n * Mirrors CodeGraph src/vectors/ (embedder.ts + manager.ts) adapted for KiroGraph:\n * - Cache dir: ~/.kirograph/models/ (not ~/.codegraph/models/)\n * - Embeddings stored in the `vectors` SQLite table\n * - Cosine similarity search done in-process by default (no extra deps)\n * - ANN search via sqlite-vec opt-in: set config.useVecIndex = true\n * (requires `npm install better-sqlite3 sqlite-vec`)\n * - Disabled by default; opt-in via config.enableEmbeddings = true\n */\n\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport { homedir } from 'os';\nimport { logDebug, logWarn, logError } from '../errors';\nimport type { KiroGraphConfig } from '../config';\nimport type { Node } from '../types';\nimport type { GraphDatabase } from '../db/database';\nimport { VecIndex } from './vec-index';\nimport { OramaIndex } from './orama-index';\nimport { PGliteIndex } from './pglite-index';\nimport { LanceDBIndex } from './lancedb-index';\nimport { QdrantIndex } from './qdrant-index';\nimport { TypesenseIndex } from './typesense-index';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst DEFAULT_MODEL = 'nomic-ai/nomic-embed-text-v1.5';\nconst DEFAULT_EMBEDDING_DIM = 768;\nconst GLOBAL_MODELS_DIR = path.join(homedir(), '.kirograph', 'models');\nconst BATCH_SIZE = 32;\nconst MIN_BATCH_SIZE = 4;\nconst MAX_TOKEN_CHARS = 2000;\n\n/** Node kinds worth embedding \u2014 high information density */\nconst EMBEDDABLE_KINDS = new Set<Node['kind']>([\n 'function', 'method', 'class', 'interface', 'type_alias', 'component', 'module',\n]);\n\n// \u2500\u2500 Embedder \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype Pipeline = any;\nlet transformers: typeof import('@huggingface/transformers') | null = null;\n\nasync function getTransformers() {\n if (!transformers) {\n transformers = await import('@huggingface/transformers');\n }\n return transformers;\n}\n\n/**\n * Build a searchable text representation of a node.\n * Mirrors CodeGraph TextEmbedder.createNodeText().\n * Truncated to MAX_TOKEN_CHARS to stay within the model's memory-safe token limit.\n * Priority: kind + name > qualified name > file path > signature > docstring.\n * This ensures the most important search signal is always preserved.\n */\nfunction nodeToText(node: Node): string {\n const parts = [`${node.kind}: ${node.name}`];\n if (node.qualifiedName && node.qualifiedName !== node.name) {\n parts.push(`path: ${node.qualifiedName}`);\n }\n parts.push(`file: ${node.filePath}`);\n if (node.signature) parts.push(`signature: ${node.signature}`);\n if (node.docstring) parts.push(`documentation: ${node.docstring}`);\n const text = parts.join('\\n');\n if (text.length > MAX_TOKEN_CHARS) {\n logDebug(`nodeToText: truncated ${node.id} from ${text.length} to ${MAX_TOKEN_CHARS} chars`);\n return text.slice(0, MAX_TOKEN_CHARS);\n }\n return text;\n}\n\n/** Cosine similarity between two equal-length Float32Arrays. */\nfunction cosine(a: Float32Array, b: Float32Array): number {\n let dot = 0, na = 0, nb = 0;\n for (let i = 0; i < a.length; i++) {\n dot += a[i]! * b[i]!;\n na += a[i]! * a[i]!;\n nb += b[i]! * b[i]!;\n }\n const denom = Math.sqrt(na) * Math.sqrt(nb);\n return denom === 0 ? 0 : dot / denom;\n}\n\n/** Extract a flat Float32Array from the transformer pipeline output. */\nfunction toFloat32Array(data: unknown): Float32Array {\n if (data instanceof Float32Array) return data;\n if (Array.isArray(data)) return new Float32Array(data);\n if (data && typeof data === 'object' && 'length' in data) {\n return Float32Array.from(Array.from(data as ArrayLike<number>));\n }\n throw new Error('Unsupported embedding data format');\n}\n\n// \u2500\u2500 VectorManager \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class VectorManager {\n private pipeline: Pipeline | null = null;\n private _initialized = false;\n private vecIndex: VecIndex | null = null;\n private oramaIndex: OramaIndex | null = null;\n private pgliteIndex: PGliteIndex | null = null;\n private lancedbIndex: LanceDBIndex | null = null;\n private qdrantIndex: QdrantIndex | null = null;\n private typesenseIndex: TypesenseIndex | null = null;\n private _engineFallback: string | null = null;\n\n constructor(\n private readonly db: GraphDatabase,\n private readonly config: KiroGraphConfig,\n private readonly projectRoot?: string,\n ) {}\n\n isInitialized(): boolean {\n return this.config.enableEmbeddings === true && this._initialized;\n }\n\n /** Non-null when the configured engine failed to load and cosine is being used instead. */\n getEngineFallback(): string | null {\n return this._engineFallback;\n }\n\n /**\n * Load the embedding model. No-op when embeddings are disabled.\n * Fails silently so callers can continue without semantic search.\n * When config.useVecIndex is true, also initializes the sqlite-vec ANN index.\n */\n async initialize(onProgress?: (file: string, loaded: number, total: number, done: boolean) => void): Promise<void> {\n if (!this.config.enableEmbeddings) {\n logDebug('VectorManager: embeddings disabled');\n return;\n }\n if (this._initialized) return;\n\n const rawModel = this.config.embeddingModel || DEFAULT_MODEL;\n // Guard against an invalid model ID (e.g. 'y' typed by mistake in the installer)\n const modelId = rawModel.includes('/') ? rawModel : DEFAULT_MODEL;\n if (rawModel !== modelId) {\n logWarn(`VectorManager: invalid embeddingModel \"${rawModel}\", using default instead`, { default: DEFAULT_MODEL });\n }\n const cacheDir = GLOBAL_MODELS_DIR;\n\n try {\n const { pipeline, env } = await getTransformers();\n env.cacheDir = cacheDir;\n\n if (!fs.existsSync(cacheDir)) {\n fs.mkdirSync(cacheDir, { recursive: true });\n }\n\n // Skip remote check if model already cached (HuggingFace uses '--' as path separator)\n // HuggingFace transformers v3 stores models as <org>/<model>/ (v2 used <org>--<model>)\n const cached = fs.existsSync(path.join(cacheDir, modelId));\n if (cached) env.allowRemoteModels = false;\n\n let lastFile = '';\n this.pipeline = await pipeline('feature-extraction', modelId, {\n dtype: 'auto',\n ...(!cached && onProgress ? {\n progress_callback: (p: { status: string; file?: string; loaded?: number; total?: number }) => {\n if (p.status === 'progress' && p.file) {\n lastFile = p.file;\n onProgress(p.file, p.loaded ?? 0, p.total ?? 0, false);\n } else if (p.status === 'done' && lastFile) {\n onProgress(lastFile, 1, 1, true);\n lastFile = '';\n }\n },\n } : {}),\n });\n\n // Validate embeddingDim against the model's actual output shape.\n // Run a single test embedding and compare dims[1] to config.embeddingDim.\n // If they differ, warn and update the runtime dim so downstream engines\n // are initialised with the correct size (config.json is not rewritten here).\n try {\n const testOut = await this.pipeline('test', { pooling: 'mean', normalize: true });\n const actualDim: number = testOut.dims?.[1] ?? (testOut.data?.length as number);\n const configuredDim = this.config.embeddingDim ?? DEFAULT_EMBEDDING_DIM;\n if (actualDim && actualDim !== configuredDim) {\n logWarn(\n `VectorManager: embeddingDim mismatch \u2014 config says ${configuredDim} but model outputs ${actualDim}. Using actual dim.`,\n { model: modelId, configuredDim, actualDim },\n );\n // Patch the runtime config so all engine constructors below use the correct dim\n (this.config as unknown as Record<string, unknown>).embeddingDim = actualDim;\n }\n } catch { /* test embedding failed \u2014 proceed with configured dim */ }\n\n this._initialized = true;\n logDebug('VectorManager: model loaded', { modelId, embeddingDim: this.config.embeddingDim ?? DEFAULT_EMBEDDING_DIM });\n } catch (err) {\n logError('VectorManager: failed to load embedding model', {\n model: modelId,\n error: String(err),\n });\n this._initialized = false;\n return;\n }\n\n // Initialize the selected search engine\n const engine = this.config.semanticEngine ?? (this.config.useVecIndex ? 'sqlite-vec' : 'cosine');\n\n if (this.projectRoot && engine !== 'cosine') {\n const kirographDir = path.join(this.projectRoot, '.kirograph');\n\n const embeddingDim = this.config.embeddingDim ?? DEFAULT_EMBEDDING_DIM;\n\n if (engine === 'sqlite-vec') {\n this.vecIndex = new VecIndex(kirographDir, embeddingDim);\n await this.vecIndex.initialize();\n if (this.vecIndex.isAvailable()) {\n logDebug('VectorManager: sqlite-vec ANN index ready');\n } else {\n this._engineFallback = 'sqlite-vec unavailable \u2014 run: npm install better-sqlite3 sqlite-vec';\n logDebug('VectorManager: sqlite-vec unavailable, falling back to in-process cosine');\n }\n } else if (engine === 'orama') {\n this.oramaIndex = new OramaIndex(kirographDir, embeddingDim);\n await this.oramaIndex.initialize();\n if (this.oramaIndex.isAvailable()) {\n logDebug('VectorManager: Orama hybrid index ready');\n } else {\n this._engineFallback = 'orama unavailable \u2014 run: npm install @orama/orama @orama/plugin-data-persistence';\n logDebug('VectorManager: Orama unavailable, falling back to in-process cosine');\n }\n } else if (engine === 'pglite') {\n this.pgliteIndex = new PGliteIndex(kirographDir, embeddingDim);\n await this.pgliteIndex.initialize();\n if (this.pgliteIndex.isAvailable()) {\n logDebug('VectorManager: PGlite+pgvector hybrid index ready');\n } else {\n this._engineFallback = 'pglite unavailable \u2014 run: npm install @electric-sql/pglite';\n logDebug('VectorManager: PGlite unavailable, falling back to in-process cosine');\n }\n } else if (engine === 'lancedb') {\n this.lancedbIndex = new LanceDBIndex(kirographDir, embeddingDim);\n await this.lancedbIndex.initialize();\n if (this.lancedbIndex.isAvailable()) {\n logDebug('VectorManager: LanceDB ANN index ready');\n } else {\n this._engineFallback = 'lancedb unavailable \u2014 run: npm install @lancedb/lancedb';\n logDebug('VectorManager: LanceDB unavailable, falling back to in-process cosine');\n }\n } else if (engine === 'qdrant') {\n this.qdrantIndex = new QdrantIndex(kirographDir, embeddingDim);\n await this.qdrantIndex.initialize();\n if (this.qdrantIndex.isAvailable()) {\n logDebug('VectorManager: Qdrant ANN index ready');\n } else {\n this._engineFallback = 'qdrant unavailable \u2014 run: npm install qdrant-local';\n logDebug('VectorManager: Qdrant unavailable, falling back to in-process cosine');\n }\n } else if (engine === 'typesense') {\n this.typesenseIndex = new TypesenseIndex(kirographDir, embeddingDim);\n await this.typesenseIndex.initialize();\n if (this.typesenseIndex.isAvailable()) {\n logDebug('VectorManager: Typesense ANN index ready');\n } else {\n const reason = this.typesenseIndex.getFailReason();\n this._engineFallback = reason\n ? `typesense initialization failed: ${reason}`\n : 'typesense unavailable \u2014 run: npm install typesense';\n logDebug('VectorManager: Typesense unavailable, falling back to in-process cosine');\n }\n }\n }\n }\n\n /**\n * Embed a single node and persist to the vectors table.\n * Skips silently when disabled; logs on failure without throwing.\n */\n async embedNode(node: Node): Promise<void> {\n if (!this.config.enableEmbeddings) return;\n if (!this._initialized || !this.pipeline) {\n logError('Embedding model unavailable', { model: this.config.embeddingModel });\n return;\n }\n if (!EMBEDDABLE_KINDS.has(node.kind)) return;\n\n try {\n const text = `search_document: ${nodeToText(node)}`;\n const output = await this.pipeline(text, { pooling: 'mean', normalize: true });\n const embedding = toFloat32Array(output.data);\n // non-cosine engines are sole stores of record when active \u2014 skip the SQLite vectors table\n if (!this.vecIndex?.isAvailable() && !this.oramaIndex?.isAvailable() && !this.pgliteIndex?.isAvailable() && !this.lancedbIndex?.isAvailable() && !this.qdrantIndex?.isAvailable() && !this.typesenseIndex?.isAvailable()) {\n this.db.storeEmbedding(node.id, embedding, this.config.embeddingModel || DEFAULT_MODEL);\n }\n this.vecIndex?.upsert(node.id, embedding);\n if (this.oramaIndex?.isAvailable()) await this.oramaIndex.upsert(node, embedding);\n if (this.pgliteIndex?.isAvailable()) await this.pgliteIndex.upsert(node, embedding);\n if (this.lancedbIndex?.isAvailable()) await this.lancedbIndex.upsert(node, embedding);\n if (this.qdrantIndex?.isAvailable()) await this.qdrantIndex.upsert(node, embedding);\n if (this.typesenseIndex?.isAvailable()) await this.typesenseIndex.upsert(node, embedding);\n } catch (err) {\n logWarn('Failed to embed node', { nodeId: node.id, error: String(err) });\n }\n }\n\n /** Number of entries currently in the active ANN/hybrid index (0 when not in use). */\n async vecIndexCount(): Promise<number> {\n if (this.vecIndex?.isAvailable()) return this.vecIndex.count();\n if (this.oramaIndex?.isAvailable()) return this.oramaIndex.count();\n if (this.pgliteIndex?.isAvailable()) return this.pgliteIndex.count();\n if (this.lancedbIndex?.isAvailable()) return this.lancedbIndex.count();\n if (this.qdrantIndex?.isAvailable()) return this.qdrantIndex.count();\n if (this.typesenseIndex?.isAvailable()) return this.typesenseIndex.count();\n return 0;\n }\n\n /**\n * Remove embeddings for the given node IDs from the active index.\n * For cosine the `vectors` SQLite table is cleaned up automatically via FK cascade\n * when nodes are deleted. For sqlite-vec, orama, and pglite the engine itself is\n * the sole store of record, so we delete from it explicitly here.\n */\n async deleteEmbeddings(nodeIds: string[]): Promise<void> {\n for (const id of nodeIds) {\n this.vecIndex?.delete(id);\n if (this.oramaIndex?.isAvailable()) await this.oramaIndex.delete(id);\n if (this.pgliteIndex?.isAvailable()) await this.pgliteIndex.delete(id);\n if (this.lancedbIndex?.isAvailable()) await this.lancedbIndex.delete(id);\n if (this.qdrantIndex?.isAvailable()) await this.qdrantIndex.delete(id);\n if (this.typesenseIndex?.isAvailable()) await this.typesenseIndex.delete(id);\n }\n }\n\n /**\n * Embed all eligible nodes in the database that don't yet have embeddings.\n * Streams nodes in pages to avoid loading the entire node set into memory \u2014\n * critical for large codebases (100K+ symbols) where a single getAllNodes()\n * call can exhaust the Node.js heap or the WASM linear memory.\n *\n * Uses dynamic batch sizing: starts at BATCH_SIZE, halves on OOM errors,\n * and recovers back to full size after successful batches.\n *\n * Emits a pre-flight warning via onProgress when the embeddable node count\n * exceeds LARGE_CODEBASE_THRESHOLD so the CLI can surface it to the user.\n */\n async embedAll(onProgress?: (current: number, total: number) => void): Promise<number> {\n if (!this.isInitialized() || !this.pipeline) return 0;\n\n const modelId = this.config.embeddingModel || DEFAULT_MODEL;\n const EMBEDDABLE_KINDS_ARRAY = [...EMBEDDABLE_KINDS] as string[];\n\n // Pre-flight: count embeddable nodes without loading them\n const totalEmbeddable = this.db.countEmbeddableNodes(EMBEDDABLE_KINDS_ARRAY);\n const LARGE_CODEBASE_THRESHOLD = 100_000;\n if (totalEmbeddable > LARGE_CODEBASE_THRESHOLD) {\n // Signal the large-codebase warning via a special progress event.\n // current=-1 is the sentinel; the CLI renderer checks for it.\n onProgress?.(-1, totalEmbeddable);\n }\n\n // Collect already-embedded IDs (needed to skip nodes already in the index)\n const existingIds = new Set(\n this.typesenseIndex?.isAvailable()\n ? await this.typesenseIndex.getEmbeddedNodeIds()\n : this.qdrantIndex?.isAvailable()\n ? await this.qdrantIndex.getEmbeddedNodeIds()\n : this.lancedbIndex?.isAvailable()\n ? await this.lancedbIndex.getEmbeddedNodeIds()\n : this.pgliteIndex?.isAvailable()\n ? await this.pgliteIndex.getEmbeddedNodeIds()\n : this.oramaIndex?.isAvailable()\n ? await this.oramaIndex.getEmbeddedNodeIds()\n : this.vecIndex?.isAvailable()\n ? this.vecIndex.getEmbeddedNodeIds()\n : this.db.getEmbeddedNodeIds()\n );\n\n // Stream nodes in pages \u2014 never hold more than PAGE_SIZE nodes in memory at once\n const PAGE_SIZE = 2000;\n let pageOffset = 0;\n let processed = 0;\n let currentBatchSize = BATCH_SIZE;\n let consecutiveSuccesses = 0;\n\n // We need to know the total pending count for progress reporting.\n // Approximate: totalEmbeddable - existingIds.size (may be slightly off if\n // existingIds contains IDs for non-embeddable kinds, but close enough).\n const totalPending = Math.max(0, totalEmbeddable - existingIds.size);\n if (totalPending === 0) {\n if (this.oramaIndex?.isAvailable()) await this.oramaIndex.save();\n return 0;\n }\n\n logDebug(`VectorManager: embedding ~${totalPending} nodes (${existingIds.size} already embedded, streaming in pages of ${PAGE_SIZE})`);\n\n // Buffer of pending nodes from the current page\n let pageBuffer: Node[] = [];\n let pageBufferOffset = 0; // index within pageBuffer\n let pageExhausted = false;\n\n const fetchNextPage = () => {\n const page = this.db.getEmbeddableNodesPaged(EMBEDDABLE_KINDS_ARRAY, PAGE_SIZE, pageOffset);\n pageOffset += page.length;\n pageBuffer = page.filter(n => !existingIds.has(n.id));\n pageBufferOffset = 0;\n if (page.length < PAGE_SIZE) pageExhausted = true;\n };\n\n fetchNextPage();\n\n while (pageBuffer.length > 0 || (!pageExhausted && pageBufferOffset >= pageBuffer.length)) {\n // Refill page buffer when exhausted\n if (pageBufferOffset >= pageBuffer.length) {\n if (pageExhausted) break;\n fetchNextPage();\n if (pageBuffer.length === 0) break;\n }\n\n // Slice a batch from the current page buffer\n const batch = pageBuffer.slice(pageBufferOffset, pageBufferOffset + currentBatchSize);\n if (batch.length === 0) break;\n\n const texts = batch.map(n => `search_document: ${nodeToText(n)}`);\n\n try {\n const outputs = await this.pipeline(texts, { pooling: 'mean', normalize: true });\n const dims: number[] = outputs.dims;\n const dim = dims[1] ?? (this.config.embeddingDim ?? DEFAULT_EMBEDDING_DIM);\n const flat = toFloat32Array(outputs.data);\n\n const tsNodes: Node[] = [];\n const tsEmbeddings: Float32Array[] = [];\n const qdNodes: Node[] = [];\n const qdEmbeddings: Float32Array[] = [];\n\n for (let j = 0; j < batch.length; j++) {\n const node = batch[j]!;\n const embedding = flat.slice(j * dim, (j + 1) * dim);\n if (!this.vecIndex?.isAvailable() && !this.oramaIndex?.isAvailable() && !this.pgliteIndex?.isAvailable() && !this.lancedbIndex?.isAvailable() && !this.qdrantIndex?.isAvailable() && !this.typesenseIndex?.isAvailable()) {\n this.db.storeEmbedding(node.id, embedding, modelId);\n }\n this.vecIndex?.upsert(node.id, embedding);\n if (this.oramaIndex?.isAvailable()) await this.oramaIndex.upsert(node, embedding);\n if (this.pgliteIndex?.isAvailable()) await this.pgliteIndex.upsert(node, embedding);\n if (this.lancedbIndex?.isAvailable()) await this.lancedbIndex.upsert(node, embedding);\n if (this.qdrantIndex?.isAvailable()) { qdNodes.push(node); qdEmbeddings.push(embedding); }\n if (this.typesenseIndex?.isAvailable()) { tsNodes.push(node); tsEmbeddings.push(embedding); }\n }\n\n if (qdNodes.length > 0) await this.qdrantIndex!.bulkUpsert(qdNodes, qdEmbeddings);\n if (tsNodes.length > 0) await this.typesenseIndex!.bulkUpsert(tsNodes, tsEmbeddings);\n\n pageBufferOffset += batch.length;\n processed += batch.length;\n consecutiveSuccesses++;\n\n if (currentBatchSize < BATCH_SIZE && consecutiveSuccesses >= 5) {\n currentBatchSize = Math.min(currentBatchSize * 2, BATCH_SIZE);\n logDebug(`VectorManager: batch size recovered to ${currentBatchSize}`);\n consecutiveSuccesses = 0;\n }\n } catch (err) {\n const errMsg = String(err);\n const isOOM = errMsg.includes('bad allocation') || errMsg.includes('OOM') || errMsg.includes('out of memory');\n\n if (isOOM && currentBatchSize > MIN_BATCH_SIZE) {\n currentBatchSize = Math.max(Math.floor(currentBatchSize / 2), MIN_BATCH_SIZE);\n consecutiveSuccesses = 0;\n logWarn(`VectorManager: OOM at batch offset ${pageBufferOffset} \u2014 reducing batch size to ${currentBatchSize} and retrying`, {\n batchSize: currentBatchSize,\n nodeIds: batch.slice(0, 3).map(n => n.id),\n });\n // Don't advance pageBufferOffset \u2014 retry the same batch\n } else if (isOOM && currentBatchSize <= MIN_BATCH_SIZE) {\n logError(`VectorManager: OOM even at minimum batch size ${MIN_BATCH_SIZE} \u2014 skipping ${batch.length} nodes`, {\n batchStart: pageBufferOffset,\n skippedNodes: batch.map(n => `${n.kind}:${n.name} (${n.filePath})`).slice(0, 5),\n });\n pageBufferOffset += batch.length;\n processed += batch.length;\n consecutiveSuccesses = 0;\n } else {\n logWarn(`VectorManager: batch embedding failed at offset ${pageBufferOffset}`, {\n batchSize: currentBatchSize,\n error: errMsg,\n });\n pageBufferOffset += batch.length;\n processed += batch.length;\n consecutiveSuccesses = 0;\n }\n }\n\n onProgress?.(processed, totalPending);\n }\n\n if (this.oramaIndex?.isAvailable()) await this.oramaIndex.save();\n\n logDebug(`VectorManager: embedding complete \u2014 ${processed} processed, final batch size: ${currentBatchSize}`);\n\n return processed;\n }\n\n /**\n * Semantic search: embed the query and return top-N nodes by similarity.\n *\n * When sqlite-vec is available (useVecIndex: true), delegates ANN search to\n * VecIndex (fast, sub-linear). Otherwise falls back to in-process cosine\n * similarity over all stored embeddings (linear scan, no extra deps).\n *\n * Returns empty array when not initialized.\n */\n async search(query: string, topN = 10): Promise<Node[]> {\n if (!this.isInitialized() || !this.pipeline) return [];\n\n try {\n const text = `search_query: ${query}`;\n const output = await this.pipeline(text, { pooling: 'mean', normalize: true });\n const queryVec = toFloat32Array(output.data);\n\n let nodeIds: string[];\n\n if (this.pgliteIndex?.isAvailable()) {\n // Hybrid search via PGlite+pgvector \u2014 exact vector + full-text in one SQL query\n nodeIds = await this.pgliteIndex.search(query, queryVec, topN);\n } else if (this.oramaIndex?.isAvailable()) {\n // Hybrid search via Orama \u2014 full-text + vector combined\n nodeIds = await this.oramaIndex.search(query, queryVec, topN);\n } else if (this.lancedbIndex?.isAvailable()) {\n // ANN search via LanceDB \u2014 columnar Lance format, cosine metric\n nodeIds = await this.lancedbIndex.search(queryVec, topN);\n } else if (this.qdrantIndex?.isAvailable()) {\n // ANN search via Qdrant \u2014 HNSW index, cosine metric\n nodeIds = await this.qdrantIndex.search(queryVec, topN);\n } else if (this.typesenseIndex?.isAvailable()) {\n // ANN search via Typesense \u2014 HNSW index, cosine metric\n nodeIds = await this.typesenseIndex.search(queryVec, topN);\n } else if (this.vecIndex?.isAvailable()) {\n // ANN search via sqlite-vec \u2014 fast, sub-linear\n nodeIds = this.vecIndex.search(queryVec, topN);\n } else {\n // In-process cosine similarity \u2014 linear scan over all stored embeddings\n const allEmbeddings = this.db.getAllEmbeddings();\n nodeIds = allEmbeddings\n .map(({ nodeId, embedding }) => ({ nodeId, score: cosine(queryVec, embedding) }))\n .filter(r => r.score >= 0.3)\n .sort((a, b) => b.score - a.score)\n .slice(0, topN)\n .map(r => r.nodeId);\n }\n\n const results: Node[] = [];\n for (const nodeId of nodeIds) {\n const node = this.db.getNode(nodeId);\n if (node) results.push(node);\n }\n return results;\n } catch (err) {\n logWarn('VectorManager: search failed', { error: String(err) });\n return [];\n }\n }\n\n /** Release engine resources (e.g. kill Qdrant child process). */\n close(): void {\n this.qdrantIndex?.close();\n this.typesenseIndex?.close();\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * KiroGraph LanceDB Index
3
+ *
4
+ * ANN vector search backed by @lancedb/lancedb (Apache Arrow / Lance format).
5
+ * The database is persisted to .kirograph/lancedb/ (Lance columnar file storage).
6
+ *
7
+ * Opt-in: set config.semanticEngine = 'lancedb'
8
+ * Required optional dependency (not installed by default):
9
+ * npm install @lancedb/lancedb
10
+ *
11
+ * Key characteristics:
12
+ * - Pure JS/WASM, no native compilation required
13
+ * - Columnar storage (Apache Lance format) — efficient for batch reads/writes
14
+ * - ANN search via IVF-PQ or HNSW index for sub-linear query time
15
+ * - Native upsert via mergeInsert (single round-trip, no delete+insert dance)
16
+ */
17
+ import type { Node } from '../types';
18
+ export declare class LanceDBIndex {
19
+ private readonly kirographDir;
20
+ private readonly dim;
21
+ private db;
22
+ private table;
23
+ private _available;
24
+ private dbPath;
25
+ constructor(kirographDir: string, dim?: number);
26
+ isAvailable(): boolean;
27
+ /**
28
+ * Load @lancedb/lancedb, open the file-persisted database, and open or create
29
+ * the kg_nodes table. Silent no-op when the optional dep is missing.
30
+ */
31
+ initialize(): Promise<void>;
32
+ /**
33
+ * Insert or update a node using LanceDB's native mergeInsert — a single
34
+ * round-trip that updates the row if node_id exists, inserts it otherwise.
35
+ */
36
+ upsert(node: Node, embedding: Float32Array): Promise<void>;
37
+ /**
38
+ * Remove a node's record from the index.
39
+ */
40
+ delete(nodeId: string): Promise<void>;
41
+ /**
42
+ * ANN vector search. Returns node IDs ordered by cosine similarity (descending).
43
+ */
44
+ search(queryVec: Float32Array, topN?: number): Promise<string[]>;
45
+ /** Return all node IDs currently stored in the index. */
46
+ getEmbeddedNodeIds(): Promise<string[]>;
47
+ /** Number of records currently in the index. */
48
+ count(): Promise<number>;
49
+ }
50
+ //# sourceMappingURL=lancedb-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lancedb-index.d.ts","sourceRoot":"","sources":["../../src/vectors/lancedb-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAUrC,qBAAa,YAAY;IAOrB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPtB,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAS;gBAGJ,YAAY,EAAE,MAAM,EACpB,GAAG,SAAc;IAKpC,WAAW,IAAI,OAAO;IAItB;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAsCjC;;;OAGG;IACG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBhE;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU3C;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,SAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAiBlE,yDAAyD;IACnD,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAU7C,gDAAgD;IAC1C,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;CAQ/B"}