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,1518 @@
1
+ # Phase 2 Features Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Complete all remaining features from the CLI specification: document chunking, full-text search, hybrid search, progress bars, HTTP server, file watching, web crawling, and export/import.
6
+
7
+ **Architecture:** Build incrementally on existing service layer. Add chunking to IndexService, FTS to LanceStore, hybrid search to SearchService. Add Hono server that reuses same services. Python bridge for web crawling via JSON-RPC subprocess.
8
+
9
+ **Tech Stack:** LanceDB (FTS built-in), Hono, ora, chokidar, Python crawl4ai
10
+
11
+ ---
12
+
13
+ ## Group A: Search Improvements
14
+
15
+ ### Task A.1: Create ChunkingService
16
+
17
+ **Files:**
18
+ - Create: `src/services/chunking.service.ts`
19
+ - Create: `src/services/chunking.service.test.ts`
20
+
21
+ **Step 1: Write the failing test**
22
+
23
+ Create `src/services/chunking.service.test.ts`:
24
+ ```typescript
25
+ import { describe, it, expect } from 'vitest';
26
+ import { ChunkingService } from './chunking.service.js';
27
+
28
+ describe('ChunkingService', () => {
29
+ const chunker = new ChunkingService({ chunkSize: 100, chunkOverlap: 20 });
30
+
31
+ it('splits text into chunks', () => {
32
+ const text = 'A'.repeat(250);
33
+ const chunks = chunker.chunk(text);
34
+ expect(chunks.length).toBeGreaterThan(1);
35
+ expect(chunks.every(c => c.content.length <= 100)).toBe(true);
36
+ });
37
+
38
+ it('preserves overlap between chunks', () => {
39
+ const text = 'word '.repeat(50); // 250 chars
40
+ const chunks = chunker.chunk(text);
41
+ if (chunks.length >= 2) {
42
+ const end1 = chunks[0]!.content.slice(-20);
43
+ const start2 = chunks[1]!.content.slice(0, 20);
44
+ expect(end1).toBe(start2);
45
+ }
46
+ });
47
+
48
+ it('returns single chunk for small text', () => {
49
+ const text = 'small text';
50
+ const chunks = chunker.chunk(text);
51
+ expect(chunks).toHaveLength(1);
52
+ expect(chunks[0]!.content).toBe(text);
53
+ });
54
+
55
+ it('assigns chunk indices', () => {
56
+ const text = 'A'.repeat(300);
57
+ const chunks = chunker.chunk(text);
58
+ expect(chunks[0]!.chunkIndex).toBe(0);
59
+ expect(chunks[1]!.chunkIndex).toBe(1);
60
+ expect(chunks.every(c => c.totalChunks === chunks.length)).toBe(true);
61
+ });
62
+ });
63
+ ```
64
+
65
+ **Step 2: Run test to verify it fails**
66
+
67
+ ```bash
68
+ npm run test:run -- src/services/chunking.service.test.ts
69
+ ```
70
+
71
+ Expected: FAIL - module not found
72
+
73
+ **Step 3: Write implementation**
74
+
75
+ Create `src/services/chunking.service.ts`:
76
+ ```typescript
77
+ export interface ChunkConfig {
78
+ chunkSize: number;
79
+ chunkOverlap: number;
80
+ }
81
+
82
+ export interface Chunk {
83
+ content: string;
84
+ chunkIndex: number;
85
+ totalChunks: number;
86
+ startOffset: number;
87
+ endOffset: number;
88
+ }
89
+
90
+ export class ChunkingService {
91
+ private readonly chunkSize: number;
92
+ private readonly chunkOverlap: number;
93
+
94
+ constructor(config: ChunkConfig) {
95
+ this.chunkSize = config.chunkSize;
96
+ this.chunkOverlap = config.chunkOverlap;
97
+ }
98
+
99
+ chunk(text: string): Chunk[] {
100
+ if (text.length <= this.chunkSize) {
101
+ return [{
102
+ content: text,
103
+ chunkIndex: 0,
104
+ totalChunks: 1,
105
+ startOffset: 0,
106
+ endOffset: text.length,
107
+ }];
108
+ }
109
+
110
+ const chunks: Chunk[] = [];
111
+ const step = this.chunkSize - this.chunkOverlap;
112
+ let start = 0;
113
+
114
+ while (start < text.length) {
115
+ const end = Math.min(start + this.chunkSize, text.length);
116
+ chunks.push({
117
+ content: text.slice(start, end),
118
+ chunkIndex: chunks.length,
119
+ totalChunks: 0, // Will be set after
120
+ startOffset: start,
121
+ endOffset: end,
122
+ });
123
+ start += step;
124
+ if (end === text.length) break;
125
+ }
126
+
127
+ // Set totalChunks
128
+ for (const chunk of chunks) {
129
+ chunk.totalChunks = chunks.length;
130
+ }
131
+
132
+ return chunks;
133
+ }
134
+ }
135
+ ```
136
+
137
+ **Step 4: Run test to verify it passes**
138
+
139
+ ```bash
140
+ npm run test:run -- src/services/chunking.service.test.ts
141
+ ```
142
+
143
+ Expected: PASS
144
+
145
+ **Step 5: Commit**
146
+
147
+ ```bash
148
+ git add src/services/chunking.service.ts src/services/chunking.service.test.ts
149
+ git commit -m "feat: add ChunkingService for document splitting"
150
+ ```
151
+
152
+ ---
153
+
154
+ ### Task A.2: Integrate chunking into IndexService
155
+
156
+ **Files:**
157
+ - Modify: `src/services/index.service.ts`
158
+ - Modify: `src/services/index.service.test.ts`
159
+
160
+ **Step 1: Update test to verify chunking**
161
+
162
+ Add to `src/services/index.service.test.ts`:
163
+ ```typescript
164
+ it('chunks large files', async () => {
165
+ // Create a large test file
166
+ const largeContent = 'This is test content. '.repeat(100); // ~2200 chars
167
+ await writeFile(join(testFilesDir, 'large.txt'), largeContent);
168
+
169
+ const store: FileStore = {
170
+ type: 'file',
171
+ id: storeId,
172
+ name: 'Test Store',
173
+ path: testFilesDir,
174
+ createdAt: new Date(),
175
+ updatedAt: new Date(),
176
+ };
177
+
178
+ const result = await indexService.indexStore(store);
179
+
180
+ expect(result.success).toBe(true);
181
+ if (result.success) {
182
+ expect(result.data.chunksCreated).toBeGreaterThan(result.data.documentsIndexed);
183
+ }
184
+ });
185
+ ```
186
+
187
+ **Step 2: Run test to verify it fails**
188
+
189
+ ```bash
190
+ npm run test:run -- src/services/index.service.test.ts
191
+ ```
192
+
193
+ Expected: FAIL - chunks equal documents (no chunking)
194
+
195
+ **Step 3: Update IndexService implementation**
196
+
197
+ Update `src/services/index.service.ts`:
198
+ ```typescript
199
+ import { readFile, readdir } from 'node:fs/promises';
200
+ import { join, extname } from 'node:path';
201
+ import { createHash } from 'node:crypto';
202
+ import type { LanceStore } from '../db/lance.js';
203
+ import type { EmbeddingEngine } from '../db/embeddings.js';
204
+ import type { Store, FileStore, RepoStore } from '../types/store.js';
205
+ import type { Document } from '../types/document.js';
206
+ import { createDocumentId } from '../types/brands.js';
207
+ import type { Result } from '../types/result.js';
208
+ import { ok, err } from '../types/result.js';
209
+ import { ChunkingService } from './chunking.service.js';
210
+
211
+ interface IndexResult {
212
+ documentsIndexed: number;
213
+ chunksCreated: number;
214
+ timeMs: number;
215
+ }
216
+
217
+ interface IndexOptions {
218
+ chunkSize?: number;
219
+ chunkOverlap?: number;
220
+ }
221
+
222
+ const TEXT_EXTENSIONS = new Set([
223
+ '.txt', '.md', '.js', '.ts', '.jsx', '.tsx', '.json', '.yaml', '.yml',
224
+ '.html', '.css', '.scss', '.less', '.py', '.rb', '.go', '.rs', '.java',
225
+ '.c', '.cpp', '.h', '.hpp', '.sh', '.bash', '.zsh', '.sql', '.xml',
226
+ ]);
227
+
228
+ export class IndexService {
229
+ private readonly lanceStore: LanceStore;
230
+ private readonly embeddingEngine: EmbeddingEngine;
231
+ private readonly chunker: ChunkingService;
232
+
233
+ constructor(
234
+ lanceStore: LanceStore,
235
+ embeddingEngine: EmbeddingEngine,
236
+ options: IndexOptions = {}
237
+ ) {
238
+ this.lanceStore = lanceStore;
239
+ this.embeddingEngine = embeddingEngine;
240
+ this.chunker = new ChunkingService({
241
+ chunkSize: options.chunkSize ?? 512,
242
+ chunkOverlap: options.chunkOverlap ?? 50,
243
+ });
244
+ }
245
+
246
+ async indexStore(store: Store): Promise<Result<IndexResult>> {
247
+ try {
248
+ if (store.type === 'file' || store.type === 'repo') {
249
+ return await this.indexFileStore(store);
250
+ }
251
+ return err(new Error(`Indexing not supported for store type: ${store.type}`));
252
+ } catch (error) {
253
+ return err(error instanceof Error ? error : new Error(String(error)));
254
+ }
255
+ }
256
+
257
+ private async indexFileStore(store: FileStore | RepoStore): Promise<Result<IndexResult>> {
258
+ const startTime = Date.now();
259
+ const files = await this.scanDirectory(store.path);
260
+ const documents: Document[] = [];
261
+ let filesProcessed = 0;
262
+
263
+ for (const filePath of files) {
264
+ const content = await readFile(filePath, 'utf-8');
265
+ const fileHash = createHash('md5').update(content).digest('hex');
266
+ const chunks = this.chunker.chunk(content);
267
+
268
+ for (const chunk of chunks) {
269
+ const vector = await this.embeddingEngine.embed(chunk.content);
270
+ const chunkId = chunks.length > 1
271
+ ? `${store.id}-${fileHash}-${chunk.chunkIndex}`
272
+ : `${store.id}-${fileHash}`;
273
+
274
+ const doc: Document = {
275
+ id: createDocumentId(chunkId),
276
+ content: chunk.content,
277
+ vector,
278
+ metadata: {
279
+ type: chunks.length > 1 ? 'chunk' : 'file',
280
+ storeId: store.id,
281
+ path: filePath,
282
+ indexedAt: new Date(),
283
+ fileHash,
284
+ chunkIndex: chunk.chunkIndex,
285
+ totalChunks: chunk.totalChunks,
286
+ },
287
+ };
288
+ documents.push(doc);
289
+ }
290
+ filesProcessed++;
291
+ }
292
+
293
+ if (documents.length > 0) {
294
+ await this.lanceStore.addDocuments(store.id, documents);
295
+ }
296
+
297
+ return ok({
298
+ documentsIndexed: filesProcessed,
299
+ chunksCreated: documents.length,
300
+ timeMs: Date.now() - startTime,
301
+ });
302
+ }
303
+
304
+ private async scanDirectory(dir: string): Promise<string[]> {
305
+ const files: string[] = [];
306
+ const entries = await readdir(dir, { withFileTypes: true });
307
+
308
+ for (const entry of entries) {
309
+ const fullPath = join(dir, entry.name);
310
+ if (entry.isDirectory()) {
311
+ if (!['node_modules', '.git', 'dist', 'build'].includes(entry.name)) {
312
+ files.push(...(await this.scanDirectory(fullPath)));
313
+ }
314
+ } else if (entry.isFile()) {
315
+ const ext = extname(entry.name).toLowerCase();
316
+ if (TEXT_EXTENSIONS.has(ext)) {
317
+ files.push(fullPath);
318
+ }
319
+ }
320
+ }
321
+ return files;
322
+ }
323
+ }
324
+ ```
325
+
326
+ **Step 4: Run test to verify it passes**
327
+
328
+ ```bash
329
+ npm run test:run -- src/services/index.service.test.ts
330
+ ```
331
+
332
+ Expected: PASS
333
+
334
+ **Step 5: Commit**
335
+
336
+ ```bash
337
+ git add src/services/index.service.ts src/services/index.service.test.ts
338
+ git commit -m "feat: integrate chunking into IndexService"
339
+ ```
340
+
341
+ ---
342
+
343
+ ### Task A.3: Add full-text search to LanceStore
344
+
345
+ **Files:**
346
+ - Modify: `src/db/lance.ts`
347
+ - Modify: `src/db/lance.test.ts`
348
+
349
+ **Step 1: Add FTS test**
350
+
351
+ Add to `src/db/lance.test.ts`:
352
+ ```typescript
353
+ it('performs full-text search', async () => {
354
+ const doc = {
355
+ id: createDocumentId('fts-doc'),
356
+ content: 'The quick brown fox jumps over the lazy dog',
357
+ vector: new Array(384).fill(0.1),
358
+ metadata: {
359
+ type: 'file' as const,
360
+ storeId,
361
+ indexedAt: new Date(),
362
+ },
363
+ };
364
+
365
+ await store.addDocuments(storeId, [doc]);
366
+
367
+ const results = await store.fullTextSearch(storeId, 'quick brown', 10);
368
+ expect(results.length).toBeGreaterThan(0);
369
+ expect(results[0]?.content).toContain('quick');
370
+ });
371
+ ```
372
+
373
+ **Step 2: Run test to verify it fails**
374
+
375
+ ```bash
376
+ npm run test:run -- src/db/lance.test.ts
377
+ ```
378
+
379
+ Expected: FAIL - fullTextSearch not defined
380
+
381
+ **Step 3: Add FTS implementation**
382
+
383
+ Add to `src/db/lance.ts`:
384
+ ```typescript
385
+ async createFtsIndex(storeId: StoreId): Promise<void> {
386
+ const table = await this.getTable(storeId);
387
+ await table.createIndex('content', {
388
+ config: lancedb.Index.fts(),
389
+ });
390
+ }
391
+
392
+ async fullTextSearch(
393
+ storeId: StoreId,
394
+ query: string,
395
+ limit: number
396
+ ): Promise<Array<{ id: DocumentId; content: string; score: number; metadata: DocumentMetadata }>> {
397
+ const table = await this.getTable(storeId);
398
+
399
+ try {
400
+ const results = await table
401
+ .search(query, 'fts')
402
+ .limit(limit)
403
+ .toArray() as Array<{ id: string; content: string; metadata: string; score: number }>;
404
+
405
+ return results.map((r) => ({
406
+ id: createDocumentId(r.id),
407
+ content: r.content,
408
+ score: r.score ?? 1,
409
+ metadata: JSON.parse(r.metadata) as DocumentMetadata,
410
+ }));
411
+ } catch {
412
+ // FTS index may not exist, return empty
413
+ return [];
414
+ }
415
+ }
416
+ ```
417
+
418
+ **Step 4: Run test to verify it passes**
419
+
420
+ ```bash
421
+ npm run test:run -- src/db/lance.test.ts
422
+ ```
423
+
424
+ Expected: PASS
425
+
426
+ **Step 5: Commit**
427
+
428
+ ```bash
429
+ git add src/db/lance.ts src/db/lance.test.ts
430
+ git commit -m "feat: add full-text search to LanceStore"
431
+ ```
432
+
433
+ ---
434
+
435
+ ### Task A.4: Add hybrid search with RRF to SearchService
436
+
437
+ **Files:**
438
+ - Modify: `src/services/search.service.ts`
439
+ - Modify: `src/services/search.service.test.ts`
440
+
441
+ **Step 1: Add hybrid search test**
442
+
443
+ Add to `src/services/search.service.test.ts`:
444
+ ```typescript
445
+ it('performs hybrid search combining vector and FTS', async () => {
446
+ const results = await searchService.search({
447
+ query: 'JavaScript programming',
448
+ stores: [storeId],
449
+ mode: 'hybrid',
450
+ limit: 10,
451
+ });
452
+
453
+ expect(results.mode).toBe('hybrid');
454
+ expect(results.results.length).toBeGreaterThan(0);
455
+ });
456
+ ```
457
+
458
+ **Step 2: Run test to verify it fails**
459
+
460
+ ```bash
461
+ npm run test:run -- src/services/search.service.test.ts
462
+ ```
463
+
464
+ Expected: FAIL or PASS (current implementation falls back to vector)
465
+
466
+ **Step 3: Implement hybrid search with RRF**
467
+
468
+ Update `src/services/search.service.ts`:
469
+ ```typescript
470
+ import type { LanceStore } from '../db/lance.js';
471
+ import type { EmbeddingEngine } from '../db/embeddings.js';
472
+ import type { SearchQuery, SearchResponse, SearchResult } from '../types/search.js';
473
+ import type { StoreId, DocumentId } from '../types/brands.js';
474
+
475
+ interface RRFConfig {
476
+ k: number;
477
+ vectorWeight: number;
478
+ ftsWeight: number;
479
+ }
480
+
481
+ export class SearchService {
482
+ private readonly lanceStore: LanceStore;
483
+ private readonly embeddingEngine: EmbeddingEngine;
484
+ private readonly rrfConfig: RRFConfig;
485
+
486
+ constructor(
487
+ lanceStore: LanceStore,
488
+ embeddingEngine: EmbeddingEngine,
489
+ rrfConfig: RRFConfig = { k: 60, vectorWeight: 0.7, ftsWeight: 0.3 }
490
+ ) {
491
+ this.lanceStore = lanceStore;
492
+ this.embeddingEngine = embeddingEngine;
493
+ this.rrfConfig = rrfConfig;
494
+ }
495
+
496
+ async search(query: SearchQuery): Promise<SearchResponse> {
497
+ const startTime = Date.now();
498
+ const mode = query.mode ?? 'hybrid';
499
+ const limit = query.limit ?? 10;
500
+ const stores = query.stores ?? [];
501
+
502
+ let allResults: SearchResult[] = [];
503
+
504
+ if (mode === 'vector') {
505
+ allResults = await this.vectorSearch(query.query, stores, limit, query.threshold);
506
+ } else if (mode === 'fts') {
507
+ allResults = await this.ftsSearch(query.query, stores, limit);
508
+ } else {
509
+ // Hybrid: combine vector and FTS with RRF
510
+ allResults = await this.hybridSearch(query.query, stores, limit, query.threshold);
511
+ }
512
+
513
+ return {
514
+ query: query.query,
515
+ mode,
516
+ stores,
517
+ results: allResults,
518
+ totalResults: allResults.length,
519
+ timeMs: Date.now() - startTime,
520
+ };
521
+ }
522
+
523
+ private async vectorSearch(
524
+ query: string,
525
+ stores: readonly StoreId[],
526
+ limit: number,
527
+ threshold?: number
528
+ ): Promise<SearchResult[]> {
529
+ const queryVector = await this.embeddingEngine.embed(query);
530
+ const results: SearchResult[] = [];
531
+
532
+ for (const storeId of stores) {
533
+ const hits = await this.lanceStore.search(storeId, queryVector, limit, threshold);
534
+ results.push(...hits.map(r => ({
535
+ id: r.id,
536
+ score: r.score,
537
+ content: r.content,
538
+ metadata: r.metadata,
539
+ })));
540
+ }
541
+
542
+ return results.sort((a, b) => b.score - a.score).slice(0, limit);
543
+ }
544
+
545
+ private async ftsSearch(
546
+ query: string,
547
+ stores: readonly StoreId[],
548
+ limit: number
549
+ ): Promise<SearchResult[]> {
550
+ const results: SearchResult[] = [];
551
+
552
+ for (const storeId of stores) {
553
+ const hits = await this.lanceStore.fullTextSearch(storeId, query, limit);
554
+ results.push(...hits.map(r => ({
555
+ id: r.id,
556
+ score: r.score,
557
+ content: r.content,
558
+ metadata: r.metadata,
559
+ })));
560
+ }
561
+
562
+ return results.sort((a, b) => b.score - a.score).slice(0, limit);
563
+ }
564
+
565
+ private async hybridSearch(
566
+ query: string,
567
+ stores: readonly StoreId[],
568
+ limit: number,
569
+ threshold?: number
570
+ ): Promise<SearchResult[]> {
571
+ // Get both result sets
572
+ const [vectorResults, ftsResults] = await Promise.all([
573
+ this.vectorSearch(query, stores, limit * 2, threshold),
574
+ this.ftsSearch(query, stores, limit * 2),
575
+ ]);
576
+
577
+ // Build rank maps
578
+ const vectorRanks = new Map<string, number>();
579
+ const ftsRanks = new Map<string, number>();
580
+ const allDocs = new Map<string, SearchResult>();
581
+
582
+ vectorResults.forEach((r, i) => {
583
+ vectorRanks.set(r.id, i + 1);
584
+ allDocs.set(r.id, r);
585
+ });
586
+
587
+ ftsResults.forEach((r, i) => {
588
+ ftsRanks.set(r.id, i + 1);
589
+ if (!allDocs.has(r.id)) {
590
+ allDocs.set(r.id, r);
591
+ }
592
+ });
593
+
594
+ // Calculate RRF scores
595
+ const rrfScores: Array<{ id: string; score: number; result: SearchResult }> = [];
596
+ const { k, vectorWeight, ftsWeight } = this.rrfConfig;
597
+
598
+ for (const [id, result] of allDocs) {
599
+ const vectorRank = vectorRanks.get(id) ?? Infinity;
600
+ const ftsRank = ftsRanks.get(id) ?? Infinity;
601
+
602
+ const vectorRRF = vectorRank !== Infinity ? vectorWeight / (k + vectorRank) : 0;
603
+ const ftsRRF = ftsRank !== Infinity ? ftsWeight / (k + ftsRank) : 0;
604
+
605
+ rrfScores.push({
606
+ id,
607
+ score: vectorRRF + ftsRRF,
608
+ result,
609
+ });
610
+ }
611
+
612
+ // Sort by RRF score and return
613
+ return rrfScores
614
+ .sort((a, b) => b.score - a.score)
615
+ .slice(0, limit)
616
+ .map(r => ({ ...r.result, score: r.score }));
617
+ }
618
+
619
+ async searchAllStores(query: SearchQuery, storeIds: StoreId[]): Promise<SearchResponse> {
620
+ return this.search({ ...query, stores: storeIds });
621
+ }
622
+ }
623
+ ```
624
+
625
+ **Step 4: Run all search tests**
626
+
627
+ ```bash
628
+ npm run test:run -- src/services/search.service.test.ts
629
+ ```
630
+
631
+ Expected: PASS
632
+
633
+ **Step 5: Commit**
634
+
635
+ ```bash
636
+ git add src/services/search.service.ts src/services/search.service.test.ts
637
+ git commit -m "feat: add hybrid search with RRF fusion"
638
+ ```
639
+
640
+ ---
641
+
642
+ ## Group B: User Experience
643
+
644
+ ### Task B.1: Add progress reporting to IndexService
645
+
646
+ **Files:**
647
+ - Modify: `src/services/index.service.ts`
648
+ - Create: `src/types/progress.ts`
649
+
650
+ **Step 1: Create progress types**
651
+
652
+ Create `src/types/progress.ts`:
653
+ ```typescript
654
+ export interface ProgressEvent {
655
+ type: 'start' | 'progress' | 'complete' | 'error';
656
+ current: number;
657
+ total: number;
658
+ message: string;
659
+ details?: Record<string, unknown>;
660
+ }
661
+
662
+ export type ProgressCallback = (event: ProgressEvent) => void;
663
+ ```
664
+
665
+ **Step 2: Add progress callback to IndexService**
666
+
667
+ Update `src/services/index.service.ts` to accept optional progress callback:
668
+ ```typescript
669
+ async indexStore(
670
+ store: Store,
671
+ onProgress?: ProgressCallback
672
+ ): Promise<Result<IndexResult>> {
673
+ // ... in indexFileStore, emit progress events:
674
+ onProgress?.({ type: 'start', current: 0, total: files.length, message: 'Starting index' });
675
+
676
+ // In loop:
677
+ onProgress?.({
678
+ type: 'progress',
679
+ current: filesProcessed,
680
+ total: files.length,
681
+ message: `Indexing ${filePath}`
682
+ });
683
+
684
+ // At end:
685
+ onProgress?.({ type: 'complete', current: files.length, total: files.length, message: 'Indexing complete' });
686
+ }
687
+ ```
688
+
689
+ **Step 3: Commit**
690
+
691
+ ```bash
692
+ git add src/types/progress.ts src/services/index.service.ts
693
+ git commit -m "feat: add progress callback to IndexService"
694
+ ```
695
+
696
+ ---
697
+
698
+ ### Task B.2: Add progress bars to CLI
699
+
700
+ **Files:**
701
+ - Modify: `src/cli/commands/index-cmd.ts`
702
+
703
+ **Step 1: Update index command with ora spinner**
704
+
705
+ Update `src/cli/commands/index-cmd.ts`:
706
+ ```typescript
707
+ import { Command } from 'commander';
708
+ import ora from 'ora';
709
+ import { createServices } from '../../services/index.js';
710
+ import type { GlobalOptions } from '../program.js';
711
+
712
+ export function createIndexCommand(getOptions: () => GlobalOptions): Command {
713
+ const index = new Command('index')
714
+ .description('Index a knowledge store')
715
+ .argument('<store>', 'Store ID or name')
716
+ .option('--force', 'Force reindex all files')
717
+ .action(async (storeIdOrName: string, options: { force?: boolean }) => {
718
+ const globalOpts = getOptions();
719
+ const services = await createServices(globalOpts.config, globalOpts.dataDir);
720
+
721
+ const store = await services.store.getByIdOrName(storeIdOrName);
722
+ if (store === undefined) {
723
+ console.error(`Store not found: ${storeIdOrName}`);
724
+ process.exit(3);
725
+ }
726
+
727
+ const spinner = ora(`Indexing store: ${store.name}`).start();
728
+ await services.lance.initialize(store.id);
729
+
730
+ const result = await services.index.indexStore(store, (event) => {
731
+ if (event.type === 'progress') {
732
+ spinner.text = `Indexing: ${event.current}/${event.total} files - ${event.message}`;
733
+ }
734
+ });
735
+
736
+ if (result.success) {
737
+ spinner.succeed(`Indexed ${result.data.documentsIndexed} files, ${result.data.chunksCreated} chunks in ${result.data.timeMs}ms`);
738
+ if (globalOpts.format === 'json') {
739
+ console.log(JSON.stringify(result.data, null, 2));
740
+ }
741
+ } else {
742
+ spinner.fail(`Error: ${result.error.message}`);
743
+ process.exit(4);
744
+ }
745
+ });
746
+
747
+ return index;
748
+ }
749
+ ```
750
+
751
+ **Step 2: Build and test**
752
+
753
+ ```bash
754
+ npm run build
755
+ ```
756
+
757
+ **Step 3: Commit**
758
+
759
+ ```bash
760
+ git add src/cli/commands/index-cmd.ts
761
+ git commit -m "feat: add progress spinner to index command"
762
+ ```
763
+
764
+ ---
765
+
766
+ ### Task B.3: Add file watching
767
+
768
+ **Files:**
769
+ - Create: `src/services/watch.service.ts`
770
+ - Modify: `src/cli/commands/index-cmd.ts`
771
+
772
+ **Step 1: Create WatchService**
773
+
774
+ Create `src/services/watch.service.ts`:
775
+ ```typescript
776
+ import { watch, type FSWatcher } from 'chokidar';
777
+ import type { Store, FileStore, RepoStore } from '../types/store.js';
778
+ import type { IndexService } from './index.service.js';
779
+ import type { LanceStore } from '../db/lance.js';
780
+
781
+ export class WatchService {
782
+ private watchers: Map<string, FSWatcher> = new Map();
783
+ private readonly indexService: IndexService;
784
+ private readonly lanceStore: LanceStore;
785
+
786
+ constructor(indexService: IndexService, lanceStore: LanceStore) {
787
+ this.indexService = indexService;
788
+ this.lanceStore = lanceStore;
789
+ }
790
+
791
+ async watch(
792
+ store: FileStore | RepoStore,
793
+ debounceMs = 1000,
794
+ onReindex?: () => void
795
+ ): Promise<void> {
796
+ if (this.watchers.has(store.id)) {
797
+ return; // Already watching
798
+ }
799
+
800
+ let timeout: NodeJS.Timeout | null = null;
801
+
802
+ const watcher = watch(store.path, {
803
+ ignored: /(^|[\/\\])\.(git|node_modules|dist|build)/,
804
+ persistent: true,
805
+ ignoreInitial: true,
806
+ });
807
+
808
+ watcher.on('all', () => {
809
+ if (timeout) clearTimeout(timeout);
810
+ timeout = setTimeout(async () => {
811
+ await this.lanceStore.initialize(store.id);
812
+ await this.indexService.indexStore(store);
813
+ onReindex?.();
814
+ }, debounceMs);
815
+ });
816
+
817
+ this.watchers.set(store.id, watcher);
818
+ }
819
+
820
+ async unwatch(storeId: string): Promise<void> {
821
+ const watcher = this.watchers.get(storeId);
822
+ if (watcher) {
823
+ await watcher.close();
824
+ this.watchers.delete(storeId);
825
+ }
826
+ }
827
+
828
+ async unwatchAll(): Promise<void> {
829
+ for (const [id] of this.watchers) {
830
+ await this.unwatch(id);
831
+ }
832
+ }
833
+ }
834
+ ```
835
+
836
+ **Step 2: Add watch subcommand to index**
837
+
838
+ Add to `src/cli/commands/index-cmd.ts`:
839
+ ```typescript
840
+ index
841
+ .command('watch <store>')
842
+ .description('Watch for changes and auto-reindex')
843
+ .option('--debounce <ms>', 'Debounce interval in ms', '1000')
844
+ .action(async (storeIdOrName: string, options: { debounce?: string }) => {
845
+ const globalOpts = getOptions();
846
+ const services = await createServices(globalOpts.config, globalOpts.dataDir);
847
+
848
+ const store = await services.store.getByIdOrName(storeIdOrName);
849
+ if (store === undefined || (store.type !== 'file' && store.type !== 'repo')) {
850
+ console.error(`File/repo store not found: ${storeIdOrName}`);
851
+ process.exit(3);
852
+ }
853
+
854
+ const { WatchService } = await import('../../services/watch.service.js');
855
+ const watchService = new WatchService(services.index, services.lance);
856
+
857
+ console.log(`Watching ${store.name} for changes...`);
858
+ await watchService.watch(store, parseInt(options.debounce ?? '1000', 10), () => {
859
+ console.log(`Re-indexed ${store.name}`);
860
+ });
861
+
862
+ // Keep process alive
863
+ process.on('SIGINT', async () => {
864
+ await watchService.unwatchAll();
865
+ process.exit(0);
866
+ });
867
+ });
868
+ ```
869
+
870
+ **Step 3: Commit**
871
+
872
+ ```bash
873
+ git add src/services/watch.service.ts src/cli/commands/index-cmd.ts
874
+ git commit -m "feat: add file watching with auto-reindex"
875
+ ```
876
+
877
+ ---
878
+
879
+ ## Group C: HTTP Server
880
+
881
+ ### Task C.1: Create Hono server
882
+
883
+ **Files:**
884
+ - Create: `src/server/app.ts`
885
+ - Modify: `src/server/index.ts`
886
+
887
+ **Step 1: Create server app**
888
+
889
+ Create `src/server/app.ts`:
890
+ ```typescript
891
+ import { Hono } from 'hono';
892
+ import { cors } from 'hono/cors';
893
+ import type { ServiceContainer } from '../services/index.js';
894
+
895
+ export function createApp(services: ServiceContainer): Hono {
896
+ const app = new Hono();
897
+
898
+ app.use('*', cors());
899
+
900
+ // Health check
901
+ app.get('/health', (c) => c.json({ status: 'ok' }));
902
+
903
+ // Stores
904
+ app.get('/api/stores', async (c) => {
905
+ const stores = await services.store.list();
906
+ return c.json(stores);
907
+ });
908
+
909
+ app.post('/api/stores', async (c) => {
910
+ const body = await c.req.json();
911
+ const result = await services.store.create(body);
912
+ if (result.success) {
913
+ return c.json(result.data, 201);
914
+ }
915
+ return c.json({ error: result.error.message }, 400);
916
+ });
917
+
918
+ app.get('/api/stores/:id', async (c) => {
919
+ const store = await services.store.getByIdOrName(c.req.param('id'));
920
+ if (!store) return c.json({ error: 'Not found' }, 404);
921
+ return c.json(store);
922
+ });
923
+
924
+ app.delete('/api/stores/:id', async (c) => {
925
+ const store = await services.store.getByIdOrName(c.req.param('id'));
926
+ if (!store) return c.json({ error: 'Not found' }, 404);
927
+ const result = await services.store.delete(store.id);
928
+ if (result.success) return c.json({ deleted: true });
929
+ return c.json({ error: result.error.message }, 400);
930
+ });
931
+
932
+ // Search
933
+ app.post('/api/search', async (c) => {
934
+ const body = await c.req.json();
935
+ const storeIds = (await services.store.list()).map(s => s.id);
936
+
937
+ for (const id of storeIds) {
938
+ await services.lance.initialize(id);
939
+ }
940
+
941
+ const results = await services.search.search({
942
+ ...body,
943
+ stores: body.stores ?? storeIds,
944
+ });
945
+ return c.json(results);
946
+ });
947
+
948
+ // Index
949
+ app.post('/api/stores/:id/index', async (c) => {
950
+ const store = await services.store.getByIdOrName(c.req.param('id'));
951
+ if (!store) return c.json({ error: 'Not found' }, 404);
952
+
953
+ await services.lance.initialize(store.id);
954
+ const result = await services.index.indexStore(store);
955
+
956
+ if (result.success) return c.json(result.data);
957
+ return c.json({ error: result.error.message }, 400);
958
+ });
959
+
960
+ return app;
961
+ }
962
+ ```
963
+
964
+ **Step 2: Update server barrel**
965
+
966
+ Update `src/server/index.ts`:
967
+ ```typescript
968
+ export { createApp } from './app.js';
969
+ ```
970
+
971
+ **Step 3: Commit**
972
+
973
+ ```bash
974
+ git add src/server/app.ts src/server/index.ts
975
+ git commit -m "feat: add Hono HTTP server with REST API"
976
+ ```
977
+
978
+ ---
979
+
980
+ ### Task C.2: Add serve command
981
+
982
+ **Files:**
983
+ - Create: `src/cli/commands/serve.ts`
984
+ - Modify: `src/index.ts`
985
+
986
+ **Step 1: Create serve command**
987
+
988
+ Create `src/cli/commands/serve.ts`:
989
+ ```typescript
990
+ import { Command } from 'commander';
991
+ import { serve } from '@hono/node-server';
992
+ import { createServices } from '../../services/index.js';
993
+ import { createApp } from '../../server/app.js';
994
+ import type { GlobalOptions } from '../program.js';
995
+
996
+ export function createServeCommand(getOptions: () => GlobalOptions): Command {
997
+ return new Command('serve')
998
+ .description('Start HTTP server for API access')
999
+ .option('-p, --port <port>', 'Port number', '3847')
1000
+ .option('--host <host>', 'Host to bind', '127.0.0.1')
1001
+ .action(async (options: { port?: string; host?: string }) => {
1002
+ const globalOpts = getOptions();
1003
+ const services = await createServices(globalOpts.config, globalOpts.dataDir);
1004
+ const app = createApp(services);
1005
+
1006
+ const port = parseInt(options.port ?? '3847', 10);
1007
+ const host = options.host ?? '127.0.0.1';
1008
+
1009
+ console.log(`Starting server on http://${host}:${port}`);
1010
+
1011
+ serve({
1012
+ fetch: app.fetch,
1013
+ port,
1014
+ hostname: host,
1015
+ });
1016
+ });
1017
+ }
1018
+ ```
1019
+
1020
+ **Step 2: Register serve command**
1021
+
1022
+ Update `src/index.ts`:
1023
+ ```typescript
1024
+ import { createServeCommand } from './cli/commands/serve.js';
1025
+
1026
+ // Add with other commands:
1027
+ program.addCommand(createServeCommand(() => getGlobalOptions(program)));
1028
+ ```
1029
+
1030
+ **Step 3: Update CLI barrel**
1031
+
1032
+ Update `src/cli/index.ts`:
1033
+ ```typescript
1034
+ export { createServeCommand } from './commands/serve.js';
1035
+ ```
1036
+
1037
+ **Step 4: Commit**
1038
+
1039
+ ```bash
1040
+ git add src/cli/commands/serve.ts src/index.ts src/cli/index.ts
1041
+ git commit -m "feat: add serve command for HTTP server"
1042
+ ```
1043
+
1044
+ ---
1045
+
1046
+ ## Group D: Web Crawling
1047
+
1048
+ ### Task D.1: Create Python crawl worker
1049
+
1050
+ **Files:**
1051
+ - Create: `python/requirements.txt`
1052
+ - Create: `python/crawl_worker.py`
1053
+
1054
+ **Step 1: Create requirements.txt**
1055
+
1056
+ Create `python/requirements.txt`:
1057
+ ```
1058
+ crawl4ai>=0.3.0
1059
+ beautifulsoup4>=4.12.0
1060
+ ```
1061
+
1062
+ **Step 2: Create crawl worker**
1063
+
1064
+ Create `python/crawl_worker.py`:
1065
+ ```python
1066
+ #!/usr/bin/env python3
1067
+ import sys
1068
+ import json
1069
+ from crawl4ai import WebCrawler
1070
+
1071
+ def main():
1072
+ crawler = WebCrawler()
1073
+ crawler.warmup()
1074
+
1075
+ for line in sys.stdin:
1076
+ try:
1077
+ request = json.loads(line.strip())
1078
+ if request.get('method') == 'crawl':
1079
+ params = request.get('params', {})
1080
+ url = params.get('url')
1081
+
1082
+ result = crawler.run(url=url)
1083
+
1084
+ response = {
1085
+ 'jsonrpc': '2.0',
1086
+ 'id': request.get('id'),
1087
+ 'result': {
1088
+ 'pages': [{
1089
+ 'url': url,
1090
+ 'title': result.title or '',
1091
+ 'content': result.markdown or result.text or '',
1092
+ 'links': result.links or [],
1093
+ 'crawledAt': result.crawled_at or '',
1094
+ }]
1095
+ }
1096
+ }
1097
+ print(json.dumps(response), flush=True)
1098
+
1099
+ except Exception as e:
1100
+ error_response = {
1101
+ 'jsonrpc': '2.0',
1102
+ 'id': request.get('id') if 'request' in dir() else None,
1103
+ 'error': {'code': -1, 'message': str(e)}
1104
+ }
1105
+ print(json.dumps(error_response), flush=True)
1106
+
1107
+ if __name__ == '__main__':
1108
+ main()
1109
+ ```
1110
+
1111
+ **Step 3: Commit**
1112
+
1113
+ ```bash
1114
+ git add python/
1115
+ git commit -m "feat: add Python crawl worker with crawl4ai"
1116
+ ```
1117
+
1118
+ ---
1119
+
1120
+ ### Task D.2: Create Python bridge
1121
+
1122
+ **Files:**
1123
+ - Create: `src/crawl/bridge.ts`
1124
+
1125
+ **Step 1: Create bridge**
1126
+
1127
+ Create `src/crawl/bridge.ts`:
1128
+ ```typescript
1129
+ import { spawn, type ChildProcess } from 'node:child_process';
1130
+ import { createInterface } from 'node:readline';
1131
+ import { randomUUID } from 'node:crypto';
1132
+
1133
+ interface CrawlResult {
1134
+ pages: Array<{
1135
+ url: string;
1136
+ title: string;
1137
+ content: string;
1138
+ links: string[];
1139
+ crawledAt: string;
1140
+ }>;
1141
+ }
1142
+
1143
+ export class PythonBridge {
1144
+ private process: ChildProcess | null = null;
1145
+ private pending: Map<string, { resolve: (v: CrawlResult) => void; reject: (e: Error) => void }> = new Map();
1146
+
1147
+ async start(): Promise<void> {
1148
+ if (this.process) return;
1149
+
1150
+ this.process = spawn('python3', ['python/crawl_worker.py'], {
1151
+ stdio: ['pipe', 'pipe', 'pipe'],
1152
+ });
1153
+
1154
+ const rl = createInterface({ input: this.process.stdout! });
1155
+ rl.on('line', (line) => {
1156
+ try {
1157
+ const response = JSON.parse(line);
1158
+ const pending = this.pending.get(response.id);
1159
+ if (pending) {
1160
+ if (response.error) {
1161
+ pending.reject(new Error(response.error.message));
1162
+ } else {
1163
+ pending.resolve(response.result);
1164
+ }
1165
+ this.pending.delete(response.id);
1166
+ }
1167
+ } catch {}
1168
+ });
1169
+ }
1170
+
1171
+ async crawl(url: string): Promise<CrawlResult> {
1172
+ if (!this.process) await this.start();
1173
+
1174
+ const id = randomUUID();
1175
+ const request = {
1176
+ jsonrpc: '2.0',
1177
+ id,
1178
+ method: 'crawl',
1179
+ params: { url },
1180
+ };
1181
+
1182
+ return new Promise((resolve, reject) => {
1183
+ this.pending.set(id, { resolve, reject });
1184
+ this.process!.stdin!.write(JSON.stringify(request) + '\n');
1185
+ });
1186
+ }
1187
+
1188
+ async stop(): Promise<void> {
1189
+ if (this.process) {
1190
+ this.process.kill();
1191
+ this.process = null;
1192
+ }
1193
+ }
1194
+ }
1195
+ ```
1196
+
1197
+ **Step 2: Commit**
1198
+
1199
+ ```bash
1200
+ git add src/crawl/bridge.ts
1201
+ git commit -m "feat: add Python bridge for web crawling"
1202
+ ```
1203
+
1204
+ ---
1205
+
1206
+ ### Task D.3: Add crawl command
1207
+
1208
+ **Files:**
1209
+ - Create: `src/cli/commands/crawl.ts`
1210
+ - Modify: `src/index.ts`
1211
+
1212
+ **Step 1: Create crawl command**
1213
+
1214
+ Create `src/cli/commands/crawl.ts`:
1215
+ ```typescript
1216
+ import { Command } from 'commander';
1217
+ import ora from 'ora';
1218
+ import { createServices } from '../../services/index.js';
1219
+ import { PythonBridge } from '../../crawl/bridge.js';
1220
+ import { createDocumentId } from '../../types/brands.js';
1221
+ import type { GlobalOptions } from '../program.js';
1222
+ import type { Document } from '../../types/document.js';
1223
+
1224
+ export function createCrawlCommand(getOptions: () => GlobalOptions): Command {
1225
+ return new Command('crawl')
1226
+ .description('Crawl a URL and add to store')
1227
+ .argument('<url>', 'URL to crawl')
1228
+ .requiredOption('-s, --store <store>', 'Target store ID/name')
1229
+ .action(async (url: string, options: { store: string }) => {
1230
+ const globalOpts = getOptions();
1231
+ const services = await createServices(globalOpts.config, globalOpts.dataDir);
1232
+
1233
+ const store = await services.store.getByIdOrName(options.store);
1234
+ if (!store || store.type !== 'web') {
1235
+ console.error('Web store not found:', options.store);
1236
+ process.exit(3);
1237
+ }
1238
+
1239
+ const spinner = ora(`Crawling ${url}`).start();
1240
+ const bridge = new PythonBridge();
1241
+
1242
+ try {
1243
+ const result = await bridge.crawl(url);
1244
+ spinner.text = 'Indexing crawled content...';
1245
+
1246
+ await services.lance.initialize(store.id);
1247
+
1248
+ const docs: Document[] = [];
1249
+ for (const page of result.pages) {
1250
+ const vector = await services.embeddings.embed(page.content);
1251
+ docs.push({
1252
+ id: createDocumentId(`${store.id}-${Buffer.from(page.url).toString('base64').slice(0, 20)}`),
1253
+ content: page.content,
1254
+ vector,
1255
+ metadata: {
1256
+ type: 'web',
1257
+ storeId: store.id,
1258
+ url: page.url,
1259
+ indexedAt: new Date(),
1260
+ },
1261
+ });
1262
+ }
1263
+
1264
+ await services.lance.addDocuments(store.id, docs);
1265
+ spinner.succeed(`Crawled and indexed ${result.pages.length} pages`);
1266
+ } catch (error) {
1267
+ spinner.fail(`Crawl failed: ${error}`);
1268
+ process.exit(6);
1269
+ } finally {
1270
+ await bridge.stop();
1271
+ }
1272
+ });
1273
+ }
1274
+ ```
1275
+
1276
+ **Step 2: Register command**
1277
+
1278
+ Update `src/index.ts`:
1279
+ ```typescript
1280
+ import { createCrawlCommand } from './cli/commands/crawl.js';
1281
+
1282
+ program.addCommand(createCrawlCommand(() => getGlobalOptions(program)));
1283
+ ```
1284
+
1285
+ **Step 3: Commit**
1286
+
1287
+ ```bash
1288
+ git add src/cli/commands/crawl.ts src/index.ts
1289
+ git commit -m "feat: add crawl command for web content"
1290
+ ```
1291
+
1292
+ ---
1293
+
1294
+ ## Group E: Export/Import
1295
+
1296
+ ### Task E.1: Add export command
1297
+
1298
+ **Files:**
1299
+ - Create: `src/cli/commands/export.ts`
1300
+
1301
+ **Step 1: Create export command**
1302
+
1303
+ Create `src/cli/commands/export.ts`:
1304
+ ```typescript
1305
+ import { Command } from 'commander';
1306
+ import { writeFile } from 'node:fs/promises';
1307
+ import { createServices } from '../../services/index.js';
1308
+ import type { GlobalOptions } from '../program.js';
1309
+
1310
+ export function createExportCommand(getOptions: () => GlobalOptions): Command {
1311
+ return new Command('export')
1312
+ .description('Export store to file')
1313
+ .argument('<store>', 'Store ID or name')
1314
+ .requiredOption('-o, --output <path>', 'Output file path')
1315
+ .action(async (storeIdOrName: string, options: { output: string }) => {
1316
+ const globalOpts = getOptions();
1317
+ const services = await createServices(globalOpts.config, globalOpts.dataDir);
1318
+
1319
+ const store = await services.store.getByIdOrName(storeIdOrName);
1320
+ if (!store) {
1321
+ console.error('Store not found:', storeIdOrName);
1322
+ process.exit(3);
1323
+ }
1324
+
1325
+ await services.lance.initialize(store.id);
1326
+
1327
+ // Get all documents by doing a search with empty vector
1328
+ const dummyVector = new Array(384).fill(0);
1329
+ const docs = await services.lance.search(store.id, dummyVector, 10000);
1330
+
1331
+ const exportData = {
1332
+ version: 1,
1333
+ store,
1334
+ documents: docs,
1335
+ exportedAt: new Date().toISOString(),
1336
+ };
1337
+
1338
+ await writeFile(options.output, JSON.stringify(exportData, null, 2));
1339
+ console.log(`Exported ${docs.length} documents to ${options.output}`);
1340
+ });
1341
+ }
1342
+ ```
1343
+
1344
+ **Step 2: Register command**
1345
+
1346
+ Update `src/index.ts`:
1347
+ ```typescript
1348
+ import { createExportCommand } from './cli/commands/export.js';
1349
+
1350
+ program.addCommand(createExportCommand(() => getGlobalOptions(program)));
1351
+ ```
1352
+
1353
+ **Step 3: Commit**
1354
+
1355
+ ```bash
1356
+ git add src/cli/commands/export.ts src/index.ts
1357
+ git commit -m "feat: add export command"
1358
+ ```
1359
+
1360
+ ---
1361
+
1362
+ ### Task E.2: Add import command
1363
+
1364
+ **Files:**
1365
+ - Create: `src/cli/commands/import.ts`
1366
+
1367
+ **Step 1: Create import command**
1368
+
1369
+ Create `src/cli/commands/import.ts`:
1370
+ ```typescript
1371
+ import { Command } from 'commander';
1372
+ import { readFile } from 'node:fs/promises';
1373
+ import { createServices } from '../../services/index.js';
1374
+ import { createStoreId } from '../../types/brands.js';
1375
+ import type { GlobalOptions } from '../program.js';
1376
+
1377
+ export function createImportCommand(getOptions: () => GlobalOptions): Command {
1378
+ return new Command('import')
1379
+ .description('Import store from file')
1380
+ .argument('<path>', 'Import file path')
1381
+ .requiredOption('-n, --name <name>', 'New store name')
1382
+ .action(async (path: string, options: { name: string }) => {
1383
+ const globalOpts = getOptions();
1384
+ const services = await createServices(globalOpts.config, globalOpts.dataDir);
1385
+
1386
+ const content = await readFile(path, 'utf-8');
1387
+ const data = JSON.parse(content);
1388
+
1389
+ // Create new store with imported data
1390
+ const result = await services.store.create({
1391
+ name: options.name,
1392
+ type: data.store.type,
1393
+ path: data.store.path,
1394
+ url: data.store.url,
1395
+ description: `Imported from ${path}`,
1396
+ });
1397
+
1398
+ if (!result.success) {
1399
+ console.error('Failed to create store:', result.error.message);
1400
+ process.exit(1);
1401
+ }
1402
+
1403
+ const store = result.data;
1404
+ await services.lance.initialize(store.id);
1405
+
1406
+ // Re-embed and add documents
1407
+ for (const doc of data.documents) {
1408
+ const vector = await services.embeddings.embed(doc.content);
1409
+ await services.lance.addDocuments(store.id, [{
1410
+ id: doc.id,
1411
+ content: doc.content,
1412
+ vector,
1413
+ metadata: { ...doc.metadata, storeId: store.id },
1414
+ }]);
1415
+ }
1416
+
1417
+ console.log(`Imported ${data.documents.length} documents as "${options.name}"`);
1418
+ });
1419
+ }
1420
+ ```
1421
+
1422
+ **Step 2: Register command**
1423
+
1424
+ Update `src/index.ts`:
1425
+ ```typescript
1426
+ import { createImportCommand } from './cli/commands/import.js';
1427
+
1428
+ program.addCommand(createImportCommand(() => getGlobalOptions(program)));
1429
+ ```
1430
+
1431
+ **Step 3: Commit**
1432
+
1433
+ ```bash
1434
+ git add src/cli/commands/import.ts src/index.ts
1435
+ git commit -m "feat: add import command"
1436
+ ```
1437
+
1438
+ ---
1439
+
1440
+ ## Final: Update exports and run tests
1441
+
1442
+ ### Task F.1: Update all barrel exports
1443
+
1444
+ **Files:**
1445
+ - Modify: `src/types/index.ts`
1446
+ - Modify: `src/services/index.ts`
1447
+ - Modify: `src/cli/index.ts`
1448
+
1449
+ **Step 1: Update types barrel**
1450
+
1451
+ Add to `src/types/index.ts`:
1452
+ ```typescript
1453
+ export { type ProgressEvent, type ProgressCallback } from './progress.js';
1454
+ ```
1455
+
1456
+ **Step 2: Update services barrel**
1457
+
1458
+ Add to `src/services/index.ts`:
1459
+ ```typescript
1460
+ export { ChunkingService } from './chunking.service.js';
1461
+ export { WatchService } from './watch.service.js';
1462
+ ```
1463
+
1464
+ **Step 3: Update CLI barrel**
1465
+
1466
+ Add to `src/cli/index.ts`:
1467
+ ```typescript
1468
+ export { createServeCommand } from './commands/serve.js';
1469
+ export { createCrawlCommand } from './commands/crawl.js';
1470
+ export { createExportCommand } from './commands/export.js';
1471
+ export { createImportCommand } from './commands/import.js';
1472
+ ```
1473
+
1474
+ **Step 4: Run all tests**
1475
+
1476
+ ```bash
1477
+ npm run build && npm run test:run
1478
+ ```
1479
+
1480
+ **Step 5: Commit**
1481
+
1482
+ ```bash
1483
+ git add .
1484
+ git commit -m "feat: complete Phase 2 features - all exports updated"
1485
+ ```
1486
+
1487
+ ---
1488
+
1489
+ ## Summary
1490
+
1491
+ **Total Tasks:** 15
1492
+
1493
+ **Group A - Search Improvements (4 tasks):**
1494
+ - A.1: ChunkingService
1495
+ - A.2: Integrate chunking into IndexService
1496
+ - A.3: Full-text search in LanceStore
1497
+ - A.4: Hybrid search with RRF
1498
+
1499
+ **Group B - User Experience (3 tasks):**
1500
+ - B.1: Progress reporting
1501
+ - B.2: Progress bars (ora)
1502
+ - B.3: File watching
1503
+
1504
+ **Group C - HTTP Server (2 tasks):**
1505
+ - C.1: Hono server
1506
+ - C.2: Serve command
1507
+
1508
+ **Group D - Web Crawling (3 tasks):**
1509
+ - D.1: Python crawl worker
1510
+ - D.2: Python bridge
1511
+ - D.3: Crawl command
1512
+
1513
+ **Group E - Export/Import (2 tasks):**
1514
+ - E.1: Export command
1515
+ - E.2: Import command
1516
+
1517
+ **Final (1 task):**
1518
+ - F.1: Update exports and test