bluera-knowledge 0.9.21

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 (652) hide show
  1. package/.claude/commands/commit.md +37 -0
  2. package/.claude/hooks/post-edit-check.sh +41 -0
  3. package/.claude/settings.local.json.example +40 -0
  4. package/.claude/skills/atomic-commits/SKILL.md +53 -0
  5. package/.claude-plugin/plugin.json +13 -0
  6. package/.editorconfig +15 -0
  7. package/.github/workflows/auto-release.yml +59 -0
  8. package/.github/workflows/ci.yml +142 -0
  9. package/.github/workflows/release.yml +66 -0
  10. package/.github/workflows/update-marketplace.yml +96 -0
  11. package/.husky/pre-commit +47 -0
  12. package/.husky/pre-push +29 -0
  13. package/.versionrc.json +28 -0
  14. package/CHANGELOG.md +410 -0
  15. package/CLAUDE.md +109 -0
  16. package/LICENSE +21 -0
  17. package/NOTICE +47 -0
  18. package/README.md +1546 -0
  19. package/SECURITY.md +65 -0
  20. package/bun.lock +1758 -0
  21. package/commands/add-folder.md +48 -0
  22. package/commands/add-repo.md +50 -0
  23. package/commands/cancel.md +63 -0
  24. package/commands/check-status.md +78 -0
  25. package/commands/crawl.md +51 -0
  26. package/commands/index.md +48 -0
  27. package/commands/remove-store.md +52 -0
  28. package/commands/search.md +79 -0
  29. package/commands/search.sh +63 -0
  30. package/commands/stores.md +54 -0
  31. package/commands/suggest.md +82 -0
  32. package/dist/chunk-5QMHZUC4.js +3617 -0
  33. package/dist/chunk-5QMHZUC4.js.map +1 -0
  34. package/dist/chunk-BICFAWMN.js +656 -0
  35. package/dist/chunk-BICFAWMN.js.map +1 -0
  36. package/dist/chunk-J7J6LXOJ.js +958 -0
  37. package/dist/chunk-J7J6LXOJ.js.map +1 -0
  38. package/dist/chunk-L2YVNC63.js +59 -0
  39. package/dist/chunk-L2YVNC63.js.map +1 -0
  40. package/dist/index.d.ts +1 -0
  41. package/dist/index.js +1429 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/mcp/server.d.ts +15 -0
  44. package/dist/mcp/server.js +11 -0
  45. package/dist/mcp/server.js.map +1 -0
  46. package/dist/watch.service-YAIKKDCF.js +7 -0
  47. package/dist/watch.service-YAIKKDCF.js.map +1 -0
  48. package/dist/workers/background-worker-cli.d.ts +1 -0
  49. package/dist/workers/background-worker-cli.js +310 -0
  50. package/dist/workers/background-worker-cli.js.map +1 -0
  51. package/docs/plans/2024-12-17-ai-search-quality-implementation.md +752 -0
  52. package/docs/plans/2024-12-17-ai-search-quality-testing-design.md +201 -0
  53. package/docs/plans/2025-12-16-bluera-knowledge-cli.md +2951 -0
  54. package/docs/plans/2025-12-16-phase2-features.md +1518 -0
  55. package/docs/plans/2025-12-17-hil-implementation.md +926 -0
  56. package/docs/plans/2025-12-17-hil-quality-testing.md +224 -0
  57. package/docs/plans/2025-12-17-search-quality-phase1-implementation.md +1416 -0
  58. package/docs/plans/2025-12-17-search-quality-testing-v2-design.md +212 -0
  59. package/docs/plans/2025-12-28-ai-agent-optimization.md +1630 -0
  60. package/eslint-rules/require-skip-comment.js +81 -0
  61. package/eslint.config.js +61 -0
  62. package/hooks/check-dependencies.sh +110 -0
  63. package/hooks/format-search-results.py +132 -0
  64. package/hooks/hooks.json +27 -0
  65. package/hooks/job-status-hook.sh +51 -0
  66. package/knip.json +43 -0
  67. package/mcp.plugin.json +12 -0
  68. package/package.json +103 -0
  69. package/python/crawl_worker.py +275 -0
  70. package/python/requirements.txt +2 -0
  71. package/scripts/readme-version-updater.cjs +18 -0
  72. package/skills/advanced-workflows/SKILL.md +273 -0
  73. package/skills/atomic-commits/SKILL.md +77 -0
  74. package/skills/knowledge-search/SKILL.md +54 -0
  75. package/skills/search-optimization/SKILL.md +396 -0
  76. package/skills/store-lifecycle/SKILL.md +470 -0
  77. package/skills/when-to-query/SKILL.md +66 -0
  78. package/src/analysis/ast-parser.test.ts +423 -0
  79. package/src/analysis/ast-parser.ts +192 -0
  80. package/src/analysis/code-graph.test.ts +698 -0
  81. package/src/analysis/code-graph.ts +245 -0
  82. package/src/analysis/dependency-usage-analyzer.test.ts +799 -0
  83. package/src/analysis/dependency-usage-analyzer.ts +405 -0
  84. package/src/analysis/go-ast-parser.test.ts +531 -0
  85. package/src/analysis/go-ast-parser.ts +478 -0
  86. package/src/analysis/parser-factory.test.ts +132 -0
  87. package/src/analysis/parser-factory.ts +44 -0
  88. package/src/analysis/python-ast-parser.test.ts +210 -0
  89. package/src/analysis/python-ast-parser.ts +34 -0
  90. package/src/analysis/repo-url-resolver.test.ts +533 -0
  91. package/src/analysis/repo-url-resolver.ts +233 -0
  92. package/src/analysis/rust-ast-parser.test.ts +568 -0
  93. package/src/analysis/rust-ast-parser.ts +477 -0
  94. package/src/analysis/tree-sitter-parser.test.ts +297 -0
  95. package/src/analysis/tree-sitter-parser.ts +223 -0
  96. package/src/cli/commands/crawl.test.ts +942 -0
  97. package/src/cli/commands/crawl.ts +141 -0
  98. package/src/cli/commands/index-cmd.test.ts +722 -0
  99. package/src/cli/commands/index-cmd.ts +105 -0
  100. package/src/cli/commands/mcp.test.ts +218 -0
  101. package/src/cli/commands/mcp.ts +18 -0
  102. package/src/cli/commands/plugin-api.test.ts +313 -0
  103. package/src/cli/commands/plugin-api.ts +45 -0
  104. package/src/cli/commands/search.test.ts +911 -0
  105. package/src/cli/commands/search.ts +113 -0
  106. package/src/cli/commands/serve.test.ts +329 -0
  107. package/src/cli/commands/serve.ts +28 -0
  108. package/src/cli/commands/setup.test.ts +820 -0
  109. package/src/cli/commands/setup.ts +153 -0
  110. package/src/cli/commands/store.test.ts +1003 -0
  111. package/src/cli/commands/store.ts +167 -0
  112. package/src/cli/index.ts +7 -0
  113. package/src/cli/program.ts +59 -0
  114. package/src/crawl/article-converter.test.ts +604 -0
  115. package/src/crawl/article-converter.ts +98 -0
  116. package/src/crawl/bridge.test.ts +674 -0
  117. package/src/crawl/bridge.ts +236 -0
  118. package/src/crawl/claude-client.test.ts +663 -0
  119. package/src/crawl/claude-client.ts +234 -0
  120. package/src/crawl/intelligent-crawler.test.ts +931 -0
  121. package/src/crawl/intelligent-crawler.ts +428 -0
  122. package/src/crawl/markdown-utils.test.ts +703 -0
  123. package/src/crawl/markdown-utils.ts +228 -0
  124. package/src/crawl/schemas.ts +114 -0
  125. package/src/db/embeddings.test.ts +63 -0
  126. package/src/db/embeddings.ts +69 -0
  127. package/src/db/index.ts +2 -0
  128. package/src/db/lance.test.ts +390 -0
  129. package/src/db/lance.ts +164 -0
  130. package/src/defaults/repos.ts +67 -0
  131. package/src/index.ts +107 -0
  132. package/src/mcp/cache.test.ts +202 -0
  133. package/src/mcp/cache.ts +103 -0
  134. package/src/mcp/commands/index.ts +20 -0
  135. package/src/mcp/commands/job.commands.ts +54 -0
  136. package/src/mcp/commands/meta.commands.ts +54 -0
  137. package/src/mcp/commands/registry.ts +183 -0
  138. package/src/mcp/commands/store.commands.ts +75 -0
  139. package/src/mcp/handlers/execute.handler.test.ts +179 -0
  140. package/src/mcp/handlers/execute.handler.ts +24 -0
  141. package/src/mcp/handlers/index.ts +43 -0
  142. package/src/mcp/handlers/job.handler.test.ts +189 -0
  143. package/src/mcp/handlers/job.handler.ts +116 -0
  144. package/src/mcp/handlers/search.handler.test.ts +334 -0
  145. package/src/mcp/handlers/search.handler.ts +209 -0
  146. package/src/mcp/handlers/store.handler.test.ts +415 -0
  147. package/src/mcp/handlers/store.handler.ts +295 -0
  148. package/src/mcp/schemas/index.test.ts +315 -0
  149. package/src/mcp/schemas/index.ts +138 -0
  150. package/src/mcp/server.test.ts +36 -0
  151. package/src/mcp/server.ts +162 -0
  152. package/src/mcp/types.ts +41 -0
  153. package/src/plugin/commands.test.ts +789 -0
  154. package/src/plugin/commands.ts +257 -0
  155. package/src/plugin/dependency-analyzer.test.ts +380 -0
  156. package/src/plugin/dependency-analyzer.ts +147 -0
  157. package/src/plugin/git-clone.test.ts +332 -0
  158. package/src/plugin/git-clone.ts +57 -0
  159. package/src/server/app.test.ts +752 -0
  160. package/src/server/app.ts +119 -0
  161. package/src/server/index.test.ts +477 -0
  162. package/src/server/index.ts +1 -0
  163. package/src/services/chunking.service.test.ts +363 -0
  164. package/src/services/chunking.service.ts +350 -0
  165. package/src/services/code-graph.service.test.ts +304 -0
  166. package/src/services/code-graph.service.ts +302 -0
  167. package/src/services/code-unit.service.test.ts +596 -0
  168. package/src/services/code-unit.service.ts +115 -0
  169. package/src/services/config.service.test.ts +127 -0
  170. package/src/services/config.service.ts +69 -0
  171. package/src/services/index.service.test.ts +1002 -0
  172. package/src/services/index.service.ts +266 -0
  173. package/src/services/index.ts +75 -0
  174. package/src/services/job.service.test.ts +418 -0
  175. package/src/services/job.service.ts +246 -0
  176. package/src/services/project-root.service.test.ts +506 -0
  177. package/src/services/project-root.service.ts +112 -0
  178. package/src/services/search.service.test.ts +1105 -0
  179. package/src/services/search.service.ts +892 -0
  180. package/src/services/services.test.ts +38 -0
  181. package/src/services/snippet.service.test.ts +205 -0
  182. package/src/services/snippet.service.ts +166 -0
  183. package/src/services/store.service.test.ts +474 -0
  184. package/src/services/store.service.ts +225 -0
  185. package/src/services/watch.service.test.ts +553 -0
  186. package/src/services/watch.service.ts +71 -0
  187. package/src/types/brands.test.ts +45 -0
  188. package/src/types/brands.ts +32 -0
  189. package/src/types/config.ts +79 -0
  190. package/src/types/document.ts +30 -0
  191. package/src/types/index.ts +66 -0
  192. package/src/types/job.ts +46 -0
  193. package/src/types/progress.ts +9 -0
  194. package/src/types/result.test.ts +44 -0
  195. package/src/types/result.ts +41 -0
  196. package/src/types/search.ts +95 -0
  197. package/src/types/store.test.ts +69 -0
  198. package/src/types/store.ts +47 -0
  199. package/src/utils/type-guards.test.ts +346 -0
  200. package/src/utils/type-guards.ts +61 -0
  201. package/src/workers/background-worker-cli.ts +105 -0
  202. package/src/workers/background-worker.test.ts +178 -0
  203. package/src/workers/background-worker.ts +294 -0
  204. package/src/workers/spawn-worker.test.ts +128 -0
  205. package/src/workers/spawn-worker.ts +49 -0
  206. package/tests/analysis/ast-parser.test.ts +98 -0
  207. package/tests/analysis/code-graph.test.ts +60 -0
  208. package/tests/fixtures/README.md +114 -0
  209. package/tests/fixtures/code-snippets/api/error-handling.ts +267 -0
  210. package/tests/fixtures/code-snippets/api/rest-controller.ts +303 -0
  211. package/tests/fixtures/code-snippets/auth/jwt-auth.ts +213 -0
  212. package/tests/fixtures/code-snippets/auth/oauth-flow.ts +245 -0
  213. package/tests/fixtures/code-snippets/database/repository-pattern.ts +272 -0
  214. package/tests/fixtures/corpus/VERSION.md +25 -0
  215. package/tests/fixtures/corpus/articles/jwt-authentication.md +97 -0
  216. package/tests/fixtures/corpus/articles/react-hooks-patterns.md +127 -0
  217. package/tests/fixtures/corpus/articles/typescript-generics.md +111 -0
  218. package/tests/fixtures/corpus/documentation/express-middleware.md +71 -0
  219. package/tests/fixtures/corpus/documentation/express-routing.md +83 -0
  220. package/tests/fixtures/corpus/documentation/node-streams.md +78 -0
  221. package/tests/fixtures/corpus/oss-repos/express/History.md +3871 -0
  222. package/tests/fixtures/corpus/oss-repos/express/LICENSE +24 -0
  223. package/tests/fixtures/corpus/oss-repos/express/Readme.md +276 -0
  224. package/tests/fixtures/corpus/oss-repos/express/SECURITY.md +56 -0
  225. package/tests/fixtures/corpus/oss-repos/express/benchmarks/Makefile +17 -0
  226. package/tests/fixtures/corpus/oss-repos/express/benchmarks/README.md +34 -0
  227. package/tests/fixtures/corpus/oss-repos/express/benchmarks/middleware.js +20 -0
  228. package/tests/fixtures/corpus/oss-repos/express/benchmarks/run +18 -0
  229. package/tests/fixtures/corpus/oss-repos/express/examples/README.md +29 -0
  230. package/tests/fixtures/corpus/oss-repos/express/examples/auth/index.js +134 -0
  231. package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/foot.ejs +2 -0
  232. package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/head.ejs +20 -0
  233. package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/login.ejs +21 -0
  234. package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/db.js +9 -0
  235. package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/index.js +46 -0
  236. package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/users.js +19 -0
  237. package/tests/fixtures/corpus/oss-repos/express/examples/cookie-sessions/index.js +25 -0
  238. package/tests/fixtures/corpus/oss-repos/express/examples/cookies/index.js +53 -0
  239. package/tests/fixtures/corpus/oss-repos/express/examples/downloads/files/CCTV/345/244/247/350/265/233/344/270/212/346/265/267/345/210/206/350/265/233/345/214/272.txt +2 -0
  240. package/tests/fixtures/corpus/oss-repos/express/examples/downloads/files/amazing.txt +1 -0
  241. package/tests/fixtures/corpus/oss-repos/express/examples/downloads/files/notes/groceries.txt +3 -0
  242. package/tests/fixtures/corpus/oss-repos/express/examples/downloads/index.js +40 -0
  243. package/tests/fixtures/corpus/oss-repos/express/examples/ejs/index.js +57 -0
  244. package/tests/fixtures/corpus/oss-repos/express/examples/ejs/public/stylesheets/style.css +4 -0
  245. package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/footer.html +2 -0
  246. package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/header.html +9 -0
  247. package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/users.html +10 -0
  248. package/tests/fixtures/corpus/oss-repos/express/examples/error/index.js +53 -0
  249. package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/index.js +103 -0
  250. package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/404.ejs +3 -0
  251. package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/500.ejs +8 -0
  252. package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/error_header.ejs +10 -0
  253. package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/footer.ejs +2 -0
  254. package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/index.ejs +20 -0
  255. package/tests/fixtures/corpus/oss-repos/express/examples/hello-world/index.js +15 -0
  256. package/tests/fixtures/corpus/oss-repos/express/examples/markdown/index.js +44 -0
  257. package/tests/fixtures/corpus/oss-repos/express/examples/markdown/views/index.md +4 -0
  258. package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/controllers/api_v1.js +15 -0
  259. package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/controllers/api_v2.js +15 -0
  260. package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/index.js +18 -0
  261. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/main/index.js +5 -0
  262. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/index.js +31 -0
  263. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/views/edit.ejs +17 -0
  264. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/views/show.ejs +15 -0
  265. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/index.js +41 -0
  266. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/edit.hbs +27 -0
  267. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/list.hbs +18 -0
  268. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/show.hbs +31 -0
  269. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user-pet/index.js +22 -0
  270. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/db.js +16 -0
  271. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/index.js +95 -0
  272. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/lib/boot.js +83 -0
  273. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/public/style.css +14 -0
  274. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/views/404.ejs +13 -0
  275. package/tests/fixtures/corpus/oss-repos/express/examples/mvc/views/5xx.ejs +13 -0
  276. package/tests/fixtures/corpus/oss-repos/express/examples/online/index.js +61 -0
  277. package/tests/fixtures/corpus/oss-repos/express/examples/params/index.js +74 -0
  278. package/tests/fixtures/corpus/oss-repos/express/examples/resource/index.js +95 -0
  279. package/tests/fixtures/corpus/oss-repos/express/examples/route-map/index.js +75 -0
  280. package/tests/fixtures/corpus/oss-repos/express/examples/route-middleware/index.js +90 -0
  281. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/index.js +55 -0
  282. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/post.js +13 -0
  283. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/public/style.css +24 -0
  284. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/site.js +5 -0
  285. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/user.js +47 -0
  286. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/footer.ejs +2 -0
  287. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/header.ejs +9 -0
  288. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/index.ejs +10 -0
  289. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/posts/index.ejs +12 -0
  290. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/edit.ejs +23 -0
  291. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/index.ejs +14 -0
  292. package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/view.ejs +9 -0
  293. package/tests/fixtures/corpus/oss-repos/express/examples/search/index.js +61 -0
  294. package/tests/fixtures/corpus/oss-repos/express/examples/search/public/client.js +15 -0
  295. package/tests/fixtures/corpus/oss-repos/express/examples/search/public/index.html +21 -0
  296. package/tests/fixtures/corpus/oss-repos/express/examples/session/index.js +37 -0
  297. package/tests/fixtures/corpus/oss-repos/express/examples/session/redis.js +39 -0
  298. package/tests/fixtures/corpus/oss-repos/express/examples/static-files/index.js +43 -0
  299. package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/css/style.css +3 -0
  300. package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/hello.txt +1 -0
  301. package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/js/app.js +1 -0
  302. package/tests/fixtures/corpus/oss-repos/express/examples/vhost/index.js +53 -0
  303. package/tests/fixtures/corpus/oss-repos/express/examples/view-constructor/github-view.js +53 -0
  304. package/tests/fixtures/corpus/oss-repos/express/examples/view-constructor/index.js +48 -0
  305. package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/index.js +155 -0
  306. package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/user.js +36 -0
  307. package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/views/index.ejs +20 -0
  308. package/tests/fixtures/corpus/oss-repos/express/examples/web-service/index.js +117 -0
  309. package/tests/fixtures/corpus/oss-repos/express/index.js +11 -0
  310. package/tests/fixtures/corpus/oss-repos/express/lib/application.js +631 -0
  311. package/tests/fixtures/corpus/oss-repos/express/lib/express.js +81 -0
  312. package/tests/fixtures/corpus/oss-repos/express/lib/request.js +514 -0
  313. package/tests/fixtures/corpus/oss-repos/express/lib/response.js +1053 -0
  314. package/tests/fixtures/corpus/oss-repos/express/lib/utils.js +271 -0
  315. package/tests/fixtures/corpus/oss-repos/express/lib/view.js +205 -0
  316. package/tests/fixtures/corpus/oss-repos/express/package.json +99 -0
  317. package/tests/fixtures/corpus/oss-repos/express/test/Route.js +274 -0
  318. package/tests/fixtures/corpus/oss-repos/express/test/Router.js +636 -0
  319. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/auth.js +117 -0
  320. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/content-negotiation.js +49 -0
  321. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/cookie-sessions.js +38 -0
  322. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/cookies.js +71 -0
  323. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/downloads.js +47 -0
  324. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/ejs.js +17 -0
  325. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/error-pages.js +99 -0
  326. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/error.js +29 -0
  327. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/hello-world.js +21 -0
  328. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/markdown.js +21 -0
  329. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/multi-router.js +44 -0
  330. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/mvc.js +132 -0
  331. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/params.js +44 -0
  332. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/resource.js +68 -0
  333. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/route-map.js +45 -0
  334. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/route-separation.js +97 -0
  335. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/vhost.js +46 -0
  336. package/tests/fixtures/corpus/oss-repos/express/test/acceptance/web-service.js +105 -0
  337. package/tests/fixtures/corpus/oss-repos/express/test/app.all.js +38 -0
  338. package/tests/fixtures/corpus/oss-repos/express/test/app.engine.js +83 -0
  339. package/tests/fixtures/corpus/oss-repos/express/test/app.head.js +66 -0
  340. package/tests/fixtures/corpus/oss-repos/express/test/app.js +120 -0
  341. package/tests/fixtures/corpus/oss-repos/express/test/app.listen.js +55 -0
  342. package/tests/fixtures/corpus/oss-repos/express/test/app.locals.js +26 -0
  343. package/tests/fixtures/corpus/oss-repos/express/test/app.options.js +116 -0
  344. package/tests/fixtures/corpus/oss-repos/express/test/app.param.js +323 -0
  345. package/tests/fixtures/corpus/oss-repos/express/test/app.render.js +374 -0
  346. package/tests/fixtures/corpus/oss-repos/express/test/app.request.js +143 -0
  347. package/tests/fixtures/corpus/oss-repos/express/test/app.response.js +143 -0
  348. package/tests/fixtures/corpus/oss-repos/express/test/app.route.js +197 -0
  349. package/tests/fixtures/corpus/oss-repos/express/test/app.router.js +1217 -0
  350. package/tests/fixtures/corpus/oss-repos/express/test/app.routes.error.js +62 -0
  351. package/tests/fixtures/corpus/oss-repos/express/test/app.use.js +542 -0
  352. package/tests/fixtures/corpus/oss-repos/express/test/config.js +207 -0
  353. package/tests/fixtures/corpus/oss-repos/express/test/exports.js +82 -0
  354. package/tests/fixtures/corpus/oss-repos/express/test/express.json.js +755 -0
  355. package/tests/fixtures/corpus/oss-repos/express/test/express.raw.js +513 -0
  356. package/tests/fixtures/corpus/oss-repos/express/test/express.static.js +815 -0
  357. package/tests/fixtures/corpus/oss-repos/express/test/express.text.js +566 -0
  358. package/tests/fixtures/corpus/oss-repos/express/test/express.urlencoded.js +828 -0
  359. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/% of dogs.txt +1 -0
  360. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/.name +1 -0
  361. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/blog/index.html +1 -0
  362. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/blog/post/index.tmpl +1 -0
  363. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/broken.send +0 -0
  364. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/default_layout/name.tmpl +1 -0
  365. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/default_layout/user.tmpl +1 -0
  366. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/email.tmpl +1 -0
  367. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/empty.txt +0 -0
  368. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/local_layout/user.tmpl +1 -0
  369. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/name.tmpl +1 -0
  370. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/name.txt +1 -0
  371. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/nums.txt +1 -0
  372. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/pets/names.txt +1 -0
  373. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/snow /342/230/203/.gitkeep +0 -0
  374. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/todo.html +1 -0
  375. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/todo.txt +1 -0
  376. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/user.html +1 -0
  377. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/user.tmpl +1 -0
  378. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/users/index.html +1 -0
  379. package/tests/fixtures/corpus/oss-repos/express/test/fixtures/users/tobi.txt +1 -0
  380. package/tests/fixtures/corpus/oss-repos/express/test/middleware.basic.js +42 -0
  381. package/tests/fixtures/corpus/oss-repos/express/test/regression.js +20 -0
  382. package/tests/fixtures/corpus/oss-repos/express/test/req.accepts.js +125 -0
  383. package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsCharsets.js +50 -0
  384. package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsEncodings.js +39 -0
  385. package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsLanguages.js +57 -0
  386. package/tests/fixtures/corpus/oss-repos/express/test/req.baseUrl.js +88 -0
  387. package/tests/fixtures/corpus/oss-repos/express/test/req.fresh.js +70 -0
  388. package/tests/fixtures/corpus/oss-repos/express/test/req.get.js +60 -0
  389. package/tests/fixtures/corpus/oss-repos/express/test/req.host.js +156 -0
  390. package/tests/fixtures/corpus/oss-repos/express/test/req.hostname.js +188 -0
  391. package/tests/fixtures/corpus/oss-repos/express/test/req.ip.js +113 -0
  392. package/tests/fixtures/corpus/oss-repos/express/test/req.ips.js +71 -0
  393. package/tests/fixtures/corpus/oss-repos/express/test/req.is.js +169 -0
  394. package/tests/fixtures/corpus/oss-repos/express/test/req.path.js +20 -0
  395. package/tests/fixtures/corpus/oss-repos/express/test/req.protocol.js +113 -0
  396. package/tests/fixtures/corpus/oss-repos/express/test/req.query.js +106 -0
  397. package/tests/fixtures/corpus/oss-repos/express/test/req.range.js +104 -0
  398. package/tests/fixtures/corpus/oss-repos/express/test/req.route.js +28 -0
  399. package/tests/fixtures/corpus/oss-repos/express/test/req.secure.js +101 -0
  400. package/tests/fixtures/corpus/oss-repos/express/test/req.signedCookies.js +37 -0
  401. package/tests/fixtures/corpus/oss-repos/express/test/req.stale.js +50 -0
  402. package/tests/fixtures/corpus/oss-repos/express/test/req.subdomains.js +173 -0
  403. package/tests/fixtures/corpus/oss-repos/express/test/req.xhr.js +42 -0
  404. package/tests/fixtures/corpus/oss-repos/express/test/res.append.js +116 -0
  405. package/tests/fixtures/corpus/oss-repos/express/test/res.attachment.js +79 -0
  406. package/tests/fixtures/corpus/oss-repos/express/test/res.clearCookie.js +62 -0
  407. package/tests/fixtures/corpus/oss-repos/express/test/res.cookie.js +295 -0
  408. package/tests/fixtures/corpus/oss-repos/express/test/res.download.js +487 -0
  409. package/tests/fixtures/corpus/oss-repos/express/test/res.format.js +248 -0
  410. package/tests/fixtures/corpus/oss-repos/express/test/res.get.js +21 -0
  411. package/tests/fixtures/corpus/oss-repos/express/test/res.json.js +186 -0
  412. package/tests/fixtures/corpus/oss-repos/express/test/res.jsonp.js +344 -0
  413. package/tests/fixtures/corpus/oss-repos/express/test/res.links.js +65 -0
  414. package/tests/fixtures/corpus/oss-repos/express/test/res.locals.js +40 -0
  415. package/tests/fixtures/corpus/oss-repos/express/test/res.location.js +316 -0
  416. package/tests/fixtures/corpus/oss-repos/express/test/res.redirect.js +214 -0
  417. package/tests/fixtures/corpus/oss-repos/express/test/res.render.js +367 -0
  418. package/tests/fixtures/corpus/oss-repos/express/test/res.send.js +569 -0
  419. package/tests/fixtures/corpus/oss-repos/express/test/res.sendFile.js +913 -0
  420. package/tests/fixtures/corpus/oss-repos/express/test/res.sendStatus.js +44 -0
  421. package/tests/fixtures/corpus/oss-repos/express/test/res.set.js +124 -0
  422. package/tests/fixtures/corpus/oss-repos/express/test/res.status.js +206 -0
  423. package/tests/fixtures/corpus/oss-repos/express/test/res.type.js +46 -0
  424. package/tests/fixtures/corpus/oss-repos/express/test/res.vary.js +90 -0
  425. package/tests/fixtures/corpus/oss-repos/express/test/support/env.js +3 -0
  426. package/tests/fixtures/corpus/oss-repos/express/test/support/tmpl.js +36 -0
  427. package/tests/fixtures/corpus/oss-repos/express/test/support/utils.js +86 -0
  428. package/tests/fixtures/corpus/oss-repos/express/test/utils.js +83 -0
  429. package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/Dockerfile +11 -0
  430. package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/devcontainer.json +21 -0
  431. package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/docker-compose.yml +18 -0
  432. package/tests/fixtures/corpus/oss-repos/hono/.eslintignore +1 -0
  433. package/tests/fixtures/corpus/oss-repos/hono/.eslintrc.cjs +9 -0
  434. package/tests/fixtures/corpus/oss-repos/hono/.gitpod.yml +9 -0
  435. package/tests/fixtures/corpus/oss-repos/hono/.prettierrc +9 -0
  436. package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/jsx-runtime-default.ts +15 -0
  437. package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/jsx-runtime-dom.ts +15 -0
  438. package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/setup-vitest.ts +47 -0
  439. package/tests/fixtures/corpus/oss-repos/hono/LICENSE +21 -0
  440. package/tests/fixtures/corpus/oss-repos/hono/README.md +91 -0
  441. package/tests/fixtures/corpus/oss-repos/hono/build.ts +80 -0
  442. package/tests/fixtures/corpus/oss-repos/hono/bun.lockb +0 -0
  443. package/tests/fixtures/corpus/oss-repos/hono/bunfig.toml +7 -0
  444. package/tests/fixtures/corpus/oss-repos/hono/codecov.yml +13 -0
  445. package/tests/fixtures/corpus/oss-repos/hono/docs/CODE_OF_CONDUCT.md +128 -0
  446. package/tests/fixtures/corpus/oss-repos/hono/docs/CONTRIBUTING.md +62 -0
  447. package/tests/fixtures/corpus/oss-repos/hono/docs/MIGRATION.md +295 -0
  448. package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-logo.png +0 -0
  449. package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-logo.pxm +0 -0
  450. package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-logo.svg +6 -0
  451. package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-title.png +0 -0
  452. package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-title.pxm +0 -0
  453. package/tests/fixtures/corpus/oss-repos/hono/jsr.json +119 -0
  454. package/tests/fixtures/corpus/oss-repos/hono/package.cjs.json +3 -0
  455. package/tests/fixtures/corpus/oss-repos/hono/package.json +650 -0
  456. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +492 -0
  457. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/index.ts +13 -0
  458. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/types.ts +144 -0
  459. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/conninfo.ts +28 -0
  460. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/index.ts +9 -0
  461. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/serve-static.ts +35 -0
  462. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/server.ts +30 -0
  463. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/ssg.ts +27 -0
  464. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/websocket.ts +110 -0
  465. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +120 -0
  466. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/index.ts +7 -0
  467. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/conninfo.ts +7 -0
  468. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/index.ts +8 -0
  469. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static-module.ts +12 -0
  470. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +39 -0
  471. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/utils.ts +50 -0
  472. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/websocket.ts +50 -0
  473. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/conninfo.ts +17 -0
  474. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/deno.d.ts +28 -0
  475. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/index.ts +9 -0
  476. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/serve-static.ts +40 -0
  477. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/ssg.ts +27 -0
  478. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/websocket.ts +51 -0
  479. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/conninfo.ts +15 -0
  480. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/handler.ts +189 -0
  481. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/index.ts +14 -0
  482. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/handler.ts +10 -0
  483. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/index.ts +6 -0
  484. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/mod.ts +1 -0
  485. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/handler.ts +34 -0
  486. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/index.ts +5 -0
  487. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/types.ts +14 -0
  488. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/conninfo.ts +8 -0
  489. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/handler.ts +9 -0
  490. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/index.ts +7 -0
  491. package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +214 -0
  492. package/tests/fixtures/corpus/oss-repos/hono/src/client/index.ts +14 -0
  493. package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +180 -0
  494. package/tests/fixtures/corpus/oss-repos/hono/src/client/utils.ts +54 -0
  495. package/tests/fixtures/corpus/oss-repos/hono/src/compose.ts +94 -0
  496. package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +914 -0
  497. package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +81 -0
  498. package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/index.ts +6 -0
  499. package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +85 -0
  500. package/tests/fixtures/corpus/oss-repos/hono/src/helper/conninfo/index.ts +6 -0
  501. package/tests/fixtures/corpus/oss-repos/hono/src/helper/conninfo/types.ts +45 -0
  502. package/tests/fixtures/corpus/oss-repos/hono/src/helper/cookie/index.ts +130 -0
  503. package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/common.ts +243 -0
  504. package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +220 -0
  505. package/tests/fixtures/corpus/oss-repos/hono/src/helper/dev/index.ts +79 -0
  506. package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +246 -0
  507. package/tests/fixtures/corpus/oss-repos/hono/src/helper/html/index.ts +56 -0
  508. package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/index.ts +13 -0
  509. package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/middleware.ts +79 -0
  510. package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +388 -0
  511. package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/utils.ts +71 -0
  512. package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/index.ts +9 -0
  513. package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/sse.ts +89 -0
  514. package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/stream.ts +36 -0
  515. package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/text.ts +15 -0
  516. package/tests/fixtures/corpus/oss-repos/hono/src/helper/testing/index.ts +26 -0
  517. package/tests/fixtures/corpus/oss-repos/hono/src/helper/websocket/index.ts +57 -0
  518. package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +523 -0
  519. package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +34 -0
  520. package/tests/fixtures/corpus/oss-repos/hono/src/http-exception.ts +78 -0
  521. package/tests/fixtures/corpus/oss-repos/hono/src/index.ts +51 -0
  522. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/base.ts +419 -0
  523. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/children.ts +20 -0
  524. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/components.ts +195 -0
  525. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/constants.ts +5 -0
  526. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/context.ts +50 -0
  527. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/client.ts +89 -0
  528. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/components.ts +39 -0
  529. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/context.ts +52 -0
  530. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +246 -0
  531. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/hooks/index.ts +91 -0
  532. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/index.ts +159 -0
  533. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +398 -0
  534. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/jsx-dev-runtime.ts +22 -0
  535. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/jsx-runtime.ts +7 -0
  536. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +772 -0
  537. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/server.ts +70 -0
  538. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/utils.ts +7 -0
  539. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +426 -0
  540. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/index.ts +114 -0
  541. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/common.ts +11 -0
  542. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +196 -0
  543. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-elements.ts +924 -0
  544. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/jsx-dev-runtime.ts +26 -0
  545. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/jsx-runtime.ts +18 -0
  546. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/streaming.ts +184 -0
  547. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/types.ts +41 -0
  548. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +36 -0
  549. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/basic-auth/index.ts +128 -0
  550. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/bearer-auth/index.ts +159 -0
  551. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/body-limit/index.ts +115 -0
  552. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/cache/index.ts +127 -0
  553. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/combine/index.ts +153 -0
  554. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/compress/index.ts +79 -0
  555. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/context-storage/index.ts +55 -0
  556. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/cors/index.ts +141 -0
  557. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/csrf/index.ts +90 -0
  558. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/etag/index.ts +88 -0
  559. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/ip-restriction/index.ts +178 -0
  560. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +158 -0
  561. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jwt/index.ts +8 -0
  562. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jwt/jwt.ts +159 -0
  563. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/logger/index.ts +93 -0
  564. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/method-override/index.ts +146 -0
  565. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/powered-by/index.ts +13 -0
  566. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/pretty-json/index.ts +50 -0
  567. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/request-id/index.ts +8 -0
  568. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/request-id/request-id.ts +59 -0
  569. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/index.ts +8 -0
  570. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/permissions-policy.ts +86 -0
  571. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/secure-headers.ts +319 -0
  572. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +140 -0
  573. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timeout/index.ts +58 -0
  574. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timing/index.ts +7 -0
  575. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timing/timing.ts +225 -0
  576. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/trailing-slash/index.ts +71 -0
  577. package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +24 -0
  578. package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +20 -0
  579. package/tests/fixtures/corpus/oss-repos/hono/src/request.ts +403 -0
  580. package/tests/fixtures/corpus/oss-repos/hono/src/router/linear-router/index.ts +6 -0
  581. package/tests/fixtures/corpus/oss-repos/hono/src/router/linear-router/router.ts +132 -0
  582. package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/index.ts +6 -0
  583. package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +54 -0
  584. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/index.ts +6 -0
  585. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +159 -0
  586. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +274 -0
  587. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/trie.ts +74 -0
  588. package/tests/fixtures/corpus/oss-repos/hono/src/router/smart-router/index.ts +6 -0
  589. package/tests/fixtures/corpus/oss-repos/hono/src/router/smart-router/router.ts +69 -0
  590. package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/index.ts +6 -0
  591. package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +205 -0
  592. package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/router.ts +28 -0
  593. package/tests/fixtures/corpus/oss-repos/hono/src/router.ts +103 -0
  594. package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +2009 -0
  595. package/tests/fixtures/corpus/oss-repos/hono/src/utils/basic-auth.ts +26 -0
  596. package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +225 -0
  597. package/tests/fixtures/corpus/oss-repos/hono/src/utils/buffer.ts +65 -0
  598. package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +26 -0
  599. package/tests/fixtures/corpus/oss-repos/hono/src/utils/concurrent.ts +55 -0
  600. package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +230 -0
  601. package/tests/fixtures/corpus/oss-repos/hono/src/utils/crypto.ts +65 -0
  602. package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +34 -0
  603. package/tests/fixtures/corpus/oss-repos/hono/src/utils/filepath.ts +56 -0
  604. package/tests/fixtures/corpus/oss-repos/hono/src/utils/handler.ts +15 -0
  605. package/tests/fixtures/corpus/oss-repos/hono/src/utils/html.ts +182 -0
  606. package/tests/fixtures/corpus/oss-repos/hono/src/utils/http-status.ts +69 -0
  607. package/tests/fixtures/corpus/oss-repos/hono/src/utils/ipaddr.ts +113 -0
  608. package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/index.ts +7 -0
  609. package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jwa.ts +23 -0
  610. package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jws.ts +226 -0
  611. package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jwt.ts +114 -0
  612. package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/types.ts +83 -0
  613. package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/utf8.ts +7 -0
  614. package/tests/fixtures/corpus/oss-repos/hono/src/utils/mime.ts +142 -0
  615. package/tests/fixtures/corpus/oss-repos/hono/src/utils/stream.ts +96 -0
  616. package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +105 -0
  617. package/tests/fixtures/corpus/oss-repos/hono/src/utils/url.ts +310 -0
  618. package/tests/fixtures/corpus/oss-repos/hono/src/validator/index.ts +7 -0
  619. package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +151 -0
  620. package/tests/fixtures/corpus/oss-repos/hono/tsconfig.build.json +23 -0
  621. package/tests/fixtures/corpus/oss-repos/hono/tsconfig.json +28 -0
  622. package/tests/fixtures/corpus/oss-repos/hono/vitest.config.ts +34 -0
  623. package/tests/fixtures/corpus/oss-repos/hono/yarn.lock +6232 -0
  624. package/tests/fixtures/documentation/api-reference.md +412 -0
  625. package/tests/fixtures/documentation/architecture.md +214 -0
  626. package/tests/fixtures/documentation/deployment-guide.md +420 -0
  627. package/tests/fixtures/github-readmes/express.md +133 -0
  628. package/tests/fixtures/github-readmes/nextjs.md +106 -0
  629. package/tests/fixtures/github-readmes/react.md +74 -0
  630. package/tests/fixtures/github-readmes/typescript.md +93 -0
  631. package/tests/fixtures/github-readmes/vite.md +79 -0
  632. package/tests/fixtures/queries/core.json +125 -0
  633. package/tests/fixtures/queries/extended.json +427 -0
  634. package/tests/fixtures/queries/generated/.gitkeep +0 -0
  635. package/tests/fixtures/test-server.ts +267 -0
  636. package/tests/helpers/performance-metrics.ts +387 -0
  637. package/tests/helpers/search-relevance.ts +381 -0
  638. package/tests/integration/cli-consistency.test.ts +299 -0
  639. package/tests/integration/cli.test.ts +69 -0
  640. package/tests/integration/e2e-workflow.test.ts +612 -0
  641. package/tests/integration/python-bridge.test.ts +183 -0
  642. package/tests/integration/search-quality.test.ts +718 -0
  643. package/tests/integration/stress.test.ts +326 -0
  644. package/tests/mcp/server.test.ts +15 -0
  645. package/tests/scripts/schemas/evaluation.json +44 -0
  646. package/tests/scripts/schemas/query-generation.json +21 -0
  647. package/tests/services/code-unit.service.test.ts +47 -0
  648. package/tests/services/search.progressive-context.test.ts +35 -0
  649. package/tsconfig.json +34 -0
  650. package/tsup.config.ts +15 -0
  651. package/turndown-plugin-gfm.d.ts +29 -0
  652. package/vitest.config.ts +79 -0
@@ -0,0 +1,3617 @@
1
+ // src/services/job.service.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { randomUUID } from "crypto";
5
+
6
+ // src/types/result.ts
7
+ function ok(data) {
8
+ return { success: true, data };
9
+ }
10
+ function err(error) {
11
+ return { success: false, error };
12
+ }
13
+
14
+ // src/services/job.service.ts
15
+ var JobService = class {
16
+ jobsDir;
17
+ constructor(dataDir) {
18
+ const baseDir = dataDir ?? path.join(
19
+ process.env["HOME"] ?? process.env["USERPROFILE"] ?? ".",
20
+ ".local/share/bluera-knowledge"
21
+ );
22
+ this.jobsDir = path.join(baseDir, "jobs");
23
+ if (!fs.existsSync(this.jobsDir)) {
24
+ fs.mkdirSync(this.jobsDir, { recursive: true });
25
+ }
26
+ }
27
+ /**
28
+ * Create a new job
29
+ */
30
+ createJob(params) {
31
+ const job = {
32
+ id: `job_${randomUUID().replace(/-/g, "").substring(0, 12)}`,
33
+ type: params.type,
34
+ status: "pending",
35
+ progress: 0,
36
+ message: params.message ?? `${params.type} job created`,
37
+ details: params.details,
38
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
39
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
40
+ };
41
+ this.writeJob(job);
42
+ return job;
43
+ }
44
+ /**
45
+ * Update an existing job
46
+ */
47
+ updateJob(jobId, updates) {
48
+ const job = this.getJob(jobId);
49
+ if (!job) {
50
+ throw new Error(`Job ${jobId} not found`);
51
+ }
52
+ if (updates.status !== void 0) {
53
+ job.status = updates.status;
54
+ }
55
+ if (updates.progress !== void 0) {
56
+ job.progress = updates.progress;
57
+ }
58
+ if (updates.message !== void 0) {
59
+ job.message = updates.message;
60
+ }
61
+ if (updates.details !== void 0) {
62
+ job.details = { ...job.details, ...updates.details };
63
+ }
64
+ job.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
65
+ this.writeJob(job);
66
+ }
67
+ /**
68
+ * Get a job by ID
69
+ */
70
+ getJob(jobId) {
71
+ const jobFile = path.join(this.jobsDir, `${jobId}.json`);
72
+ if (!fs.existsSync(jobFile)) {
73
+ return null;
74
+ }
75
+ try {
76
+ const content = fs.readFileSync(jobFile, "utf-8");
77
+ return JSON.parse(content);
78
+ } catch (error) {
79
+ console.error(`Error reading job ${jobId}:`, error);
80
+ return null;
81
+ }
82
+ }
83
+ /**
84
+ * List all jobs with optional status filter
85
+ */
86
+ listJobs(statusFilter) {
87
+ if (!fs.existsSync(this.jobsDir)) {
88
+ return [];
89
+ }
90
+ const files = fs.readdirSync(this.jobsDir);
91
+ const jobs = [];
92
+ for (const file of files) {
93
+ if (!file.endsWith(".json") || file.endsWith(".pid")) {
94
+ continue;
95
+ }
96
+ try {
97
+ const content = fs.readFileSync(path.join(this.jobsDir, file), "utf-8");
98
+ const job = JSON.parse(content);
99
+ if (statusFilter !== void 0) {
100
+ const filters = Array.isArray(statusFilter) ? statusFilter : [statusFilter];
101
+ if (filters.includes(job.status)) {
102
+ jobs.push(job);
103
+ }
104
+ } else {
105
+ jobs.push(job);
106
+ }
107
+ } catch (error) {
108
+ console.error(`Error reading job file ${file}:`, error);
109
+ }
110
+ }
111
+ jobs.sort(
112
+ (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
113
+ );
114
+ return jobs;
115
+ }
116
+ /**
117
+ * List active jobs (pending or running)
118
+ */
119
+ listActiveJobs() {
120
+ return this.listJobs(["pending", "running"]);
121
+ }
122
+ /**
123
+ * Cancel a job
124
+ */
125
+ cancelJob(jobId) {
126
+ const job = this.getJob(jobId);
127
+ if (!job) {
128
+ return err(new Error(`Job ${jobId} not found`));
129
+ }
130
+ if (job.status === "completed" || job.status === "failed") {
131
+ return err(new Error(`Cannot cancel ${job.status} job`));
132
+ }
133
+ if (job.status === "cancelled") {
134
+ return ok(void 0);
135
+ }
136
+ this.updateJob(jobId, {
137
+ status: "cancelled",
138
+ message: "Job cancelled by user",
139
+ details: { cancelledAt: (/* @__PURE__ */ new Date()).toISOString() }
140
+ });
141
+ const pidFile = path.join(this.jobsDir, `${jobId}.pid`);
142
+ if (fs.existsSync(pidFile)) {
143
+ try {
144
+ const pid = parseInt(fs.readFileSync(pidFile, "utf-8"), 10);
145
+ process.kill(pid, "SIGTERM");
146
+ } catch {
147
+ }
148
+ try {
149
+ fs.unlinkSync(pidFile);
150
+ } catch {
151
+ }
152
+ }
153
+ return ok(void 0);
154
+ }
155
+ /**
156
+ * Clean up old completed/failed/cancelled jobs
157
+ */
158
+ cleanupOldJobs(olderThanHours = 24) {
159
+ const jobs = this.listJobs();
160
+ const cutoffTime = Date.now() - olderThanHours * 60 * 60 * 1e3;
161
+ let cleaned = 0;
162
+ for (const job of jobs) {
163
+ if ((job.status === "completed" || job.status === "failed" || job.status === "cancelled") && new Date(job.updatedAt).getTime() < cutoffTime) {
164
+ const jobFile = path.join(this.jobsDir, `${job.id}.json`);
165
+ try {
166
+ fs.unlinkSync(jobFile);
167
+ cleaned++;
168
+ } catch (error) {
169
+ console.error(`Error deleting job file ${job.id}:`, error);
170
+ }
171
+ }
172
+ }
173
+ return cleaned;
174
+ }
175
+ /**
176
+ * Delete a specific job
177
+ */
178
+ deleteJob(jobId) {
179
+ const jobFile = path.join(this.jobsDir, `${jobId}.json`);
180
+ if (!fs.existsSync(jobFile)) {
181
+ return false;
182
+ }
183
+ try {
184
+ fs.unlinkSync(jobFile);
185
+ return true;
186
+ } catch (error) {
187
+ console.error(`Error deleting job ${jobId}:`, error);
188
+ return false;
189
+ }
190
+ }
191
+ /**
192
+ * Write job to file
193
+ */
194
+ writeJob(job) {
195
+ const jobFile = path.join(this.jobsDir, `${job.id}.json`);
196
+ fs.writeFileSync(jobFile, JSON.stringify(job, null, 2), "utf-8");
197
+ }
198
+ };
199
+
200
+ // src/services/config.service.ts
201
+ import { readFile, writeFile, mkdir } from "fs/promises";
202
+ import { dirname as dirname2, resolve } from "path";
203
+ import { homedir } from "os";
204
+
205
+ // src/types/config.ts
206
+ var DEFAULT_CONFIG = {
207
+ version: 1,
208
+ dataDir: ".bluera/bluera-knowledge/data",
209
+ embedding: {
210
+ model: "Xenova/all-MiniLM-L6-v2",
211
+ batchSize: 32,
212
+ dimensions: 384
213
+ },
214
+ indexing: {
215
+ concurrency: 4,
216
+ chunkSize: 1e3,
217
+ chunkOverlap: 150,
218
+ ignorePatterns: ["node_modules/**", ".git/**", "*.min.js", "*.map"]
219
+ },
220
+ search: {
221
+ defaultMode: "hybrid",
222
+ defaultLimit: 10,
223
+ minScore: 0.5,
224
+ rrf: {
225
+ k: 40,
226
+ vectorWeight: 0.7,
227
+ ftsWeight: 0.3
228
+ }
229
+ },
230
+ crawl: {
231
+ userAgent: "BlueraKnowledge/1.0",
232
+ timeout: 3e4,
233
+ maxConcurrency: 3
234
+ },
235
+ server: {
236
+ port: 3847,
237
+ host: "127.0.0.1"
238
+ }
239
+ };
240
+
241
+ // src/services/project-root.service.ts
242
+ import { existsSync, statSync, realpathSync } from "fs";
243
+ import { dirname, join, normalize, sep } from "path";
244
+ var ProjectRootService = class {
245
+ /**
246
+ * Resolve project root directory using hierarchical detection.
247
+ */
248
+ static resolve(options) {
249
+ if (options?.projectRoot !== void 0 && options.projectRoot !== "") {
250
+ return this.normalize(options.projectRoot);
251
+ }
252
+ const projectRootEnv = process.env["PROJECT_ROOT"];
253
+ if (projectRootEnv !== void 0 && projectRootEnv !== "") {
254
+ return this.normalize(projectRootEnv);
255
+ }
256
+ const pwdEnv = process.env["PWD"];
257
+ if (pwdEnv !== void 0 && pwdEnv !== "") {
258
+ return this.normalize(pwdEnv);
259
+ }
260
+ const gitRoot = this.findGitRoot(process.cwd());
261
+ if (gitRoot !== null) {
262
+ return gitRoot;
263
+ }
264
+ return process.cwd();
265
+ }
266
+ /**
267
+ * Find git repository root by walking up the directory tree looking for .git
268
+ */
269
+ static findGitRoot(startPath) {
270
+ let currentPath = normalize(startPath);
271
+ const root = normalize(sep);
272
+ while (currentPath !== root) {
273
+ const gitPath = join(currentPath, ".git");
274
+ if (existsSync(gitPath)) {
275
+ try {
276
+ const stats = statSync(gitPath);
277
+ if (stats.isDirectory() || stats.isFile()) {
278
+ return currentPath;
279
+ }
280
+ } catch {
281
+ }
282
+ }
283
+ const parentPath = dirname(currentPath);
284
+ if (parentPath === currentPath) {
285
+ break;
286
+ }
287
+ currentPath = parentPath;
288
+ }
289
+ return null;
290
+ }
291
+ /**
292
+ * Normalize path by resolving symlinks and normalizing separators
293
+ */
294
+ static normalize(path3) {
295
+ try {
296
+ const realPath = realpathSync(path3);
297
+ return normalize(realPath);
298
+ } catch {
299
+ return normalize(path3);
300
+ }
301
+ }
302
+ /**
303
+ * Validate that a path exists and is a directory
304
+ */
305
+ static validate(path3) {
306
+ try {
307
+ const stats = statSync(path3);
308
+ return stats.isDirectory();
309
+ } catch {
310
+ return false;
311
+ }
312
+ }
313
+ };
314
+
315
+ // src/services/config.service.ts
316
+ var ConfigService = class {
317
+ configPath;
318
+ dataDir;
319
+ config = null;
320
+ constructor(configPath = `${homedir()}/.bluera/bluera-knowledge/config.json`, dataDir, projectRoot) {
321
+ this.configPath = configPath;
322
+ if (dataDir !== void 0 && dataDir !== "") {
323
+ this.dataDir = dataDir;
324
+ } else {
325
+ const root = projectRoot ?? ProjectRootService.resolve();
326
+ this.dataDir = this.expandPath(DEFAULT_CONFIG.dataDir, root);
327
+ }
328
+ }
329
+ async load() {
330
+ if (this.config !== null) {
331
+ return this.config;
332
+ }
333
+ try {
334
+ const content = await readFile(this.configPath, "utf-8");
335
+ this.config = { ...DEFAULT_CONFIG, ...JSON.parse(content) };
336
+ } catch {
337
+ this.config = { ...DEFAULT_CONFIG };
338
+ }
339
+ return this.config;
340
+ }
341
+ async save(config) {
342
+ await mkdir(dirname2(this.configPath), { recursive: true });
343
+ await writeFile(this.configPath, JSON.stringify(config, null, 2));
344
+ this.config = config;
345
+ }
346
+ resolveDataDir() {
347
+ return this.dataDir;
348
+ }
349
+ expandPath(path3, baseDir) {
350
+ if (path3.startsWith("~")) {
351
+ return path3.replace("~", homedir());
352
+ }
353
+ if (!path3.startsWith("/")) {
354
+ return resolve(baseDir, path3);
355
+ }
356
+ return path3;
357
+ }
358
+ };
359
+
360
+ // src/services/store.service.ts
361
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir3, stat } from "fs/promises";
362
+ import { join as join2, resolve as resolve2 } from "path";
363
+ import { randomUUID as randomUUID2 } from "crypto";
364
+
365
+ // src/types/brands.ts
366
+ var ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
367
+ function isStoreId(value) {
368
+ return value.length > 0 && ID_PATTERN.test(value);
369
+ }
370
+ function isDocumentId(value) {
371
+ return value.length > 0 && ID_PATTERN.test(value);
372
+ }
373
+ function createStoreId(value) {
374
+ if (!isStoreId(value)) {
375
+ throw new Error(`Invalid store ID: ${value}`);
376
+ }
377
+ return value;
378
+ }
379
+ function createDocumentId(value) {
380
+ if (!isDocumentId(value)) {
381
+ throw new Error(`Invalid document ID: ${value}`);
382
+ }
383
+ return value;
384
+ }
385
+
386
+ // src/plugin/git-clone.ts
387
+ import { spawn } from "child_process";
388
+ import { mkdir as mkdir2 } from "fs/promises";
389
+ async function cloneRepository(options) {
390
+ const { url, targetDir, branch, depth = 1 } = options;
391
+ await mkdir2(targetDir, { recursive: true });
392
+ const args = ["clone", "--depth", String(depth)];
393
+ if (branch !== void 0) {
394
+ args.push("--branch", branch);
395
+ }
396
+ args.push(url, targetDir);
397
+ return new Promise((resolve3) => {
398
+ const git = spawn("git", args, { stdio: ["ignore", "pipe", "pipe"] });
399
+ let stderr = "";
400
+ git.stderr.on("data", (data) => {
401
+ stderr += data.toString();
402
+ });
403
+ git.on("close", (code) => {
404
+ if (code === 0) {
405
+ resolve3(ok(targetDir));
406
+ } else {
407
+ resolve3(err(new Error(`Git clone failed: ${stderr}`)));
408
+ }
409
+ });
410
+ });
411
+ }
412
+ function extractRepoName(url) {
413
+ const match = /\/([^/]+?)(\.git)?$/.exec(url);
414
+ const name = match?.[1];
415
+ if (name === void 0) {
416
+ return "repository";
417
+ }
418
+ return name;
419
+ }
420
+
421
+ // src/services/store.service.ts
422
+ var StoreService = class {
423
+ dataDir;
424
+ registry = { stores: [] };
425
+ constructor(dataDir) {
426
+ this.dataDir = dataDir;
427
+ }
428
+ async initialize() {
429
+ await mkdir3(this.dataDir, { recursive: true });
430
+ await this.loadRegistry();
431
+ }
432
+ async create(input) {
433
+ const existing = await this.getByName(input.name);
434
+ if (existing !== void 0) {
435
+ return err(new Error(`Store with name "${input.name}" already exists`));
436
+ }
437
+ const id = createStoreId(randomUUID2());
438
+ const now = /* @__PURE__ */ new Date();
439
+ let store;
440
+ switch (input.type) {
441
+ case "file": {
442
+ if (input.path === void 0) {
443
+ return err(new Error("Path is required for file stores"));
444
+ }
445
+ const normalizedPath = resolve2(input.path);
446
+ try {
447
+ const stats = await stat(normalizedPath);
448
+ if (!stats.isDirectory()) {
449
+ return err(new Error(`Path is not a directory: ${normalizedPath}`));
450
+ }
451
+ } catch {
452
+ return err(new Error(`Directory does not exist: ${normalizedPath}`));
453
+ }
454
+ store = {
455
+ type: "file",
456
+ id,
457
+ name: input.name,
458
+ path: normalizedPath,
459
+ description: input.description,
460
+ tags: input.tags,
461
+ status: "ready",
462
+ createdAt: now,
463
+ updatedAt: now
464
+ };
465
+ break;
466
+ }
467
+ case "repo": {
468
+ let repoPath = input.path;
469
+ if (input.url !== void 0) {
470
+ const cloneDir = join2(this.dataDir, "repos", id);
471
+ const result = await cloneRepository({
472
+ url: input.url,
473
+ targetDir: cloneDir,
474
+ ...input.branch !== void 0 ? { branch: input.branch } : {},
475
+ depth: input.depth ?? 1
476
+ });
477
+ if (!result.success) {
478
+ return err(result.error);
479
+ }
480
+ repoPath = result.data;
481
+ }
482
+ if (repoPath === void 0) {
483
+ return err(new Error("Path or URL required for repo stores"));
484
+ }
485
+ const normalizedRepoPath = resolve2(repoPath);
486
+ store = {
487
+ type: "repo",
488
+ id,
489
+ name: input.name,
490
+ path: normalizedRepoPath,
491
+ url: input.url,
492
+ branch: input.branch,
493
+ description: input.description,
494
+ tags: input.tags,
495
+ status: "ready",
496
+ createdAt: now,
497
+ updatedAt: now
498
+ };
499
+ break;
500
+ }
501
+ case "web":
502
+ if (input.url === void 0) {
503
+ return err(new Error("URL is required for web stores"));
504
+ }
505
+ store = {
506
+ type: "web",
507
+ id,
508
+ name: input.name,
509
+ url: input.url,
510
+ depth: input.depth ?? 1,
511
+ description: input.description,
512
+ tags: input.tags,
513
+ status: "ready",
514
+ createdAt: now,
515
+ updatedAt: now
516
+ };
517
+ break;
518
+ }
519
+ this.registry.stores.push(store);
520
+ await this.saveRegistry();
521
+ return ok(store);
522
+ }
523
+ async list(type) {
524
+ if (type !== void 0) {
525
+ return Promise.resolve(this.registry.stores.filter((s) => s.type === type));
526
+ }
527
+ return Promise.resolve([...this.registry.stores]);
528
+ }
529
+ async get(id) {
530
+ return Promise.resolve(this.registry.stores.find((s) => s.id === id));
531
+ }
532
+ async getByName(name) {
533
+ return Promise.resolve(this.registry.stores.find((s) => s.name === name));
534
+ }
535
+ async getByIdOrName(idOrName) {
536
+ return Promise.resolve(this.registry.stores.find((s) => s.id === idOrName || s.name === idOrName));
537
+ }
538
+ async update(id, updates) {
539
+ const index = this.registry.stores.findIndex((s) => s.id === id);
540
+ if (index === -1) {
541
+ return err(new Error(`Store not found: ${id}`));
542
+ }
543
+ const store = this.registry.stores[index];
544
+ if (store === void 0) {
545
+ return err(new Error(`Store not found: ${id}`));
546
+ }
547
+ const updated = {
548
+ ...store,
549
+ ...updates,
550
+ updatedAt: /* @__PURE__ */ new Date()
551
+ };
552
+ this.registry.stores[index] = updated;
553
+ await this.saveRegistry();
554
+ return ok(updated);
555
+ }
556
+ async delete(id) {
557
+ const index = this.registry.stores.findIndex((s) => s.id === id);
558
+ if (index === -1) {
559
+ return err(new Error(`Store not found: ${id}`));
560
+ }
561
+ this.registry.stores.splice(index, 1);
562
+ await this.saveRegistry();
563
+ return ok(void 0);
564
+ }
565
+ async loadRegistry() {
566
+ const registryPath = join2(this.dataDir, "stores.json");
567
+ try {
568
+ const content = await readFile2(registryPath, "utf-8");
569
+ const data = JSON.parse(content);
570
+ this.registry = {
571
+ stores: data.stores.map((s) => ({
572
+ ...s,
573
+ id: createStoreId(s.id),
574
+ createdAt: new Date(s.createdAt),
575
+ updatedAt: new Date(s.updatedAt)
576
+ }))
577
+ };
578
+ } catch {
579
+ this.registry = { stores: [] };
580
+ }
581
+ }
582
+ async saveRegistry() {
583
+ const registryPath = join2(this.dataDir, "stores.json");
584
+ await writeFile2(registryPath, JSON.stringify(this.registry, null, 2));
585
+ }
586
+ };
587
+
588
+ // src/services/code-unit.service.ts
589
+ var CodeUnitService = class {
590
+ extractCodeUnit(code, symbolName, language) {
591
+ const lines = code.split("\n");
592
+ let startLine = -1;
593
+ let type = "function";
594
+ for (let i = 0; i < lines.length; i++) {
595
+ const line = lines[i] ?? "";
596
+ if (line.includes(`function ${symbolName}`)) {
597
+ startLine = i + 1;
598
+ type = "function";
599
+ break;
600
+ }
601
+ if (line.includes(`class ${symbolName}`)) {
602
+ startLine = i + 1;
603
+ type = "class";
604
+ break;
605
+ }
606
+ if (line.match(new RegExp(`(?:const|let|var)\\s+${symbolName}\\s*=`))) {
607
+ startLine = i + 1;
608
+ type = "const";
609
+ break;
610
+ }
611
+ }
612
+ if (startLine === -1) return void 0;
613
+ let endLine = startLine;
614
+ let braceCount = 0;
615
+ let foundFirstBrace = false;
616
+ for (let i = startLine - 1; i < lines.length; i++) {
617
+ const line = lines[i] ?? "";
618
+ for (const char of line) {
619
+ if (char === "{") {
620
+ braceCount++;
621
+ foundFirstBrace = true;
622
+ }
623
+ if (char === "}") braceCount--;
624
+ }
625
+ if (foundFirstBrace && braceCount === 0) {
626
+ endLine = i + 1;
627
+ break;
628
+ }
629
+ }
630
+ const fullContent = lines.slice(startLine - 1, endLine).join("\n");
631
+ const firstLine = lines[startLine - 1] ?? "";
632
+ const signature = this.extractSignature(firstLine, symbolName, type);
633
+ return {
634
+ type,
635
+ name: symbolName,
636
+ signature,
637
+ fullContent,
638
+ startLine,
639
+ endLine,
640
+ language
641
+ };
642
+ }
643
+ extractSignature(line, name, type) {
644
+ const sig = line.replace(/^\s*export\s+/, "").replace(/^\s*async\s+/, "").trim();
645
+ if (type === "function") {
646
+ const match = sig.match(/function\s+(\w+\([^)]*\):\s*\w+)/);
647
+ if (match?.[1] !== void 0 && match[1].length > 0) return match[1];
648
+ }
649
+ if (type === "class") {
650
+ return `class ${name}`;
651
+ }
652
+ if (type === "const") {
653
+ const arrowMatch = sig.match(new RegExp(`((?:const|let|var)\\s+${name}\\s*=\\s*(?:async\\s+)?\\([^)]*\\)(?::\\s*[^=]+)?)`));
654
+ if (arrowMatch?.[1] != null && arrowMatch[1] !== "") return arrowMatch[1].trim();
655
+ return `const ${name}`;
656
+ }
657
+ return sig;
658
+ }
659
+ };
660
+
661
+ // src/services/search.service.ts
662
+ var INTENT_FILE_BOOSTS = {
663
+ "how-to": {
664
+ "documentation-primary": 1.3,
665
+ // Strong boost for docs
666
+ "documentation": 1.2,
667
+ "example": 1.5,
668
+ // Examples are ideal for "how to"
669
+ "source": 0.85,
670
+ // Moderate penalty - source might still have good content
671
+ "source-internal": 0.7,
672
+ // Stronger penalty - internal code less useful
673
+ "test": 0.8,
674
+ "config": 0.7,
675
+ "other": 0.9
676
+ },
677
+ "implementation": {
678
+ "documentation-primary": 0.95,
679
+ "documentation": 1,
680
+ "example": 1,
681
+ "source": 1.1,
682
+ // Slight boost for source code
683
+ "source-internal": 1.05,
684
+ // Internal code can be relevant
685
+ "test": 1,
686
+ "config": 0.95,
687
+ "other": 1
688
+ },
689
+ "conceptual": {
690
+ "documentation-primary": 1.1,
691
+ "documentation": 1.05,
692
+ "example": 1,
693
+ "source": 0.95,
694
+ "source-internal": 0.9,
695
+ "test": 0.9,
696
+ "config": 0.85,
697
+ "other": 0.95
698
+ },
699
+ "comparison": {
700
+ "documentation-primary": 1.15,
701
+ "documentation": 1.1,
702
+ "example": 1.05,
703
+ "source": 0.9,
704
+ "source-internal": 0.85,
705
+ "test": 0.9,
706
+ "config": 0.85,
707
+ "other": 0.95
708
+ },
709
+ "debugging": {
710
+ "documentation-primary": 1,
711
+ "documentation": 1,
712
+ "example": 1.05,
713
+ "source": 1,
714
+ // Source code helps with debugging
715
+ "source-internal": 0.95,
716
+ "test": 1.05,
717
+ // Tests can show expected behavior
718
+ "config": 0.9,
719
+ "other": 1
720
+ }
721
+ };
722
+ var FRAMEWORK_PATTERNS = [
723
+ { pattern: /\bexpress\b/i, terms: ["express", "expressjs", "express.js"] },
724
+ { pattern: /\bhono\b/i, terms: ["hono"] },
725
+ { pattern: /\bzod\b/i, terms: ["zod"] },
726
+ { pattern: /\breact\b/i, terms: ["react", "reactjs", "react.js"] },
727
+ { pattern: /\bvue\b/i, terms: ["vue", "vuejs", "vue.js", "vue3"] },
728
+ { pattern: /\bnode\b/i, terms: ["node", "nodejs", "node.js"] },
729
+ { pattern: /\btypescript\b/i, terms: ["typescript", "ts"] },
730
+ { pattern: /\bjwt\b/i, terms: ["jwt", "jsonwebtoken", "json-web-token"] }
731
+ ];
732
+ function classifyQueryIntent(query) {
733
+ const q = query.toLowerCase();
734
+ const howToPatterns = [
735
+ /how (do|can|should|would) (i|you|we)/i,
736
+ /how to\b/i,
737
+ /what('s| is) the (best |right |correct )?(way|approach) to/i,
738
+ /i (need|want|have) to/i,
739
+ /show me how/i,
740
+ /\bwhat's the syntax\b/i,
741
+ /\bhow do i (use|create|make|set up|configure|implement|add|get)\b/i,
742
+ /\bi'm (trying|building|creating|making)\b/i
743
+ ];
744
+ const implementationPatterns = [
745
+ /how (does|is) .* (implemented|work internally)/i,
746
+ /\binternal(ly)?\b/i,
747
+ /\bsource code\b/i,
748
+ /\bunder the hood\b/i,
749
+ /\bimplementation (of|details?)\b/i
750
+ ];
751
+ const comparisonPatterns = [
752
+ /\b(vs\.?|versus)\b/i,
753
+ /\bdifference(s)? between\b/i,
754
+ /\bcompare\b/i,
755
+ /\bshould (i|we) use .* or\b/i,
756
+ /\bwhat's the difference\b/i,
757
+ /\bwhich (one|is better)\b/i,
758
+ /\bwhen (should|to) use\b/i
759
+ ];
760
+ const debuggingPatterns = [
761
+ /\b(error|bug|issue|problem|crash|fail|broken|wrong)\b/i,
762
+ /\bdoesn't (work|compile|run)\b/i,
763
+ /\bisn't (working|updating|rendering)\b/i,
764
+ /\bwhy (is|does|doesn't|isn't)\b/i,
765
+ /\bwhat('s| is) (wrong|happening|going on)\b/i,
766
+ /\bwhat am i doing wrong\b/i,
767
+ /\bnot (working|updating|showing)\b/i,
768
+ /\bhow do i (fix|debug|solve|resolve)\b/i
769
+ ];
770
+ const conceptualPatterns = [
771
+ /\bwhat (is|are)\b/i,
772
+ /\bexplain\b/i,
773
+ /\bwhat does .* (mean|do)\b/i,
774
+ /\bhow does .* work\b/i,
775
+ /\bwhat('s| is) the (purpose|point|idea)\b/i
776
+ ];
777
+ if (implementationPatterns.some((p) => p.test(q))) {
778
+ return "implementation";
779
+ }
780
+ if (debuggingPatterns.some((p) => p.test(q))) {
781
+ return "debugging";
782
+ }
783
+ if (comparisonPatterns.some((p) => p.test(q))) {
784
+ return "comparison";
785
+ }
786
+ if (howToPatterns.some((p) => p.test(q))) {
787
+ return "how-to";
788
+ }
789
+ if (conceptualPatterns.some((p) => p.test(q))) {
790
+ return "conceptual";
791
+ }
792
+ return "how-to";
793
+ }
794
+ var SearchService = class {
795
+ lanceStore;
796
+ embeddingEngine;
797
+ rrfConfig;
798
+ codeUnitService;
799
+ codeGraphService;
800
+ graphCache;
801
+ constructor(lanceStore, embeddingEngine, rrfConfig = { k: 20, vectorWeight: 0.6, ftsWeight: 0.4 }, codeGraphService) {
802
+ this.lanceStore = lanceStore;
803
+ this.embeddingEngine = embeddingEngine;
804
+ this.rrfConfig = rrfConfig;
805
+ this.codeUnitService = new CodeUnitService();
806
+ this.codeGraphService = codeGraphService;
807
+ this.graphCache = /* @__PURE__ */ new Map();
808
+ }
809
+ /**
810
+ * Load code graph for a store, with caching.
811
+ * Returns null if no graph is available.
812
+ */
813
+ async loadGraphForStore(storeId) {
814
+ if (!this.codeGraphService) return null;
815
+ const cached = this.graphCache.get(storeId);
816
+ if (cached !== void 0) return cached;
817
+ const graph = await this.codeGraphService.loadGraph(storeId);
818
+ const result = graph ?? null;
819
+ this.graphCache.set(storeId, result);
820
+ return result;
821
+ }
822
+ async search(query) {
823
+ const startTime = Date.now();
824
+ const mode = query.mode ?? "hybrid";
825
+ const limit = query.limit ?? 10;
826
+ const stores = query.stores ?? [];
827
+ const detail = query.detail ?? "minimal";
828
+ let allResults = [];
829
+ const fetchLimit = limit * 3;
830
+ if (mode === "vector") {
831
+ allResults = await this.vectorSearch(query.query, stores, fetchLimit, query.threshold);
832
+ } else if (mode === "fts") {
833
+ allResults = await this.ftsSearch(query.query, stores, fetchLimit);
834
+ } else {
835
+ allResults = await this.hybridSearch(query.query, stores, fetchLimit, query.threshold);
836
+ }
837
+ const dedupedResults = this.deduplicateBySource(allResults, query.query);
838
+ const resultsToEnhance = dedupedResults.slice(0, limit);
839
+ const graphs = /* @__PURE__ */ new Map();
840
+ if (detail === "contextual" || detail === "full") {
841
+ const storeIds = new Set(resultsToEnhance.map((r) => r.metadata.storeId));
842
+ for (const storeId of storeIds) {
843
+ graphs.set(storeId, await this.loadGraphForStore(storeId));
844
+ }
845
+ }
846
+ const enhancedResults = resultsToEnhance.map((r) => {
847
+ const graph = graphs.get(r.metadata.storeId) ?? null;
848
+ return this.addProgressiveContext(r, query.query, detail, graph);
849
+ });
850
+ return {
851
+ query: query.query,
852
+ mode,
853
+ stores,
854
+ results: enhancedResults,
855
+ totalResults: enhancedResults.length,
856
+ timeMs: Date.now() - startTime
857
+ };
858
+ }
859
+ /**
860
+ * Deduplicate results by source file path.
861
+ * Keeps the best chunk for each unique source, considering both score and query relevance.
862
+ */
863
+ deduplicateBySource(results, query) {
864
+ const bySource = /* @__PURE__ */ new Map();
865
+ const queryTerms = query.toLowerCase().split(/\s+/).filter((t2) => t2.length > 2);
866
+ for (const result of results) {
867
+ const sourceKey = result.metadata.path ?? result.metadata.url ?? result.id;
868
+ const existing = bySource.get(sourceKey);
869
+ if (!existing) {
870
+ bySource.set(sourceKey, result);
871
+ } else {
872
+ const existingTermCount = this.countQueryTerms(existing.content, queryTerms);
873
+ const newTermCount = this.countQueryTerms(result.content, queryTerms);
874
+ if (newTermCount > existingTermCount || newTermCount === existingTermCount && result.score > existing.score) {
875
+ bySource.set(sourceKey, result);
876
+ }
877
+ }
878
+ }
879
+ return Array.from(bySource.values()).sort((a, b) => b.score - a.score);
880
+ }
881
+ /**
882
+ * Count how many query terms appear in the content.
883
+ */
884
+ countQueryTerms(content, queryTerms) {
885
+ const lowerContent = content.toLowerCase();
886
+ return queryTerms.filter((term) => lowerContent.includes(term)).length;
887
+ }
888
+ async vectorSearch(query, stores, limit, threshold) {
889
+ const queryVector = await this.embeddingEngine.embed(query);
890
+ const results = [];
891
+ for (const storeId of stores) {
892
+ const hits = await this.lanceStore.search(storeId, queryVector, limit, threshold);
893
+ results.push(...hits.map((r) => ({
894
+ id: r.id,
895
+ score: r.score,
896
+ content: r.content,
897
+ metadata: r.metadata
898
+ })));
899
+ }
900
+ return results.sort((a, b) => b.score - a.score).slice(0, limit);
901
+ }
902
+ async ftsSearch(query, stores, limit) {
903
+ const results = [];
904
+ for (const storeId of stores) {
905
+ const hits = await this.lanceStore.fullTextSearch(storeId, query, limit);
906
+ results.push(...hits.map((r) => ({
907
+ id: r.id,
908
+ score: r.score,
909
+ content: r.content,
910
+ metadata: r.metadata
911
+ })));
912
+ }
913
+ return results.sort((a, b) => b.score - a.score).slice(0, limit);
914
+ }
915
+ async hybridSearch(query, stores, limit, threshold) {
916
+ const intent = classifyQueryIntent(query);
917
+ const [vectorResults, ftsResults] = await Promise.all([
918
+ this.vectorSearch(query, stores, limit * 2, threshold),
919
+ this.ftsSearch(query, stores, limit * 2)
920
+ ]);
921
+ const vectorRanks = /* @__PURE__ */ new Map();
922
+ const ftsRanks = /* @__PURE__ */ new Map();
923
+ const allDocs = /* @__PURE__ */ new Map();
924
+ vectorResults.forEach((r, i) => {
925
+ vectorRanks.set(r.id, i + 1);
926
+ allDocs.set(r.id, r);
927
+ });
928
+ ftsResults.forEach((r, i) => {
929
+ ftsRanks.set(r.id, i + 1);
930
+ if (!allDocs.has(r.id)) {
931
+ allDocs.set(r.id, r);
932
+ }
933
+ });
934
+ const rrfScores = [];
935
+ const { k, vectorWeight, ftsWeight } = this.rrfConfig;
936
+ for (const [id, result] of allDocs) {
937
+ const vectorRank = vectorRanks.get(id) ?? Infinity;
938
+ const ftsRank = ftsRanks.get(id) ?? Infinity;
939
+ const vectorRRF = vectorRank !== Infinity ? vectorWeight / (k + vectorRank) : 0;
940
+ const ftsRRF = ftsRank !== Infinity ? ftsWeight / (k + ftsRank) : 0;
941
+ const fileTypeBoost = this.getFileTypeBoost(
942
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
943
+ result.metadata["fileType"],
944
+ intent
945
+ );
946
+ const frameworkBoost = this.getFrameworkContextBoost(query, result);
947
+ const metadata = {
948
+ vectorRRF,
949
+ ftsRRF,
950
+ fileTypeBoost,
951
+ frameworkBoost
952
+ };
953
+ if (vectorRank !== Infinity) {
954
+ metadata.vectorRank = vectorRank;
955
+ }
956
+ if (ftsRank !== Infinity) {
957
+ metadata.ftsRank = ftsRank;
958
+ }
959
+ rrfScores.push({
960
+ id,
961
+ score: (vectorRRF + ftsRRF) * fileTypeBoost * frameworkBoost,
962
+ result,
963
+ metadata
964
+ });
965
+ }
966
+ const sorted = rrfScores.sort((a, b) => b.score - a.score).slice(0, limit);
967
+ if (sorted.length > 0) {
968
+ const first = sorted[0];
969
+ const last = sorted[sorted.length - 1];
970
+ if (first === void 0 || last === void 0) {
971
+ return sorted.map((r) => ({
972
+ ...r.result,
973
+ score: r.score,
974
+ rankingMetadata: r.metadata
975
+ }));
976
+ }
977
+ const maxScore = first.score;
978
+ const minScore = last.score;
979
+ const range = maxScore - minScore;
980
+ if (range > 0) {
981
+ return sorted.map((r) => ({
982
+ ...r.result,
983
+ score: (r.score - minScore) / range,
984
+ rankingMetadata: r.metadata
985
+ }));
986
+ }
987
+ }
988
+ return sorted.map((r) => ({
989
+ ...r.result,
990
+ score: r.score,
991
+ rankingMetadata: r.metadata
992
+ }));
993
+ }
994
+ async searchAllStores(query, storeIds) {
995
+ return this.search({
996
+ ...query,
997
+ stores: storeIds
998
+ });
999
+ }
1000
+ /**
1001
+ * Get a score multiplier based on file type and query intent.
1002
+ * Documentation files get a strong boost to surface them higher.
1003
+ * Phase 4: Strengthened boosts for better documentation ranking.
1004
+ * Phase 1: Intent-based adjustments for context-aware ranking.
1005
+ */
1006
+ getFileTypeBoost(fileType, intent) {
1007
+ let baseBoost;
1008
+ switch (fileType) {
1009
+ case "documentation-primary":
1010
+ baseBoost = 1.8;
1011
+ break;
1012
+ case "documentation":
1013
+ baseBoost = 1.5;
1014
+ break;
1015
+ case "example":
1016
+ baseBoost = 1.4;
1017
+ break;
1018
+ case "source":
1019
+ baseBoost = 1;
1020
+ break;
1021
+ case "source-internal":
1022
+ baseBoost = 0.75;
1023
+ break;
1024
+ case "test":
1025
+ baseBoost = 0.7;
1026
+ break;
1027
+ case "config":
1028
+ baseBoost = 0.5;
1029
+ break;
1030
+ default:
1031
+ baseBoost = 1;
1032
+ }
1033
+ const intentBoosts = INTENT_FILE_BOOSTS[intent];
1034
+ const intentMultiplier = intentBoosts[fileType ?? "other"] ?? 1;
1035
+ return baseBoost * intentMultiplier;
1036
+ }
1037
+ /**
1038
+ * Get a score multiplier based on framework context.
1039
+ * If query mentions a framework, boost results from that framework's files.
1040
+ */
1041
+ getFrameworkContextBoost(query, result) {
1042
+ const path3 = result.metadata.path ?? result.metadata.url ?? "";
1043
+ const content = result.content.toLowerCase();
1044
+ const pathLower = path3.toLowerCase();
1045
+ for (const { pattern, terms } of FRAMEWORK_PATTERNS) {
1046
+ if (pattern.test(query)) {
1047
+ const resultMatchesFramework = terms.some(
1048
+ (term) => pathLower.includes(term) || content.includes(term)
1049
+ );
1050
+ if (resultMatchesFramework) {
1051
+ return 1.5;
1052
+ } else {
1053
+ return 0.8;
1054
+ }
1055
+ }
1056
+ }
1057
+ return 1;
1058
+ }
1059
+ addProgressiveContext(result, query, detail, graph) {
1060
+ const enhanced = { ...result };
1061
+ const path3 = result.metadata.path ?? result.metadata.url ?? "unknown";
1062
+ const fileType = result.metadata["fileType"];
1063
+ const codeUnit = this.extractCodeUnitFromResult(result);
1064
+ const symbolName = codeUnit?.name ?? this.extractSymbolName(result.content);
1065
+ enhanced.summary = {
1066
+ type: this.inferType(fileType, codeUnit),
1067
+ name: symbolName,
1068
+ signature: codeUnit?.signature ?? "",
1069
+ purpose: this.generatePurpose(result.content, query),
1070
+ location: `${path3}${codeUnit ? ":" + String(codeUnit.startLine) : ""}`,
1071
+ relevanceReason: this.generateRelevanceReason(result, query)
1072
+ };
1073
+ if (detail === "contextual" || detail === "full") {
1074
+ const usage = this.getUsageFromGraph(graph, path3, symbolName);
1075
+ enhanced.context = {
1076
+ interfaces: this.extractInterfaces(result.content),
1077
+ keyImports: this.extractImports(result.content),
1078
+ relatedConcepts: this.extractConcepts(result.content, query),
1079
+ usage
1080
+ };
1081
+ }
1082
+ if (detail === "full") {
1083
+ const relatedCode = this.getRelatedCodeFromGraph(graph, path3, symbolName);
1084
+ enhanced.full = {
1085
+ completeCode: codeUnit?.fullContent ?? result.content,
1086
+ relatedCode,
1087
+ documentation: this.extractDocumentation(result.content),
1088
+ tests: void 0
1089
+ };
1090
+ }
1091
+ return enhanced;
1092
+ }
1093
+ extractCodeUnitFromResult(result) {
1094
+ const path3 = result.metadata.path;
1095
+ if (path3 === void 0 || path3 === "") return void 0;
1096
+ const ext = path3.split(".").pop() ?? "";
1097
+ const language = ext === "ts" || ext === "tsx" ? "typescript" : ext === "js" || ext === "jsx" ? "javascript" : ext;
1098
+ const symbolName = this.extractSymbolName(result.content);
1099
+ if (symbolName === "") return void 0;
1100
+ return this.codeUnitService.extractCodeUnit(result.content, symbolName, language);
1101
+ }
1102
+ extractSymbolName(content) {
1103
+ const funcMatch = content.match(/(?:export\s+)?(?:async\s+)?function\s+(\w+)/);
1104
+ if (funcMatch !== null && funcMatch[1] !== void 0 && funcMatch[1] !== "") return funcMatch[1];
1105
+ const classMatch = content.match(/(?:export\s+)?class\s+(\w+)/);
1106
+ if (classMatch !== null && classMatch[1] !== void 0 && classMatch[1] !== "") return classMatch[1];
1107
+ const constMatch = content.match(/(?:export\s+)?const\s+(\w+)/);
1108
+ if (constMatch !== null && constMatch[1] !== void 0 && constMatch[1] !== "") return constMatch[1];
1109
+ return "(anonymous)";
1110
+ }
1111
+ inferType(fileType, codeUnit) {
1112
+ if (codeUnit) return codeUnit.type;
1113
+ if (fileType === "documentation" || fileType === "documentation-primary") return "documentation";
1114
+ return "function";
1115
+ }
1116
+ generatePurpose(content, query) {
1117
+ const docMatch = content.match(/\/\*\*\s*\n\s*\*\s*([^\n]+)/);
1118
+ if (docMatch !== null && docMatch[1] !== void 0 && docMatch[1] !== "") return docMatch[1].trim();
1119
+ const lines = content.split("\n");
1120
+ const queryTerms = query.toLowerCase().split(/\s+/).filter((t2) => t2.length > 2);
1121
+ const shouldSkip = (cleaned) => {
1122
+ return cleaned.startsWith("import ") || cleaned.startsWith("export ") || cleaned.startsWith("interface ") || cleaned.startsWith("type ");
1123
+ };
1124
+ const scoreLine = (cleaned) => {
1125
+ const lowerLine = cleaned.toLowerCase();
1126
+ return queryTerms.filter((term) => lowerLine.includes(term)).length;
1127
+ };
1128
+ const isMeaningful = (cleaned) => {
1129
+ if (cleaned.length === 0) return false;
1130
+ if (cleaned.startsWith("//") || cleaned.startsWith("/*")) return false;
1131
+ if (cleaned.startsWith("#") && cleaned.length > 3) return true;
1132
+ return cleaned.length >= 15;
1133
+ };
1134
+ let bestLine = null;
1135
+ let bestScore = 0;
1136
+ for (const line of lines) {
1137
+ const cleaned = line.trim();
1138
+ if (shouldSkip(cleaned) || !isMeaningful(cleaned)) continue;
1139
+ let score = scoreLine(cleaned);
1140
+ if (/[.!?]$/.test(cleaned)) {
1141
+ score += 0.5;
1142
+ }
1143
+ if (/\w+\([^)]*\)|=\s*\w+\(|=>/.test(cleaned)) {
1144
+ score += 0.6;
1145
+ }
1146
+ if (score > bestScore) {
1147
+ bestScore = score;
1148
+ bestLine = cleaned;
1149
+ }
1150
+ }
1151
+ if (bestLine !== null && bestLine !== "" && bestScore > 0) {
1152
+ if (bestLine.length > 150) {
1153
+ const firstSentence = bestLine.match(/^[^.!?]+[.!?]/);
1154
+ if (firstSentence && firstSentence[0].length >= 20 && firstSentence[0].length <= 150) {
1155
+ return firstSentence[0].trim();
1156
+ }
1157
+ return bestLine.substring(0, 147) + "...";
1158
+ }
1159
+ return bestLine;
1160
+ }
1161
+ for (const line of lines) {
1162
+ const cleaned = line.trim();
1163
+ if (shouldSkip(cleaned) || !isMeaningful(cleaned)) continue;
1164
+ if (cleaned.length > 150) {
1165
+ const firstSentence = cleaned.match(/^[^.!?]+[.!?]/);
1166
+ if (firstSentence && firstSentence[0].length >= 20 && firstSentence[0].length <= 150) {
1167
+ return firstSentence[0].trim();
1168
+ }
1169
+ return cleaned.substring(0, 147) + "...";
1170
+ }
1171
+ return cleaned;
1172
+ }
1173
+ return "Code related to query";
1174
+ }
1175
+ generateRelevanceReason(result, query) {
1176
+ const queryTerms = query.toLowerCase().split(/\s+/).filter((t2) => t2.length > 2);
1177
+ const contentLower = result.content.toLowerCase();
1178
+ const matchedTerms = queryTerms.filter((term) => contentLower.includes(term));
1179
+ if (matchedTerms.length > 0) {
1180
+ return `Matches: ${matchedTerms.join(", ")}`;
1181
+ }
1182
+ return "Semantically similar to query";
1183
+ }
1184
+ extractInterfaces(content) {
1185
+ const interfaces = [];
1186
+ const matches = content.matchAll(/interface\s+(\w+)/g);
1187
+ for (const match of matches) {
1188
+ if (match[1] !== void 0 && match[1] !== "") interfaces.push(match[1]);
1189
+ }
1190
+ return interfaces;
1191
+ }
1192
+ extractImports(content) {
1193
+ const imports = [];
1194
+ const matches = content.matchAll(/import\s+.*?from\s+['"]([^'"]+)['"]/g);
1195
+ for (const match of matches) {
1196
+ if (match[1] !== void 0 && match[1] !== "") imports.push(match[1]);
1197
+ }
1198
+ return imports.slice(0, 5);
1199
+ }
1200
+ extractConcepts(content, _query) {
1201
+ const stopwords = /* @__PURE__ */ new Set([
1202
+ "this",
1203
+ "that",
1204
+ "these",
1205
+ "those",
1206
+ "from",
1207
+ "with",
1208
+ "have",
1209
+ "will",
1210
+ "would",
1211
+ "should",
1212
+ "could",
1213
+ "about",
1214
+ "been",
1215
+ "were",
1216
+ "being",
1217
+ "function",
1218
+ "return",
1219
+ "const",
1220
+ "import",
1221
+ "export",
1222
+ "default",
1223
+ "type",
1224
+ "interface",
1225
+ "class",
1226
+ "extends",
1227
+ "implements",
1228
+ "async",
1229
+ "await",
1230
+ "then",
1231
+ "catch",
1232
+ "throw",
1233
+ "error",
1234
+ "undefined",
1235
+ "null",
1236
+ "true",
1237
+ "false",
1238
+ "void",
1239
+ "number",
1240
+ "string",
1241
+ "boolean",
1242
+ "object",
1243
+ "array",
1244
+ "promise",
1245
+ "callback",
1246
+ "resolve",
1247
+ "reject",
1248
+ "value",
1249
+ "param",
1250
+ "params",
1251
+ "args",
1252
+ "props",
1253
+ "options",
1254
+ "config",
1255
+ "data"
1256
+ ]);
1257
+ const words = content.toLowerCase().match(/\b[a-z]{4,}\b/g) ?? [];
1258
+ const frequency = /* @__PURE__ */ new Map();
1259
+ for (const word of words) {
1260
+ if (stopwords.has(word)) continue;
1261
+ frequency.set(word, (frequency.get(word) ?? 0) + 1);
1262
+ }
1263
+ return Array.from(frequency.entries()).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([word]) => word);
1264
+ }
1265
+ extractDocumentation(content) {
1266
+ const docMatch = content.match(/\/\*\*([\s\S]*?)\*\//);
1267
+ if (docMatch !== null && docMatch[1] !== void 0 && docMatch[1] !== "") {
1268
+ return docMatch[1].split("\n").map((line) => line.replace(/^\s*\*\s?/, "").trim()).filter((line) => line.length > 0).join("\n");
1269
+ }
1270
+ return "";
1271
+ }
1272
+ /**
1273
+ * Get usage stats from code graph.
1274
+ * Returns default values if no graph is available.
1275
+ */
1276
+ getUsageFromGraph(graph, filePath, symbolName) {
1277
+ if (!graph || symbolName === "" || symbolName === "(anonymous)") {
1278
+ return { calledBy: 0, calls: 0 };
1279
+ }
1280
+ const nodeId = `${filePath}:${symbolName}`;
1281
+ return {
1282
+ calledBy: graph.getCalledByCount(nodeId),
1283
+ calls: graph.getCallsCount(nodeId)
1284
+ };
1285
+ }
1286
+ /**
1287
+ * Get related code from graph.
1288
+ * Returns callers and callees for the symbol.
1289
+ */
1290
+ getRelatedCodeFromGraph(graph, filePath, symbolName) {
1291
+ if (!graph || symbolName === "" || symbolName === "(anonymous)") {
1292
+ return [];
1293
+ }
1294
+ const nodeId = `${filePath}:${symbolName}`;
1295
+ const related = [];
1296
+ const incoming = graph.getIncomingEdges(nodeId);
1297
+ for (const edge of incoming) {
1298
+ if (edge.type === "calls") {
1299
+ const [file, symbol] = this.parseNodeId(edge.from);
1300
+ related.push({
1301
+ file,
1302
+ summary: symbol ? `${symbol}()` : "unknown",
1303
+ relationship: "calls this"
1304
+ });
1305
+ }
1306
+ }
1307
+ const outgoing = graph.getEdges(nodeId);
1308
+ for (const edge of outgoing) {
1309
+ if (edge.type === "calls") {
1310
+ const [file, symbol] = this.parseNodeId(edge.to);
1311
+ related.push({
1312
+ file,
1313
+ summary: symbol ? `${symbol}()` : "unknown",
1314
+ relationship: "called by this"
1315
+ });
1316
+ }
1317
+ }
1318
+ return related.slice(0, 10);
1319
+ }
1320
+ /**
1321
+ * Parse a node ID into file path and symbol name.
1322
+ */
1323
+ parseNodeId(nodeId) {
1324
+ const lastColon = nodeId.lastIndexOf(":");
1325
+ if (lastColon === -1) {
1326
+ return [nodeId, ""];
1327
+ }
1328
+ return [nodeId.substring(0, lastColon), nodeId.substring(lastColon + 1)];
1329
+ }
1330
+ };
1331
+
1332
+ // src/services/index.service.ts
1333
+ import { readFile as readFile3, readdir } from "fs/promises";
1334
+ import { join as join3, extname, basename } from "path";
1335
+ import { createHash } from "crypto";
1336
+
1337
+ // src/services/chunking.service.ts
1338
+ var ChunkingService = class {
1339
+ chunkSize;
1340
+ chunkOverlap;
1341
+ constructor(config) {
1342
+ this.chunkSize = config.chunkSize;
1343
+ this.chunkOverlap = config.chunkOverlap;
1344
+ }
1345
+ /**
1346
+ * Chunk text content. Uses semantic chunking for Markdown and code files,
1347
+ * falling back to sliding window for other content.
1348
+ */
1349
+ chunk(text, filePath) {
1350
+ if (filePath !== void 0 && filePath !== "" && /\.md$/i.test(filePath)) {
1351
+ return this.chunkMarkdown(text);
1352
+ }
1353
+ if (filePath !== void 0 && filePath !== "" && /\.(ts|tsx|js|jsx)$/i.test(filePath)) {
1354
+ return this.chunkCode(text);
1355
+ }
1356
+ return this.chunkSlidingWindow(text);
1357
+ }
1358
+ /**
1359
+ * Semantic chunking for Markdown files.
1360
+ * Splits on section headers to keep related content together.
1361
+ */
1362
+ chunkMarkdown(text) {
1363
+ const headerRegex = /^(#{1,4})\s+(.+)$/gm;
1364
+ const sections = [];
1365
+ let lastIndex = 0;
1366
+ let lastHeader = "";
1367
+ let match;
1368
+ while ((match = headerRegex.exec(text)) !== null) {
1369
+ if (match.index > lastIndex) {
1370
+ const content = text.slice(lastIndex, match.index).trim();
1371
+ if (content) {
1372
+ sections.push({
1373
+ header: lastHeader,
1374
+ content,
1375
+ startOffset: lastIndex
1376
+ });
1377
+ }
1378
+ }
1379
+ lastHeader = match[2] ?? "";
1380
+ lastIndex = match.index;
1381
+ }
1382
+ const finalContent = text.slice(lastIndex).trim();
1383
+ if (finalContent) {
1384
+ sections.push({
1385
+ header: lastHeader,
1386
+ content: finalContent,
1387
+ startOffset: lastIndex
1388
+ });
1389
+ }
1390
+ if (sections.length === 0) {
1391
+ return this.chunkSlidingWindow(text);
1392
+ }
1393
+ const chunks = [];
1394
+ for (const section of sections) {
1395
+ if (section.content.length <= this.chunkSize) {
1396
+ chunks.push({
1397
+ content: section.content,
1398
+ chunkIndex: chunks.length,
1399
+ totalChunks: 0,
1400
+ startOffset: section.startOffset,
1401
+ endOffset: section.startOffset + section.content.length,
1402
+ sectionHeader: section.header || void 0
1403
+ });
1404
+ } else {
1405
+ const sectionChunks = this.chunkSlidingWindow(section.content);
1406
+ for (const subChunk of sectionChunks) {
1407
+ chunks.push({
1408
+ ...subChunk,
1409
+ chunkIndex: chunks.length,
1410
+ startOffset: section.startOffset + subChunk.startOffset,
1411
+ endOffset: section.startOffset + subChunk.endOffset,
1412
+ sectionHeader: section.header || void 0
1413
+ });
1414
+ }
1415
+ }
1416
+ }
1417
+ for (const chunk of chunks) {
1418
+ chunk.totalChunks = chunks.length;
1419
+ }
1420
+ return chunks;
1421
+ }
1422
+ /**
1423
+ * Semantic chunking for TypeScript/JavaScript code files.
1424
+ * Splits on top-level declarations to keep functions/classes together.
1425
+ */
1426
+ chunkCode(text) {
1427
+ const declarationRegex = /^(?:\/\*\*[\s\S]*?\*\/\s*)?(?:export\s+)?(?:async\s+)?(?:function|class|interface|type|const|let|var|enum)\s+(\w+)/gm;
1428
+ const declarations = [];
1429
+ let match;
1430
+ while ((match = declarationRegex.exec(text)) !== null) {
1431
+ const name = match[1];
1432
+ const decl = {
1433
+ startOffset: match.index,
1434
+ endOffset: match.index
1435
+ };
1436
+ if (name !== void 0) {
1437
+ decl.name = name;
1438
+ }
1439
+ declarations.push(decl);
1440
+ }
1441
+ if (declarations.length === 0) {
1442
+ return this.chunkSlidingWindow(text);
1443
+ }
1444
+ for (let i = 0; i < declarations.length; i++) {
1445
+ const currentDecl = declarations[i];
1446
+ const nextDecl = declarations[i + 1];
1447
+ if (currentDecl === void 0) continue;
1448
+ const declText = text.slice(currentDecl.startOffset);
1449
+ if (/^(?:\/\*\*[\s\S]*?\*\/\s*)?(?:export\s+)?(?:async\s+)?(?:function|class|enum)\s+/m.test(declText)) {
1450
+ const boundary = this.findDeclarationEnd(declText);
1451
+ if (boundary > 0) {
1452
+ currentDecl.endOffset = currentDecl.startOffset + boundary;
1453
+ } else {
1454
+ currentDecl.endOffset = nextDecl !== void 0 ? nextDecl.startOffset : text.length;
1455
+ }
1456
+ } else {
1457
+ currentDecl.endOffset = nextDecl !== void 0 ? nextDecl.startOffset : text.length;
1458
+ }
1459
+ }
1460
+ const chunks = [];
1461
+ for (const decl of declarations) {
1462
+ const content = text.slice(decl.startOffset, decl.endOffset).trim();
1463
+ if (content.length <= this.chunkSize) {
1464
+ chunks.push({
1465
+ content,
1466
+ chunkIndex: chunks.length,
1467
+ totalChunks: 0,
1468
+ startOffset: decl.startOffset,
1469
+ endOffset: decl.endOffset,
1470
+ functionName: decl.name
1471
+ });
1472
+ } else {
1473
+ const declChunks = this.chunkSlidingWindow(content);
1474
+ for (const subChunk of declChunks) {
1475
+ chunks.push({
1476
+ ...subChunk,
1477
+ chunkIndex: chunks.length,
1478
+ startOffset: decl.startOffset + subChunk.startOffset,
1479
+ endOffset: decl.startOffset + subChunk.endOffset,
1480
+ functionName: decl.name
1481
+ });
1482
+ }
1483
+ }
1484
+ }
1485
+ for (const chunk of chunks) {
1486
+ chunk.totalChunks = chunks.length;
1487
+ }
1488
+ return chunks.length > 0 ? chunks : this.chunkSlidingWindow(text);
1489
+ }
1490
+ /**
1491
+ * Find the end of a code declaration by counting braces while ignoring
1492
+ * braces inside strings and comments.
1493
+ * Returns the offset where the declaration ends, or -1 if not found.
1494
+ */
1495
+ findDeclarationEnd(text) {
1496
+ let braceCount = 0;
1497
+ let inString = false;
1498
+ let inSingleLineComment = false;
1499
+ let inMultiLineComment = false;
1500
+ let stringChar = "";
1501
+ let i = 0;
1502
+ let foundFirstBrace = false;
1503
+ while (i < text.length) {
1504
+ const char = text[i];
1505
+ const nextChar = i + 1 < text.length ? text[i + 1] : "";
1506
+ if (!inString && !inMultiLineComment && char === "/" && nextChar === "/") {
1507
+ inSingleLineComment = true;
1508
+ i += 2;
1509
+ continue;
1510
+ }
1511
+ if (!inString && !inSingleLineComment && char === "/" && nextChar === "*") {
1512
+ inMultiLineComment = true;
1513
+ i += 2;
1514
+ continue;
1515
+ }
1516
+ if (inMultiLineComment && char === "*" && nextChar === "/") {
1517
+ inMultiLineComment = false;
1518
+ i += 2;
1519
+ continue;
1520
+ }
1521
+ if (inSingleLineComment && char === "\n") {
1522
+ inSingleLineComment = false;
1523
+ i++;
1524
+ continue;
1525
+ }
1526
+ if (inSingleLineComment || inMultiLineComment) {
1527
+ i++;
1528
+ continue;
1529
+ }
1530
+ if (!inString && (char === '"' || char === "'" || char === "`")) {
1531
+ inString = true;
1532
+ stringChar = char;
1533
+ i++;
1534
+ continue;
1535
+ }
1536
+ if (inString && char === "\\") {
1537
+ i += 2;
1538
+ continue;
1539
+ }
1540
+ if (inString && char === stringChar) {
1541
+ inString = false;
1542
+ stringChar = "";
1543
+ i++;
1544
+ continue;
1545
+ }
1546
+ if (inString) {
1547
+ i++;
1548
+ continue;
1549
+ }
1550
+ if (char === "{") {
1551
+ braceCount++;
1552
+ foundFirstBrace = true;
1553
+ } else if (char === "}") {
1554
+ braceCount--;
1555
+ if (foundFirstBrace && braceCount === 0) {
1556
+ return i + 1;
1557
+ }
1558
+ }
1559
+ i++;
1560
+ }
1561
+ return -1;
1562
+ }
1563
+ /**
1564
+ * Traditional sliding window chunking for non-Markdown content.
1565
+ */
1566
+ chunkSlidingWindow(text) {
1567
+ if (text.length <= this.chunkSize) {
1568
+ return [{
1569
+ content: text,
1570
+ chunkIndex: 0,
1571
+ totalChunks: 1,
1572
+ startOffset: 0,
1573
+ endOffset: text.length
1574
+ }];
1575
+ }
1576
+ const chunks = [];
1577
+ const step = this.chunkSize - this.chunkOverlap;
1578
+ let start = 0;
1579
+ while (start < text.length) {
1580
+ const end = Math.min(start + this.chunkSize, text.length);
1581
+ chunks.push({
1582
+ content: text.slice(start, end),
1583
+ chunkIndex: chunks.length,
1584
+ totalChunks: 0,
1585
+ startOffset: start,
1586
+ endOffset: end
1587
+ });
1588
+ start += step;
1589
+ if (end === text.length) break;
1590
+ }
1591
+ for (const chunk of chunks) {
1592
+ chunk.totalChunks = chunks.length;
1593
+ }
1594
+ return chunks;
1595
+ }
1596
+ };
1597
+
1598
+ // src/services/index.service.ts
1599
+ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
1600
+ ".txt",
1601
+ ".md",
1602
+ ".js",
1603
+ ".ts",
1604
+ ".jsx",
1605
+ ".tsx",
1606
+ ".json",
1607
+ ".yaml",
1608
+ ".yml",
1609
+ ".html",
1610
+ ".css",
1611
+ ".scss",
1612
+ ".less",
1613
+ ".py",
1614
+ ".rb",
1615
+ ".go",
1616
+ ".rs",
1617
+ ".java",
1618
+ ".c",
1619
+ ".cpp",
1620
+ ".h",
1621
+ ".hpp",
1622
+ ".sh",
1623
+ ".bash",
1624
+ ".zsh",
1625
+ ".sql",
1626
+ ".xml"
1627
+ ]);
1628
+ var IndexService = class {
1629
+ lanceStore;
1630
+ embeddingEngine;
1631
+ chunker;
1632
+ codeGraphService;
1633
+ constructor(lanceStore, embeddingEngine, options = {}) {
1634
+ this.lanceStore = lanceStore;
1635
+ this.embeddingEngine = embeddingEngine;
1636
+ this.chunker = new ChunkingService({
1637
+ chunkSize: options.chunkSize ?? 768,
1638
+ chunkOverlap: options.chunkOverlap ?? 100
1639
+ });
1640
+ this.codeGraphService = options.codeGraphService;
1641
+ }
1642
+ async indexStore(store, onProgress) {
1643
+ try {
1644
+ if (store.type === "file" || store.type === "repo") {
1645
+ return await this.indexFileStore(store, onProgress);
1646
+ }
1647
+ return err(new Error(`Indexing not supported for store type: ${store.type}`));
1648
+ } catch (error) {
1649
+ return err(error instanceof Error ? error : new Error(String(error)));
1650
+ }
1651
+ }
1652
+ async indexFileStore(store, onProgress) {
1653
+ const startTime = Date.now();
1654
+ const files = await this.scanDirectory(store.path);
1655
+ const documents = [];
1656
+ let filesProcessed = 0;
1657
+ const sourceFiles = [];
1658
+ onProgress?.({
1659
+ type: "start",
1660
+ current: 0,
1661
+ total: files.length,
1662
+ message: "Starting index"
1663
+ });
1664
+ for (const filePath of files) {
1665
+ const content = await readFile3(filePath, "utf-8");
1666
+ const fileHash = createHash("md5").update(content).digest("hex");
1667
+ const chunks = this.chunker.chunk(content, filePath);
1668
+ const ext = extname(filePath).toLowerCase();
1669
+ const fileName = basename(filePath).toLowerCase();
1670
+ const fileType = this.classifyFileType(ext, fileName, filePath);
1671
+ if ([".ts", ".tsx", ".js", ".jsx"].includes(ext)) {
1672
+ sourceFiles.push({ path: filePath, content });
1673
+ }
1674
+ for (const chunk of chunks) {
1675
+ const vector = await this.embeddingEngine.embed(chunk.content);
1676
+ const chunkId = chunks.length > 1 ? `${store.id}-${fileHash}-${String(chunk.chunkIndex)}` : `${store.id}-${fileHash}`;
1677
+ const doc = {
1678
+ id: createDocumentId(chunkId),
1679
+ content: chunk.content,
1680
+ vector,
1681
+ metadata: {
1682
+ type: chunks.length > 1 ? "chunk" : "file",
1683
+ storeId: store.id,
1684
+ path: filePath,
1685
+ indexedAt: /* @__PURE__ */ new Date(),
1686
+ fileHash,
1687
+ chunkIndex: chunk.chunkIndex,
1688
+ totalChunks: chunk.totalChunks,
1689
+ // New metadata for ranking
1690
+ fileType,
1691
+ sectionHeader: chunk.sectionHeader,
1692
+ functionName: chunk.functionName,
1693
+ hasDocComments: /\/\*\*[\s\S]*?\*\//.test(chunk.content),
1694
+ docSummary: chunk.docSummary
1695
+ }
1696
+ };
1697
+ documents.push(doc);
1698
+ }
1699
+ filesProcessed++;
1700
+ onProgress?.({
1701
+ type: "progress",
1702
+ current: filesProcessed,
1703
+ total: files.length,
1704
+ message: `Indexing ${filePath}`
1705
+ });
1706
+ }
1707
+ if (documents.length > 0) {
1708
+ await this.lanceStore.addDocuments(store.id, documents);
1709
+ }
1710
+ if (this.codeGraphService && sourceFiles.length > 0) {
1711
+ const graph = await this.codeGraphService.buildGraph(sourceFiles);
1712
+ await this.codeGraphService.saveGraph(store.id, graph);
1713
+ }
1714
+ onProgress?.({
1715
+ type: "complete",
1716
+ current: files.length,
1717
+ total: files.length,
1718
+ message: "Indexing complete"
1719
+ });
1720
+ return ok({
1721
+ documentsIndexed: filesProcessed,
1722
+ chunksCreated: documents.length,
1723
+ timeMs: Date.now() - startTime
1724
+ });
1725
+ }
1726
+ async scanDirectory(dir) {
1727
+ const files = [];
1728
+ const entries = await readdir(dir, { withFileTypes: true });
1729
+ for (const entry of entries) {
1730
+ const fullPath = join3(dir, entry.name);
1731
+ if (entry.isDirectory()) {
1732
+ if (!["node_modules", ".git", "dist", "build"].includes(entry.name)) {
1733
+ files.push(...await this.scanDirectory(fullPath));
1734
+ }
1735
+ } else if (entry.isFile()) {
1736
+ const ext = extname(entry.name).toLowerCase();
1737
+ if (TEXT_EXTENSIONS.has(ext)) {
1738
+ files.push(fullPath);
1739
+ }
1740
+ }
1741
+ }
1742
+ return files;
1743
+ }
1744
+ /**
1745
+ * Classify file type for ranking purposes.
1746
+ * Documentation files rank higher than source code for documentation queries.
1747
+ * Phase 4: Enhanced to detect internal implementation files.
1748
+ */
1749
+ classifyFileType(ext, fileName, filePath) {
1750
+ if (ext === ".md") {
1751
+ if (fileName === "changelog.md" || fileName === "changes.md" || /changelog/i.test(fileName)) {
1752
+ return "changelog";
1753
+ }
1754
+ if (["readme.md", "migration.md", "contributing.md"].includes(fileName)) {
1755
+ return "documentation-primary";
1756
+ }
1757
+ if (/\/(docs?|documentation|guides?|tutorials?|articles?)\//i.test(filePath)) {
1758
+ return "documentation";
1759
+ }
1760
+ return "documentation";
1761
+ }
1762
+ if (/\.(test|spec)\.[jt]sx?$/.test(fileName) || /\/__tests__\//.test(filePath)) {
1763
+ return "test";
1764
+ }
1765
+ if (/\/examples?\//.test(filePath) || fileName.includes("example")) {
1766
+ return "example";
1767
+ }
1768
+ if (/^(tsconfig|package|\.eslint|\.prettier|vite\.config|next\.config)/i.test(fileName)) {
1769
+ return "config";
1770
+ }
1771
+ if ([".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java"].includes(ext)) {
1772
+ if (this.isInternalImplementation(filePath, fileName)) {
1773
+ return "source-internal";
1774
+ }
1775
+ return "source";
1776
+ }
1777
+ return "other";
1778
+ }
1779
+ /**
1780
+ * Detect if a source file is internal implementation code.
1781
+ * Internal code should rank lower than public-facing APIs and docs.
1782
+ */
1783
+ isInternalImplementation(filePath, fileName) {
1784
+ const pathLower = filePath.toLowerCase();
1785
+ const fileNameLower = fileName.toLowerCase();
1786
+ if (/\/packages\/[^/]+\/src\//.test(pathLower)) {
1787
+ if (fileNameLower === "index.ts" || fileNameLower === "index.js") {
1788
+ return false;
1789
+ }
1790
+ return true;
1791
+ }
1792
+ if (/\/(internal|lib\/core|core\/src|_internal|private)\//.test(pathLower)) {
1793
+ return true;
1794
+ }
1795
+ if (/\/(compiler|transforms?|parse|codegen)\//.test(pathLower) && !fileNameLower.includes("readme") && !fileNameLower.includes("index")) {
1796
+ return true;
1797
+ }
1798
+ return false;
1799
+ }
1800
+ };
1801
+
1802
+ // src/services/code-graph.service.ts
1803
+ import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
1804
+ import { join as join4, dirname as dirname3 } from "path";
1805
+
1806
+ // src/analysis/code-graph.ts
1807
+ var CodeGraph = class {
1808
+ nodes = /* @__PURE__ */ new Map();
1809
+ edges = /* @__PURE__ */ new Map();
1810
+ addNodes(nodes, file) {
1811
+ for (const node of nodes) {
1812
+ const id = `${file}:${node.name}`;
1813
+ const graphNode = {
1814
+ id,
1815
+ file,
1816
+ type: node.type,
1817
+ name: node.name,
1818
+ exported: node.exported,
1819
+ startLine: node.startLine,
1820
+ endLine: node.endLine
1821
+ };
1822
+ if (node.signature !== void 0) {
1823
+ graphNode.signature = node.signature;
1824
+ }
1825
+ this.nodes.set(id, graphNode);
1826
+ if (!this.edges.has(id)) {
1827
+ this.edges.set(id, []);
1828
+ }
1829
+ if (node.type === "class" && node.methods !== void 0) {
1830
+ for (const method of node.methods) {
1831
+ const methodId = `${file}:${node.name}.${method.name}`;
1832
+ const methodNode = {
1833
+ id: methodId,
1834
+ file,
1835
+ type: "method",
1836
+ name: method.name,
1837
+ exported: node.exported,
1838
+ // Methods inherit export status from class
1839
+ startLine: method.startLine,
1840
+ endLine: method.endLine,
1841
+ signature: method.signature
1842
+ };
1843
+ this.nodes.set(methodId, methodNode);
1844
+ if (!this.edges.has(methodId)) {
1845
+ this.edges.set(methodId, []);
1846
+ }
1847
+ }
1848
+ }
1849
+ }
1850
+ }
1851
+ addImport(fromFile, toFile, specifiers) {
1852
+ const resolvedTo = this.resolveImportPath(fromFile, toFile);
1853
+ for (const spec of specifiers) {
1854
+ const edge = {
1855
+ from: fromFile,
1856
+ to: `${resolvedTo}:${spec}`,
1857
+ type: "imports",
1858
+ confidence: 1
1859
+ };
1860
+ const edges = this.edges.get(fromFile) ?? [];
1861
+ edges.push(edge);
1862
+ this.edges.set(fromFile, edges);
1863
+ }
1864
+ }
1865
+ analyzeCallRelationships(code, file, functionName) {
1866
+ const nodeId = `${file}:${functionName}`;
1867
+ const callPattern = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/g;
1868
+ const calls = /* @__PURE__ */ new Set();
1869
+ let match;
1870
+ while ((match = callPattern.exec(code)) !== null) {
1871
+ if (match[1] !== void 0 && match[1] !== "") {
1872
+ calls.add(match[1]);
1873
+ }
1874
+ }
1875
+ const edges = this.edges.get(nodeId) ?? [];
1876
+ for (const calledFunction of calls) {
1877
+ const targetNode = this.findNodeByName(calledFunction);
1878
+ if (targetNode) {
1879
+ edges.push({
1880
+ from: nodeId,
1881
+ to: targetNode.id,
1882
+ type: "calls",
1883
+ confidence: 0.8
1884
+ // Lower confidence for regex-based detection
1885
+ });
1886
+ } else {
1887
+ edges.push({
1888
+ from: nodeId,
1889
+ to: `unknown:${calledFunction}`,
1890
+ type: "calls",
1891
+ confidence: 0.5
1892
+ });
1893
+ }
1894
+ }
1895
+ this.edges.set(nodeId, edges);
1896
+ }
1897
+ getNode(id) {
1898
+ return this.nodes.get(id);
1899
+ }
1900
+ getEdges(nodeId) {
1901
+ return this.edges.get(nodeId) ?? [];
1902
+ }
1903
+ /**
1904
+ * Add an edge to the graph (used when restoring from serialized data)
1905
+ */
1906
+ addEdge(edge) {
1907
+ const edges = this.edges.get(edge.from) ?? [];
1908
+ edges.push(edge);
1909
+ this.edges.set(edge.from, edges);
1910
+ }
1911
+ /**
1912
+ * Add a graph node directly (used when restoring from serialized data)
1913
+ */
1914
+ addGraphNode(node) {
1915
+ this.nodes.set(node.id, node);
1916
+ if (!this.edges.has(node.id)) {
1917
+ this.edges.set(node.id, []);
1918
+ }
1919
+ }
1920
+ /**
1921
+ * Get edges where this node is the target (callers of this function)
1922
+ */
1923
+ getIncomingEdges(nodeId) {
1924
+ const incoming = [];
1925
+ for (const edges of this.edges.values()) {
1926
+ for (const edge of edges) {
1927
+ if (edge.to === nodeId) {
1928
+ incoming.push(edge);
1929
+ }
1930
+ }
1931
+ }
1932
+ return incoming;
1933
+ }
1934
+ /**
1935
+ * Count how many nodes call this node
1936
+ */
1937
+ getCalledByCount(nodeId) {
1938
+ return this.getIncomingEdges(nodeId).filter((e) => e.type === "calls").length;
1939
+ }
1940
+ /**
1941
+ * Count how many nodes this node calls
1942
+ */
1943
+ getCallsCount(nodeId) {
1944
+ return this.getEdges(nodeId).filter((e) => e.type === "calls").length;
1945
+ }
1946
+ getAllNodes() {
1947
+ return Array.from(this.nodes.values());
1948
+ }
1949
+ findNodeByName(name) {
1950
+ for (const node of this.nodes.values()) {
1951
+ if (node.name === name) {
1952
+ return node;
1953
+ }
1954
+ }
1955
+ return void 0;
1956
+ }
1957
+ resolveImportPath(fromFile, importPath) {
1958
+ if (importPath.startsWith(".")) {
1959
+ const fromDir = fromFile.split("/").slice(0, -1).join("/");
1960
+ const parts = importPath.split("/");
1961
+ let resolved = fromDir;
1962
+ for (const part of parts) {
1963
+ if (part === "..") {
1964
+ resolved = resolved.split("/").slice(0, -1).join("/");
1965
+ } else if (part !== ".") {
1966
+ resolved += "/" + part;
1967
+ }
1968
+ }
1969
+ return resolved.replace(/\.js$/, "");
1970
+ }
1971
+ return importPath;
1972
+ }
1973
+ toJSON() {
1974
+ const allEdges = [];
1975
+ for (const edges of this.edges.values()) {
1976
+ allEdges.push(...edges);
1977
+ }
1978
+ return {
1979
+ nodes: Array.from(this.nodes.values()),
1980
+ edges: allEdges.map((e) => ({ from: e.from, to: e.to, type: e.type }))
1981
+ };
1982
+ }
1983
+ };
1984
+
1985
+ // src/analysis/ast-parser.ts
1986
+ import { parse } from "@babel/parser";
1987
+ import traverseModule from "@babel/traverse";
1988
+ import * as t from "@babel/types";
1989
+ function getTraverse(mod) {
1990
+ if (typeof mod === "function") {
1991
+ return mod;
1992
+ }
1993
+ if (mod !== null && typeof mod === "object" && "default" in mod) {
1994
+ const withDefault = mod;
1995
+ if (typeof withDefault.default === "function") {
1996
+ return withDefault.default;
1997
+ }
1998
+ }
1999
+ throw new Error("Invalid traverse module export");
2000
+ }
2001
+ var traverse = getTraverse(traverseModule);
2002
+ var ASTParser = class {
2003
+ parse(code, language) {
2004
+ try {
2005
+ const plugins = ["jsx"];
2006
+ if (language === "typescript") {
2007
+ plugins.push("typescript");
2008
+ }
2009
+ const ast = parse(code, {
2010
+ sourceType: "module",
2011
+ plugins
2012
+ });
2013
+ const nodes = [];
2014
+ traverse(ast, {
2015
+ FunctionDeclaration: (path3) => {
2016
+ const node = path3.node;
2017
+ if (!node.id) return;
2018
+ const exported = path3.parent.type === "ExportNamedDeclaration" || path3.parent.type === "ExportDefaultDeclaration";
2019
+ nodes.push({
2020
+ type: "function",
2021
+ name: node.id.name,
2022
+ exported,
2023
+ async: node.async,
2024
+ startLine: node.loc?.start.line ?? 0,
2025
+ endLine: node.loc?.end.line ?? 0,
2026
+ signature: this.extractFunctionSignature(node)
2027
+ });
2028
+ },
2029
+ ClassDeclaration: (path3) => {
2030
+ const node = path3.node;
2031
+ if (!node.id) return;
2032
+ const exported = path3.parent.type === "ExportNamedDeclaration" || path3.parent.type === "ExportDefaultDeclaration";
2033
+ const methods = [];
2034
+ for (const member of node.body.body) {
2035
+ if (t.isClassMethod(member) && t.isIdentifier(member.key)) {
2036
+ methods.push({
2037
+ name: member.key.name,
2038
+ async: member.async,
2039
+ signature: this.extractMethodSignature(member),
2040
+ startLine: member.loc?.start.line ?? 0,
2041
+ endLine: member.loc?.end.line ?? 0
2042
+ });
2043
+ }
2044
+ }
2045
+ nodes.push({
2046
+ type: "class",
2047
+ name: node.id.name,
2048
+ exported,
2049
+ startLine: node.loc?.start.line ?? 0,
2050
+ endLine: node.loc?.end.line ?? 0,
2051
+ methods
2052
+ });
2053
+ },
2054
+ TSInterfaceDeclaration: (path3) => {
2055
+ const node = path3.node;
2056
+ const exported = path3.parent.type === "ExportNamedDeclaration";
2057
+ nodes.push({
2058
+ type: "interface",
2059
+ name: node.id.name,
2060
+ exported,
2061
+ startLine: node.loc?.start.line ?? 0,
2062
+ endLine: node.loc?.end.line ?? 0
2063
+ });
2064
+ }
2065
+ });
2066
+ return nodes;
2067
+ } catch {
2068
+ return [];
2069
+ }
2070
+ }
2071
+ extractImports(code) {
2072
+ try {
2073
+ const ast = parse(code, {
2074
+ sourceType: "module",
2075
+ plugins: ["typescript", "jsx"]
2076
+ });
2077
+ const imports = [];
2078
+ traverse(ast, {
2079
+ ImportDeclaration: (path3) => {
2080
+ const node = path3.node;
2081
+ const specifiers = [];
2082
+ for (const spec of node.specifiers) {
2083
+ if (t.isImportDefaultSpecifier(spec)) {
2084
+ specifiers.push(spec.local.name);
2085
+ } else if (t.isImportSpecifier(spec)) {
2086
+ specifiers.push(spec.local.name);
2087
+ } else if (t.isImportNamespaceSpecifier(spec)) {
2088
+ specifiers.push(spec.local.name);
2089
+ }
2090
+ }
2091
+ imports.push({
2092
+ source: node.source.value,
2093
+ specifiers,
2094
+ isType: node.importKind === "type"
2095
+ });
2096
+ }
2097
+ });
2098
+ return imports;
2099
+ } catch {
2100
+ return [];
2101
+ }
2102
+ }
2103
+ extractFunctionSignature(node) {
2104
+ const params = node.params.map((p) => {
2105
+ if (t.isIdentifier(p)) return p.name;
2106
+ return "param";
2107
+ }).join(", ");
2108
+ return `${node.id?.name ?? "anonymous"}(${params})`;
2109
+ }
2110
+ extractMethodSignature(node) {
2111
+ const params = node.params.map((p) => {
2112
+ if (t.isIdentifier(p)) return p.name;
2113
+ return "param";
2114
+ }).join(", ");
2115
+ const name = t.isIdentifier(node.key) ? node.key.name : "method";
2116
+ return `${name}(${params})`;
2117
+ }
2118
+ };
2119
+
2120
+ // src/analysis/tree-sitter-parser.ts
2121
+ import Parser from "tree-sitter";
2122
+ import Rust from "tree-sitter-rust";
2123
+ import Go from "tree-sitter-go";
2124
+ function createRustParser() {
2125
+ const parser = new Parser();
2126
+ parser.setLanguage(Rust);
2127
+ return parser;
2128
+ }
2129
+ function parseRustCode(code) {
2130
+ try {
2131
+ const parser = createRustParser();
2132
+ return parser.parse(code);
2133
+ } catch {
2134
+ return null;
2135
+ }
2136
+ }
2137
+ function createGoParser() {
2138
+ const parser = new Parser();
2139
+ parser.setLanguage(Go);
2140
+ return parser;
2141
+ }
2142
+ function parseGoCode(code) {
2143
+ try {
2144
+ const parser = createGoParser();
2145
+ return parser.parse(code);
2146
+ } catch {
2147
+ return null;
2148
+ }
2149
+ }
2150
+ function positionToLineNumber(position) {
2151
+ return position.row + 1;
2152
+ }
2153
+ function getFirstChildOfType(node, type) {
2154
+ return node.children.find((child) => child.type === type) ?? null;
2155
+ }
2156
+ function getChildByFieldName(node, fieldName) {
2157
+ return node.childForFieldName(fieldName);
2158
+ }
2159
+ function hasVisibilityModifier(node) {
2160
+ return node.children.some((child) => child.type === "visibility_modifier");
2161
+ }
2162
+ function isAsyncFunction(node) {
2163
+ return node.children.some((child) => child.type === "async" || child.text === "async");
2164
+ }
2165
+ function getFunctionSignature(node) {
2166
+ const nameNode = getChildByFieldName(node, "name");
2167
+ const parametersNode = getChildByFieldName(node, "parameters");
2168
+ const returnTypeNode = getChildByFieldName(node, "return_type");
2169
+ const typeParametersNode = getChildByFieldName(node, "type_parameters");
2170
+ if (nameNode === null) {
2171
+ return "";
2172
+ }
2173
+ let signature = nameNode.text;
2174
+ if (typeParametersNode !== null) {
2175
+ signature += typeParametersNode.text;
2176
+ }
2177
+ if (parametersNode !== null) {
2178
+ signature += parametersNode.text;
2179
+ }
2180
+ if (returnTypeNode !== null) {
2181
+ signature += " " + returnTypeNode.text;
2182
+ }
2183
+ return signature;
2184
+ }
2185
+ function queryNodesByType(tree, nodeType) {
2186
+ const types = Array.isArray(nodeType) ? nodeType : [nodeType];
2187
+ return tree.rootNode.descendantsOfType(types);
2188
+ }
2189
+ function extractImportPath(useNode) {
2190
+ const argumentNode = getChildByFieldName(useNode, "argument");
2191
+ if (argumentNode === null) {
2192
+ return "";
2193
+ }
2194
+ return argumentNode.text;
2195
+ }
2196
+
2197
+ // src/analysis/rust-ast-parser.ts
2198
+ var RustASTParser = class {
2199
+ /**
2200
+ * Parse Rust code into CodeNode array
2201
+ * @param code Rust source code
2202
+ * @param filePath File path for error context
2203
+ * @returns Array of CodeNode objects representing Rust constructs
2204
+ */
2205
+ parse(code, _filePath) {
2206
+ try {
2207
+ const tree = parseRustCode(code);
2208
+ if (tree === null) {
2209
+ return [];
2210
+ }
2211
+ const nodes = [];
2212
+ const functions = this.parseFunctions(tree);
2213
+ nodes.push(...functions);
2214
+ const structs = this.parseStructs(tree);
2215
+ nodes.push(...structs);
2216
+ const traits = this.parseTraits(tree);
2217
+ nodes.push(...traits);
2218
+ const types = this.parseTypeAliases(tree);
2219
+ nodes.push(...types);
2220
+ const constants = this.parseConstants(tree);
2221
+ nodes.push(...constants);
2222
+ this.parseImplBlocks(tree, nodes);
2223
+ return nodes;
2224
+ } catch {
2225
+ return [];
2226
+ }
2227
+ }
2228
+ /**
2229
+ * Extract imports from Rust code
2230
+ * @param code Rust source code
2231
+ * @returns Array of ImportInfo objects
2232
+ */
2233
+ extractImports(code) {
2234
+ try {
2235
+ const tree = parseRustCode(code);
2236
+ if (tree === null) {
2237
+ return [];
2238
+ }
2239
+ const useDeclarations = queryNodesByType(tree, "use_declaration");
2240
+ const imports = [];
2241
+ for (const useNode of useDeclarations) {
2242
+ const importPath = extractImportPath(useNode);
2243
+ if (importPath === "") {
2244
+ continue;
2245
+ }
2246
+ const { source, specifiers } = this.parseImportPath(importPath);
2247
+ imports.push({
2248
+ source,
2249
+ specifiers,
2250
+ isType: false
2251
+ // Rust doesn't distinguish type-only imports at syntax level
2252
+ });
2253
+ }
2254
+ return imports;
2255
+ } catch {
2256
+ return [];
2257
+ }
2258
+ }
2259
+ /**
2260
+ * Parse function declarations (excluding impl block methods)
2261
+ */
2262
+ parseFunctions(tree) {
2263
+ const functionNodes = queryNodesByType(tree, "function_item");
2264
+ const nodes = [];
2265
+ for (const fnNode of functionNodes) {
2266
+ if (this.isInsideImplBlock(fnNode)) {
2267
+ continue;
2268
+ }
2269
+ const nameNode = getChildByFieldName(fnNode, "name");
2270
+ if (nameNode === null) {
2271
+ continue;
2272
+ }
2273
+ const name = nameNode.text;
2274
+ const exported = hasVisibilityModifier(fnNode);
2275
+ const async = isAsyncFunction(fnNode);
2276
+ const startLine = positionToLineNumber(fnNode.startPosition);
2277
+ const endLine = positionToLineNumber(fnNode.endPosition);
2278
+ const signature = getFunctionSignature(fnNode);
2279
+ nodes.push({
2280
+ type: "function",
2281
+ name,
2282
+ exported,
2283
+ async,
2284
+ startLine,
2285
+ endLine,
2286
+ signature
2287
+ });
2288
+ }
2289
+ return nodes;
2290
+ }
2291
+ /**
2292
+ * Check if a node is inside an impl block
2293
+ */
2294
+ isInsideImplBlock(node) {
2295
+ let current = node.parent;
2296
+ while (current !== null) {
2297
+ if (current.type === "impl_item") {
2298
+ return true;
2299
+ }
2300
+ current = current.parent;
2301
+ }
2302
+ return false;
2303
+ }
2304
+ /**
2305
+ * Parse struct definitions
2306
+ */
2307
+ parseStructs(tree) {
2308
+ const structNodes = queryNodesByType(tree, "struct_item");
2309
+ const nodes = [];
2310
+ for (const structNode of structNodes) {
2311
+ const nameNode = getChildByFieldName(structNode, "name");
2312
+ if (nameNode === null) {
2313
+ continue;
2314
+ }
2315
+ const name = nameNode.text;
2316
+ const exported = hasVisibilityModifier(structNode);
2317
+ const startLine = positionToLineNumber(structNode.startPosition);
2318
+ const endLine = positionToLineNumber(structNode.endPosition);
2319
+ const typeParamsNode = getChildByFieldName(structNode, "type_parameters");
2320
+ const signature = typeParamsNode !== null ? `${name}${typeParamsNode.text}` : name;
2321
+ nodes.push({
2322
+ type: "class",
2323
+ name,
2324
+ exported,
2325
+ startLine,
2326
+ endLine,
2327
+ signature,
2328
+ methods: []
2329
+ // Will be populated by parseImplBlocks
2330
+ });
2331
+ }
2332
+ return nodes;
2333
+ }
2334
+ /**
2335
+ * Parse trait definitions
2336
+ */
2337
+ parseTraits(tree) {
2338
+ const traitNodes = queryNodesByType(tree, "trait_item");
2339
+ const nodes = [];
2340
+ for (const traitNode of traitNodes) {
2341
+ const nameNode = getChildByFieldName(traitNode, "name");
2342
+ if (nameNode === null) {
2343
+ continue;
2344
+ }
2345
+ const name = nameNode.text;
2346
+ const exported = hasVisibilityModifier(traitNode);
2347
+ const startLine = positionToLineNumber(traitNode.startPosition);
2348
+ const endLine = positionToLineNumber(traitNode.endPosition);
2349
+ const typeParamsNode = getChildByFieldName(traitNode, "type_parameters");
2350
+ const signature = typeParamsNode !== null ? `${name}${typeParamsNode.text}` : name;
2351
+ const methods = this.extractTraitMethods(traitNode);
2352
+ nodes.push({
2353
+ type: "interface",
2354
+ name,
2355
+ exported,
2356
+ startLine,
2357
+ endLine,
2358
+ signature,
2359
+ methods
2360
+ });
2361
+ }
2362
+ return nodes;
2363
+ }
2364
+ /**
2365
+ * Parse type aliases
2366
+ */
2367
+ parseTypeAliases(tree) {
2368
+ const typeNodes = queryNodesByType(tree, "type_item");
2369
+ const nodes = [];
2370
+ for (const typeNode of typeNodes) {
2371
+ const nameNode = getChildByFieldName(typeNode, "name");
2372
+ if (nameNode === null) {
2373
+ continue;
2374
+ }
2375
+ const name = nameNode.text;
2376
+ const exported = hasVisibilityModifier(typeNode);
2377
+ const startLine = positionToLineNumber(typeNode.startPosition);
2378
+ const endLine = positionToLineNumber(typeNode.endPosition);
2379
+ const valueNode = getChildByFieldName(typeNode, "type");
2380
+ const signature = valueNode !== null ? `${name} = ${valueNode.text}` : name;
2381
+ nodes.push({
2382
+ type: "type",
2383
+ name,
2384
+ exported,
2385
+ startLine,
2386
+ endLine,
2387
+ signature
2388
+ });
2389
+ }
2390
+ return nodes;
2391
+ }
2392
+ /**
2393
+ * Parse constants and statics
2394
+ */
2395
+ parseConstants(tree) {
2396
+ const constNodes = queryNodesByType(tree, ["const_item", "static_item"]);
2397
+ const nodes = [];
2398
+ for (const constNode of constNodes) {
2399
+ const nameNode = getChildByFieldName(constNode, "name");
2400
+ if (nameNode === null) {
2401
+ continue;
2402
+ }
2403
+ const name = nameNode.text;
2404
+ const exported = hasVisibilityModifier(constNode);
2405
+ const startLine = positionToLineNumber(constNode.startPosition);
2406
+ const endLine = positionToLineNumber(constNode.endPosition);
2407
+ const typeNode = getChildByFieldName(constNode, "type");
2408
+ const signature = typeNode !== null ? `${name}: ${typeNode.text}` : name;
2409
+ nodes.push({
2410
+ type: "const",
2411
+ name,
2412
+ exported,
2413
+ startLine,
2414
+ endLine,
2415
+ signature
2416
+ });
2417
+ }
2418
+ return nodes;
2419
+ }
2420
+ /**
2421
+ * Parse impl blocks and attach methods to corresponding structs
2422
+ */
2423
+ parseImplBlocks(tree, nodes) {
2424
+ const implNodes = queryNodesByType(tree, "impl_item");
2425
+ for (const implNode of implNodes) {
2426
+ const typeNode = getChildByFieldName(implNode, "type");
2427
+ if (typeNode === null) {
2428
+ continue;
2429
+ }
2430
+ const typeName = typeNode.text;
2431
+ const methods = this.extractImplMethods(implNode);
2432
+ const structNode = nodes.find(
2433
+ (node) => node.type === "class" && node.name === typeName
2434
+ );
2435
+ if (structNode !== void 0 && structNode.methods !== void 0) {
2436
+ structNode.methods.push(...methods);
2437
+ }
2438
+ }
2439
+ }
2440
+ /**
2441
+ * Extract methods from trait definition
2442
+ */
2443
+ extractTraitMethods(traitNode) {
2444
+ const methods = [];
2445
+ const bodyNode = getChildByFieldName(traitNode, "body");
2446
+ if (bodyNode === null) {
2447
+ return methods;
2448
+ }
2449
+ const functionSignatures = bodyNode.descendantsOfType("function_signature_item");
2450
+ for (const fnSigNode of functionSignatures) {
2451
+ const nameNode = getChildByFieldName(fnSigNode, "name");
2452
+ if (nameNode === null) {
2453
+ continue;
2454
+ }
2455
+ const name = nameNode.text;
2456
+ const async = isAsyncFunction(fnSigNode);
2457
+ const signature = getFunctionSignature(fnSigNode);
2458
+ const startLine = positionToLineNumber(fnSigNode.startPosition);
2459
+ const endLine = positionToLineNumber(fnSigNode.endPosition);
2460
+ methods.push({
2461
+ name,
2462
+ async,
2463
+ signature,
2464
+ startLine,
2465
+ endLine
2466
+ });
2467
+ }
2468
+ return methods;
2469
+ }
2470
+ /**
2471
+ * Extract methods from impl block
2472
+ */
2473
+ extractImplMethods(implNode) {
2474
+ const methods = [];
2475
+ const bodyNode = getChildByFieldName(implNode, "body");
2476
+ if (bodyNode === null) {
2477
+ return methods;
2478
+ }
2479
+ const functionItems = bodyNode.descendantsOfType("function_item");
2480
+ for (const fnNode of functionItems) {
2481
+ const nameNode = getChildByFieldName(fnNode, "name");
2482
+ if (nameNode === null) {
2483
+ continue;
2484
+ }
2485
+ const name = nameNode.text;
2486
+ const async = isAsyncFunction(fnNode);
2487
+ const signature = getFunctionSignature(fnNode);
2488
+ const startLine = positionToLineNumber(fnNode.startPosition);
2489
+ const endLine = positionToLineNumber(fnNode.endPosition);
2490
+ methods.push({
2491
+ name,
2492
+ async,
2493
+ signature,
2494
+ startLine,
2495
+ endLine
2496
+ });
2497
+ }
2498
+ return methods;
2499
+ }
2500
+ /**
2501
+ * Parse import path into source and specifiers
2502
+ * Examples:
2503
+ * - "std::collections::HashMap" -> { source: "std::collections", specifiers: ["HashMap"] }
2504
+ * - "crate::utils::*" -> { source: "crate::utils", specifiers: ["*"] }
2505
+ * - "super::Type" -> { source: "super", specifiers: ["Type"] }
2506
+ */
2507
+ parseImportPath(importPath) {
2508
+ const path3 = importPath.trim();
2509
+ if (path3.includes("::*")) {
2510
+ const source = path3.replace("::*", "");
2511
+ return { source, specifiers: ["*"] };
2512
+ }
2513
+ const scopedMatch = path3.match(/^(.+)::\{(.+)\}$/);
2514
+ if (scopedMatch !== null) {
2515
+ const source = scopedMatch[1] ?? "";
2516
+ const specifiersStr = scopedMatch[2] ?? "";
2517
+ const specifiers = specifiersStr.split(",").map((s) => s.trim());
2518
+ return { source, specifiers };
2519
+ }
2520
+ const parts = path3.split("::");
2521
+ if (parts.length > 1) {
2522
+ const specifiers = [parts[parts.length - 1] ?? ""];
2523
+ const source = parts.slice(0, -1).join("::");
2524
+ return { source, specifiers };
2525
+ }
2526
+ return { source: "", specifiers: [path3] };
2527
+ }
2528
+ };
2529
+
2530
+ // src/analysis/go-ast-parser.ts
2531
+ var GoASTParser = class {
2532
+ /**
2533
+ * Parse Go code into CodeNode array
2534
+ * @param code Go source code
2535
+ * @param filePath File path for error context
2536
+ * @returns Array of CodeNode objects representing Go constructs
2537
+ */
2538
+ parse(code, _filePath) {
2539
+ try {
2540
+ const tree = parseGoCode(code);
2541
+ if (tree === null) {
2542
+ return [];
2543
+ }
2544
+ const nodes = [];
2545
+ const functions = this.parseFunctions(tree);
2546
+ nodes.push(...functions);
2547
+ const structs = this.parseStructs(tree);
2548
+ nodes.push(...structs);
2549
+ const interfaces = this.parseInterfaces(tree);
2550
+ nodes.push(...interfaces);
2551
+ const types = this.parseTypeAliases(tree);
2552
+ nodes.push(...types);
2553
+ const constants = this.parseConstants(tree);
2554
+ nodes.push(...constants);
2555
+ this.parseMethods(tree, nodes);
2556
+ return nodes;
2557
+ } catch {
2558
+ return [];
2559
+ }
2560
+ }
2561
+ /**
2562
+ * Extract imports from Go code
2563
+ * @param code Go source code
2564
+ * @returns Array of ImportInfo objects
2565
+ */
2566
+ extractImports(code) {
2567
+ try {
2568
+ const tree = parseGoCode(code);
2569
+ if (tree === null) {
2570
+ return [];
2571
+ }
2572
+ const imports = [];
2573
+ const importDecls = queryNodesByType(tree, "import_declaration");
2574
+ for (const importDecl of importDecls) {
2575
+ const importSpecs = importDecl.descendantsOfType("import_spec");
2576
+ for (const spec of importSpecs) {
2577
+ const pathNode = getChildByFieldName(spec, "path");
2578
+ if (pathNode === null) {
2579
+ continue;
2580
+ }
2581
+ const stringContent = pathNode.descendantsOfType("interpreted_string_literal_content")[0];
2582
+ const path3 = stringContent !== void 0 ? stringContent.text : pathNode.text.replace(/"/g, "");
2583
+ if (path3 !== "") {
2584
+ imports.push({
2585
+ source: path3,
2586
+ specifiers: [],
2587
+ isType: false
2588
+ });
2589
+ }
2590
+ }
2591
+ }
2592
+ return imports;
2593
+ } catch {
2594
+ return [];
2595
+ }
2596
+ }
2597
+ /**
2598
+ * Parse function declarations
2599
+ */
2600
+ parseFunctions(tree) {
2601
+ const functionNodes = queryNodesByType(tree, "function_declaration");
2602
+ const nodes = [];
2603
+ for (const fnNode of functionNodes) {
2604
+ const nameNode = getChildByFieldName(fnNode, "name");
2605
+ if (nameNode === null) {
2606
+ continue;
2607
+ }
2608
+ const name = nameNode.text;
2609
+ const exported = this.isExported(name);
2610
+ const startLine = positionToLineNumber(fnNode.startPosition);
2611
+ const endLine = positionToLineNumber(fnNode.endPosition);
2612
+ const signature = getFunctionSignature(fnNode);
2613
+ nodes.push({
2614
+ type: "function",
2615
+ name,
2616
+ exported,
2617
+ async: false,
2618
+ startLine,
2619
+ endLine,
2620
+ signature
2621
+ });
2622
+ }
2623
+ return nodes;
2624
+ }
2625
+ /**
2626
+ * Parse struct definitions
2627
+ */
2628
+ parseStructs(tree) {
2629
+ const typeDecls = queryNodesByType(tree, "type_declaration");
2630
+ const nodes = [];
2631
+ for (const typeDecl of typeDecls) {
2632
+ const typeSpec = getFirstChildOfType(typeDecl, "type_spec");
2633
+ if (typeSpec === null) {
2634
+ continue;
2635
+ }
2636
+ const nameNode = getChildByFieldName(typeSpec, "name");
2637
+ const typeNode = getChildByFieldName(typeSpec, "type");
2638
+ if (nameNode === null || typeNode === null) {
2639
+ continue;
2640
+ }
2641
+ if (typeNode.type !== "struct_type") {
2642
+ continue;
2643
+ }
2644
+ const name = nameNode.text;
2645
+ const exported = this.isExported(name);
2646
+ const startLine = positionToLineNumber(typeDecl.startPosition);
2647
+ const endLine = positionToLineNumber(typeDecl.endPosition);
2648
+ nodes.push({
2649
+ type: "class",
2650
+ name,
2651
+ exported,
2652
+ startLine,
2653
+ endLine,
2654
+ signature: name,
2655
+ methods: []
2656
+ });
2657
+ }
2658
+ return nodes;
2659
+ }
2660
+ /**
2661
+ * Parse interface definitions
2662
+ */
2663
+ parseInterfaces(tree) {
2664
+ const typeDecls = queryNodesByType(tree, "type_declaration");
2665
+ const nodes = [];
2666
+ for (const typeDecl of typeDecls) {
2667
+ const typeSpec = getFirstChildOfType(typeDecl, "type_spec");
2668
+ if (typeSpec === null) {
2669
+ continue;
2670
+ }
2671
+ const nameNode = getChildByFieldName(typeSpec, "name");
2672
+ const typeNode = getChildByFieldName(typeSpec, "type");
2673
+ if (nameNode === null || typeNode === null) {
2674
+ continue;
2675
+ }
2676
+ if (typeNode.type !== "interface_type") {
2677
+ continue;
2678
+ }
2679
+ const name = nameNode.text;
2680
+ const exported = this.isExported(name);
2681
+ const startLine = positionToLineNumber(typeDecl.startPosition);
2682
+ const endLine = positionToLineNumber(typeDecl.endPosition);
2683
+ const methods = this.extractInterfaceMethods(typeNode);
2684
+ nodes.push({
2685
+ type: "interface",
2686
+ name,
2687
+ exported,
2688
+ startLine,
2689
+ endLine,
2690
+ signature: name,
2691
+ methods
2692
+ });
2693
+ }
2694
+ return nodes;
2695
+ }
2696
+ /**
2697
+ * Parse type aliases
2698
+ */
2699
+ parseTypeAliases(tree) {
2700
+ const typeDecls = queryNodesByType(tree, "type_declaration");
2701
+ const nodes = [];
2702
+ for (const typeDecl of typeDecls) {
2703
+ const typeSpec = getFirstChildOfType(typeDecl, "type_spec");
2704
+ if (typeSpec === null) {
2705
+ continue;
2706
+ }
2707
+ const nameNode = getChildByFieldName(typeSpec, "name");
2708
+ const typeNode = getChildByFieldName(typeSpec, "type");
2709
+ if (nameNode === null || typeNode === null) {
2710
+ continue;
2711
+ }
2712
+ if (typeNode.type === "struct_type" || typeNode.type === "interface_type") {
2713
+ continue;
2714
+ }
2715
+ const name = nameNode.text;
2716
+ const exported = this.isExported(name);
2717
+ const startLine = positionToLineNumber(typeDecl.startPosition);
2718
+ const endLine = positionToLineNumber(typeDecl.endPosition);
2719
+ const signature = `${name} = ${typeNode.text}`;
2720
+ nodes.push({
2721
+ type: "type",
2722
+ name,
2723
+ exported,
2724
+ startLine,
2725
+ endLine,
2726
+ signature
2727
+ });
2728
+ }
2729
+ return nodes;
2730
+ }
2731
+ /**
2732
+ * Parse constants and variables
2733
+ */
2734
+ parseConstants(tree) {
2735
+ const nodes = [];
2736
+ const constDecls = queryNodesByType(tree, "const_declaration");
2737
+ for (const constDecl of constDecls) {
2738
+ const specs = constDecl.descendantsOfType("const_spec");
2739
+ for (const spec of specs) {
2740
+ const nameNode = getChildByFieldName(spec, "name");
2741
+ if (nameNode === null) {
2742
+ continue;
2743
+ }
2744
+ const name = nameNode.text;
2745
+ const exported = this.isExported(name);
2746
+ const startLine = positionToLineNumber(spec.startPosition);
2747
+ const endLine = positionToLineNumber(spec.endPosition);
2748
+ const typeNode = getChildByFieldName(spec, "type");
2749
+ const signature = typeNode !== null ? `${name}: ${typeNode.text}` : name;
2750
+ nodes.push({
2751
+ type: "const",
2752
+ name,
2753
+ exported,
2754
+ startLine,
2755
+ endLine,
2756
+ signature
2757
+ });
2758
+ }
2759
+ }
2760
+ const varDecls = queryNodesByType(tree, "var_declaration");
2761
+ for (const varDecl of varDecls) {
2762
+ const specs = varDecl.descendantsOfType("var_spec");
2763
+ for (const spec of specs) {
2764
+ const nameNode = getChildByFieldName(spec, "name");
2765
+ if (nameNode === null) {
2766
+ continue;
2767
+ }
2768
+ const name = nameNode.text;
2769
+ const exported = this.isExported(name);
2770
+ const startLine = positionToLineNumber(spec.startPosition);
2771
+ const endLine = positionToLineNumber(spec.endPosition);
2772
+ const typeNode = getChildByFieldName(spec, "type");
2773
+ const signature = typeNode !== null ? `${name}: ${typeNode.text}` : name;
2774
+ nodes.push({
2775
+ type: "const",
2776
+ name,
2777
+ exported,
2778
+ startLine,
2779
+ endLine,
2780
+ signature
2781
+ });
2782
+ }
2783
+ }
2784
+ return nodes;
2785
+ }
2786
+ /**
2787
+ * Parse methods and attach to corresponding structs
2788
+ */
2789
+ parseMethods(tree, nodes) {
2790
+ const methodNodes = queryNodesByType(tree, "method_declaration");
2791
+ for (const methodNode of methodNodes) {
2792
+ const receiverType = this.getReceiverType(methodNode);
2793
+ if (receiverType === null) {
2794
+ continue;
2795
+ }
2796
+ const nameNode = getChildByFieldName(methodNode, "name");
2797
+ if (nameNode === null) {
2798
+ continue;
2799
+ }
2800
+ const name = nameNode.text;
2801
+ const signature = getFunctionSignature(methodNode);
2802
+ const startLine = positionToLineNumber(methodNode.startPosition);
2803
+ const endLine = positionToLineNumber(methodNode.endPosition);
2804
+ const structNode = nodes.find(
2805
+ (node) => node.type === "class" && node.name === receiverType
2806
+ );
2807
+ if (structNode !== void 0 && structNode.methods !== void 0) {
2808
+ structNode.methods.push({
2809
+ name,
2810
+ async: false,
2811
+ signature,
2812
+ startLine,
2813
+ endLine
2814
+ });
2815
+ }
2816
+ }
2817
+ }
2818
+ /**
2819
+ * Extract methods from interface definition
2820
+ */
2821
+ extractInterfaceMethods(interfaceNode) {
2822
+ const methods = [];
2823
+ const methodElems = interfaceNode.descendantsOfType("method_elem");
2824
+ for (const methodElem of methodElems) {
2825
+ const nameNode = getChildByFieldName(methodElem, "name");
2826
+ if (nameNode === null) {
2827
+ continue;
2828
+ }
2829
+ const name = nameNode.text;
2830
+ const signature = getFunctionSignature(methodElem);
2831
+ const startLine = positionToLineNumber(methodElem.startPosition);
2832
+ const endLine = positionToLineNumber(methodElem.endPosition);
2833
+ methods.push({
2834
+ name,
2835
+ async: false,
2836
+ signature,
2837
+ startLine,
2838
+ endLine
2839
+ });
2840
+ }
2841
+ return methods;
2842
+ }
2843
+ /**
2844
+ * Get the receiver type name for a method
2845
+ */
2846
+ getReceiverType(methodNode) {
2847
+ const receiverNode = getChildByFieldName(methodNode, "receiver");
2848
+ if (receiverNode === null) {
2849
+ return null;
2850
+ }
2851
+ const paramDecl = getFirstChildOfType(receiverNode, "parameter_declaration");
2852
+ if (paramDecl === null) {
2853
+ return null;
2854
+ }
2855
+ const typeNode = getChildByFieldName(paramDecl, "type");
2856
+ if (typeNode === null) {
2857
+ return null;
2858
+ }
2859
+ if (typeNode.type === "pointer_type") {
2860
+ const innerType = typeNode.children.find(
2861
+ (child) => child.type === "type_identifier"
2862
+ );
2863
+ return innerType !== void 0 ? innerType.text : null;
2864
+ }
2865
+ if (typeNode.type === "type_identifier") {
2866
+ return typeNode.text;
2867
+ }
2868
+ return null;
2869
+ }
2870
+ /**
2871
+ * Check if a name is exported (starts with uppercase letter)
2872
+ */
2873
+ isExported(name) {
2874
+ if (name.length === 0) {
2875
+ return false;
2876
+ }
2877
+ const firstChar = name[0];
2878
+ if (firstChar === void 0) {
2879
+ return false;
2880
+ }
2881
+ return firstChar === firstChar.toUpperCase();
2882
+ }
2883
+ };
2884
+
2885
+ // src/analysis/parser-factory.ts
2886
+ import path2 from "path";
2887
+
2888
+ // src/analysis/python-ast-parser.ts
2889
+ var PythonASTParser = class {
2890
+ constructor(bridge) {
2891
+ this.bridge = bridge;
2892
+ }
2893
+ async parse(code, filePath) {
2894
+ const result = await this.bridge.parsePython(code, filePath);
2895
+ return result.nodes.map((node) => {
2896
+ const codeNode = {
2897
+ type: node.type,
2898
+ name: node.name,
2899
+ exported: node.exported,
2900
+ startLine: node.startLine,
2901
+ endLine: node.endLine
2902
+ };
2903
+ if (node.async !== void 0) {
2904
+ codeNode.async = node.async;
2905
+ }
2906
+ if (node.signature !== void 0) {
2907
+ codeNode.signature = node.signature;
2908
+ }
2909
+ if (node.methods !== void 0) {
2910
+ codeNode.methods = node.methods;
2911
+ }
2912
+ return codeNode;
2913
+ });
2914
+ }
2915
+ };
2916
+
2917
+ // src/analysis/parser-factory.ts
2918
+ var ParserFactory = class {
2919
+ constructor(pythonBridge) {
2920
+ this.pythonBridge = pythonBridge;
2921
+ }
2922
+ async parseFile(filePath, code) {
2923
+ const ext = path2.extname(filePath);
2924
+ if ([".ts", ".tsx"].includes(ext)) {
2925
+ const parser = new ASTParser();
2926
+ return parser.parse(code, "typescript");
2927
+ }
2928
+ if ([".js", ".jsx"].includes(ext)) {
2929
+ const parser = new ASTParser();
2930
+ return parser.parse(code, "javascript");
2931
+ }
2932
+ if (ext === ".py") {
2933
+ if (!this.pythonBridge) {
2934
+ throw new Error("Python bridge not available for parsing Python files");
2935
+ }
2936
+ const parser = new PythonASTParser(this.pythonBridge);
2937
+ return await parser.parse(code, filePath);
2938
+ }
2939
+ if (ext === ".rs") {
2940
+ const parser = new RustASTParser();
2941
+ return parser.parse(code, filePath);
2942
+ }
2943
+ if (ext === ".go") {
2944
+ const parser = new GoASTParser();
2945
+ return parser.parse(code, filePath);
2946
+ }
2947
+ return [];
2948
+ }
2949
+ };
2950
+
2951
+ // src/services/code-graph.service.ts
2952
+ var CodeGraphService = class {
2953
+ dataDir;
2954
+ parser;
2955
+ parserFactory;
2956
+ graphCache;
2957
+ constructor(dataDir, pythonBridge) {
2958
+ this.dataDir = dataDir;
2959
+ this.parser = new ASTParser();
2960
+ this.parserFactory = new ParserFactory(pythonBridge);
2961
+ this.graphCache = /* @__PURE__ */ new Map();
2962
+ }
2963
+ /**
2964
+ * Build a code graph from source files.
2965
+ */
2966
+ async buildGraph(files) {
2967
+ const graph = new CodeGraph();
2968
+ for (const file of files) {
2969
+ const ext = file.path.split(".").pop() ?? "";
2970
+ if (!["ts", "tsx", "js", "jsx", "py", "rs", "go"].includes(ext)) continue;
2971
+ const nodes = await this.parserFactory.parseFile(file.path, file.content);
2972
+ graph.addNodes(nodes, file.path);
2973
+ if (ext === "rs") {
2974
+ const rustParser = new RustASTParser();
2975
+ const imports = rustParser.extractImports(file.content);
2976
+ for (const imp of imports) {
2977
+ if (!imp.isType) {
2978
+ graph.addImport(file.path, imp.source, imp.specifiers);
2979
+ }
2980
+ }
2981
+ } else if (ext === "go") {
2982
+ const goParser = new GoASTParser();
2983
+ const imports = goParser.extractImports(file.content);
2984
+ for (const imp of imports) {
2985
+ if (!imp.isType) {
2986
+ graph.addImport(file.path, imp.source, imp.specifiers);
2987
+ }
2988
+ }
2989
+ } else if (ext !== "py") {
2990
+ const imports = this.parser.extractImports(file.content);
2991
+ for (const imp of imports) {
2992
+ if (!imp.isType) {
2993
+ graph.addImport(file.path, imp.source, imp.specifiers);
2994
+ }
2995
+ }
2996
+ }
2997
+ for (const node of nodes) {
2998
+ const lines = file.content.split("\n");
2999
+ if (node.type === "function") {
3000
+ const functionCode = lines.slice(node.startLine - 1, node.endLine).join("\n");
3001
+ graph.analyzeCallRelationships(functionCode, file.path, node.name);
3002
+ } else if (node.type === "class" && node.methods !== void 0) {
3003
+ for (const method of node.methods) {
3004
+ const methodCode = lines.slice(method.startLine - 1, method.endLine).join("\n");
3005
+ graph.analyzeCallRelationships(methodCode, file.path, `${node.name}.${method.name}`);
3006
+ }
3007
+ }
3008
+ }
3009
+ }
3010
+ return graph;
3011
+ }
3012
+ /**
3013
+ * Save a code graph for a store.
3014
+ */
3015
+ async saveGraph(storeId, graph) {
3016
+ const graphPath = this.getGraphPath(storeId);
3017
+ await mkdir4(dirname3(graphPath), { recursive: true });
3018
+ const serialized = graph.toJSON();
3019
+ await writeFile3(graphPath, JSON.stringify(serialized, null, 2));
3020
+ }
3021
+ /**
3022
+ * Load a code graph for a store.
3023
+ * Returns undefined if no graph exists.
3024
+ */
3025
+ async loadGraph(storeId) {
3026
+ const cached = this.graphCache.get(storeId);
3027
+ if (cached) return cached;
3028
+ const graphPath = this.getGraphPath(storeId);
3029
+ try {
3030
+ const content = await readFile4(graphPath, "utf-8");
3031
+ const parsed = JSON.parse(content);
3032
+ if (!this.isSerializedGraph(parsed)) {
3033
+ return void 0;
3034
+ }
3035
+ const serialized = parsed;
3036
+ const graph = new CodeGraph();
3037
+ for (const node of serialized.nodes) {
3038
+ const nodeType = this.validateNodeType(node.type);
3039
+ if (!nodeType) continue;
3040
+ if (nodeType === "method") {
3041
+ const graphNode = {
3042
+ id: node.id,
3043
+ file: node.file,
3044
+ type: "method",
3045
+ name: node.name,
3046
+ exported: node.exported,
3047
+ startLine: node.startLine,
3048
+ endLine: node.endLine
3049
+ };
3050
+ if (node.signature !== void 0) {
3051
+ graphNode.signature = node.signature;
3052
+ }
3053
+ graph.addGraphNode(graphNode);
3054
+ continue;
3055
+ }
3056
+ const codeNode = {
3057
+ type: nodeType,
3058
+ name: node.name,
3059
+ exported: node.exported,
3060
+ startLine: node.startLine,
3061
+ endLine: node.endLine
3062
+ };
3063
+ if (node.signature !== void 0) {
3064
+ codeNode.signature = node.signature;
3065
+ }
3066
+ graph.addNodes([codeNode], node.file);
3067
+ }
3068
+ for (const edge of serialized.edges) {
3069
+ const edgeType = this.validateEdgeType(edge.type);
3070
+ if (!edgeType) continue;
3071
+ graph.addEdge({
3072
+ from: edge.from,
3073
+ to: edge.to,
3074
+ type: edgeType,
3075
+ confidence: edge.confidence
3076
+ });
3077
+ }
3078
+ this.graphCache.set(storeId, graph);
3079
+ return graph;
3080
+ } catch {
3081
+ return void 0;
3082
+ }
3083
+ }
3084
+ /**
3085
+ * Get usage stats for a code element.
3086
+ */
3087
+ getUsageStats(graph, filePath, symbolName) {
3088
+ const nodeId = `${filePath}:${symbolName}`;
3089
+ return {
3090
+ calledBy: graph.getCalledByCount(nodeId),
3091
+ calls: graph.getCallsCount(nodeId)
3092
+ };
3093
+ }
3094
+ /**
3095
+ * Get related code (callers and callees) for a code element.
3096
+ */
3097
+ getRelatedCode(graph, filePath, symbolName) {
3098
+ const nodeId = `${filePath}:${symbolName}`;
3099
+ const related = [];
3100
+ const incoming = graph.getIncomingEdges(nodeId);
3101
+ for (const edge of incoming) {
3102
+ if (edge.type === "calls") {
3103
+ related.push({ id: edge.from, relationship: "calls this" });
3104
+ }
3105
+ }
3106
+ const outgoing = graph.getEdges(nodeId);
3107
+ for (const edge of outgoing) {
3108
+ if (edge.type === "calls") {
3109
+ related.push({ id: edge.to, relationship: "called by this" });
3110
+ }
3111
+ }
3112
+ return related;
3113
+ }
3114
+ /**
3115
+ * Clear cached graphs.
3116
+ */
3117
+ clearCache() {
3118
+ this.graphCache.clear();
3119
+ }
3120
+ getGraphPath(storeId) {
3121
+ return join4(this.dataDir, "graphs", `${storeId}.json`);
3122
+ }
3123
+ /**
3124
+ * Type guard for SerializedGraph structure.
3125
+ */
3126
+ isSerializedGraph(value) {
3127
+ if (typeof value !== "object" || value === null) return false;
3128
+ if (!("nodes" in value) || !("edges" in value)) return false;
3129
+ const obj = value;
3130
+ return Array.isArray(obj.nodes) && Array.isArray(obj.edges);
3131
+ }
3132
+ /**
3133
+ * Type guard for valid node types.
3134
+ */
3135
+ isValidNodeType(type) {
3136
+ return ["function", "class", "interface", "type", "const", "method"].includes(type);
3137
+ }
3138
+ /**
3139
+ * Validate and return a node type, or undefined if invalid.
3140
+ */
3141
+ validateNodeType(type) {
3142
+ if (this.isValidNodeType(type)) {
3143
+ return type;
3144
+ }
3145
+ return void 0;
3146
+ }
3147
+ /**
3148
+ * Type guard for valid edge types.
3149
+ */
3150
+ isValidEdgeType(type) {
3151
+ return ["calls", "imports", "extends", "implements"].includes(type);
3152
+ }
3153
+ /**
3154
+ * Validate and return an edge type, or undefined if invalid.
3155
+ */
3156
+ validateEdgeType(type) {
3157
+ if (this.isValidEdgeType(type)) {
3158
+ return type;
3159
+ }
3160
+ return void 0;
3161
+ }
3162
+ };
3163
+
3164
+ // src/db/lance.ts
3165
+ import * as lancedb from "@lancedb/lancedb";
3166
+ var LanceStore = class {
3167
+ connection = null;
3168
+ tables = /* @__PURE__ */ new Map();
3169
+ dataDir;
3170
+ constructor(dataDir) {
3171
+ this.dataDir = dataDir;
3172
+ }
3173
+ async initialize(storeId) {
3174
+ if (this.connection === null) {
3175
+ this.connection = await lancedb.connect(this.dataDir);
3176
+ }
3177
+ const tableName = this.getTableName(storeId);
3178
+ const tableNames = await this.connection.tableNames();
3179
+ if (!tableNames.includes(tableName)) {
3180
+ const table = await this.connection.createTable(tableName, [
3181
+ {
3182
+ id: "__init__",
3183
+ content: "",
3184
+ vector: new Array(384).fill(0),
3185
+ metadata: "{}"
3186
+ }
3187
+ ]);
3188
+ await table.delete('id = "__init__"');
3189
+ this.tables.set(tableName, table);
3190
+ } else {
3191
+ const table = await this.connection.openTable(tableName);
3192
+ this.tables.set(tableName, table);
3193
+ }
3194
+ }
3195
+ async addDocuments(storeId, documents) {
3196
+ const table = await this.getTable(storeId);
3197
+ const lanceDocuments = documents.map((doc) => ({
3198
+ id: doc.id,
3199
+ content: doc.content,
3200
+ vector: [...doc.vector],
3201
+ metadata: JSON.stringify(doc.metadata)
3202
+ }));
3203
+ await table.add(lanceDocuments);
3204
+ }
3205
+ async deleteDocuments(storeId, documentIds) {
3206
+ const table = await this.getTable(storeId);
3207
+ const idList = documentIds.map((id) => `"${id}"`).join(", ");
3208
+ await table.delete(`id IN (${idList})`);
3209
+ }
3210
+ async search(storeId, vector, limit, threshold) {
3211
+ const table = await this.getTable(storeId);
3212
+ let query = table.vectorSearch(vector).limit(limit);
3213
+ if (threshold !== void 0) {
3214
+ query = query.distanceType("cosine");
3215
+ }
3216
+ const results = await query.toArray();
3217
+ return results.filter((r) => {
3218
+ if (threshold === void 0) return true;
3219
+ const score = 1 - r._distance;
3220
+ return score >= threshold;
3221
+ }).map((r) => ({
3222
+ id: createDocumentId(r.id),
3223
+ content: r.content,
3224
+ score: 1 - r._distance,
3225
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
3226
+ metadata: JSON.parse(r.metadata)
3227
+ }));
3228
+ }
3229
+ async createFtsIndex(storeId) {
3230
+ const table = await this.getTable(storeId);
3231
+ await table.createIndex("content", {
3232
+ config: lancedb.Index.fts()
3233
+ });
3234
+ }
3235
+ async fullTextSearch(storeId, query, limit) {
3236
+ const table = await this.getTable(storeId);
3237
+ try {
3238
+ const results = await table.search(query, "fts").limit(limit).toArray();
3239
+ return results.map((r) => ({
3240
+ id: createDocumentId(r.id),
3241
+ content: r.content,
3242
+ score: r.score,
3243
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
3244
+ metadata: JSON.parse(r.metadata)
3245
+ }));
3246
+ } catch {
3247
+ return [];
3248
+ }
3249
+ }
3250
+ async deleteStore(storeId) {
3251
+ const tableName = this.getTableName(storeId);
3252
+ if (this.connection !== null) {
3253
+ await this.connection.dropTable(tableName);
3254
+ this.tables.delete(tableName);
3255
+ }
3256
+ }
3257
+ getTableName(storeId) {
3258
+ return `documents_${storeId}`;
3259
+ }
3260
+ async getTable(storeId) {
3261
+ const tableName = this.getTableName(storeId);
3262
+ let table = this.tables.get(tableName);
3263
+ if (table === void 0) {
3264
+ await this.initialize(storeId);
3265
+ table = this.tables.get(tableName);
3266
+ }
3267
+ if (table === void 0) {
3268
+ throw new Error(`Table not found for store: ${storeId}`);
3269
+ }
3270
+ return table;
3271
+ }
3272
+ };
3273
+
3274
+ // src/db/embeddings.ts
3275
+ import { pipeline, env } from "@huggingface/transformers";
3276
+ import { homedir as homedir2 } from "os";
3277
+ import { join as join5 } from "path";
3278
+ env.cacheDir = join5(homedir2(), ".cache", "huggingface-transformers");
3279
+ var EmbeddingEngine = class {
3280
+ extractor = null;
3281
+ modelName;
3282
+ dimensions;
3283
+ constructor(modelName = "Xenova/all-MiniLM-L6-v2", dimensions = 384) {
3284
+ this.modelName = modelName;
3285
+ this.dimensions = dimensions;
3286
+ }
3287
+ async initialize() {
3288
+ if (this.extractor !== null) return;
3289
+ this.extractor = await pipeline("feature-extraction", this.modelName, {
3290
+ dtype: "fp32"
3291
+ });
3292
+ }
3293
+ async embed(text) {
3294
+ if (this.extractor === null) {
3295
+ await this.initialize();
3296
+ }
3297
+ if (this.extractor === null) {
3298
+ throw new Error("Failed to initialize embedding model");
3299
+ }
3300
+ const output = await this.extractor(text, {
3301
+ pooling: "mean",
3302
+ normalize: true
3303
+ });
3304
+ const result = Array.from(output.data);
3305
+ return result.map((v) => Number(v));
3306
+ }
3307
+ async embedBatch(texts) {
3308
+ const BATCH_SIZE = 32;
3309
+ const results = [];
3310
+ for (let i = 0; i < texts.length; i += BATCH_SIZE) {
3311
+ const batch = texts.slice(i, i + BATCH_SIZE);
3312
+ const batchResults = await Promise.all(
3313
+ batch.map((text) => this.embed(text))
3314
+ );
3315
+ results.push(...batchResults);
3316
+ if (i + BATCH_SIZE < texts.length) {
3317
+ await new Promise((resolve3) => setTimeout(resolve3, 100));
3318
+ }
3319
+ }
3320
+ return results;
3321
+ }
3322
+ getDimensions() {
3323
+ return this.dimensions;
3324
+ }
3325
+ };
3326
+
3327
+ // src/crawl/bridge.ts
3328
+ import { spawn as spawn2 } from "child_process";
3329
+ import { createInterface } from "readline";
3330
+ import { randomUUID as randomUUID3 } from "crypto";
3331
+ import { ZodError } from "zod";
3332
+
3333
+ // src/crawl/schemas.ts
3334
+ import { z } from "zod";
3335
+ var CrawledLinkSchema = z.object({
3336
+ href: z.string(),
3337
+ text: z.string(),
3338
+ title: z.string().optional(),
3339
+ base_domain: z.string().optional(),
3340
+ head_data: z.unknown().optional(),
3341
+ head_extraction_status: z.unknown().optional(),
3342
+ head_extraction_error: z.unknown().optional(),
3343
+ intrinsic_score: z.number().optional(),
3344
+ contextual_score: z.unknown().optional(),
3345
+ total_score: z.unknown().optional()
3346
+ });
3347
+ var CrawlPageSchema = z.object({
3348
+ url: z.string(),
3349
+ title: z.string(),
3350
+ content: z.string(),
3351
+ links: z.array(z.string()),
3352
+ crawledAt: z.string()
3353
+ });
3354
+ var CrawlResultSchema = z.object({
3355
+ pages: z.array(CrawlPageSchema)
3356
+ });
3357
+ var HeadlessResultSchema = z.object({
3358
+ html: z.string(),
3359
+ markdown: z.string(),
3360
+ links: z.array(z.union([CrawledLinkSchema, z.string()]))
3361
+ });
3362
+ function validateHeadlessResult(data) {
3363
+ return HeadlessResultSchema.parse(data);
3364
+ }
3365
+ function validateCrawlResult(data) {
3366
+ return CrawlResultSchema.parse(data);
3367
+ }
3368
+ var MethodInfoSchema = z.object({
3369
+ name: z.string(),
3370
+ async: z.boolean(),
3371
+ signature: z.string(),
3372
+ startLine: z.number(),
3373
+ endLine: z.number(),
3374
+ calls: z.array(z.string())
3375
+ });
3376
+ var CodeNodeSchema = z.object({
3377
+ type: z.enum(["function", "class"]),
3378
+ name: z.string(),
3379
+ exported: z.boolean(),
3380
+ startLine: z.number(),
3381
+ endLine: z.number(),
3382
+ async: z.boolean().optional(),
3383
+ signature: z.string().optional(),
3384
+ calls: z.array(z.string()).optional(),
3385
+ methods: z.array(MethodInfoSchema).optional()
3386
+ });
3387
+ var ImportInfoSchema = z.object({
3388
+ source: z.string(),
3389
+ imported: z.string(),
3390
+ alias: z.string().optional().nullable()
3391
+ });
3392
+ var ParsePythonResultSchema = z.object({
3393
+ nodes: z.array(CodeNodeSchema),
3394
+ imports: z.array(ImportInfoSchema)
3395
+ });
3396
+ function validateParsePythonResult(data) {
3397
+ return ParsePythonResultSchema.parse(data);
3398
+ }
3399
+
3400
+ // src/crawl/bridge.ts
3401
+ var PythonBridge = class {
3402
+ process = null;
3403
+ pending = /* @__PURE__ */ new Map();
3404
+ stoppingIntentionally = false;
3405
+ start() {
3406
+ if (this.process) return Promise.resolve();
3407
+ this.process = spawn2("python3", ["python/crawl_worker.py"], {
3408
+ stdio: ["pipe", "pipe", "pipe"]
3409
+ });
3410
+ this.process.on("error", (err2) => {
3411
+ console.error("Python bridge process error:", err2);
3412
+ this.rejectAllPending(new Error(`Process error: ${err2.message}`));
3413
+ });
3414
+ this.process.on("exit", (code, signal) => {
3415
+ if (code !== 0 && code !== null) {
3416
+ console.error(`Python bridge process exited with code ${String(code)}`);
3417
+ this.rejectAllPending(new Error(`Process exited with code ${String(code)}`));
3418
+ } else if (signal && !this.stoppingIntentionally) {
3419
+ console.error(`Python bridge process killed with signal ${signal}`);
3420
+ this.rejectAllPending(new Error(`Process killed with signal ${signal}`));
3421
+ }
3422
+ this.process = null;
3423
+ this.stoppingIntentionally = false;
3424
+ });
3425
+ if (this.process.stderr) {
3426
+ const stderrRl = createInterface({ input: this.process.stderr });
3427
+ stderrRl.on("line", (line) => {
3428
+ console.error("Python bridge stderr:", line);
3429
+ });
3430
+ }
3431
+ if (this.process.stdout === null) {
3432
+ this.process = null;
3433
+ return Promise.reject(new Error("Python bridge process stdout is null"));
3434
+ }
3435
+ const rl = createInterface({ input: this.process.stdout });
3436
+ rl.on("line", (line) => {
3437
+ if (!line.trim().startsWith("{")) {
3438
+ return;
3439
+ }
3440
+ try {
3441
+ const response = JSON.parse(line);
3442
+ const pending = this.pending.get(response.id);
3443
+ if (pending !== void 0) {
3444
+ if (response.error !== void 0) {
3445
+ clearTimeout(pending.timeout);
3446
+ this.pending.delete(response.id);
3447
+ pending.reject(new Error(response.error.message));
3448
+ } else if (response.result !== void 0) {
3449
+ clearTimeout(pending.timeout);
3450
+ this.pending.delete(response.id);
3451
+ try {
3452
+ let validated;
3453
+ if (pending.method === "crawl") {
3454
+ validated = validateCrawlResult(response.result);
3455
+ } else if (pending.method === "fetch_headless") {
3456
+ validated = validateHeadlessResult(response.result);
3457
+ } else {
3458
+ validated = validateParsePythonResult(response.result);
3459
+ }
3460
+ pending.resolve(validated);
3461
+ } catch (error) {
3462
+ if (error instanceof ZodError) {
3463
+ console.error("Python bridge response validation failed:", error.issues);
3464
+ console.error("Original response:", JSON.stringify(response.result));
3465
+ pending.reject(new Error(`Invalid response format from Python bridge: ${error.message}`));
3466
+ } else {
3467
+ const errorMessage = error instanceof Error ? error.message : String(error);
3468
+ pending.reject(new Error(`Response validation error: ${errorMessage}`));
3469
+ }
3470
+ }
3471
+ }
3472
+ }
3473
+ } catch (err2) {
3474
+ console.error("Failed to parse JSON response from Python bridge:", err2, "Line:", line);
3475
+ }
3476
+ });
3477
+ return Promise.resolve();
3478
+ }
3479
+ async crawl(url, timeoutMs = 3e4) {
3480
+ if (!this.process) await this.start();
3481
+ const id = randomUUID3();
3482
+ const request = {
3483
+ jsonrpc: "2.0",
3484
+ id,
3485
+ method: "crawl",
3486
+ params: { url }
3487
+ };
3488
+ return new Promise((resolve3, reject) => {
3489
+ const timeout = setTimeout(() => {
3490
+ const pending = this.pending.get(id);
3491
+ if (pending) {
3492
+ this.pending.delete(id);
3493
+ reject(new Error(`Crawl timeout after ${String(timeoutMs)}ms for URL: ${url}`));
3494
+ }
3495
+ }, timeoutMs);
3496
+ this.pending.set(id, { resolve: resolve3, reject, timeout, method: "crawl" });
3497
+ if (this.process === null || this.process.stdin === null) {
3498
+ reject(new Error("Python bridge process not available"));
3499
+ return;
3500
+ }
3501
+ this.process.stdin.write(JSON.stringify(request) + "\n");
3502
+ });
3503
+ }
3504
+ async fetchHeadless(url, timeoutMs = 6e4) {
3505
+ if (!this.process) await this.start();
3506
+ const id = randomUUID3();
3507
+ const request = {
3508
+ jsonrpc: "2.0",
3509
+ id,
3510
+ method: "fetch_headless",
3511
+ params: { url }
3512
+ };
3513
+ return new Promise((resolve3, reject) => {
3514
+ const timeout = setTimeout(() => {
3515
+ const pending = this.pending.get(id);
3516
+ if (pending) {
3517
+ this.pending.delete(id);
3518
+ reject(new Error(`Headless fetch timeout after ${String(timeoutMs)}ms for URL: ${url}`));
3519
+ }
3520
+ }, timeoutMs);
3521
+ this.pending.set(id, { resolve: resolve3, reject, timeout, method: "fetch_headless" });
3522
+ if (this.process === null || this.process.stdin === null) {
3523
+ reject(new Error("Python bridge process not available"));
3524
+ return;
3525
+ }
3526
+ this.process.stdin.write(JSON.stringify(request) + "\n");
3527
+ });
3528
+ }
3529
+ async parsePython(code, filePath, timeoutMs = 1e4) {
3530
+ if (!this.process) await this.start();
3531
+ const id = randomUUID3();
3532
+ const request = {
3533
+ jsonrpc: "2.0",
3534
+ id,
3535
+ method: "parse_python",
3536
+ params: { code, filePath }
3537
+ };
3538
+ return new Promise((resolve3, reject) => {
3539
+ const timeout = setTimeout(() => {
3540
+ const pending = this.pending.get(id);
3541
+ if (pending) {
3542
+ this.pending.delete(id);
3543
+ reject(new Error(`Python parsing timeout after ${String(timeoutMs)}ms for file: ${filePath}`));
3544
+ }
3545
+ }, timeoutMs);
3546
+ this.pending.set(id, { resolve: resolve3, reject, timeout, method: "parse_python" });
3547
+ if (this.process === null || this.process.stdin === null) {
3548
+ reject(new Error("Python bridge process not available"));
3549
+ return;
3550
+ }
3551
+ this.process.stdin.write(JSON.stringify(request) + "\n");
3552
+ });
3553
+ }
3554
+ stop() {
3555
+ if (this.process) {
3556
+ this.stoppingIntentionally = true;
3557
+ this.rejectAllPending(new Error("Python bridge stopped"));
3558
+ this.process.kill();
3559
+ this.process = null;
3560
+ }
3561
+ return Promise.resolve();
3562
+ }
3563
+ rejectAllPending(error) {
3564
+ for (const pending of this.pending.values()) {
3565
+ clearTimeout(pending.timeout);
3566
+ pending.reject(error);
3567
+ }
3568
+ this.pending.clear();
3569
+ }
3570
+ };
3571
+
3572
+ // src/services/index.ts
3573
+ async function createServices(configPath, dataDir, projectRoot) {
3574
+ const config = new ConfigService(configPath, dataDir, projectRoot);
3575
+ const appConfig = await config.load();
3576
+ const resolvedDataDir = config.resolveDataDir();
3577
+ const lance = new LanceStore(resolvedDataDir);
3578
+ const embeddings = new EmbeddingEngine(
3579
+ appConfig.embedding.model,
3580
+ appConfig.embedding.dimensions
3581
+ );
3582
+ await embeddings.initialize();
3583
+ const store = new StoreService(resolvedDataDir);
3584
+ await store.initialize();
3585
+ const pythonBridge = new PythonBridge();
3586
+ await pythonBridge.start();
3587
+ const codeGraph = new CodeGraphService(resolvedDataDir, pythonBridge);
3588
+ const search = new SearchService(lance, embeddings, void 0, codeGraph);
3589
+ const index = new IndexService(lance, embeddings, { codeGraphService: codeGraph });
3590
+ return {
3591
+ config,
3592
+ store,
3593
+ search,
3594
+ index,
3595
+ lance,
3596
+ embeddings,
3597
+ codeGraph,
3598
+ pythonBridge
3599
+ };
3600
+ }
3601
+ async function destroyServices(services) {
3602
+ await services.pythonBridge.stop();
3603
+ }
3604
+
3605
+ export {
3606
+ createStoreId,
3607
+ createDocumentId,
3608
+ ok,
3609
+ err,
3610
+ extractRepoName,
3611
+ ASTParser,
3612
+ PythonBridge,
3613
+ JobService,
3614
+ createServices,
3615
+ destroyServices
3616
+ };
3617
+ //# sourceMappingURL=chunk-5QMHZUC4.js.map