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,931 @@
1
+ /**
2
+ * Comprehensive tests for IntelligentCrawler
3
+ * Coverage: mode selection, network errors, loop prevention, memory, events, stop, limits, domain filtering
4
+ */
5
+
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { IntelligentCrawler } from './intelligent-crawler.js';
8
+ import type { CrawlProgress } from './intelligent-crawler.js';
9
+ import axios from 'axios';
10
+ import * as articleConverter from './article-converter.js';
11
+
12
+ // Mock dependencies
13
+ vi.mock('axios');
14
+ vi.mock('./claude-client.js');
15
+ vi.mock('./bridge.js');
16
+ vi.mock('./article-converter.js');
17
+
18
+ // Import mocked classes after mocking
19
+ const { ClaudeClient } = await import('./claude-client.js');
20
+ const { PythonBridge } = await import('./bridge.js');
21
+
22
+ describe('IntelligentCrawler', () => {
23
+ let crawler: IntelligentCrawler;
24
+ let mockClaudeClient: any;
25
+ let mockPythonBridge: any;
26
+ let progressEvents: CrawlProgress[];
27
+
28
+ beforeEach(() => {
29
+ // Reset all mocks
30
+ vi.clearAllMocks();
31
+ progressEvents = [];
32
+
33
+ // Setup ClaudeClient mock - ensure isAvailable returns true for intelligent mode tests
34
+ mockClaudeClient = {
35
+ determineCrawlUrls: vi.fn(),
36
+ extractContent: vi.fn(),
37
+ };
38
+ vi.mocked(ClaudeClient).mockImplementation(function() { return mockClaudeClient; });
39
+ // Mock static isAvailable to return true (Claude CLI is available in tests)
40
+ vi.mocked(ClaudeClient.isAvailable).mockReturnValue(true);
41
+
42
+ // Setup PythonBridge mock
43
+ mockPythonBridge = {
44
+ crawl: vi.fn(),
45
+ fetchHeadless: vi.fn(),
46
+ stop: vi.fn().mockResolvedValue(undefined),
47
+ };
48
+ vi.mocked(PythonBridge).mockImplementation(function() { return mockPythonBridge; });
49
+
50
+ // Setup axios mock
51
+ vi.mocked(axios.get).mockResolvedValue({
52
+ data: '<html><body><h1>Test</h1><a href="https://example.com/page1">Link</a></body></html>',
53
+ });
54
+
55
+ // Setup convertHtmlToMarkdown mock
56
+ vi.mocked(articleConverter.convertHtmlToMarkdown).mockResolvedValue({
57
+ success: true,
58
+ markdown: '# Test\n\nContent',
59
+ title: 'Test Page',
60
+ });
61
+
62
+ // Create crawler instance
63
+ crawler = new IntelligentCrawler();
64
+
65
+ // Listen to progress events
66
+ crawler.on('progress', (progress: CrawlProgress) => {
67
+ progressEvents.push(progress);
68
+ });
69
+ });
70
+
71
+ afterEach(async () => {
72
+ await crawler.stop();
73
+ });
74
+
75
+ describe('Mode Selection', () => {
76
+ it('should use intelligent mode when crawlInstruction is provided', async () => {
77
+ mockClaudeClient.determineCrawlUrls.mockResolvedValue({
78
+ urls: ['https://example.com/page1'],
79
+ reasoning: 'Found relevant page',
80
+ });
81
+
82
+ const results = [];
83
+ for await (const result of crawler.crawl('https://example.com', {
84
+ crawlInstruction: 'Find all docs',
85
+ })) {
86
+ results.push(result);
87
+ }
88
+
89
+ expect(mockClaudeClient.determineCrawlUrls).toHaveBeenCalledOnce();
90
+ expect(results).toHaveLength(1);
91
+ });
92
+
93
+ it('should use simple mode when crawlInstruction is empty string', async () => {
94
+ mockPythonBridge.crawl.mockResolvedValue({
95
+ pages: [{ links: [] }],
96
+ });
97
+
98
+ const results = [];
99
+ for await (const result of crawler.crawl('https://example.com', {
100
+ crawlInstruction: '',
101
+ })) {
102
+ results.push(result);
103
+ }
104
+
105
+ expect(mockClaudeClient.determineCrawlUrls).not.toHaveBeenCalled();
106
+ expect(results).toHaveLength(1);
107
+ });
108
+
109
+ it('should use simple mode when crawlInstruction is undefined', async () => {
110
+ mockPythonBridge.crawl.mockResolvedValue({
111
+ pages: [{ links: [] }],
112
+ });
113
+
114
+ const results = [];
115
+ for await (const result of crawler.crawl('https://example.com', {})) {
116
+ results.push(result);
117
+ }
118
+
119
+ expect(mockClaudeClient.determineCrawlUrls).not.toHaveBeenCalled();
120
+ expect(results).toHaveLength(1);
121
+ });
122
+
123
+ it('should force simple mode when simple option is true', async () => {
124
+ mockPythonBridge.crawl.mockResolvedValue({
125
+ pages: [{ links: [] }],
126
+ });
127
+
128
+ const results = [];
129
+ for await (const result of crawler.crawl('https://example.com', {
130
+ crawlInstruction: 'Find all docs',
131
+ simple: true,
132
+ })) {
133
+ results.push(result);
134
+ }
135
+
136
+ expect(mockClaudeClient.determineCrawlUrls).not.toHaveBeenCalled();
137
+ expect(results).toHaveLength(1);
138
+ });
139
+ });
140
+
141
+ describe('Network Error Handling', () => {
142
+ it('should handle timeout errors gracefully', async () => {
143
+ vi.mocked(axios.get).mockRejectedValueOnce({
144
+ code: 'ETIMEDOUT',
145
+ message: 'timeout of 30000ms exceeded',
146
+ });
147
+
148
+ const results = [];
149
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
150
+ results.push(result);
151
+ }
152
+
153
+ // Should fail to fetch and emit error but not crash
154
+ expect(results).toHaveLength(0);
155
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
156
+ expect(errorEvents.length).toBeGreaterThan(0);
157
+ });
158
+
159
+ it('should handle DNS failures', async () => {
160
+ vi.mocked(axios.get).mockRejectedValueOnce({
161
+ code: 'ENOTFOUND',
162
+ message: 'getaddrinfo ENOTFOUND invalid.example.com',
163
+ });
164
+
165
+ const results = [];
166
+ for await (const result of crawler.crawl('https://invalid.example.com', { simple: true })) {
167
+ results.push(result);
168
+ }
169
+
170
+ expect(results).toHaveLength(0);
171
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
172
+ expect(errorEvents.length).toBeGreaterThan(0);
173
+ });
174
+
175
+ it('should handle 404 errors', async () => {
176
+ vi.mocked(axios.get).mockRejectedValueOnce({
177
+ response: { status: 404 },
178
+ message: 'Request failed with status code 404',
179
+ });
180
+
181
+ const results = [];
182
+ for await (const result of crawler.crawl('https://example.com/404', { simple: true })) {
183
+ results.push(result);
184
+ }
185
+
186
+ expect(results).toHaveLength(0);
187
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
188
+ expect(errorEvents.length).toBeGreaterThan(0);
189
+ });
190
+
191
+ it('should handle 500 errors', async () => {
192
+ vi.mocked(axios.get).mockRejectedValueOnce({
193
+ response: { status: 500 },
194
+ message: 'Request failed with status code 500',
195
+ });
196
+
197
+ const results = [];
198
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
199
+ results.push(result);
200
+ }
201
+
202
+ expect(results).toHaveLength(0);
203
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
204
+ expect(errorEvents.length).toBeGreaterThan(0);
205
+ });
206
+
207
+ it('should handle network connection refused', async () => {
208
+ vi.mocked(axios.get).mockRejectedValueOnce({
209
+ code: 'ECONNREFUSED',
210
+ message: 'connect ECONNREFUSED 127.0.0.1:80',
211
+ });
212
+
213
+ const results = [];
214
+ for await (const result of crawler.crawl('http://localhost', { simple: true })) {
215
+ results.push(result);
216
+ }
217
+
218
+ expect(results).toHaveLength(0);
219
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
220
+ expect(errorEvents.length).toBeGreaterThan(0);
221
+ });
222
+ });
223
+
224
+ describe('Infinite Loop Prevention', () => {
225
+ it('should not visit the same URL twice in simple mode', async () => {
226
+ const circular = 'https://example.com/page1';
227
+ mockPythonBridge.crawl.mockResolvedValue({
228
+ pages: [{ links: [circular] }], // Link back to itself
229
+ });
230
+
231
+ vi.mocked(axios.get)
232
+ .mockResolvedValueOnce({ data: `<html><body><a href="${circular}">Self</a></body></html>` });
233
+
234
+ const results = [];
235
+ for await (const result of crawler.crawl(circular, { simple: true, maxPages: 10 })) {
236
+ results.push(result);
237
+ }
238
+
239
+ // Should only crawl once despite circular link
240
+ expect(results).toHaveLength(1);
241
+ expect(vi.mocked(axios.get)).toHaveBeenCalledTimes(1);
242
+ });
243
+
244
+ it('should not visit the same URL twice in intelligent mode', async () => {
245
+ const duplicate = 'https://example.com/page1';
246
+ mockClaudeClient.determineCrawlUrls.mockResolvedValue({
247
+ urls: [duplicate, duplicate, duplicate], // Same URL repeated
248
+ reasoning: 'Found duplicate URLs',
249
+ });
250
+
251
+ const results = [];
252
+ for await (const result of crawler.crawl('https://example.com', {
253
+ crawlInstruction: 'Find all',
254
+ maxPages: 10,
255
+ })) {
256
+ results.push(result);
257
+ }
258
+
259
+ // Should only crawl the URL once
260
+ expect(results).toHaveLength(1);
261
+ });
262
+
263
+ it('should handle circular references across multiple pages', async () => {
264
+ const page1 = 'https://example.com/page1';
265
+ const page2 = 'https://example.com/page2';
266
+
267
+ mockPythonBridge.crawl
268
+ .mockResolvedValueOnce({ pages: [{ links: [page2] }] }) // page1 -> page2
269
+ .mockResolvedValueOnce({ pages: [{ links: [page1] }] }); // page2 -> page1
270
+
271
+ vi.mocked(axios.get)
272
+ .mockResolvedValueOnce({ data: `<html><body><a href="${page2}">Next</a></body></html>` })
273
+ .mockResolvedValueOnce({ data: `<html><body><a href="${page1}">Back</a></body></html>` });
274
+
275
+ const results = [];
276
+ for await (const result of crawler.crawl(page1, { simple: true, maxPages: 10 })) {
277
+ results.push(result);
278
+ }
279
+
280
+ // Should crawl both pages once, not infinitely
281
+ expect(results).toHaveLength(2);
282
+ });
283
+ });
284
+
285
+ describe('Memory Management', () => {
286
+ it('should track visited URLs in a Set', async () => {
287
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
288
+
289
+ const results = [];
290
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
291
+ results.push(result);
292
+ }
293
+
294
+ expect(results).toHaveLength(1);
295
+ // Verify visited set is working by attempting to crawl again
296
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
297
+ results.push(result);
298
+ }
299
+ // Second crawl should also work (visited set cleared)
300
+ expect(results).toHaveLength(2);
301
+ });
302
+
303
+ it('should clear visited set on new crawl', async () => {
304
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
305
+
306
+ // First crawl
307
+ const results1 = [];
308
+ for await (const result of crawler.crawl('https://example.com/a', { simple: true })) {
309
+ results1.push(result);
310
+ }
311
+ expect(results1).toHaveLength(1);
312
+
313
+ // Second crawl with same URL should work (set was cleared)
314
+ const results2 = [];
315
+ for await (const result of crawler.crawl('https://example.com/a', { simple: true })) {
316
+ results2.push(result);
317
+ }
318
+ expect(results2).toHaveLength(1);
319
+ });
320
+ });
321
+
322
+ describe('Event Emission', () => {
323
+ it('should emit start event', async () => {
324
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
325
+
326
+ const results = [];
327
+ for await (const result of crawler.crawl('https://example.com', { simple: true, maxPages: 10 })) {
328
+ results.push(result);
329
+ }
330
+
331
+ const startEvents = progressEvents.filter((e) => e.type === 'start');
332
+ expect(startEvents).toHaveLength(1);
333
+ expect(startEvents[0]?.pagesVisited).toBe(0);
334
+ expect(startEvents[0]?.totalPages).toBe(10);
335
+ });
336
+
337
+ it('should emit page events', async () => {
338
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
339
+
340
+ const results = [];
341
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
342
+ results.push(result);
343
+ }
344
+
345
+ const pageEvents = progressEvents.filter((e) => e.type === 'page');
346
+ expect(pageEvents.length).toBeGreaterThan(0);
347
+ expect(pageEvents[0]?.currentUrl).toBe('https://example.com');
348
+ });
349
+
350
+ it('should emit complete event', async () => {
351
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
352
+
353
+ const results = [];
354
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
355
+ results.push(result);
356
+ }
357
+
358
+ const completeEvents = progressEvents.filter((e) => e.type === 'complete');
359
+ expect(completeEvents).toHaveLength(1);
360
+ expect(completeEvents[0]?.pagesVisited).toBe(1);
361
+ });
362
+
363
+ it('should emit strategy events in intelligent mode', async () => {
364
+ mockClaudeClient.determineCrawlUrls.mockResolvedValue({
365
+ urls: ['https://example.com/page1'],
366
+ reasoning: 'Strategy reasoning',
367
+ });
368
+
369
+ const results = [];
370
+ for await (const result of crawler.crawl('https://example.com', {
371
+ crawlInstruction: 'Find all',
372
+ })) {
373
+ results.push(result);
374
+ }
375
+
376
+ const strategyEvents = progressEvents.filter((e) => e.type === 'strategy');
377
+ expect(strategyEvents.length).toBeGreaterThanOrEqual(1);
378
+ expect(strategyEvents.some((e) => e.message?.includes('Strategy reasoning'))).toBe(true);
379
+ });
380
+
381
+ it('should emit extraction events when extract instruction provided', async () => {
382
+ mockClaudeClient.extractContent.mockResolvedValue('Extracted content');
383
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
384
+
385
+ const results = [];
386
+ for await (const result of crawler.crawl('https://example.com', {
387
+ simple: true,
388
+ extractInstruction: 'Extract pricing',
389
+ })) {
390
+ results.push(result);
391
+ }
392
+
393
+ const extractionEvents = progressEvents.filter((e) => e.type === 'extraction');
394
+ expect(extractionEvents.length).toBeGreaterThan(0);
395
+ });
396
+
397
+ it('should emit error events on page fetch failures', async () => {
398
+ vi.mocked(axios.get).mockRejectedValueOnce(new Error('Network error'));
399
+
400
+ const results = [];
401
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
402
+ results.push(result);
403
+ }
404
+
405
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
406
+ expect(errorEvents.length).toBeGreaterThan(0);
407
+ expect(errorEvents[0]?.error).toBeDefined();
408
+ });
409
+ });
410
+
411
+ describe('Stop Functionality', () => {
412
+ it('should stop crawling when stop is called', async () => {
413
+ mockPythonBridge.crawl.mockImplementation(async () => {
414
+ // Simulate slow crawl
415
+ await new Promise((resolve) => setTimeout(resolve, 100));
416
+ return { pages: [{ links: ['https://example.com/next'] }] };
417
+ });
418
+
419
+ const results = [];
420
+ const crawlPromise = (async () => {
421
+ for await (const result of crawler.crawl('https://example.com', { simple: true, maxPages: 100 })) {
422
+ results.push(result);
423
+ }
424
+ })();
425
+
426
+ // Stop after a short delay
427
+ setTimeout(() => crawler.stop(), 50);
428
+
429
+ await crawlPromise;
430
+
431
+ // Should have stopped early
432
+ expect(results.length).toBeLessThan(100);
433
+ expect(mockPythonBridge.stop).toHaveBeenCalled();
434
+ });
435
+
436
+ it('should reset stopped flag on new crawl', async () => {
437
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
438
+
439
+ // First crawl with stop
440
+ await crawler.stop();
441
+
442
+ // Second crawl should work
443
+ const results = [];
444
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
445
+ results.push(result);
446
+ }
447
+
448
+ expect(results).toHaveLength(1);
449
+ });
450
+ });
451
+
452
+ describe('Max Pages Enforcement', () => {
453
+ it('should respect maxPages limit in simple mode', async () => {
454
+ const links = Array.from({ length: 20 }, (_, i) => `https://example.com/page${i}`);
455
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links }] });
456
+
457
+ const results = [];
458
+ for await (const result of crawler.crawl('https://example.com', { simple: true, maxPages: 3 })) {
459
+ results.push(result);
460
+ }
461
+
462
+ expect(results.length).toBeLessThanOrEqual(3);
463
+ });
464
+
465
+ it('should respect maxPages limit in intelligent mode', async () => {
466
+ const urls = Array.from({ length: 20 }, (_, i) => `https://example.com/page${i}`);
467
+ mockClaudeClient.determineCrawlUrls.mockResolvedValue({
468
+ urls,
469
+ reasoning: 'Found many pages',
470
+ });
471
+
472
+ const results = [];
473
+ for await (const result of crawler.crawl('https://example.com', {
474
+ crawlInstruction: 'Find all',
475
+ maxPages: 5,
476
+ })) {
477
+ results.push(result);
478
+ }
479
+
480
+ expect(results.length).toBeLessThanOrEqual(5);
481
+ });
482
+
483
+ it('should use default maxPages of 50', async () => {
484
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
485
+
486
+ const results = [];
487
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
488
+ results.push(result);
489
+ }
490
+
491
+ const startEvent = progressEvents.find((e) => e.type === 'start');
492
+ expect(startEvent?.totalPages).toBe(50);
493
+ });
494
+ });
495
+
496
+ describe('Same-Domain Filtering Logic', () => {
497
+ it('should filter out different domain links in simple mode', async () => {
498
+ mockPythonBridge.crawl
499
+ .mockResolvedValueOnce({
500
+ pages: [
501
+ {
502
+ links: [
503
+ 'https://example.com/page1', // Same domain
504
+ 'https://other.com/page2', // Different domain
505
+ ],
506
+ },
507
+ ],
508
+ })
509
+ .mockResolvedValueOnce({ pages: [{ links: [] }] });
510
+
511
+ vi.mocked(axios.get)
512
+ .mockResolvedValueOnce({ data: '<html><body>Seed</body></html>' })
513
+ .mockResolvedValueOnce({ data: '<html><body>Page1</body></html>' });
514
+
515
+ const results = [];
516
+ for await (const result of crawler.crawl('https://example.com', { simple: true, maxPages: 10 })) {
517
+ results.push(result);
518
+ }
519
+
520
+ // Should only crawl same-domain link
521
+ expect(results).toHaveLength(2); // Seed + page1
522
+ expect(results.some((r) => r.url.includes('other.com'))).toBe(false);
523
+ });
524
+
525
+ it('should allow subdomain links', async () => {
526
+ mockPythonBridge.crawl
527
+ .mockResolvedValueOnce({
528
+ pages: [{ links: ['https://docs.example.com/page1'] }],
529
+ })
530
+ .mockResolvedValueOnce({ pages: [{ links: [] }] });
531
+
532
+ vi.mocked(axios.get)
533
+ .mockResolvedValueOnce({ data: '<html><body>Seed</body></html>' })
534
+ .mockResolvedValueOnce({ data: '<html><body>Page1</body></html>' });
535
+
536
+ const results = [];
537
+ for await (const result of crawler.crawl('https://example.com', { simple: true, maxPages: 10 })) {
538
+ results.push(result);
539
+ }
540
+
541
+ expect(results).toHaveLength(2);
542
+ expect(results.some((r) => r.url.includes('docs.example.com'))).toBe(true);
543
+ });
544
+
545
+ it('should handle invalid URLs in link extraction', async () => {
546
+ mockPythonBridge.crawl.mockResolvedValue({
547
+ pages: [
548
+ {
549
+ links: [
550
+ 'not-a-valid-url',
551
+ 'javascript:void(0)',
552
+ 'mailto:test@example.com',
553
+ ],
554
+ },
555
+ ],
556
+ });
557
+
558
+ const results = [];
559
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
560
+ results.push(result);
561
+ }
562
+
563
+ // Should only crawl the seed URL
564
+ expect(results).toHaveLength(1);
565
+ });
566
+ });
567
+
568
+ describe('Intelligent Mode Fallback', () => {
569
+ it('should fallback to simple mode when Claude strategy fails', async () => {
570
+ mockClaudeClient.determineCrawlUrls.mockRejectedValue(new Error('Claude API error'));
571
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
572
+
573
+ const results = [];
574
+ for await (const result of crawler.crawl('https://example.com', {
575
+ crawlInstruction: 'Find all docs',
576
+ })) {
577
+ results.push(result);
578
+ }
579
+
580
+ // Should still crawl using simple mode
581
+ expect(results).toHaveLength(1);
582
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
583
+ expect(errorEvents.some((e) => e.message?.includes('falling back to simple mode'))).toBe(true);
584
+ });
585
+ });
586
+
587
+ describe('Content Extraction', () => {
588
+ it('should extract content when extractInstruction provided', async () => {
589
+ mockClaudeClient.extractContent.mockResolvedValue('Extracted pricing info');
590
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
591
+
592
+ const results = [];
593
+ for await (const result of crawler.crawl('https://example.com', {
594
+ simple: true,
595
+ extractInstruction: 'Extract pricing',
596
+ })) {
597
+ results.push(result);
598
+ }
599
+
600
+ expect(results).toHaveLength(1);
601
+ expect(results[0]?.extracted).toBe('Extracted pricing info');
602
+ expect(mockClaudeClient.extractContent).toHaveBeenCalledWith(
603
+ expect.any(String),
604
+ 'Extract pricing',
605
+ );
606
+ });
607
+
608
+ it('should continue without extraction if extraction fails', async () => {
609
+ mockClaudeClient.extractContent.mockRejectedValue(new Error('Extraction failed'));
610
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
611
+
612
+ const results = [];
613
+ for await (const result of crawler.crawl('https://example.com', {
614
+ simple: true,
615
+ extractInstruction: 'Extract pricing',
616
+ })) {
617
+ results.push(result);
618
+ }
619
+
620
+ expect(results).toHaveLength(1);
621
+ expect(results[0]?.extracted).toBeUndefined();
622
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
623
+ expect(errorEvents.some((e) => e.message?.includes('storing raw markdown'))).toBe(true);
624
+ });
625
+
626
+ it('should not extract when extractInstruction is empty', async () => {
627
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
628
+
629
+ const results = [];
630
+ for await (const result of crawler.crawl('https://example.com', {
631
+ simple: true,
632
+ extractInstruction: '',
633
+ })) {
634
+ results.push(result);
635
+ }
636
+
637
+ expect(results).toHaveLength(1);
638
+ expect(results[0]?.extracted).toBeUndefined();
639
+ expect(mockClaudeClient.extractContent).not.toHaveBeenCalled();
640
+ });
641
+ });
642
+
643
+ describe('Link Extraction Error Handling', () => {
644
+ it('should throw error when Python bridge fails', async () => {
645
+ mockPythonBridge.crawl.mockRejectedValue(new Error('Network timeout'));
646
+
647
+ const crawler = new IntelligentCrawler();
648
+ // Access private property for testing
649
+ (crawler as any).pythonBridge = mockPythonBridge;
650
+
651
+ await expect((crawler as any).extractLinks('https://example.com')).rejects.toThrow(
652
+ 'Link extraction failed'
653
+ );
654
+ });
655
+
656
+ it('should throw error on invalid response structure', async () => {
657
+ // Return a response without pages array
658
+ mockPythonBridge.crawl.mockResolvedValue({ invalid: 'structure' });
659
+
660
+ const crawler = new IntelligentCrawler();
661
+ (crawler as any).pythonBridge = mockPythonBridge;
662
+
663
+ await expect((crawler as any).extractLinks('https://example.com')).rejects.toThrow(
664
+ 'Invalid crawl response structure'
665
+ );
666
+ });
667
+
668
+ it('should throw error when pages array is empty', async () => {
669
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [] });
670
+
671
+ const crawler = new IntelligentCrawler();
672
+ (crawler as any).pythonBridge = mockPythonBridge;
673
+
674
+ await expect((crawler as any).extractLinks('https://example.com')).rejects.toThrow(
675
+ 'Invalid crawl response structure'
676
+ );
677
+ });
678
+
679
+ it('should use headless mode for link extraction when enabled', async () => {
680
+ const headlessResult = {
681
+ html: '<html/>',
682
+ markdown: 'test',
683
+ links: ['https://example.com/page2', 'https://example.com/page3'],
684
+ };
685
+ mockPythonBridge.fetchHeadless.mockResolvedValue(headlessResult);
686
+
687
+ const crawler = new IntelligentCrawler();
688
+ (crawler as any).pythonBridge = mockPythonBridge;
689
+
690
+ const links = await (crawler as any).extractLinks('https://example.com', true);
691
+
692
+ expect(mockPythonBridge.fetchHeadless).toHaveBeenCalledWith('https://example.com');
693
+ expect(mockPythonBridge.crawl).not.toHaveBeenCalled();
694
+ expect(links).toEqual(['https://example.com/page2', 'https://example.com/page3']);
695
+ });
696
+
697
+ it('should extract href from link objects in headless mode', async () => {
698
+ // crawl4ai returns link objects, not strings
699
+ const headlessResult = {
700
+ html: '<html/>',
701
+ markdown: 'test',
702
+ links: [
703
+ { href: 'https://example.com/page1', text: 'Page 1', title: '', base_domain: 'example.com', head_data: null, head_extraction_status: null, head_extraction_error: null, intrinsic_score: 0, contextual_score: null, total_score: null },
704
+ { href: 'https://example.com/page2', text: 'Page 2', title: '', base_domain: 'example.com', head_data: null, head_extraction_status: null, head_extraction_error: null, intrinsic_score: 0, contextual_score: null, total_score: null },
705
+ 'https://example.com/page3', // Also support plain strings
706
+ ],
707
+ };
708
+ mockPythonBridge.fetchHeadless.mockResolvedValue(headlessResult);
709
+
710
+ const crawler = new IntelligentCrawler();
711
+ (crawler as any).pythonBridge = mockPythonBridge;
712
+
713
+ const links = await (crawler as any).extractLinks('https://example.com', true);
714
+
715
+ expect(links).toEqual([
716
+ 'https://example.com/page1',
717
+ 'https://example.com/page2',
718
+ 'https://example.com/page3',
719
+ ]);
720
+ });
721
+
722
+ it('should use regular crawl when headless is disabled', async () => {
723
+ mockPythonBridge.crawl.mockResolvedValue({
724
+ pages: [{ links: ['https://example.com/page1'] }],
725
+ });
726
+
727
+ const crawler = new IntelligentCrawler();
728
+ (crawler as any).pythonBridge = mockPythonBridge;
729
+
730
+ const links = await (crawler as any).extractLinks('https://example.com', false);
731
+
732
+ expect(mockPythonBridge.crawl).toHaveBeenCalledWith('https://example.com');
733
+ expect(mockPythonBridge.fetchHeadless).not.toHaveBeenCalled();
734
+ expect(links).toEqual(['https://example.com/page1']);
735
+ });
736
+
737
+ it('should continue crawling other pages when link extraction fails in simple mode', async () => {
738
+ // First page succeeds, link extraction fails, second page succeeds
739
+ mockClaudeClient.determineCrawlUrls.mockResolvedValue({
740
+ urls: ['https://example.com/page1', 'https://example.com/page2'],
741
+ reasoning: 'Test URLs',
742
+ });
743
+
744
+ vi.mocked(axios.get)
745
+ .mockResolvedValueOnce({ data: '<html><body>Seed</body></html>' }) // Seed page
746
+ .mockResolvedValueOnce({ data: '<html><body>Page1</body></html>' }) // First URL
747
+ .mockResolvedValueOnce({ data: '<html><body>Page2</body></html>' }); // Second URL
748
+
749
+ // Make link extraction fail for first URL only
750
+ mockPythonBridge.crawl
751
+ .mockRejectedValueOnce(new Error('Link extraction failed'))
752
+ .mockResolvedValueOnce({ pages: [{ links: [] }] });
753
+
754
+ const results = [];
755
+ for await (const result of crawler.crawl('https://example.com', {
756
+ crawlInstruction: 'Find all',
757
+ })) {
758
+ results.push(result);
759
+ }
760
+
761
+ // Should successfully crawl both URLs despite link extraction failure
762
+ expect(results).toHaveLength(2);
763
+ expect(results[0]?.url).toBe('https://example.com/page1');
764
+ expect(results[1]?.url).toBe('https://example.com/page2');
765
+ });
766
+ });
767
+
768
+ describe('HTML to Markdown Conversion', () => {
769
+ it('should convert HTML to markdown for each page', async () => {
770
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
771
+
772
+ const results = [];
773
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
774
+ results.push(result);
775
+ }
776
+
777
+ expect(vi.mocked(articleConverter.convertHtmlToMarkdown)).toHaveBeenCalledWith(
778
+ expect.any(String),
779
+ 'https://example.com',
780
+ );
781
+ expect(results[0]?.markdown).toBe('# Test\n\nContent');
782
+ });
783
+
784
+ it('should include title when available', async () => {
785
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
786
+ vi.mocked(articleConverter.convertHtmlToMarkdown).mockResolvedValue({
787
+ success: true,
788
+ markdown: '# Test',
789
+ title: 'Test Page Title',
790
+ });
791
+
792
+ const results = [];
793
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
794
+ results.push(result);
795
+ }
796
+
797
+ expect(results[0]?.title).toBe('Test Page Title');
798
+ });
799
+
800
+ it('should handle conversion failures', async () => {
801
+ mockPythonBridge.crawl.mockResolvedValue({ pages: [{ links: [] }] });
802
+ vi.mocked(articleConverter.convertHtmlToMarkdown).mockResolvedValue({
803
+ success: false,
804
+ markdown: '',
805
+ error: 'Conversion error',
806
+ });
807
+
808
+ const results = [];
809
+ for await (const result of crawler.crawl('https://example.com', { simple: true })) {
810
+ results.push(result);
811
+ }
812
+
813
+ // Should fail to create result
814
+ expect(results).toHaveLength(0);
815
+ const errorEvents = progressEvents.filter((e) => e.type === 'error');
816
+ expect(errorEvents.length).toBeGreaterThan(0);
817
+ });
818
+ });
819
+
820
+ describe('Simple Mode Depth Control', () => {
821
+ it('should respect depth limit of 2 in simple mode', async () => {
822
+ mockPythonBridge.crawl
823
+ .mockResolvedValueOnce({ pages: [{ links: ['https://example.com/depth1'] }] })
824
+ .mockResolvedValueOnce({ pages: [{ links: ['https://example.com/depth2'] }] })
825
+ .mockResolvedValueOnce({ pages: [{ links: ['https://example.com/depth3'] }] });
826
+
827
+ vi.mocked(axios.get).mockResolvedValue({ data: '<html><body>Test</body></html>' });
828
+
829
+ const results = [];
830
+ for await (const result of crawler.crawl('https://example.com', { simple: true, maxPages: 10 })) {
831
+ results.push(result);
832
+ }
833
+
834
+ // Should stop at depth 2 (seed=0, depth1=1, depth2=2)
835
+ expect(results.length).toBeLessThanOrEqual(3);
836
+ expect(results.every((r) => (r.depth ?? 0) <= 2)).toBe(true);
837
+ });
838
+ });
839
+
840
+ describe('Error Recovery', () => {
841
+ it('should continue crawling other pages after one page fails', async () => {
842
+ mockClaudeClient.determineCrawlUrls.mockResolvedValue({
843
+ urls: ['https://example.com/fail', 'https://example.com/success'],
844
+ reasoning: 'Test URLs',
845
+ });
846
+
847
+ vi.mocked(axios.get)
848
+ .mockResolvedValueOnce({ data: '<html><body>Seed page</body></html>' }) // Seed URL fetch
849
+ .mockRejectedValueOnce(new Error('Failed to fetch')) // First URL fails
850
+ .mockResolvedValueOnce({ data: '<html><body>Success</body></html>' }); // Second URL succeeds
851
+
852
+ const results = [];
853
+ for await (const result of crawler.crawl('https://example.com', {
854
+ crawlInstruction: 'Find all',
855
+ })) {
856
+ results.push(result);
857
+ }
858
+
859
+ // Should successfully crawl the second URL
860
+ expect(results).toHaveLength(1);
861
+ expect(results[0]?.url).toBe('https://example.com/success');
862
+ });
863
+ });
864
+
865
+ describe('npm Package Mode (Claude CLI Not Installed)', () => {
866
+ it('should use simple mode when Claude CLI is not available', async () => {
867
+ // Simulate npm package usage without Claude Code installed
868
+ vi.mocked(ClaudeClient.isAvailable).mockReturnValue(false);
869
+
870
+ // Setup link extraction for simple mode
871
+ mockPythonBridge.crawl.mockResolvedValue({
872
+ pages: [{ links: [] }],
873
+ });
874
+
875
+ const results: { url: string }[] = [];
876
+
877
+ for await (const result of crawler.crawl('https://example.com', {
878
+ crawlInstruction: 'Find all documentation pages', // Would use intelligent mode
879
+ maxPages: 5,
880
+ })) {
881
+ results.push(result);
882
+ }
883
+
884
+ // Should have crawled using simple BFS mode
885
+ expect(results.length).toBeGreaterThan(0);
886
+ expect(results[0]?.url).toBe('https://example.com');
887
+
888
+ // Should have emitted progress event about mode switch
889
+ const modeEvent = progressEvents.find(
890
+ e => e.type === 'error' && e.message?.includes('Claude CLI not found')
891
+ );
892
+ expect(modeEvent).toBeDefined();
893
+ expect(modeEvent?.message).toContain('using simple crawl mode');
894
+
895
+ // Should NOT have called Claude's determineCrawlUrls
896
+ expect(mockClaudeClient.determineCrawlUrls).not.toHaveBeenCalled();
897
+ });
898
+
899
+ it('should skip extraction when Claude CLI is not available', async () => {
900
+ // Simulate npm package usage without Claude Code installed
901
+ vi.mocked(ClaudeClient.isAvailable).mockReturnValue(false);
902
+
903
+ // Setup for simple mode
904
+ mockPythonBridge.crawl.mockResolvedValue({
905
+ pages: [{ links: [] }],
906
+ });
907
+
908
+ const results: { url: string; extracted?: string }[] = [];
909
+
910
+ for await (const result of crawler.crawl('https://example.com', {
911
+ simple: true,
912
+ extractInstruction: 'Extract pricing info', // Would use Claude
913
+ maxPages: 1,
914
+ })) {
915
+ results.push(result);
916
+ }
917
+
918
+ expect(results.length).toBe(1);
919
+ expect(results[0]?.extracted).toBeUndefined(); // Should not have extracted
920
+
921
+ // Should have emitted skip extraction progress event
922
+ const skipEvent = progressEvents.find(
923
+ e => e.type === 'error' && e.message?.includes('Skipping extraction')
924
+ );
925
+ expect(skipEvent).toBeDefined();
926
+
927
+ // Should NOT have called Claude's extractContent
928
+ expect(mockClaudeClient.extractContent).not.toHaveBeenCalled();
929
+ });
930
+ });
931
+ });