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,1630 @@
1
+ # AI Agent-Optimized Search Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Transform semantic search from human-focused snippet delivery to AI agent-optimized knowledge retrieval with pattern detection, progressive context delivery, and agent feedback loops.
6
+
7
+ **Architecture:** Multi-phase enhancement preserving existing search core. Phase 1 adds agent-optimized output formats and progressive context APIs. Phase 2 builds static analysis infrastructure and code graph. Phase 3 implements pattern detection and mining. Phase 4 adds agent query understanding. Phase 5 creates feedback loops for continuous improvement.
8
+
9
+ **Tech Stack:** TypeScript, @babel/parser for AST, LanceDB for pattern storage, MCP (Model Context Protocol) for agent integration, existing Transformers.js embeddings
10
+
11
+ ---
12
+
13
+ ## Phase 1: Agent-Optimized Output Format (MVP)
14
+
15
+ ### Task 1.1: Enhanced Result Schema
16
+
17
+ **Goal:** Add structured code unit extraction to search results for AI agents.
18
+
19
+ **Files:**
20
+ - Modify: `src/types/search.ts`
21
+ - Modify: `src/services/search.service.ts`
22
+ - Create: `src/services/code-unit.service.ts`
23
+ - Create: `tests/services/code-unit.service.test.ts`
24
+
25
+ **Step 1: Write failing test for code unit extraction**
26
+
27
+ Create `tests/services/code-unit.service.test.ts`:
28
+
29
+ ```typescript
30
+ import { describe, it, expect } from 'vitest';
31
+ import { CodeUnitService } from '../src/services/code-unit.service.js';
32
+
33
+ describe('CodeUnitService', () => {
34
+ it('should extract full function from TypeScript code', () => {
35
+ const code = `
36
+ export function validateToken(token: string): boolean {
37
+ if (!token) return false;
38
+ return token.length > 0;
39
+ }
40
+
41
+ export function parseToken(token: string): object {
42
+ return JSON.parse(token);
43
+ }
44
+ `;
45
+
46
+ const service = new CodeUnitService();
47
+ const unit = service.extractCodeUnit(code, 'validateToken', 'typescript');
48
+
49
+ expect(unit).toBeDefined();
50
+ expect(unit.type).toBe('function');
51
+ expect(unit.name).toBe('validateToken');
52
+ expect(unit.signature).toBe('validateToken(token: string): boolean');
53
+ expect(unit.fullContent).toContain('export function validateToken');
54
+ expect(unit.startLine).toBe(2);
55
+ expect(unit.endLine).toBe(5);
56
+ });
57
+
58
+ it('should extract class with methods', () => {
59
+ const code = `
60
+ export class UserService {
61
+ constructor(private repo: UserRepo) {}
62
+
63
+ async create(data: CreateUserData): Promise<User> {
64
+ return this.repo.save(data);
65
+ }
66
+ }
67
+ `;
68
+
69
+ const service = new CodeUnitService();
70
+ const unit = service.extractCodeUnit(code, 'UserService', 'typescript');
71
+
72
+ expect(unit.type).toBe('class');
73
+ expect(unit.name).toBe('UserService');
74
+ expect(unit.fullContent).toContain('class UserService');
75
+ });
76
+ });
77
+ ```
78
+
79
+ **Step 2: Run test to verify it fails**
80
+
81
+ ```bash
82
+ npm run test code-unit.service.test.ts
83
+ ```
84
+
85
+ Expected: FAIL - "Cannot find module '../src/services/code-unit.service.js'"
86
+
87
+ **Step 3: Create CodeUnitService with minimal implementation**
88
+
89
+ Create `src/services/code-unit.service.ts`:
90
+
91
+ ```typescript
92
+ export interface CodeUnit {
93
+ type: 'function' | 'class' | 'interface' | 'type' | 'const' | 'documentation' | 'example';
94
+ name: string;
95
+ signature: string;
96
+ fullContent: string;
97
+ startLine: number;
98
+ endLine: number;
99
+ language: string;
100
+ }
101
+
102
+ export class CodeUnitService {
103
+ extractCodeUnit(code: string, symbolName: string, language: string): CodeUnit | undefined {
104
+ const lines = code.split('\n');
105
+
106
+ // Find the line containing the symbol
107
+ let startLine = -1;
108
+ let type: CodeUnit['type'] = 'function';
109
+
110
+ for (let i = 0; i < lines.length; i++) {
111
+ const line = lines[i] ?? '';
112
+
113
+ if (line.includes(`function ${symbolName}`)) {
114
+ startLine = i + 1; // 1-indexed
115
+ type = 'function';
116
+ break;
117
+ }
118
+
119
+ if (line.includes(`class ${symbolName}`)) {
120
+ startLine = i + 1;
121
+ type = 'class';
122
+ break;
123
+ }
124
+ }
125
+
126
+ if (startLine === -1) return undefined;
127
+
128
+ // Find end line (naive: next empty line or next top-level declaration)
129
+ let endLine = startLine;
130
+ let braceCount = 0;
131
+ let foundFirstBrace = false;
132
+
133
+ for (let i = startLine - 1; i < lines.length; i++) {
134
+ const line = lines[i] ?? '';
135
+
136
+ for (const char of line) {
137
+ if (char === '{') {
138
+ braceCount++;
139
+ foundFirstBrace = true;
140
+ }
141
+ if (char === '}') braceCount--;
142
+ }
143
+
144
+ if (foundFirstBrace && braceCount === 0) {
145
+ endLine = i + 1;
146
+ break;
147
+ }
148
+ }
149
+
150
+ const fullContent = lines.slice(startLine - 1, endLine).join('\n');
151
+
152
+ // Extract signature (first line, cleaned)
153
+ const firstLine = lines[startLine - 1] ?? '';
154
+ const signature = this.extractSignature(firstLine, symbolName, type);
155
+
156
+ return {
157
+ type,
158
+ name: symbolName,
159
+ signature,
160
+ fullContent,
161
+ startLine,
162
+ endLine,
163
+ language
164
+ };
165
+ }
166
+
167
+ private extractSignature(line: string, name: string, type: string): string {
168
+ // Remove 'export', 'async', trim whitespace
169
+ let sig = line.replace(/^\s*export\s+/, '').replace(/^\s*async\s+/, '').trim();
170
+
171
+ if (type === 'function') {
172
+ // Extract just "functionName(params): returnType"
173
+ const match = sig.match(/function\s+(\w+\([^)]*\):\s*\w+)/);
174
+ if (match && match[1]) return match[1];
175
+ }
176
+
177
+ if (type === 'class') {
178
+ return `class ${name}`;
179
+ }
180
+
181
+ return sig;
182
+ }
183
+ }
184
+ ```
185
+
186
+ **Step 4: Run test to verify it passes**
187
+
188
+ ```bash
189
+ npm run test code-unit.service.test.ts
190
+ ```
191
+
192
+ Expected: PASS
193
+
194
+ **Step 5: Add code unit to SearchResult type**
195
+
196
+ Modify `src/types/search.ts`:
197
+
198
+ ```typescript
199
+ import type { DocumentMetadata } from './document.js';
200
+ import type { StoreId } from './brands.js';
201
+
202
+ export interface CodeUnit {
203
+ type: 'function' | 'class' | 'interface' | 'type' | 'const' | 'documentation' | 'example';
204
+ name: string;
205
+ signature: string;
206
+ fullContent: string;
207
+ startLine: number;
208
+ endLine: number;
209
+ language: string;
210
+ }
211
+
212
+ export interface SearchResult {
213
+ readonly id: string;
214
+ readonly score: number;
215
+ readonly content: string;
216
+ readonly metadata: DocumentMetadata;
217
+ readonly highlight?: string | undefined;
218
+
219
+ // NEW: Structured code unit for AI agents
220
+ readonly codeUnit?: CodeUnit | undefined;
221
+ }
222
+
223
+ // ... rest of existing types
224
+ ```
225
+
226
+ **Step 6: Run typecheck**
227
+
228
+ ```bash
229
+ npm run typecheck
230
+ ```
231
+
232
+ Expected: PASS
233
+
234
+ **Step 7: Commit**
235
+
236
+ ```bash
237
+ git add src/services/code-unit.service.ts tests/services/code-unit.service.test.ts src/types/search.ts
238
+ git commit -m "feat(search): add code unit extraction service for AI agents"
239
+ ```
240
+
241
+ ---
242
+
243
+ ### Task 1.2: Progressive Context Layers
244
+
245
+ **Goal:** Implement three-tier context delivery (summary, contextual, full) for token budget optimization.
246
+
247
+ **Files:**
248
+ - Modify: `src/types/search.ts`
249
+ - Modify: `src/services/search.service.ts`
250
+ - Modify: `src/cli/commands/search.ts`
251
+ - Create: `tests/services/search.progressive-context.test.ts`
252
+
253
+ **Step 1: Write failing test for progressive context**
254
+
255
+ Create `tests/services/search.progressive-context.test.ts`:
256
+
257
+ ```typescript
258
+ import { describe, it, expect } from 'vitest';
259
+ import type { SearchResult } from '../src/types/search.js';
260
+
261
+ describe('Progressive Context', () => {
262
+ it('should return minimal summary by default', () => {
263
+ const result: SearchResult = {
264
+ id: 'test-1',
265
+ score: 0.95,
266
+ content: 'function code here...',
267
+ metadata: {
268
+ type: 'chunk',
269
+ storeId: 'test-store' as any,
270
+ path: 'src/auth.ts',
271
+ indexedAt: new Date(),
272
+ },
273
+ summary: {
274
+ type: 'function',
275
+ name: 'validateToken',
276
+ signature: 'validateToken(token: string): boolean',
277
+ purpose: 'Validates JWT token',
278
+ location: 'src/auth.ts:45',
279
+ relevanceReason: 'Matches query about token validation'
280
+ }
281
+ };
282
+
283
+ expect(result.summary).toBeDefined();
284
+ expect(result.context).toBeUndefined();
285
+ expect(result.full).toBeUndefined();
286
+ });
287
+
288
+ it('should include context when detail=contextual', () => {
289
+ // Test that context layer is populated
290
+ expect(true).toBe(true); // Placeholder until implemented
291
+ });
292
+ });
293
+ ```
294
+
295
+ **Step 2: Run test**
296
+
297
+ ```bash
298
+ npm run test search.progressive-context.test.ts
299
+ ```
300
+
301
+ Expected: FAIL - "Property 'summary' does not exist on type 'SearchResult'"
302
+
303
+ **Step 3: Add progressive context to SearchResult type**
304
+
305
+ Modify `src/types/search.ts`:
306
+
307
+ ```typescript
308
+ export interface ResultSummary {
309
+ readonly type: 'function' | 'class' | 'interface' | 'pattern' | 'documentation';
310
+ readonly name: string;
311
+ readonly signature: string;
312
+ readonly purpose: string;
313
+ readonly location: string;
314
+ readonly relevanceReason: string;
315
+ }
316
+
317
+ export interface ResultContext {
318
+ readonly interfaces: readonly string[];
319
+ readonly keyImports: readonly string[];
320
+ readonly relatedConcepts: readonly string[];
321
+ readonly usage: {
322
+ readonly calledBy: number;
323
+ readonly calls: number;
324
+ };
325
+ }
326
+
327
+ export interface ResultFull {
328
+ readonly completeCode: string;
329
+ readonly relatedCode: ReadonlyArray<{
330
+ readonly file: string;
331
+ readonly summary: string;
332
+ readonly relationship: string;
333
+ }>;
334
+ readonly documentation: string;
335
+ readonly tests?: string | undefined;
336
+ }
337
+
338
+ export interface SearchResult {
339
+ readonly id: string;
340
+ readonly score: number;
341
+ readonly content: string;
342
+ readonly metadata: DocumentMetadata;
343
+ readonly highlight?: string | undefined;
344
+ readonly codeUnit?: CodeUnit | undefined;
345
+
346
+ // NEW: Progressive context layers
347
+ readonly summary?: ResultSummary | undefined;
348
+ readonly context?: ResultContext | undefined;
349
+ readonly full?: ResultFull | undefined;
350
+ }
351
+
352
+ export type DetailLevel = 'minimal' | 'contextual' | 'full';
353
+
354
+ export interface SearchQuery {
355
+ readonly query: string;
356
+ readonly stores?: readonly StoreId[] | undefined;
357
+ readonly mode?: SearchMode | undefined;
358
+ readonly threshold?: number | undefined;
359
+ readonly limit?: number | undefined;
360
+ readonly filter?: Record<string, unknown> | undefined;
361
+ readonly includeContent?: boolean | undefined;
362
+ readonly contextLines?: number | undefined;
363
+
364
+ // NEW: Detail level for progressive context
365
+ readonly detail?: DetailLevel | undefined;
366
+ }
367
+ ```
368
+
369
+ **Step 4: Run typecheck**
370
+
371
+ ```bash
372
+ npm run typecheck
373
+ ```
374
+
375
+ Expected: PASS
376
+
377
+ **Step 5: Implement summary generation in SearchService**
378
+
379
+ Modify `src/services/search.service.ts`:
380
+
381
+ ```typescript
382
+ import { CodeUnitService } from './code-unit.service.js';
383
+
384
+ export class SearchService {
385
+ private readonly lanceStore: LanceStore;
386
+ private readonly embeddingEngine: EmbeddingEngine;
387
+ private readonly rrfConfig: RRFConfig;
388
+ private readonly codeUnitService: CodeUnitService;
389
+
390
+ constructor(
391
+ lanceStore: LanceStore,
392
+ embeddingEngine: EmbeddingEngine,
393
+ rrfConfig: RRFConfig = { k: 20, vectorWeight: 0.6, ftsWeight: 0.4 }
394
+ ) {
395
+ this.lanceStore = lanceStore;
396
+ this.embeddingEngine = embeddingEngine;
397
+ this.rrfConfig = rrfConfig;
398
+ this.codeUnitService = new CodeUnitService();
399
+ }
400
+
401
+ async search(query: SearchQuery): Promise<SearchResponse> {
402
+ const startTime = Date.now();
403
+ const mode = query.mode ?? 'hybrid';
404
+ const limit = query.limit ?? 10;
405
+ const stores = query.stores ?? [];
406
+ const detail = query.detail ?? 'minimal';
407
+
408
+ let allResults: SearchResult[] = [];
409
+
410
+ const fetchLimit = limit * 3;
411
+
412
+ if (mode === 'vector') {
413
+ allResults = await this.vectorSearch(query.query, stores, fetchLimit, query.threshold);
414
+ } else if (mode === 'fts') {
415
+ allResults = await this.ftsSearch(query.query, stores, fetchLimit);
416
+ } else {
417
+ allResults = await this.hybridSearch(query.query, stores, fetchLimit, query.threshold);
418
+ }
419
+
420
+ const dedupedResults = this.deduplicateBySource(allResults, query.query);
421
+
422
+ // Enhance results with progressive context
423
+ const enhancedResults = dedupedResults.slice(0, limit).map(r =>
424
+ this.addProgressiveContext(r, query.query, detail)
425
+ );
426
+
427
+ return {
428
+ query: query.query,
429
+ mode,
430
+ stores,
431
+ results: enhancedResults,
432
+ totalResults: enhancedResults.length,
433
+ timeMs: Date.now() - startTime,
434
+ };
435
+ }
436
+
437
+ private addProgressiveContext(
438
+ result: SearchResult,
439
+ query: string,
440
+ detail: DetailLevel
441
+ ): SearchResult {
442
+ const enhanced = { ...result };
443
+
444
+ // Layer 1: Always add summary
445
+ const path = result.metadata.path ?? result.metadata.url ?? 'unknown';
446
+ const fileType = result.metadata['fileType'] as string | undefined;
447
+
448
+ // Try to extract code unit
449
+ const codeUnit = this.extractCodeUnitFromResult(result);
450
+
451
+ enhanced.summary = {
452
+ type: this.inferType(fileType, codeUnit),
453
+ name: codeUnit?.name ?? this.extractSymbolName(result.content),
454
+ signature: codeUnit?.signature ?? '',
455
+ purpose: this.generatePurpose(result.content, query),
456
+ location: `${path}${codeUnit ? ':' + codeUnit.startLine : ''}`,
457
+ relevanceReason: this.generateRelevanceReason(result, query)
458
+ };
459
+
460
+ // Layer 2: Add context if requested
461
+ if (detail === 'contextual' || detail === 'full') {
462
+ enhanced.context = {
463
+ interfaces: this.extractInterfaces(result.content),
464
+ keyImports: this.extractImports(result.content),
465
+ relatedConcepts: this.extractConcepts(result.content, query),
466
+ usage: {
467
+ calledBy: 0, // TODO: Implement from code graph
468
+ calls: 0
469
+ }
470
+ };
471
+ }
472
+
473
+ // Layer 3: Add full context if requested
474
+ if (detail === 'full') {
475
+ enhanced.full = {
476
+ completeCode: codeUnit?.fullContent ?? result.content,
477
+ relatedCode: [], // TODO: Implement from code graph
478
+ documentation: this.extractDocumentation(result.content),
479
+ tests: undefined
480
+ };
481
+ }
482
+
483
+ return enhanced;
484
+ }
485
+
486
+ private extractCodeUnitFromResult(result: SearchResult): CodeUnit | undefined {
487
+ const path = result.metadata.path;
488
+ if (!path) return undefined;
489
+
490
+ const ext = path.split('.').pop() ?? '';
491
+ const language = ext === 'ts' || ext === 'tsx' ? 'typescript' :
492
+ ext === 'js' || ext === 'jsx' ? 'javascript' : ext;
493
+
494
+ // Try to find a symbol name in the content
495
+ const symbolName = this.extractSymbolName(result.content);
496
+ if (!symbolName) return undefined;
497
+
498
+ return this.codeUnitService.extractCodeUnit(result.content, symbolName, language);
499
+ }
500
+
501
+ private extractSymbolName(content: string): string {
502
+ // Extract function or class name
503
+ const funcMatch = content.match(/(?:export\s+)?(?:async\s+)?function\s+(\w+)/);
504
+ if (funcMatch && funcMatch[1]) return funcMatch[1];
505
+
506
+ const classMatch = content.match(/(?:export\s+)?class\s+(\w+)/);
507
+ if (classMatch && classMatch[1]) return classMatch[1];
508
+
509
+ const constMatch = content.match(/(?:export\s+)?const\s+(\w+)/);
510
+ if (constMatch && constMatch[1]) return constMatch[1];
511
+
512
+ return '';
513
+ }
514
+
515
+ private inferType(fileType: string | undefined, codeUnit: CodeUnit | undefined): ResultSummary['type'] {
516
+ if (codeUnit) return codeUnit.type as ResultSummary['type'];
517
+ if (fileType === 'documentation' || fileType === 'documentation-primary') return 'documentation';
518
+ return 'function';
519
+ }
520
+
521
+ private generatePurpose(content: string, query: string): string {
522
+ // Extract first line of JSDoc comment if present
523
+ const docMatch = content.match(/\/\*\*\s*\n\s*\*\s*([^\n]+)/);
524
+ if (docMatch && docMatch[1]) return docMatch[1].trim();
525
+
526
+ // Fallback: first line that looks like a purpose
527
+ const lines = content.split('\n');
528
+ for (const line of lines) {
529
+ const cleaned = line.trim();
530
+ if (cleaned.length > 20 && cleaned.length < 100 && !cleaned.startsWith('//')) {
531
+ return cleaned;
532
+ }
533
+ }
534
+
535
+ return 'Code related to query';
536
+ }
537
+
538
+ private generateRelevanceReason(result: SearchResult, query: string): string {
539
+ const queryTerms = query.toLowerCase().split(/\s+/).filter(t => t.length > 2);
540
+ const contentLower = result.content.toLowerCase();
541
+
542
+ const matchedTerms = queryTerms.filter(term => contentLower.includes(term));
543
+
544
+ if (matchedTerms.length > 0) {
545
+ return `Matches: ${matchedTerms.join(', ')}`;
546
+ }
547
+
548
+ return 'Semantically similar to query';
549
+ }
550
+
551
+ private extractInterfaces(content: string): string[] {
552
+ const interfaces: string[] = [];
553
+ const matches = content.matchAll(/interface\s+(\w+)/g);
554
+ for (const match of matches) {
555
+ if (match[1]) interfaces.push(match[1]);
556
+ }
557
+ return interfaces;
558
+ }
559
+
560
+ private extractImports(content: string): string[] {
561
+ const imports: string[] = [];
562
+ const matches = content.matchAll(/import\s+.*?from\s+['"]([^'"]+)['"]/g);
563
+ for (const match of matches) {
564
+ if (match[1]) imports.push(match[1]);
565
+ }
566
+ return imports.slice(0, 5); // Top 5
567
+ }
568
+
569
+ private extractConcepts(content: string, query: string): string[] {
570
+ // Simple keyword extraction
571
+ const words = content.toLowerCase().match(/\b[a-z]{4,}\b/g) ?? [];
572
+ const frequency = new Map<string, number>();
573
+
574
+ for (const word of words) {
575
+ frequency.set(word, (frequency.get(word) ?? 0) + 1);
576
+ }
577
+
578
+ return Array.from(frequency.entries())
579
+ .sort((a, b) => b[1] - a[1])
580
+ .slice(0, 5)
581
+ .map(([word]) => word);
582
+ }
583
+
584
+ private extractDocumentation(content: string): string {
585
+ const docMatch = content.match(/\/\*\*([\s\S]*?)\*\//);
586
+ if (docMatch && docMatch[1]) {
587
+ return docMatch[1]
588
+ .split('\n')
589
+ .map(line => line.replace(/^\s*\*\s?/, '').trim())
590
+ .filter(line => line.length > 0)
591
+ .join('\n');
592
+ }
593
+ return '';
594
+ }
595
+
596
+ // ... rest of existing methods
597
+ }
598
+ ```
599
+
600
+ **Step 6: Run typecheck**
601
+
602
+ ```bash
603
+ npm run typecheck
604
+ ```
605
+
606
+ Expected: PASS
607
+
608
+ **Step 7: Add --detail CLI flag**
609
+
610
+ Modify `src/cli/commands/search.ts`:
611
+
612
+ ```typescript
613
+ export function createSearchCommand(getOptions: () => GlobalOptions): Command {
614
+ const search = new Command('search')
615
+ .description('Search indexed documents using vector similarity + full-text matching')
616
+ .argument('<query>', 'Search query')
617
+ .option('-s, --stores <stores>', 'Limit search to specific stores (comma-separated IDs or names)')
618
+ .option('-m, --mode <mode>', 'vector (embeddings only), fts (text only), hybrid (both, default)', 'hybrid')
619
+ .option('-n, --limit <count>', 'Maximum results to return (default: 10)', '10')
620
+ .option('-t, --threshold <score>', 'Minimum score 0-1; omit low-relevance results')
621
+ .option('--include-content', 'Show full document content, not just preview snippet')
622
+ .option('--detail <level>', 'Context detail: minimal, contextual, full (default: minimal)', 'minimal')
623
+ .action(async (query: string, options: {
624
+ stores?: string;
625
+ mode?: SearchMode;
626
+ limit?: string;
627
+ threshold?: string;
628
+ includeContent?: boolean;
629
+ detail?: DetailLevel;
630
+ }) => {
631
+ const globalOpts = getOptions();
632
+ const services = await createServices(globalOpts.config, globalOpts.dataDir);
633
+
634
+ let storeIds = (await services.store.list()).map((s) => s.id);
635
+
636
+ if (options.stores !== undefined) {
637
+ const requestedStores = options.stores.split(',').map((s) => s.trim());
638
+ const resolvedStores = [];
639
+
640
+ for (const requested of requestedStores) {
641
+ const store = await services.store.getByIdOrName(requested);
642
+ if (store !== undefined) {
643
+ resolvedStores.push(store.id);
644
+ } else {
645
+ console.error(`Error: Store not found: ${requested}`);
646
+ process.exit(3);
647
+ }
648
+ }
649
+
650
+ storeIds = resolvedStores;
651
+ }
652
+
653
+ if (storeIds.length === 0) {
654
+ console.error('No stores to search. Create a store first.');
655
+ process.exit(1);
656
+ }
657
+
658
+ for (const storeId of storeIds) {
659
+ await services.lance.initialize(storeId);
660
+ }
661
+
662
+ const results = await services.search.search({
663
+ query,
664
+ stores: storeIds,
665
+ mode: options.mode ?? 'hybrid',
666
+ limit: parseInt(options.limit ?? '10', 10),
667
+ threshold: options.threshold !== undefined ? parseFloat(options.threshold) : undefined,
668
+ includeContent: options.includeContent,
669
+ detail: options.detail ?? 'minimal',
670
+ });
671
+
672
+ if (globalOpts.format === 'json') {
673
+ console.log(JSON.stringify(results, null, 2));
674
+ } else if (globalOpts.quiet === true) {
675
+ for (const r of results.results) {
676
+ const path = r.metadata.path ?? r.metadata.url ?? 'unknown';
677
+ console.log(path);
678
+ }
679
+ } else {
680
+ console.log(`\nSearch: "${query}"`);
681
+ console.log(`Mode: ${results.mode} | Detail: ${options.detail} | Stores: ${results.stores.length} | Results: ${results.totalResults} | Time: ${results.timeMs}ms\n`);
682
+
683
+ if (results.results.length === 0) {
684
+ console.log('No results found.\n');
685
+ } else {
686
+ for (let i = 0; i < results.results.length; i++) {
687
+ const r = results.results[i]!;
688
+
689
+ if (r.summary) {
690
+ console.log(`${i + 1}. [${r.score.toFixed(2)}] ${r.summary.type}: ${r.summary.name}`);
691
+ console.log(` ${r.summary.location}`);
692
+ console.log(` ${r.summary.purpose}`);
693
+
694
+ if (r.context && options.detail !== 'minimal') {
695
+ console.log(` Imports: ${r.context.keyImports.slice(0, 3).join(', ')}`);
696
+ console.log(` Related: ${r.context.relatedConcepts.slice(0, 3).join(', ')}`);
697
+ }
698
+
699
+ console.log();
700
+ } else {
701
+ // Fallback to old format
702
+ const path = r.metadata.path ?? r.metadata.url ?? 'unknown';
703
+ console.log(`${i + 1}. [${r.score.toFixed(2)}] ${path}`);
704
+ const preview = r.highlight ?? r.content.slice(0, 150).replace(/\n/g, ' ') + (r.content.length > 150 ? '...' : '');
705
+ console.log(` ${preview}\n`);
706
+ }
707
+ }
708
+ }
709
+ }
710
+ });
711
+
712
+ return search;
713
+ }
714
+ ```
715
+
716
+ **Step 8: Run typecheck**
717
+
718
+ ```bash
719
+ npm run typecheck
720
+ ```
721
+
722
+ Expected: PASS
723
+
724
+ **Step 9: Test manually**
725
+
726
+ ```bash
727
+ npm run build
728
+ ./dist/index.js search "validate token" --detail contextual
729
+ ```
730
+
731
+ Expected: Output shows summary with context information
732
+
733
+ **Step 10: Commit**
734
+
735
+ ```bash
736
+ git add src/types/search.ts src/services/search.service.ts src/cli/commands/search.ts tests/services/search.progressive-context.test.ts
737
+ git commit -m "feat(search): add progressive context layers for token optimization"
738
+ ```
739
+
740
+ ---
741
+
742
+ ### Task 1.3: MCP Server Integration
743
+
744
+ **Goal:** Expose search capabilities via Model Context Protocol for AI agent integration.
745
+
746
+ **Files:**
747
+ - Create: `src/mcp/server.ts`
748
+ - Create: `src/mcp/tools/search.ts`
749
+ - Create: `src/mcp/tools/get-context.ts`
750
+ - Modify: `package.json`
751
+ - Create: `src/cli/commands/mcp.ts`
752
+ - Modify: `src/cli/program.ts`
753
+ - Create: `tests/mcp/server.test.ts`
754
+
755
+ **Step 1: Install MCP SDK**
756
+
757
+ ```bash
758
+ npm install @modelcontextprotocol/sdk
759
+ ```
760
+
761
+ **Step 2: Write failing test for MCP server**
762
+
763
+ Create `tests/mcp/server.test.ts`:
764
+
765
+ ```typescript
766
+ import { describe, it, expect, beforeEach } from 'vitest';
767
+ import { createMCPServer } from '../src/mcp/server.js';
768
+
769
+ describe('MCP Server', () => {
770
+ it('should create server with search tool', () => {
771
+ const server = createMCPServer({
772
+ dataDir: '/tmp/test',
773
+ config: undefined
774
+ });
775
+
776
+ expect(server).toBeDefined();
777
+ // MCP SDK doesn't expose tools list directly, so we test via integration
778
+ });
779
+
780
+ it('should handle search tool call', async () => {
781
+ // Integration test - will implement after server is created
782
+ expect(true).toBe(true);
783
+ });
784
+ });
785
+ ```
786
+
787
+ **Step 3: Run test**
788
+
789
+ ```bash
790
+ npm run test mcp/server.test.ts
791
+ ```
792
+
793
+ Expected: FAIL - "Cannot find module '../src/mcp/server.js'"
794
+
795
+ **Step 4: Create MCP server**
796
+
797
+ Create `src/mcp/server.ts`:
798
+
799
+ ```typescript
800
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
801
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
802
+ import {
803
+ CallToolRequestSchema,
804
+ ListToolsRequestSchema,
805
+ } from '@modelcontextprotocol/sdk/types.js';
806
+ import { createServices } from '../services/index.js';
807
+ import type { SearchQuery, DetailLevel } from '../types/search.js';
808
+
809
+ interface MCPServerOptions {
810
+ dataDir?: string;
811
+ config?: string;
812
+ }
813
+
814
+ export function createMCPServer(options: MCPServerOptions) {
815
+ const server = new Server(
816
+ {
817
+ name: 'bluera-knowledge',
818
+ version: '1.0.0',
819
+ },
820
+ {
821
+ capabilities: {
822
+ tools: {},
823
+ },
824
+ }
825
+ );
826
+
827
+ // List available tools
828
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
829
+ return {
830
+ tools: [
831
+ {
832
+ name: 'search',
833
+ description: 'Search all indexed knowledge stores with pattern detection and AI-optimized results. Returns structured code units with progressive context layers.',
834
+ inputSchema: {
835
+ type: 'object',
836
+ properties: {
837
+ query: {
838
+ type: 'string',
839
+ description: 'Search query (can include type signatures, constraints, or natural language)'
840
+ },
841
+ intent: {
842
+ type: 'string',
843
+ enum: ['find-pattern', 'find-implementation', 'find-usage', 'find-definition', 'find-documentation'],
844
+ description: 'Search intent for better ranking'
845
+ },
846
+ detail: {
847
+ type: 'string',
848
+ enum: ['minimal', 'contextual', 'full'],
849
+ default: 'minimal',
850
+ description: 'Context detail level: minimal (summary only), contextual (+ imports/types), full (+ complete code)'
851
+ },
852
+ limit: {
853
+ type: 'number',
854
+ default: 10,
855
+ description: 'Maximum number of results'
856
+ },
857
+ stores: {
858
+ type: 'array',
859
+ items: { type: 'string' },
860
+ description: 'Specific store IDs to search (optional)'
861
+ }
862
+ },
863
+ required: ['query']
864
+ }
865
+ },
866
+ {
867
+ name: 'get_full_context',
868
+ description: 'Get complete code and context for a specific search result by ID. Use this after search to get full implementation details.',
869
+ inputSchema: {
870
+ type: 'object',
871
+ properties: {
872
+ resultId: {
873
+ type: 'string',
874
+ description: 'Result ID from previous search'
875
+ }
876
+ },
877
+ required: ['resultId']
878
+ }
879
+ }
880
+ ]
881
+ };
882
+ });
883
+
884
+ // Handle tool calls
885
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
886
+ const { name, arguments: args } = request.params;
887
+
888
+ if (name === 'search') {
889
+ const services = await createServices(options.config, options.dataDir);
890
+
891
+ const query = args.query as string;
892
+ const detail = (args.detail as DetailLevel) ?? 'minimal';
893
+ const limit = (args.limit as number) ?? 10;
894
+ const stores = args.stores as string[] | undefined;
895
+
896
+ // Get all stores if none specified
897
+ let storeIds = stores ?? (await services.store.list()).map(s => s.id);
898
+
899
+ // Initialize stores
900
+ for (const storeId of storeIds) {
901
+ await services.lance.initialize(storeId);
902
+ }
903
+
904
+ // Perform search
905
+ const searchQuery: SearchQuery = {
906
+ query,
907
+ stores: storeIds,
908
+ mode: 'hybrid',
909
+ limit,
910
+ detail
911
+ };
912
+
913
+ const results = await services.search.search(searchQuery);
914
+
915
+ // Calculate estimated tokens
916
+ const estimatedTokens = results.results.reduce((sum, r) => {
917
+ let tokens = 100; // Base for summary
918
+ if (r.context) tokens += 200;
919
+ if (r.full) tokens += 800;
920
+ return sum + tokens;
921
+ }, 0);
922
+
923
+ return {
924
+ content: [
925
+ {
926
+ type: 'text',
927
+ text: JSON.stringify({
928
+ results: results.results.map(r => ({
929
+ id: r.id,
930
+ score: r.score,
931
+ summary: r.summary,
932
+ context: r.context,
933
+ full: r.full
934
+ })),
935
+ totalResults: results.totalResults,
936
+ estimatedTokens,
937
+ mode: results.mode,
938
+ timeMs: results.timeMs
939
+ }, null, 2)
940
+ }
941
+ ]
942
+ };
943
+ }
944
+
945
+ if (name === 'get_full_context') {
946
+ // TODO: Implement result caching and retrieval by ID
947
+ return {
948
+ content: [
949
+ {
950
+ type: 'text',
951
+ text: JSON.stringify({
952
+ error: 'Not yet implemented'
953
+ })
954
+ }
955
+ ]
956
+ };
957
+ }
958
+
959
+ throw new Error(`Unknown tool: ${name}`);
960
+ });
961
+
962
+ return server;
963
+ }
964
+
965
+ export async function runMCPServer(options: MCPServerOptions) {
966
+ const server = createMCPServer(options);
967
+ const transport = new StdioServerTransport();
968
+ await server.connect(transport);
969
+
970
+ console.error('Bluera Knowledge MCP server running on stdio');
971
+ }
972
+ ```
973
+
974
+ **Step 5: Create MCP CLI command**
975
+
976
+ Create `src/cli/commands/mcp.ts`:
977
+
978
+ ```typescript
979
+ import { Command } from 'commander';
980
+ import type { GlobalOptions } from '../program.js';
981
+ import { runMCPServer } from '../../mcp/server.js';
982
+
983
+ export function createMCPCommand(getOptions: () => GlobalOptions): Command {
984
+ const mcp = new Command('mcp')
985
+ .description('Start MCP (Model Context Protocol) server for AI agent integration')
986
+ .action(async () => {
987
+ const opts = getOptions();
988
+
989
+ await runMCPServer({
990
+ dataDir: opts.dataDir,
991
+ config: opts.config
992
+ });
993
+ });
994
+
995
+ return mcp;
996
+ }
997
+ ```
998
+
999
+ **Step 6: Register MCP command**
1000
+
1001
+ Modify `src/cli/program.ts`:
1002
+
1003
+ ```typescript
1004
+ import { createMCPCommand } from './commands/mcp.js';
1005
+
1006
+ // In createProgram function, add:
1007
+ program.addCommand(createMCPCommand(getGlobalOptions));
1008
+ ```
1009
+
1010
+ **Step 7: Run typecheck**
1011
+
1012
+ ```bash
1013
+ npm run typecheck
1014
+ ```
1015
+
1016
+ Expected: PASS
1017
+
1018
+ **Step 8: Build and test MCP server**
1019
+
1020
+ ```bash
1021
+ npm run build
1022
+ ./dist/index.js mcp
1023
+ ```
1024
+
1025
+ In another terminal:
1026
+ ```bash
1027
+ echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | ./dist/index.js mcp
1028
+ ```
1029
+
1030
+ Expected: JSON response with tools list
1031
+
1032
+ **Step 9: Commit**
1033
+
1034
+ ```bash
1035
+ git add src/mcp/ src/cli/commands/mcp.ts src/cli/program.ts package.json tests/mcp/
1036
+ git commit -m "feat(mcp): add MCP server for AI agent integration"
1037
+ ```
1038
+
1039
+ ---
1040
+
1041
+ ## Phase 2: Static Analysis & Code Graph
1042
+
1043
+ ### Task 2.1: TypeScript AST Parser
1044
+
1045
+ **Goal:** Parse TypeScript/JavaScript files to extract structured code elements (functions, classes, imports).
1046
+
1047
+ **Files:**
1048
+ - Create: `src/analysis/ast-parser.ts`
1049
+ - Create: `tests/analysis/ast-parser.test.ts`
1050
+ - Modify: `package.json`
1051
+
1052
+ **Step 1: Install Babel parser**
1053
+
1054
+ ```bash
1055
+ npm install @babel/parser @babel/traverse @babel/types
1056
+ npm install -D @types/babel__traverse @types/babel__core
1057
+ ```
1058
+
1059
+ **Step 2: Write failing test**
1060
+
1061
+ Create `tests/analysis/ast-parser.test.ts`:
1062
+
1063
+ ```typescript
1064
+ import { describe, it, expect } from 'vitest';
1065
+ import { ASTParser } from '../src/analysis/ast-parser.js';
1066
+
1067
+ describe('ASTParser', () => {
1068
+ it('should extract functions from TypeScript code', () => {
1069
+ const code = `
1070
+ export async function validateToken(token: string): Promise<boolean> {
1071
+ return token.length > 0;
1072
+ }
1073
+
1074
+ function helperFunction() {
1075
+ return true;
1076
+ }
1077
+ `;
1078
+
1079
+ const parser = new ASTParser();
1080
+ const nodes = parser.parse(code, 'typescript');
1081
+
1082
+ expect(nodes).toHaveLength(2);
1083
+ expect(nodes[0]?.type).toBe('function');
1084
+ expect(nodes[0]?.name).toBe('validateToken');
1085
+ expect(nodes[0]?.exported).toBe(true);
1086
+ expect(nodes[0]?.async).toBe(true);
1087
+ expect(nodes[1]?.name).toBe('helperFunction');
1088
+ expect(nodes[1]?.exported).toBe(false);
1089
+ });
1090
+
1091
+ it('should extract classes with methods', () => {
1092
+ const code = `
1093
+ export class UserService {
1094
+ constructor(private repo: UserRepo) {}
1095
+
1096
+ async create(data: CreateUserData): Promise<User> {
1097
+ return this.repo.save(data);
1098
+ }
1099
+
1100
+ delete(id: string): void {
1101
+ this.repo.delete(id);
1102
+ }
1103
+ }
1104
+ `;
1105
+
1106
+ const parser = new ASTParser();
1107
+ const nodes = parser.parse(code, 'typescript');
1108
+
1109
+ const classNode = nodes.find(n => n.type === 'class');
1110
+ expect(classNode).toBeDefined();
1111
+ expect(classNode?.name).toBe('UserService');
1112
+ expect(classNode?.methods).toHaveLength(3); // constructor + create + delete
1113
+ });
1114
+
1115
+ it('should extract imports', () => {
1116
+ const code = `
1117
+ import { User } from './models/user.js';
1118
+ import type { Repository } from '../types.js';
1119
+ import express from 'express';
1120
+ `;
1121
+
1122
+ const parser = new ASTParser();
1123
+ const imports = parser.extractImports(code);
1124
+
1125
+ expect(imports).toHaveLength(3);
1126
+ expect(imports[0]?.source).toBe('./models/user.js');
1127
+ expect(imports[0]?.specifiers).toContain('User');
1128
+ expect(imports[2]?.specifiers).toContain('express');
1129
+ });
1130
+ });
1131
+ ```
1132
+
1133
+ **Step 3: Run test**
1134
+
1135
+ ```bash
1136
+ npm run test ast-parser.test.ts
1137
+ ```
1138
+
1139
+ Expected: FAIL - "Cannot find module '../src/analysis/ast-parser.js'"
1140
+
1141
+ **Step 4: Implement AST parser**
1142
+
1143
+ Create `src/analysis/ast-parser.ts`:
1144
+
1145
+ ```typescript
1146
+ import { parse } from '@babel/parser';
1147
+ import traverse from '@babel/traverse';
1148
+ import * as t from '@babel/types';
1149
+
1150
+ export interface CodeNode {
1151
+ type: 'function' | 'class' | 'interface' | 'type' | 'const';
1152
+ name: string;
1153
+ exported: boolean;
1154
+ async?: boolean;
1155
+ startLine: number;
1156
+ endLine: number;
1157
+ signature?: string;
1158
+ methods?: Array<{
1159
+ name: string;
1160
+ async: boolean;
1161
+ signature: string;
1162
+ }>;
1163
+ }
1164
+
1165
+ export interface ImportInfo {
1166
+ source: string;
1167
+ specifiers: string[];
1168
+ isType: boolean;
1169
+ }
1170
+
1171
+ export class ASTParser {
1172
+ parse(code: string, language: 'typescript' | 'javascript'): CodeNode[] {
1173
+ const plugins: any[] = ['jsx'];
1174
+ if (language === 'typescript') {
1175
+ plugins.push('typescript');
1176
+ }
1177
+
1178
+ const ast = parse(code, {
1179
+ sourceType: 'module',
1180
+ plugins
1181
+ });
1182
+
1183
+ const nodes: CodeNode[] = [];
1184
+
1185
+ traverse(ast, {
1186
+ FunctionDeclaration: (path) => {
1187
+ const node = path.node;
1188
+ if (!node.id) return;
1189
+
1190
+ const exported = path.parent.type === 'ExportNamedDeclaration' ||
1191
+ path.parent.type === 'ExportDefaultDeclaration';
1192
+
1193
+ nodes.push({
1194
+ type: 'function',
1195
+ name: node.id.name,
1196
+ exported,
1197
+ async: node.async,
1198
+ startLine: node.loc?.start.line ?? 0,
1199
+ endLine: node.loc?.end.line ?? 0,
1200
+ signature: this.extractFunctionSignature(node)
1201
+ });
1202
+ },
1203
+
1204
+ ClassDeclaration: (path) => {
1205
+ const node = path.node;
1206
+ if (!node.id) return;
1207
+
1208
+ const exported = path.parent.type === 'ExportNamedDeclaration' ||
1209
+ path.parent.type === 'ExportDefaultDeclaration';
1210
+
1211
+ const methods: CodeNode['methods'] = [];
1212
+
1213
+ for (const member of node.body.body) {
1214
+ if (t.isClassMethod(member) && t.isIdentifier(member.key)) {
1215
+ methods.push({
1216
+ name: member.key.name,
1217
+ async: member.async,
1218
+ signature: this.extractMethodSignature(member)
1219
+ });
1220
+ }
1221
+ }
1222
+
1223
+ nodes.push({
1224
+ type: 'class',
1225
+ name: node.id.name,
1226
+ exported,
1227
+ startLine: node.loc?.start.line ?? 0,
1228
+ endLine: node.loc?.end.line ?? 0,
1229
+ methods
1230
+ });
1231
+ },
1232
+
1233
+ TSInterfaceDeclaration: (path) => {
1234
+ const node = path.node;
1235
+
1236
+ const exported = path.parent.type === 'ExportNamedDeclaration';
1237
+
1238
+ nodes.push({
1239
+ type: 'interface',
1240
+ name: node.id.name,
1241
+ exported,
1242
+ startLine: node.loc?.start.line ?? 0,
1243
+ endLine: node.loc?.end.line ?? 0
1244
+ });
1245
+ }
1246
+ });
1247
+
1248
+ return nodes;
1249
+ }
1250
+
1251
+ extractImports(code: string): ImportInfo[] {
1252
+ const ast = parse(code, {
1253
+ sourceType: 'module',
1254
+ plugins: ['typescript', 'jsx']
1255
+ });
1256
+
1257
+ const imports: ImportInfo[] = [];
1258
+
1259
+ traverse(ast, {
1260
+ ImportDeclaration: (path) => {
1261
+ const node = path.node;
1262
+ const specifiers: string[] = [];
1263
+
1264
+ for (const spec of node.specifiers) {
1265
+ if (t.isImportDefaultSpecifier(spec)) {
1266
+ specifiers.push(spec.local.name);
1267
+ } else if (t.isImportSpecifier(spec)) {
1268
+ specifiers.push(spec.local.name);
1269
+ } else if (t.isImportNamespaceSpecifier(spec)) {
1270
+ specifiers.push(spec.local.name);
1271
+ }
1272
+ }
1273
+
1274
+ imports.push({
1275
+ source: node.source.value,
1276
+ specifiers,
1277
+ isType: node.importKind === 'type'
1278
+ });
1279
+ }
1280
+ });
1281
+
1282
+ return imports;
1283
+ }
1284
+
1285
+ private extractFunctionSignature(node: t.FunctionDeclaration): string {
1286
+ const params = node.params.map(p => {
1287
+ if (t.isIdentifier(p)) return p.name;
1288
+ return 'param';
1289
+ }).join(', ');
1290
+
1291
+ return `${node.id?.name}(${params})`;
1292
+ }
1293
+
1294
+ private extractMethodSignature(node: t.ClassMethod): string {
1295
+ const params = node.params.map(p => {
1296
+ if (t.isIdentifier(p)) return p.name;
1297
+ return 'param';
1298
+ }).join(', ');
1299
+
1300
+ const name = t.isIdentifier(node.key) ? node.key.name : 'method';
1301
+ return `${name}(${params})`;
1302
+ }
1303
+ }
1304
+ ```
1305
+
1306
+ **Step 5: Run tests**
1307
+
1308
+ ```bash
1309
+ npm run test ast-parser.test.ts
1310
+ ```
1311
+
1312
+ Expected: PASS
1313
+
1314
+ **Step 6: Run typecheck**
1315
+
1316
+ ```bash
1317
+ npm run typecheck
1318
+ ```
1319
+
1320
+ Expected: PASS
1321
+
1322
+ **Step 7: Commit**
1323
+
1324
+ ```bash
1325
+ git add src/analysis/ast-parser.ts tests/analysis/ast-parser.test.ts package.json
1326
+ git commit -m "feat(analysis): add TypeScript/JavaScript AST parser"
1327
+ ```
1328
+
1329
+ ---
1330
+
1331
+ ### Task 2.2: Code Graph Builder
1332
+
1333
+ **Goal:** Build relationship graph (calls, imports) from parsed code.
1334
+
1335
+ **Files:**
1336
+ - Create: `src/analysis/code-graph.ts`
1337
+ - Create: `tests/analysis/code-graph.test.ts`
1338
+
1339
+ **Step 1: Write failing test**
1340
+
1341
+ Create `tests/analysis/code-graph.test.ts`:
1342
+
1343
+ ```typescript
1344
+ import { describe, it, expect } from 'vitest';
1345
+ import { CodeGraph } from '../src/analysis/code-graph.js';
1346
+ import type { CodeNode } from '../src/analysis/ast-parser.js';
1347
+
1348
+ describe('CodeGraph', () => {
1349
+ it('should build graph from code nodes', () => {
1350
+ const nodes: CodeNode[] = [
1351
+ {
1352
+ type: 'function',
1353
+ name: 'validateToken',
1354
+ exported: true,
1355
+ startLine: 1,
1356
+ endLine: 5
1357
+ },
1358
+ {
1359
+ type: 'function',
1360
+ name: 'parseToken',
1361
+ exported: false,
1362
+ startLine: 7,
1363
+ endLine: 10
1364
+ }
1365
+ ];
1366
+
1367
+ const graph = new CodeGraph();
1368
+ graph.addNodes(nodes, 'src/auth.ts');
1369
+
1370
+ expect(graph.getNode('src/auth.ts:validateToken')).toBeDefined();
1371
+ expect(graph.getNode('src/auth.ts:parseToken')).toBeDefined();
1372
+ });
1373
+
1374
+ it('should track import relationships', () => {
1375
+ const graph = new CodeGraph();
1376
+
1377
+ graph.addImport('src/controllers/user.ts', './services/user.js', ['UserService']);
1378
+
1379
+ const edges = graph.getEdges('src/controllers/user.ts');
1380
+ expect(edges).toHaveLength(1);
1381
+ expect(edges[0]?.type).toBe('imports');
1382
+ expect(edges[0]?.to).toContain('UserService');
1383
+ });
1384
+
1385
+ it('should detect call relationships from code', () => {
1386
+ const code = `
1387
+ export function handler(req) {
1388
+ const valid = validateToken(req.token);
1389
+ if (!valid) return error();
1390
+ return success();
1391
+ }
1392
+ `;
1393
+
1394
+ const graph = new CodeGraph();
1395
+ graph.analyzeCallRelationships(code, 'src/handler.ts', 'handler');
1396
+
1397
+ const edges = graph.getEdges('src/handler.ts:handler');
1398
+ const callEdges = edges.filter(e => e.type === 'calls');
1399
+
1400
+ expect(callEdges.length).toBeGreaterThan(0);
1401
+ expect(callEdges.some(e => e.to.includes('validateToken'))).toBe(true);
1402
+ });
1403
+ });
1404
+ ```
1405
+
1406
+ **Step 2: Run test**
1407
+
1408
+ ```bash
1409
+ npm run test code-graph.test.ts
1410
+ ```
1411
+
1412
+ Expected: FAIL - "Cannot find module '../src/analysis/code-graph.js'"
1413
+
1414
+ **Step 3: Implement code graph**
1415
+
1416
+ Create `src/analysis/code-graph.ts`:
1417
+
1418
+ ```typescript
1419
+ import type { CodeNode } from './ast-parser.js';
1420
+
1421
+ export interface GraphNode {
1422
+ id: string;
1423
+ file: string;
1424
+ type: 'function' | 'class' | 'interface' | 'type' | 'const';
1425
+ name: string;
1426
+ exported: boolean;
1427
+ startLine: number;
1428
+ endLine: number;
1429
+ signature?: string;
1430
+ }
1431
+
1432
+ export interface GraphEdge {
1433
+ from: string;
1434
+ to: string;
1435
+ type: 'calls' | 'imports' | 'extends' | 'implements';
1436
+ confidence: number;
1437
+ }
1438
+
1439
+ export class CodeGraph {
1440
+ private nodes = new Map<string, GraphNode>();
1441
+ private edges = new Map<string, GraphEdge[]>();
1442
+
1443
+ addNodes(nodes: CodeNode[], file: string): void {
1444
+ for (const node of nodes) {
1445
+ const id = `${file}:${node.name}`;
1446
+
1447
+ this.nodes.set(id, {
1448
+ id,
1449
+ file,
1450
+ type: node.type,
1451
+ name: node.name,
1452
+ exported: node.exported,
1453
+ startLine: node.startLine,
1454
+ endLine: node.endLine,
1455
+ signature: node.signature
1456
+ });
1457
+
1458
+ // Initialize edges array for this node
1459
+ if (!this.edges.has(id)) {
1460
+ this.edges.set(id, []);
1461
+ }
1462
+ }
1463
+ }
1464
+
1465
+ addImport(fromFile: string, toFile: string, specifiers: string[]): void {
1466
+ // Normalize the toFile path (resolve relative imports)
1467
+ const resolvedTo = this.resolveImportPath(fromFile, toFile);
1468
+
1469
+ for (const spec of specifiers) {
1470
+ const edge: GraphEdge = {
1471
+ from: fromFile,
1472
+ to: `${resolvedTo}:${spec}`,
1473
+ type: 'imports',
1474
+ confidence: 1.0
1475
+ };
1476
+
1477
+ const edges = this.edges.get(fromFile) ?? [];
1478
+ edges.push(edge);
1479
+ this.edges.set(fromFile, edges);
1480
+ }
1481
+ }
1482
+
1483
+ analyzeCallRelationships(code: string, file: string, functionName: string): void {
1484
+ const nodeId = `${file}:${functionName}`;
1485
+
1486
+ // Simple regex-based call detection (can be enhanced with AST later)
1487
+ const callPattern = /\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/g;
1488
+ const calls = new Set<string>();
1489
+
1490
+ let match;
1491
+ while ((match = callPattern.exec(code)) !== null) {
1492
+ if (match[1]) {
1493
+ calls.add(match[1]);
1494
+ }
1495
+ }
1496
+
1497
+ const edges = this.edges.get(nodeId) ?? [];
1498
+
1499
+ for (const calledFunction of calls) {
1500
+ // Try to find the called function in the graph
1501
+ const targetNode = this.findNodeByName(calledFunction);
1502
+
1503
+ if (targetNode) {
1504
+ edges.push({
1505
+ from: nodeId,
1506
+ to: targetNode.id,
1507
+ type: 'calls',
1508
+ confidence: 0.8 // Lower confidence for regex-based detection
1509
+ });
1510
+ } else {
1511
+ // Unknown function, possibly from import
1512
+ edges.push({
1513
+ from: nodeId,
1514
+ to: `unknown:${calledFunction}`,
1515
+ type: 'calls',
1516
+ confidence: 0.5
1517
+ });
1518
+ }
1519
+ }
1520
+
1521
+ this.edges.set(nodeId, edges);
1522
+ }
1523
+
1524
+ getNode(id: string): GraphNode | undefined {
1525
+ return this.nodes.get(id);
1526
+ }
1527
+
1528
+ getEdges(nodeId: string): GraphEdge[] {
1529
+ return this.edges.get(nodeId) ?? [];
1530
+ }
1531
+
1532
+ getAllNodes(): GraphNode[] {
1533
+ return Array.from(this.nodes.values());
1534
+ }
1535
+
1536
+ private findNodeByName(name: string): GraphNode | undefined {
1537
+ for (const node of this.nodes.values()) {
1538
+ if (node.name === name) {
1539
+ return node;
1540
+ }
1541
+ }
1542
+ return undefined;
1543
+ }
1544
+
1545
+ private resolveImportPath(fromFile: string, importPath: string): string {
1546
+ // Simple resolution - can be enhanced
1547
+ if (importPath.startsWith('.')) {
1548
+ // Relative import
1549
+ const fromDir = fromFile.split('/').slice(0, -1).join('/');
1550
+ const parts = importPath.split('/');
1551
+
1552
+ let resolved = fromDir;
1553
+ for (const part of parts) {
1554
+ if (part === '..') {
1555
+ resolved = resolved.split('/').slice(0, -1).join('/');
1556
+ } else if (part !== '.') {
1557
+ resolved += '/' + part;
1558
+ }
1559
+ }
1560
+
1561
+ return resolved.replace(/\.js$/, '');
1562
+ }
1563
+
1564
+ // Package import
1565
+ return importPath;
1566
+ }
1567
+
1568
+ toJSON(): { nodes: GraphNode[]; edges: Array<{ from: string; to: string; type: string }> } {
1569
+ const allEdges: GraphEdge[] = [];
1570
+ for (const edges of this.edges.values()) {
1571
+ allEdges.push(...edges);
1572
+ }
1573
+
1574
+ return {
1575
+ nodes: Array.from(this.nodes.values()),
1576
+ edges: allEdges.map(e => ({ from: e.from, to: e.to, type: e.type }))
1577
+ };
1578
+ }
1579
+ }
1580
+ ```
1581
+
1582
+ **Step 4: Run tests**
1583
+
1584
+ ```bash
1585
+ npm run test code-graph.test.ts
1586
+ ```
1587
+
1588
+ Expected: PASS
1589
+
1590
+ **Step 5: Run typecheck**
1591
+
1592
+ ```bash
1593
+ npm run typecheck
1594
+ ```
1595
+
1596
+ Expected: PASS
1597
+
1598
+ **Step 6: Commit**
1599
+
1600
+ ```bash
1601
+ git add src/analysis/code-graph.ts tests/analysis/code-graph.test.ts
1602
+ git commit -m "feat(analysis): add code graph builder for relationship tracking"
1603
+ ```
1604
+
1605
+ ---
1606
+
1607
+ ## Execution Notes
1608
+
1609
+ **Total estimated time for Phase 1 (MVP):**
1610
+ - Task 1.1: 2-3 days
1611
+ - Task 1.2: 3-4 days
1612
+ - Task 1.3: 3-4 days
1613
+ - Task 2.1: 2-3 days
1614
+ - Task 2.2: 2-3 days
1615
+
1616
+ **Total: ~12-17 days (2.5-3.5 weeks)**
1617
+
1618
+ **Phase 2 (Pattern Detection) and beyond:** Detailed plans available upon request after Phase 1 completion.
1619
+
1620
+ **Testing Strategy:**
1621
+ - Unit tests for all services (TDD approach)
1622
+ - Integration tests for MCP server with real Claude Code
1623
+ - Manual testing with test corpus (Vue.js, Express, Hono)
1624
+ - Agent outcome tracking once MCP is live
1625
+
1626
+ **Success Metrics for Phase 1:**
1627
+ - Search results include structured code units (100% of code files)
1628
+ - Progressive context reduces tokens by 40% on average
1629
+ - MCP server successfully integrates with Claude Code
1630
+ - Code graph captures 90%+ of function relationships