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.
- package/.claude/commands/commit.md +37 -0
- package/.claude/hooks/post-edit-check.sh +41 -0
- package/.claude/settings.local.json.example +40 -0
- package/.claude/skills/atomic-commits/SKILL.md +53 -0
- package/.claude-plugin/plugin.json +13 -0
- package/.editorconfig +15 -0
- package/.github/workflows/auto-release.yml +59 -0
- package/.github/workflows/ci.yml +142 -0
- package/.github/workflows/release.yml +66 -0
- package/.github/workflows/update-marketplace.yml +96 -0
- package/.husky/pre-commit +47 -0
- package/.husky/pre-push +29 -0
- package/.versionrc.json +28 -0
- package/CHANGELOG.md +410 -0
- package/CLAUDE.md +109 -0
- package/LICENSE +21 -0
- package/NOTICE +47 -0
- package/README.md +1546 -0
- package/SECURITY.md +65 -0
- package/bun.lock +1758 -0
- package/commands/add-folder.md +48 -0
- package/commands/add-repo.md +50 -0
- package/commands/cancel.md +63 -0
- package/commands/check-status.md +78 -0
- package/commands/crawl.md +51 -0
- package/commands/index.md +48 -0
- package/commands/remove-store.md +52 -0
- package/commands/search.md +79 -0
- package/commands/search.sh +63 -0
- package/commands/stores.md +54 -0
- package/commands/suggest.md +82 -0
- package/dist/chunk-5QMHZUC4.js +3617 -0
- package/dist/chunk-5QMHZUC4.js.map +1 -0
- package/dist/chunk-BICFAWMN.js +656 -0
- package/dist/chunk-BICFAWMN.js.map +1 -0
- package/dist/chunk-J7J6LXOJ.js +958 -0
- package/dist/chunk-J7J6LXOJ.js.map +1 -0
- package/dist/chunk-L2YVNC63.js +59 -0
- package/dist/chunk-L2YVNC63.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1429 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +15 -0
- package/dist/mcp/server.js +11 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/watch.service-YAIKKDCF.js +7 -0
- package/dist/watch.service-YAIKKDCF.js.map +1 -0
- package/dist/workers/background-worker-cli.d.ts +1 -0
- package/dist/workers/background-worker-cli.js +310 -0
- package/dist/workers/background-worker-cli.js.map +1 -0
- package/docs/plans/2024-12-17-ai-search-quality-implementation.md +752 -0
- package/docs/plans/2024-12-17-ai-search-quality-testing-design.md +201 -0
- package/docs/plans/2025-12-16-bluera-knowledge-cli.md +2951 -0
- package/docs/plans/2025-12-16-phase2-features.md +1518 -0
- package/docs/plans/2025-12-17-hil-implementation.md +926 -0
- package/docs/plans/2025-12-17-hil-quality-testing.md +224 -0
- package/docs/plans/2025-12-17-search-quality-phase1-implementation.md +1416 -0
- package/docs/plans/2025-12-17-search-quality-testing-v2-design.md +212 -0
- package/docs/plans/2025-12-28-ai-agent-optimization.md +1630 -0
- package/eslint-rules/require-skip-comment.js +81 -0
- package/eslint.config.js +61 -0
- package/hooks/check-dependencies.sh +110 -0
- package/hooks/format-search-results.py +132 -0
- package/hooks/hooks.json +27 -0
- package/hooks/job-status-hook.sh +51 -0
- package/knip.json +43 -0
- package/mcp.plugin.json +12 -0
- package/package.json +103 -0
- package/python/crawl_worker.py +275 -0
- package/python/requirements.txt +2 -0
- package/scripts/readme-version-updater.cjs +18 -0
- package/skills/advanced-workflows/SKILL.md +273 -0
- package/skills/atomic-commits/SKILL.md +77 -0
- package/skills/knowledge-search/SKILL.md +54 -0
- package/skills/search-optimization/SKILL.md +396 -0
- package/skills/store-lifecycle/SKILL.md +470 -0
- package/skills/when-to-query/SKILL.md +66 -0
- package/src/analysis/ast-parser.test.ts +423 -0
- package/src/analysis/ast-parser.ts +192 -0
- package/src/analysis/code-graph.test.ts +698 -0
- package/src/analysis/code-graph.ts +245 -0
- package/src/analysis/dependency-usage-analyzer.test.ts +799 -0
- package/src/analysis/dependency-usage-analyzer.ts +405 -0
- package/src/analysis/go-ast-parser.test.ts +531 -0
- package/src/analysis/go-ast-parser.ts +478 -0
- package/src/analysis/parser-factory.test.ts +132 -0
- package/src/analysis/parser-factory.ts +44 -0
- package/src/analysis/python-ast-parser.test.ts +210 -0
- package/src/analysis/python-ast-parser.ts +34 -0
- package/src/analysis/repo-url-resolver.test.ts +533 -0
- package/src/analysis/repo-url-resolver.ts +233 -0
- package/src/analysis/rust-ast-parser.test.ts +568 -0
- package/src/analysis/rust-ast-parser.ts +477 -0
- package/src/analysis/tree-sitter-parser.test.ts +297 -0
- package/src/analysis/tree-sitter-parser.ts +223 -0
- package/src/cli/commands/crawl.test.ts +942 -0
- package/src/cli/commands/crawl.ts +141 -0
- package/src/cli/commands/index-cmd.test.ts +722 -0
- package/src/cli/commands/index-cmd.ts +105 -0
- package/src/cli/commands/mcp.test.ts +218 -0
- package/src/cli/commands/mcp.ts +18 -0
- package/src/cli/commands/plugin-api.test.ts +313 -0
- package/src/cli/commands/plugin-api.ts +45 -0
- package/src/cli/commands/search.test.ts +911 -0
- package/src/cli/commands/search.ts +113 -0
- package/src/cli/commands/serve.test.ts +329 -0
- package/src/cli/commands/serve.ts +28 -0
- package/src/cli/commands/setup.test.ts +820 -0
- package/src/cli/commands/setup.ts +153 -0
- package/src/cli/commands/store.test.ts +1003 -0
- package/src/cli/commands/store.ts +167 -0
- package/src/cli/index.ts +7 -0
- package/src/cli/program.ts +59 -0
- package/src/crawl/article-converter.test.ts +604 -0
- package/src/crawl/article-converter.ts +98 -0
- package/src/crawl/bridge.test.ts +674 -0
- package/src/crawl/bridge.ts +236 -0
- package/src/crawl/claude-client.test.ts +663 -0
- package/src/crawl/claude-client.ts +234 -0
- package/src/crawl/intelligent-crawler.test.ts +931 -0
- package/src/crawl/intelligent-crawler.ts +428 -0
- package/src/crawl/markdown-utils.test.ts +703 -0
- package/src/crawl/markdown-utils.ts +228 -0
- package/src/crawl/schemas.ts +114 -0
- package/src/db/embeddings.test.ts +63 -0
- package/src/db/embeddings.ts +69 -0
- package/src/db/index.ts +2 -0
- package/src/db/lance.test.ts +390 -0
- package/src/db/lance.ts +164 -0
- package/src/defaults/repos.ts +67 -0
- package/src/index.ts +107 -0
- package/src/mcp/cache.test.ts +202 -0
- package/src/mcp/cache.ts +103 -0
- package/src/mcp/commands/index.ts +20 -0
- package/src/mcp/commands/job.commands.ts +54 -0
- package/src/mcp/commands/meta.commands.ts +54 -0
- package/src/mcp/commands/registry.ts +183 -0
- package/src/mcp/commands/store.commands.ts +75 -0
- package/src/mcp/handlers/execute.handler.test.ts +179 -0
- package/src/mcp/handlers/execute.handler.ts +24 -0
- package/src/mcp/handlers/index.ts +43 -0
- package/src/mcp/handlers/job.handler.test.ts +189 -0
- package/src/mcp/handlers/job.handler.ts +116 -0
- package/src/mcp/handlers/search.handler.test.ts +334 -0
- package/src/mcp/handlers/search.handler.ts +209 -0
- package/src/mcp/handlers/store.handler.test.ts +415 -0
- package/src/mcp/handlers/store.handler.ts +295 -0
- package/src/mcp/schemas/index.test.ts +315 -0
- package/src/mcp/schemas/index.ts +138 -0
- package/src/mcp/server.test.ts +36 -0
- package/src/mcp/server.ts +162 -0
- package/src/mcp/types.ts +41 -0
- package/src/plugin/commands.test.ts +789 -0
- package/src/plugin/commands.ts +257 -0
- package/src/plugin/dependency-analyzer.test.ts +380 -0
- package/src/plugin/dependency-analyzer.ts +147 -0
- package/src/plugin/git-clone.test.ts +332 -0
- package/src/plugin/git-clone.ts +57 -0
- package/src/server/app.test.ts +752 -0
- package/src/server/app.ts +119 -0
- package/src/server/index.test.ts +477 -0
- package/src/server/index.ts +1 -0
- package/src/services/chunking.service.test.ts +363 -0
- package/src/services/chunking.service.ts +350 -0
- package/src/services/code-graph.service.test.ts +304 -0
- package/src/services/code-graph.service.ts +302 -0
- package/src/services/code-unit.service.test.ts +596 -0
- package/src/services/code-unit.service.ts +115 -0
- package/src/services/config.service.test.ts +127 -0
- package/src/services/config.service.ts +69 -0
- package/src/services/index.service.test.ts +1002 -0
- package/src/services/index.service.ts +266 -0
- package/src/services/index.ts +75 -0
- package/src/services/job.service.test.ts +418 -0
- package/src/services/job.service.ts +246 -0
- package/src/services/project-root.service.test.ts +506 -0
- package/src/services/project-root.service.ts +112 -0
- package/src/services/search.service.test.ts +1105 -0
- package/src/services/search.service.ts +892 -0
- package/src/services/services.test.ts +38 -0
- package/src/services/snippet.service.test.ts +205 -0
- package/src/services/snippet.service.ts +166 -0
- package/src/services/store.service.test.ts +474 -0
- package/src/services/store.service.ts +225 -0
- package/src/services/watch.service.test.ts +553 -0
- package/src/services/watch.service.ts +71 -0
- package/src/types/brands.test.ts +45 -0
- package/src/types/brands.ts +32 -0
- package/src/types/config.ts +79 -0
- package/src/types/document.ts +30 -0
- package/src/types/index.ts +66 -0
- package/src/types/job.ts +46 -0
- package/src/types/progress.ts +9 -0
- package/src/types/result.test.ts +44 -0
- package/src/types/result.ts +41 -0
- package/src/types/search.ts +95 -0
- package/src/types/store.test.ts +69 -0
- package/src/types/store.ts +47 -0
- package/src/utils/type-guards.test.ts +346 -0
- package/src/utils/type-guards.ts +61 -0
- package/src/workers/background-worker-cli.ts +105 -0
- package/src/workers/background-worker.test.ts +178 -0
- package/src/workers/background-worker.ts +294 -0
- package/src/workers/spawn-worker.test.ts +128 -0
- package/src/workers/spawn-worker.ts +49 -0
- package/tests/analysis/ast-parser.test.ts +98 -0
- package/tests/analysis/code-graph.test.ts +60 -0
- package/tests/fixtures/README.md +114 -0
- package/tests/fixtures/code-snippets/api/error-handling.ts +267 -0
- package/tests/fixtures/code-snippets/api/rest-controller.ts +303 -0
- package/tests/fixtures/code-snippets/auth/jwt-auth.ts +213 -0
- package/tests/fixtures/code-snippets/auth/oauth-flow.ts +245 -0
- package/tests/fixtures/code-snippets/database/repository-pattern.ts +272 -0
- package/tests/fixtures/corpus/VERSION.md +25 -0
- package/tests/fixtures/corpus/articles/jwt-authentication.md +97 -0
- package/tests/fixtures/corpus/articles/react-hooks-patterns.md +127 -0
- package/tests/fixtures/corpus/articles/typescript-generics.md +111 -0
- package/tests/fixtures/corpus/documentation/express-middleware.md +71 -0
- package/tests/fixtures/corpus/documentation/express-routing.md +83 -0
- package/tests/fixtures/corpus/documentation/node-streams.md +78 -0
- package/tests/fixtures/corpus/oss-repos/express/History.md +3871 -0
- package/tests/fixtures/corpus/oss-repos/express/LICENSE +24 -0
- package/tests/fixtures/corpus/oss-repos/express/Readme.md +276 -0
- package/tests/fixtures/corpus/oss-repos/express/SECURITY.md +56 -0
- package/tests/fixtures/corpus/oss-repos/express/benchmarks/Makefile +17 -0
- package/tests/fixtures/corpus/oss-repos/express/benchmarks/README.md +34 -0
- package/tests/fixtures/corpus/oss-repos/express/benchmarks/middleware.js +20 -0
- package/tests/fixtures/corpus/oss-repos/express/benchmarks/run +18 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/README.md +29 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/auth/index.js +134 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/foot.ejs +2 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/head.ejs +20 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/login.ejs +21 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/db.js +9 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/index.js +46 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/users.js +19 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/cookie-sessions/index.js +25 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/cookies/index.js +53 -0
- 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
- package/tests/fixtures/corpus/oss-repos/express/examples/downloads/files/amazing.txt +1 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/downloads/files/notes/groceries.txt +3 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/downloads/index.js +40 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/index.js +57 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/public/stylesheets/style.css +4 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/footer.html +2 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/header.html +9 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/users.html +10 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/error/index.js +53 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/index.js +103 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/404.ejs +3 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/500.ejs +8 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/error_header.ejs +10 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/footer.ejs +2 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/index.ejs +20 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/hello-world/index.js +15 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/markdown/index.js +44 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/markdown/views/index.md +4 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/controllers/api_v1.js +15 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/controllers/api_v2.js +15 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/index.js +18 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/main/index.js +5 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/index.js +31 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/views/edit.ejs +17 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/views/show.ejs +15 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/index.js +41 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/edit.hbs +27 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/list.hbs +18 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/show.hbs +31 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user-pet/index.js +22 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/db.js +16 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/index.js +95 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/lib/boot.js +83 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/public/style.css +14 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/views/404.ejs +13 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/views/5xx.ejs +13 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/online/index.js +61 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/params/index.js +74 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/resource/index.js +95 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-map/index.js +75 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-middleware/index.js +90 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/index.js +55 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/post.js +13 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/public/style.css +24 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/site.js +5 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/user.js +47 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/footer.ejs +2 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/header.ejs +9 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/index.ejs +10 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/posts/index.ejs +12 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/edit.ejs +23 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/index.ejs +14 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/view.ejs +9 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/search/index.js +61 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/search/public/client.js +15 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/search/public/index.html +21 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/session/index.js +37 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/session/redis.js +39 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/static-files/index.js +43 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/css/style.css +3 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/hello.txt +1 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/js/app.js +1 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/vhost/index.js +53 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/view-constructor/github-view.js +53 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/view-constructor/index.js +48 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/index.js +155 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/user.js +36 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/views/index.ejs +20 -0
- package/tests/fixtures/corpus/oss-repos/express/examples/web-service/index.js +117 -0
- package/tests/fixtures/corpus/oss-repos/express/index.js +11 -0
- package/tests/fixtures/corpus/oss-repos/express/lib/application.js +631 -0
- package/tests/fixtures/corpus/oss-repos/express/lib/express.js +81 -0
- package/tests/fixtures/corpus/oss-repos/express/lib/request.js +514 -0
- package/tests/fixtures/corpus/oss-repos/express/lib/response.js +1053 -0
- package/tests/fixtures/corpus/oss-repos/express/lib/utils.js +271 -0
- package/tests/fixtures/corpus/oss-repos/express/lib/view.js +205 -0
- package/tests/fixtures/corpus/oss-repos/express/package.json +99 -0
- package/tests/fixtures/corpus/oss-repos/express/test/Route.js +274 -0
- package/tests/fixtures/corpus/oss-repos/express/test/Router.js +636 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/auth.js +117 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/content-negotiation.js +49 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/cookie-sessions.js +38 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/cookies.js +71 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/downloads.js +47 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/ejs.js +17 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/error-pages.js +99 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/error.js +29 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/hello-world.js +21 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/markdown.js +21 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/multi-router.js +44 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/mvc.js +132 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/params.js +44 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/resource.js +68 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/route-map.js +45 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/route-separation.js +97 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/vhost.js +46 -0
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/web-service.js +105 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.all.js +38 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.engine.js +83 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.head.js +66 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.js +120 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.listen.js +55 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.locals.js +26 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.options.js +116 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.param.js +323 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.render.js +374 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.request.js +143 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.response.js +143 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.route.js +197 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.router.js +1217 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.routes.error.js +62 -0
- package/tests/fixtures/corpus/oss-repos/express/test/app.use.js +542 -0
- package/tests/fixtures/corpus/oss-repos/express/test/config.js +207 -0
- package/tests/fixtures/corpus/oss-repos/express/test/exports.js +82 -0
- package/tests/fixtures/corpus/oss-repos/express/test/express.json.js +755 -0
- package/tests/fixtures/corpus/oss-repos/express/test/express.raw.js +513 -0
- package/tests/fixtures/corpus/oss-repos/express/test/express.static.js +815 -0
- package/tests/fixtures/corpus/oss-repos/express/test/express.text.js +566 -0
- package/tests/fixtures/corpus/oss-repos/express/test/express.urlencoded.js +828 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/% of dogs.txt +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/.name +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/blog/index.html +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/blog/post/index.tmpl +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/broken.send +0 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/default_layout/name.tmpl +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/default_layout/user.tmpl +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/email.tmpl +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/empty.txt +0 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/local_layout/user.tmpl +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/name.tmpl +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/name.txt +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/nums.txt +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/pets/names.txt +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/snow /342/230/203/.gitkeep +0 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/todo.html +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/todo.txt +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/user.html +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/user.tmpl +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/users/index.html +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/users/tobi.txt +1 -0
- package/tests/fixtures/corpus/oss-repos/express/test/middleware.basic.js +42 -0
- package/tests/fixtures/corpus/oss-repos/express/test/regression.js +20 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.accepts.js +125 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsCharsets.js +50 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsEncodings.js +39 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsLanguages.js +57 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.baseUrl.js +88 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.fresh.js +70 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.get.js +60 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.host.js +156 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.hostname.js +188 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.ip.js +113 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.ips.js +71 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.is.js +169 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.path.js +20 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.protocol.js +113 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.query.js +106 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.range.js +104 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.route.js +28 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.secure.js +101 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.signedCookies.js +37 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.stale.js +50 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.subdomains.js +173 -0
- package/tests/fixtures/corpus/oss-repos/express/test/req.xhr.js +42 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.append.js +116 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.attachment.js +79 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.clearCookie.js +62 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.cookie.js +295 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.download.js +487 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.format.js +248 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.get.js +21 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.json.js +186 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.jsonp.js +344 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.links.js +65 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.locals.js +40 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.location.js +316 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.redirect.js +214 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.render.js +367 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.send.js +569 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.sendFile.js +913 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.sendStatus.js +44 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.set.js +124 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.status.js +206 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.type.js +46 -0
- package/tests/fixtures/corpus/oss-repos/express/test/res.vary.js +90 -0
- package/tests/fixtures/corpus/oss-repos/express/test/support/env.js +3 -0
- package/tests/fixtures/corpus/oss-repos/express/test/support/tmpl.js +36 -0
- package/tests/fixtures/corpus/oss-repos/express/test/support/utils.js +86 -0
- package/tests/fixtures/corpus/oss-repos/express/test/utils.js +83 -0
- package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/Dockerfile +11 -0
- package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/devcontainer.json +21 -0
- package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/docker-compose.yml +18 -0
- package/tests/fixtures/corpus/oss-repos/hono/.eslintignore +1 -0
- package/tests/fixtures/corpus/oss-repos/hono/.eslintrc.cjs +9 -0
- package/tests/fixtures/corpus/oss-repos/hono/.gitpod.yml +9 -0
- package/tests/fixtures/corpus/oss-repos/hono/.prettierrc +9 -0
- package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/jsx-runtime-default.ts +15 -0
- package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/jsx-runtime-dom.ts +15 -0
- package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/setup-vitest.ts +47 -0
- package/tests/fixtures/corpus/oss-repos/hono/LICENSE +21 -0
- package/tests/fixtures/corpus/oss-repos/hono/README.md +91 -0
- package/tests/fixtures/corpus/oss-repos/hono/build.ts +80 -0
- package/tests/fixtures/corpus/oss-repos/hono/bun.lockb +0 -0
- package/tests/fixtures/corpus/oss-repos/hono/bunfig.toml +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/codecov.yml +13 -0
- package/tests/fixtures/corpus/oss-repos/hono/docs/CODE_OF_CONDUCT.md +128 -0
- package/tests/fixtures/corpus/oss-repos/hono/docs/CONTRIBUTING.md +62 -0
- package/tests/fixtures/corpus/oss-repos/hono/docs/MIGRATION.md +295 -0
- package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-logo.png +0 -0
- package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-logo.pxm +0 -0
- package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-logo.svg +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-title.png +0 -0
- package/tests/fixtures/corpus/oss-repos/hono/docs/images/hono-title.pxm +0 -0
- package/tests/fixtures/corpus/oss-repos/hono/jsr.json +119 -0
- package/tests/fixtures/corpus/oss-repos/hono/package.cjs.json +3 -0
- package/tests/fixtures/corpus/oss-repos/hono/package.json +650 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +492 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/index.ts +13 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/types.ts +144 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/conninfo.ts +28 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/index.ts +9 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/serve-static.ts +35 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/server.ts +30 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/ssg.ts +27 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/websocket.ts +110 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +120 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/index.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/conninfo.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/index.ts +8 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static-module.ts +12 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +39 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/utils.ts +50 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/websocket.ts +50 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/conninfo.ts +17 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/deno.d.ts +28 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/index.ts +9 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/serve-static.ts +40 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/ssg.ts +27 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/websocket.ts +51 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/conninfo.ts +15 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/handler.ts +189 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/index.ts +14 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/handler.ts +10 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/index.ts +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/mod.ts +1 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/handler.ts +34 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/index.ts +5 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/types.ts +14 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/conninfo.ts +8 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/handler.ts +9 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/index.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +214 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/client/index.ts +14 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +180 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/client/utils.ts +54 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/compose.ts +94 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +914 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +81 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/index.ts +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +85 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/conninfo/index.ts +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/conninfo/types.ts +45 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/cookie/index.ts +130 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/common.ts +243 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +220 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/dev/index.ts +79 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +246 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/html/index.ts +56 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/index.ts +13 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/middleware.ts +79 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +388 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/utils.ts +71 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/index.ts +9 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/sse.ts +89 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/stream.ts +36 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/text.ts +15 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/testing/index.ts +26 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/websocket/index.ts +57 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +523 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +34 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/http-exception.ts +78 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/index.ts +51 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/base.ts +419 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/children.ts +20 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/components.ts +195 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/constants.ts +5 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/context.ts +50 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/client.ts +89 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/components.ts +39 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/context.ts +52 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +246 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/hooks/index.ts +91 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/index.ts +159 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +398 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/jsx-dev-runtime.ts +22 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/jsx-runtime.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +772 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/server.ts +70 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/utils.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +426 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/index.ts +114 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/common.ts +11 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +196 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-elements.ts +924 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/jsx-dev-runtime.ts +26 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/jsx-runtime.ts +18 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/streaming.ts +184 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/types.ts +41 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +36 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/basic-auth/index.ts +128 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/bearer-auth/index.ts +159 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/body-limit/index.ts +115 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/cache/index.ts +127 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/combine/index.ts +153 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/compress/index.ts +79 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/context-storage/index.ts +55 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/cors/index.ts +141 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/csrf/index.ts +90 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/etag/index.ts +88 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/ip-restriction/index.ts +178 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +158 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jwt/index.ts +8 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jwt/jwt.ts +159 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/logger/index.ts +93 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/method-override/index.ts +146 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/powered-by/index.ts +13 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/pretty-json/index.ts +50 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/request-id/index.ts +8 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/request-id/request-id.ts +59 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/index.ts +8 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/permissions-policy.ts +86 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/secure-headers.ts +319 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +140 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timeout/index.ts +58 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timing/index.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timing/timing.ts +225 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/trailing-slash/index.ts +71 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +24 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +20 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/request.ts +403 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/linear-router/index.ts +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/linear-router/router.ts +132 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/index.ts +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +54 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/index.ts +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +159 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +274 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/trie.ts +74 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/smart-router/index.ts +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/smart-router/router.ts +69 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/index.ts +6 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +205 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/router.ts +28 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/router.ts +103 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +2009 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/basic-auth.ts +26 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +225 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/buffer.ts +65 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +26 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/concurrent.ts +55 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +230 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/crypto.ts +65 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +34 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/filepath.ts +56 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/handler.ts +15 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/html.ts +182 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/http-status.ts +69 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/ipaddr.ts +113 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/index.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jwa.ts +23 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jws.ts +226 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jwt.ts +114 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/types.ts +83 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/utf8.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/mime.ts +142 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/stream.ts +96 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +105 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/url.ts +310 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/validator/index.ts +7 -0
- package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +151 -0
- package/tests/fixtures/corpus/oss-repos/hono/tsconfig.build.json +23 -0
- package/tests/fixtures/corpus/oss-repos/hono/tsconfig.json +28 -0
- package/tests/fixtures/corpus/oss-repos/hono/vitest.config.ts +34 -0
- package/tests/fixtures/corpus/oss-repos/hono/yarn.lock +6232 -0
- package/tests/fixtures/documentation/api-reference.md +412 -0
- package/tests/fixtures/documentation/architecture.md +214 -0
- package/tests/fixtures/documentation/deployment-guide.md +420 -0
- package/tests/fixtures/github-readmes/express.md +133 -0
- package/tests/fixtures/github-readmes/nextjs.md +106 -0
- package/tests/fixtures/github-readmes/react.md +74 -0
- package/tests/fixtures/github-readmes/typescript.md +93 -0
- package/tests/fixtures/github-readmes/vite.md +79 -0
- package/tests/fixtures/queries/core.json +125 -0
- package/tests/fixtures/queries/extended.json +427 -0
- package/tests/fixtures/queries/generated/.gitkeep +0 -0
- package/tests/fixtures/test-server.ts +267 -0
- package/tests/helpers/performance-metrics.ts +387 -0
- package/tests/helpers/search-relevance.ts +381 -0
- package/tests/integration/cli-consistency.test.ts +299 -0
- package/tests/integration/cli.test.ts +69 -0
- package/tests/integration/e2e-workflow.test.ts +612 -0
- package/tests/integration/python-bridge.test.ts +183 -0
- package/tests/integration/search-quality.test.ts +718 -0
- package/tests/integration/stress.test.ts +326 -0
- package/tests/mcp/server.test.ts +15 -0
- package/tests/scripts/schemas/evaluation.json +44 -0
- package/tests/scripts/schemas/query-generation.json +21 -0
- package/tests/services/code-unit.service.test.ts +47 -0
- package/tests/services/search.progressive-context.test.ts +35 -0
- package/tsconfig.json +34 -0
- package/tsup.config.ts +15 -0
- package/turndown-plugin-gfm.d.ts +29 -0
- package/vitest.config.ts +79 -0
|
@@ -0,0 +1,892 @@
|
|
|
1
|
+
import type { LanceStore } from '../db/lance.js';
|
|
2
|
+
import type { EmbeddingEngine } from '../db/embeddings.js';
|
|
3
|
+
import type { SearchQuery, SearchResponse, SearchResult, DetailLevel } from '../types/search.js';
|
|
4
|
+
import type { StoreId } from '../types/brands.js';
|
|
5
|
+
import { CodeUnitService } from './code-unit.service.js';
|
|
6
|
+
import type { CodeUnit } from '../types/search.js';
|
|
7
|
+
import type { CodeGraphService } from './code-graph.service.js';
|
|
8
|
+
import type { CodeGraph } from '../analysis/code-graph.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Query intent classification for context-aware ranking.
|
|
12
|
+
* Phase 1: Different intents prioritize different content types.
|
|
13
|
+
*/
|
|
14
|
+
export type QueryIntent = 'how-to' | 'implementation' | 'conceptual' | 'comparison' | 'debugging';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Intent-based file type multipliers - CONSERVATIVE version.
|
|
18
|
+
* Applied on top of base file-type boosts.
|
|
19
|
+
* Lessons learned: Too-aggressive penalties hurt when corpus lacks ideal content.
|
|
20
|
+
* These values provide gentle guidance rather than dramatic reranking.
|
|
21
|
+
*/
|
|
22
|
+
const INTENT_FILE_BOOSTS: Record<QueryIntent, Record<string, number>> = {
|
|
23
|
+
'how-to': {
|
|
24
|
+
'documentation-primary': 1.3, // Strong boost for docs
|
|
25
|
+
'documentation': 1.2,
|
|
26
|
+
'example': 1.5, // Examples are ideal for "how to"
|
|
27
|
+
'source': 0.85, // Moderate penalty - source might still have good content
|
|
28
|
+
'source-internal': 0.7, // Stronger penalty - internal code less useful
|
|
29
|
+
'test': 0.8,
|
|
30
|
+
'config': 0.7,
|
|
31
|
+
'other': 0.9,
|
|
32
|
+
},
|
|
33
|
+
'implementation': {
|
|
34
|
+
'documentation-primary': 0.95,
|
|
35
|
+
'documentation': 1.0,
|
|
36
|
+
'example': 1.0,
|
|
37
|
+
'source': 1.1, // Slight boost for source code
|
|
38
|
+
'source-internal': 1.05, // Internal code can be relevant
|
|
39
|
+
'test': 1.0,
|
|
40
|
+
'config': 0.95,
|
|
41
|
+
'other': 1.0,
|
|
42
|
+
},
|
|
43
|
+
'conceptual': {
|
|
44
|
+
'documentation-primary': 1.1,
|
|
45
|
+
'documentation': 1.05,
|
|
46
|
+
'example': 1.0,
|
|
47
|
+
'source': 0.95,
|
|
48
|
+
'source-internal': 0.9,
|
|
49
|
+
'test': 0.9,
|
|
50
|
+
'config': 0.85,
|
|
51
|
+
'other': 0.95,
|
|
52
|
+
},
|
|
53
|
+
'comparison': {
|
|
54
|
+
'documentation-primary': 1.15,
|
|
55
|
+
'documentation': 1.1,
|
|
56
|
+
'example': 1.05,
|
|
57
|
+
'source': 0.9,
|
|
58
|
+
'source-internal': 0.85,
|
|
59
|
+
'test': 0.9,
|
|
60
|
+
'config': 0.85,
|
|
61
|
+
'other': 0.95,
|
|
62
|
+
},
|
|
63
|
+
'debugging': {
|
|
64
|
+
'documentation-primary': 1.0,
|
|
65
|
+
'documentation': 1.0,
|
|
66
|
+
'example': 1.05,
|
|
67
|
+
'source': 1.0, // Source code helps with debugging
|
|
68
|
+
'source-internal': 0.95,
|
|
69
|
+
'test': 1.05, // Tests can show expected behavior
|
|
70
|
+
'config': 0.9,
|
|
71
|
+
'other': 1.0,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Known frameworks/technologies for context-aware boosting
|
|
76
|
+
const FRAMEWORK_PATTERNS: Array<{ pattern: RegExp; terms: string[] }> = [
|
|
77
|
+
{ pattern: /\bexpress\b/i, terms: ['express', 'expressjs', 'express.js'] },
|
|
78
|
+
{ pattern: /\bhono\b/i, terms: ['hono'] },
|
|
79
|
+
{ pattern: /\bzod\b/i, terms: ['zod'] },
|
|
80
|
+
{ pattern: /\breact\b/i, terms: ['react', 'reactjs', 'react.js'] },
|
|
81
|
+
{ pattern: /\bvue\b/i, terms: ['vue', 'vuejs', 'vue.js', 'vue3'] },
|
|
82
|
+
{ pattern: /\bnode\b/i, terms: ['node', 'nodejs', 'node.js'] },
|
|
83
|
+
{ pattern: /\btypescript\b/i, terms: ['typescript', 'ts'] },
|
|
84
|
+
{ pattern: /\bjwt\b/i, terms: ['jwt', 'jsonwebtoken', 'json-web-token'] },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Classify the intent of a search query.
|
|
89
|
+
* This helps adjust ranking based on what kind of answer the user wants.
|
|
90
|
+
*/
|
|
91
|
+
function classifyQueryIntent(query: string): QueryIntent {
|
|
92
|
+
const q = query.toLowerCase();
|
|
93
|
+
|
|
94
|
+
// How-to patterns: user wants to learn how to use/do something
|
|
95
|
+
const howToPatterns = [
|
|
96
|
+
/how (do|can|should|would) (i|you|we)/i,
|
|
97
|
+
/how to\b/i,
|
|
98
|
+
/what('s| is) the (best |right |correct )?(way|approach) to/i,
|
|
99
|
+
/i (need|want|have) to/i,
|
|
100
|
+
/show me how/i,
|
|
101
|
+
/\bwhat's the syntax\b/i,
|
|
102
|
+
/\bhow do i (use|create|make|set up|configure|implement|add|get)\b/i,
|
|
103
|
+
/\bi'm (trying|building|creating|making)\b/i,
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
// Implementation patterns: user wants to understand internals
|
|
107
|
+
const implementationPatterns = [
|
|
108
|
+
/how (does|is) .* (implemented|work internally)/i,
|
|
109
|
+
/\binternal(ly)?\b/i,
|
|
110
|
+
/\bsource code\b/i,
|
|
111
|
+
/\bunder the hood\b/i,
|
|
112
|
+
/\bimplementation (of|details?)\b/i,
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
// Comparison patterns: user is deciding between options
|
|
116
|
+
const comparisonPatterns = [
|
|
117
|
+
/\b(vs\.?|versus)\b/i,
|
|
118
|
+
/\bdifference(s)? between\b/i,
|
|
119
|
+
/\bcompare\b/i,
|
|
120
|
+
/\bshould (i|we) use .* or\b/i,
|
|
121
|
+
/\bwhat's the difference\b/i,
|
|
122
|
+
/\bwhich (one|is better)\b/i,
|
|
123
|
+
/\bwhen (should|to) use\b/i,
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
// Debugging patterns: user is troubleshooting a problem
|
|
127
|
+
const debuggingPatterns = [
|
|
128
|
+
/\b(error|bug|issue|problem|crash|fail|broken|wrong)\b/i,
|
|
129
|
+
/\bdoesn't (work|compile|run)\b/i,
|
|
130
|
+
/\bisn't (working|updating|rendering)\b/i,
|
|
131
|
+
/\bwhy (is|does|doesn't|isn't)\b/i,
|
|
132
|
+
/\bwhat('s| is) (wrong|happening|going on)\b/i,
|
|
133
|
+
/\bwhat am i doing wrong\b/i,
|
|
134
|
+
/\bnot (working|updating|showing)\b/i,
|
|
135
|
+
/\bhow do i (fix|debug|solve|resolve)\b/i,
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
// Conceptual patterns: user wants to understand a concept
|
|
139
|
+
const conceptualPatterns = [
|
|
140
|
+
/\bwhat (is|are)\b/i,
|
|
141
|
+
/\bexplain\b/i,
|
|
142
|
+
/\bwhat does .* (mean|do)\b/i,
|
|
143
|
+
/\bhow does .* work\b/i,
|
|
144
|
+
/\bwhat('s| is) the (purpose|point|idea)\b/i,
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
// Check patterns in order of specificity
|
|
148
|
+
if (implementationPatterns.some(p => p.test(q))) {
|
|
149
|
+
return 'implementation';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (debuggingPatterns.some(p => p.test(q))) {
|
|
153
|
+
return 'debugging';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (comparisonPatterns.some(p => p.test(q))) {
|
|
157
|
+
return 'comparison';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (howToPatterns.some(p => p.test(q))) {
|
|
161
|
+
return 'how-to';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (conceptualPatterns.some(p => p.test(q))) {
|
|
165
|
+
return 'conceptual';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Default to how-to as most queries are seeking practical usage
|
|
169
|
+
return 'how-to';
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
interface RRFConfig {
|
|
173
|
+
k: number;
|
|
174
|
+
vectorWeight: number;
|
|
175
|
+
ftsWeight: number;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export class SearchService {
|
|
179
|
+
private readonly lanceStore: LanceStore;
|
|
180
|
+
private readonly embeddingEngine: EmbeddingEngine;
|
|
181
|
+
private readonly rrfConfig: RRFConfig;
|
|
182
|
+
private readonly codeUnitService: CodeUnitService;
|
|
183
|
+
private readonly codeGraphService: CodeGraphService | undefined;
|
|
184
|
+
private readonly graphCache: Map<string, CodeGraph | null>;
|
|
185
|
+
|
|
186
|
+
constructor(
|
|
187
|
+
lanceStore: LanceStore,
|
|
188
|
+
embeddingEngine: EmbeddingEngine,
|
|
189
|
+
// Lower k value (20 vs 60) produces more differentiated scores for top results
|
|
190
|
+
rrfConfig: RRFConfig = { k: 20, vectorWeight: 0.6, ftsWeight: 0.4 },
|
|
191
|
+
codeGraphService?: CodeGraphService
|
|
192
|
+
) {
|
|
193
|
+
this.lanceStore = lanceStore;
|
|
194
|
+
this.embeddingEngine = embeddingEngine;
|
|
195
|
+
this.rrfConfig = rrfConfig;
|
|
196
|
+
this.codeUnitService = new CodeUnitService();
|
|
197
|
+
this.codeGraphService = codeGraphService;
|
|
198
|
+
this.graphCache = new Map();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Load code graph for a store, with caching.
|
|
203
|
+
* Returns null if no graph is available.
|
|
204
|
+
*/
|
|
205
|
+
private async loadGraphForStore(storeId: StoreId): Promise<CodeGraph | null> {
|
|
206
|
+
if (!this.codeGraphService) return null;
|
|
207
|
+
|
|
208
|
+
const cached = this.graphCache.get(storeId);
|
|
209
|
+
if (cached !== undefined) return cached;
|
|
210
|
+
|
|
211
|
+
const graph = await this.codeGraphService.loadGraph(storeId);
|
|
212
|
+
const result = graph ?? null;
|
|
213
|
+
this.graphCache.set(storeId, result);
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async search(query: SearchQuery): Promise<SearchResponse> {
|
|
218
|
+
const startTime = Date.now();
|
|
219
|
+
const mode = query.mode ?? 'hybrid';
|
|
220
|
+
const limit = query.limit ?? 10;
|
|
221
|
+
const stores = query.stores ?? [];
|
|
222
|
+
const detail = query.detail ?? 'minimal';
|
|
223
|
+
|
|
224
|
+
let allResults: SearchResult[] = [];
|
|
225
|
+
|
|
226
|
+
// Fetch more results than needed to allow for deduplication
|
|
227
|
+
const fetchLimit = limit * 3;
|
|
228
|
+
|
|
229
|
+
if (mode === 'vector') {
|
|
230
|
+
allResults = await this.vectorSearch(query.query, stores, fetchLimit, query.threshold);
|
|
231
|
+
} else if (mode === 'fts') {
|
|
232
|
+
allResults = await this.ftsSearch(query.query, stores, fetchLimit);
|
|
233
|
+
} else {
|
|
234
|
+
// Hybrid: combine vector and FTS with RRF
|
|
235
|
+
allResults = await this.hybridSearch(query.query, stores, fetchLimit, query.threshold);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Deduplicate by source file - keep best chunk per source (considers query relevance)
|
|
239
|
+
const dedupedResults = this.deduplicateBySource(allResults, query.query);
|
|
240
|
+
const resultsToEnhance = dedupedResults.slice(0, limit);
|
|
241
|
+
|
|
242
|
+
// Load code graphs for stores in results (for contextual/full detail levels)
|
|
243
|
+
const graphs = new Map<string, CodeGraph | null>();
|
|
244
|
+
if (detail === 'contextual' || detail === 'full') {
|
|
245
|
+
const storeIds = new Set(resultsToEnhance.map(r => r.metadata.storeId));
|
|
246
|
+
for (const storeId of storeIds) {
|
|
247
|
+
graphs.set(storeId, await this.loadGraphForStore(storeId));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Enhance results with progressive context
|
|
252
|
+
const enhancedResults = resultsToEnhance.map(r => {
|
|
253
|
+
const graph = graphs.get(r.metadata.storeId) ?? null;
|
|
254
|
+
return this.addProgressiveContext(r, query.query, detail, graph);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
query: query.query,
|
|
259
|
+
mode,
|
|
260
|
+
stores,
|
|
261
|
+
results: enhancedResults,
|
|
262
|
+
totalResults: enhancedResults.length,
|
|
263
|
+
timeMs: Date.now() - startTime,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Deduplicate results by source file path.
|
|
269
|
+
* Keeps the best chunk for each unique source, considering both score and query relevance.
|
|
270
|
+
*/
|
|
271
|
+
private deduplicateBySource(results: SearchResult[], query: string): SearchResult[] {
|
|
272
|
+
const bySource = new Map<string, SearchResult>();
|
|
273
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter(t => t.length > 2);
|
|
274
|
+
|
|
275
|
+
for (const result of results) {
|
|
276
|
+
// Use file path as the source key, fallback to document ID
|
|
277
|
+
const sourceKey = result.metadata.path ?? result.metadata.url ?? result.id;
|
|
278
|
+
|
|
279
|
+
const existing = bySource.get(sourceKey);
|
|
280
|
+
if (!existing) {
|
|
281
|
+
bySource.set(sourceKey, result);
|
|
282
|
+
} else {
|
|
283
|
+
// Compare: prefer chunk with more query terms in content
|
|
284
|
+
const existingTermCount = this.countQueryTerms(existing.content, queryTerms);
|
|
285
|
+
const newTermCount = this.countQueryTerms(result.content, queryTerms);
|
|
286
|
+
|
|
287
|
+
// Prefer chunk with more query terms, or higher score if same
|
|
288
|
+
if (newTermCount > existingTermCount ||
|
|
289
|
+
(newTermCount === existingTermCount && result.score > existing.score)) {
|
|
290
|
+
bySource.set(sourceKey, result);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Return results sorted by score
|
|
296
|
+
return Array.from(bySource.values()).sort((a, b) => b.score - a.score);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Count how many query terms appear in the content.
|
|
301
|
+
*/
|
|
302
|
+
private countQueryTerms(content: string, queryTerms: string[]): number {
|
|
303
|
+
const lowerContent = content.toLowerCase();
|
|
304
|
+
return queryTerms.filter(term => lowerContent.includes(term)).length;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private async vectorSearch(
|
|
308
|
+
query: string,
|
|
309
|
+
stores: readonly StoreId[],
|
|
310
|
+
limit: number,
|
|
311
|
+
threshold?: number
|
|
312
|
+
): Promise<SearchResult[]> {
|
|
313
|
+
const queryVector = await this.embeddingEngine.embed(query);
|
|
314
|
+
const results: SearchResult[] = [];
|
|
315
|
+
|
|
316
|
+
for (const storeId of stores) {
|
|
317
|
+
const hits = await this.lanceStore.search(storeId, queryVector, limit, threshold);
|
|
318
|
+
results.push(...hits.map(r => ({
|
|
319
|
+
id: r.id,
|
|
320
|
+
score: r.score,
|
|
321
|
+
content: r.content,
|
|
322
|
+
metadata: r.metadata,
|
|
323
|
+
})));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private async ftsSearch(
|
|
330
|
+
query: string,
|
|
331
|
+
stores: readonly StoreId[],
|
|
332
|
+
limit: number
|
|
333
|
+
): Promise<SearchResult[]> {
|
|
334
|
+
const results: SearchResult[] = [];
|
|
335
|
+
|
|
336
|
+
for (const storeId of stores) {
|
|
337
|
+
const hits = await this.lanceStore.fullTextSearch(storeId, query, limit);
|
|
338
|
+
results.push(...hits.map(r => ({
|
|
339
|
+
id: r.id,
|
|
340
|
+
score: r.score,
|
|
341
|
+
content: r.content,
|
|
342
|
+
metadata: r.metadata,
|
|
343
|
+
})));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private async hybridSearch(
|
|
350
|
+
query: string,
|
|
351
|
+
stores: readonly StoreId[],
|
|
352
|
+
limit: number,
|
|
353
|
+
threshold?: number
|
|
354
|
+
): Promise<SearchResult[]> {
|
|
355
|
+
// Phase 1: Classify query intent for context-aware ranking
|
|
356
|
+
const intent = classifyQueryIntent(query);
|
|
357
|
+
|
|
358
|
+
// Get both result sets
|
|
359
|
+
const [vectorResults, ftsResults] = await Promise.all([
|
|
360
|
+
this.vectorSearch(query, stores, limit * 2, threshold),
|
|
361
|
+
this.ftsSearch(query, stores, limit * 2),
|
|
362
|
+
]);
|
|
363
|
+
|
|
364
|
+
// Build rank maps
|
|
365
|
+
const vectorRanks = new Map<string, number>();
|
|
366
|
+
const ftsRanks = new Map<string, number>();
|
|
367
|
+
const allDocs = new Map<string, SearchResult>();
|
|
368
|
+
|
|
369
|
+
vectorResults.forEach((r, i) => {
|
|
370
|
+
vectorRanks.set(r.id, i + 1);
|
|
371
|
+
allDocs.set(r.id, r);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
ftsResults.forEach((r, i) => {
|
|
375
|
+
ftsRanks.set(r.id, i + 1);
|
|
376
|
+
if (!allDocs.has(r.id)) {
|
|
377
|
+
allDocs.set(r.id, r);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// Calculate RRF scores with file-type boosting and preserve ranking metadata
|
|
382
|
+
const rrfScores: Array<{
|
|
383
|
+
id: string;
|
|
384
|
+
score: number;
|
|
385
|
+
result: SearchResult;
|
|
386
|
+
metadata: {
|
|
387
|
+
vectorRank?: number;
|
|
388
|
+
ftsRank?: number;
|
|
389
|
+
vectorRRF: number;
|
|
390
|
+
ftsRRF: number;
|
|
391
|
+
fileTypeBoost: number;
|
|
392
|
+
frameworkBoost: number;
|
|
393
|
+
};
|
|
394
|
+
}> = [];
|
|
395
|
+
const { k, vectorWeight, ftsWeight } = this.rrfConfig;
|
|
396
|
+
|
|
397
|
+
for (const [id, result] of allDocs) {
|
|
398
|
+
const vectorRank = vectorRanks.get(id) ?? Infinity;
|
|
399
|
+
const ftsRank = ftsRanks.get(id) ?? Infinity;
|
|
400
|
+
|
|
401
|
+
const vectorRRF = vectorRank !== Infinity ? vectorWeight / (k + vectorRank) : 0;
|
|
402
|
+
const ftsRRF = ftsRank !== Infinity ? ftsWeight / (k + ftsRank) : 0;
|
|
403
|
+
|
|
404
|
+
// Apply file-type boost (base + intent-adjusted)
|
|
405
|
+
const fileTypeBoost = this.getFileTypeBoost(
|
|
406
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
407
|
+
result.metadata['fileType'] as string | undefined,
|
|
408
|
+
intent
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
// Apply framework context boost
|
|
412
|
+
const frameworkBoost = this.getFrameworkContextBoost(query, result);
|
|
413
|
+
|
|
414
|
+
const metadata: {
|
|
415
|
+
vectorRank?: number;
|
|
416
|
+
ftsRank?: number;
|
|
417
|
+
vectorRRF: number;
|
|
418
|
+
ftsRRF: number;
|
|
419
|
+
fileTypeBoost: number;
|
|
420
|
+
frameworkBoost: number;
|
|
421
|
+
} = {
|
|
422
|
+
vectorRRF,
|
|
423
|
+
ftsRRF,
|
|
424
|
+
fileTypeBoost,
|
|
425
|
+
frameworkBoost,
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
if (vectorRank !== Infinity) {
|
|
429
|
+
metadata.vectorRank = vectorRank;
|
|
430
|
+
}
|
|
431
|
+
if (ftsRank !== Infinity) {
|
|
432
|
+
metadata.ftsRank = ftsRank;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
rrfScores.push({
|
|
436
|
+
id,
|
|
437
|
+
score: (vectorRRF + ftsRRF) * fileTypeBoost * frameworkBoost,
|
|
438
|
+
result,
|
|
439
|
+
metadata,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Sort by RRF score
|
|
444
|
+
const sorted = rrfScores.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
445
|
+
|
|
446
|
+
// Normalize scores to 0-1 range for better interpretability
|
|
447
|
+
if (sorted.length > 0) {
|
|
448
|
+
const first = sorted[0];
|
|
449
|
+
const last = sorted[sorted.length - 1];
|
|
450
|
+
if (first === undefined || last === undefined) {
|
|
451
|
+
return sorted.map(r => ({
|
|
452
|
+
...r.result,
|
|
453
|
+
score: r.score,
|
|
454
|
+
rankingMetadata: r.metadata,
|
|
455
|
+
}));
|
|
456
|
+
}
|
|
457
|
+
const maxScore = first.score;
|
|
458
|
+
const minScore = last.score;
|
|
459
|
+
const range = maxScore - minScore;
|
|
460
|
+
|
|
461
|
+
if (range > 0) {
|
|
462
|
+
return sorted.map(r => ({
|
|
463
|
+
...r.result,
|
|
464
|
+
score: (r.score - minScore) / range,
|
|
465
|
+
rankingMetadata: r.metadata,
|
|
466
|
+
}));
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return sorted.map(r => ({
|
|
471
|
+
...r.result,
|
|
472
|
+
score: r.score,
|
|
473
|
+
rankingMetadata: r.metadata,
|
|
474
|
+
}));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async searchAllStores(
|
|
478
|
+
query: SearchQuery,
|
|
479
|
+
storeIds: StoreId[]
|
|
480
|
+
): Promise<SearchResponse> {
|
|
481
|
+
return this.search({
|
|
482
|
+
...query,
|
|
483
|
+
stores: storeIds,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Get a score multiplier based on file type and query intent.
|
|
489
|
+
* Documentation files get a strong boost to surface them higher.
|
|
490
|
+
* Phase 4: Strengthened boosts for better documentation ranking.
|
|
491
|
+
* Phase 1: Intent-based adjustments for context-aware ranking.
|
|
492
|
+
*/
|
|
493
|
+
private getFileTypeBoost(fileType: string | undefined, intent: QueryIntent): number {
|
|
494
|
+
// Base file-type boosts
|
|
495
|
+
let baseBoost: number;
|
|
496
|
+
switch (fileType) {
|
|
497
|
+
case 'documentation-primary':
|
|
498
|
+
baseBoost = 1.8; // README, guides get very strong boost
|
|
499
|
+
break;
|
|
500
|
+
case 'documentation':
|
|
501
|
+
baseBoost = 1.5; // docs/, tutorials/ get strong boost
|
|
502
|
+
break;
|
|
503
|
+
case 'example':
|
|
504
|
+
baseBoost = 1.4; // examples/, demos/ are highly valuable
|
|
505
|
+
break;
|
|
506
|
+
case 'source':
|
|
507
|
+
baseBoost = 1.0; // Source code baseline
|
|
508
|
+
break;
|
|
509
|
+
case 'source-internal':
|
|
510
|
+
baseBoost = 0.75; // Internal implementation files (not too harsh)
|
|
511
|
+
break;
|
|
512
|
+
case 'test':
|
|
513
|
+
baseBoost = 0.7; // Tests significantly lower
|
|
514
|
+
break;
|
|
515
|
+
case 'config':
|
|
516
|
+
baseBoost = 0.5; // Config files rarely answer questions
|
|
517
|
+
break;
|
|
518
|
+
default:
|
|
519
|
+
baseBoost = 1.0;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Apply intent-based multiplier
|
|
523
|
+
const intentBoosts = INTENT_FILE_BOOSTS[intent];
|
|
524
|
+
const intentMultiplier = intentBoosts[fileType ?? 'other'] ?? 1.0;
|
|
525
|
+
|
|
526
|
+
return baseBoost * intentMultiplier;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Get a score multiplier based on framework context.
|
|
531
|
+
* If query mentions a framework, boost results from that framework's files.
|
|
532
|
+
*/
|
|
533
|
+
private getFrameworkContextBoost(query: string, result: SearchResult): number {
|
|
534
|
+
const path = result.metadata.path ?? result.metadata.url ?? '';
|
|
535
|
+
const content = result.content.toLowerCase();
|
|
536
|
+
const pathLower = path.toLowerCase();
|
|
537
|
+
|
|
538
|
+
// Check if query mentions any known frameworks
|
|
539
|
+
for (const { pattern, terms } of FRAMEWORK_PATTERNS) {
|
|
540
|
+
if (pattern.test(query)) {
|
|
541
|
+
// Query mentions this framework - check if result is from that framework
|
|
542
|
+
const resultMatchesFramework = terms.some(term =>
|
|
543
|
+
pathLower.includes(term) || content.includes(term)
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
if (resultMatchesFramework) {
|
|
547
|
+
return 1.5; // Strong boost for matching framework
|
|
548
|
+
} else {
|
|
549
|
+
return 0.8; // Moderate penalty for non-matching when framework is specified
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return 1.0; // No framework context in query
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
private addProgressiveContext(
|
|
558
|
+
result: SearchResult,
|
|
559
|
+
query: string,
|
|
560
|
+
detail: DetailLevel,
|
|
561
|
+
graph: CodeGraph | null
|
|
562
|
+
): SearchResult {
|
|
563
|
+
const enhanced = { ...result };
|
|
564
|
+
|
|
565
|
+
// Layer 1: Always add summary
|
|
566
|
+
const path = result.metadata.path ?? result.metadata.url ?? 'unknown';
|
|
567
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
568
|
+
const fileType = result.metadata['fileType'] as string | undefined;
|
|
569
|
+
|
|
570
|
+
// Try to extract code unit
|
|
571
|
+
const codeUnit = this.extractCodeUnitFromResult(result);
|
|
572
|
+
const symbolName = codeUnit?.name ?? this.extractSymbolName(result.content);
|
|
573
|
+
|
|
574
|
+
enhanced.summary = {
|
|
575
|
+
type: this.inferType(fileType, codeUnit),
|
|
576
|
+
name: symbolName,
|
|
577
|
+
signature: codeUnit?.signature ?? '',
|
|
578
|
+
purpose: this.generatePurpose(result.content, query),
|
|
579
|
+
location: `${path}${codeUnit ? ':' + String(codeUnit.startLine) : ''}`,
|
|
580
|
+
relevanceReason: this.generateRelevanceReason(result, query)
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
// Layer 2: Add context if requested
|
|
584
|
+
if (detail === 'contextual' || detail === 'full') {
|
|
585
|
+
// Get usage stats from code graph if available
|
|
586
|
+
const usage = this.getUsageFromGraph(graph, path, symbolName);
|
|
587
|
+
|
|
588
|
+
enhanced.context = {
|
|
589
|
+
interfaces: this.extractInterfaces(result.content),
|
|
590
|
+
keyImports: this.extractImports(result.content),
|
|
591
|
+
relatedConcepts: this.extractConcepts(result.content, query),
|
|
592
|
+
usage
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Layer 3: Add full context if requested
|
|
597
|
+
if (detail === 'full') {
|
|
598
|
+
// Get related code from graph if available
|
|
599
|
+
const relatedCode = this.getRelatedCodeFromGraph(graph, path, symbolName);
|
|
600
|
+
|
|
601
|
+
enhanced.full = {
|
|
602
|
+
completeCode: codeUnit?.fullContent ?? result.content,
|
|
603
|
+
relatedCode,
|
|
604
|
+
documentation: this.extractDocumentation(result.content),
|
|
605
|
+
tests: undefined
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return enhanced;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
private extractCodeUnitFromResult(result: SearchResult): CodeUnit | undefined {
|
|
613
|
+
const path = result.metadata.path;
|
|
614
|
+
if (path === undefined || path === '') return undefined;
|
|
615
|
+
|
|
616
|
+
const ext = path.split('.').pop() ?? '';
|
|
617
|
+
const language = ext === 'ts' || ext === 'tsx' ? 'typescript' :
|
|
618
|
+
ext === 'js' || ext === 'jsx' ? 'javascript' : ext;
|
|
619
|
+
|
|
620
|
+
// Try to find a symbol name in the content
|
|
621
|
+
const symbolName = this.extractSymbolName(result.content);
|
|
622
|
+
if (symbolName === '') return undefined;
|
|
623
|
+
|
|
624
|
+
return this.codeUnitService.extractCodeUnit(result.content, symbolName, language);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
private extractSymbolName(content: string): string {
|
|
628
|
+
// Extract function or class name
|
|
629
|
+
const funcMatch = content.match(/(?:export\s+)?(?:async\s+)?function\s+(\w+)/);
|
|
630
|
+
if (funcMatch !== null && funcMatch[1] !== undefined && funcMatch[1] !== '') return funcMatch[1];
|
|
631
|
+
|
|
632
|
+
const classMatch = content.match(/(?:export\s+)?class\s+(\w+)/);
|
|
633
|
+
if (classMatch !== null && classMatch[1] !== undefined && classMatch[1] !== '') return classMatch[1];
|
|
634
|
+
|
|
635
|
+
const constMatch = content.match(/(?:export\s+)?const\s+(\w+)/);
|
|
636
|
+
if (constMatch !== null && constMatch[1] !== undefined && constMatch[1] !== '') return constMatch[1];
|
|
637
|
+
|
|
638
|
+
// Fallback: return "(anonymous)" for unnamed symbols
|
|
639
|
+
return '(anonymous)';
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
private inferType(fileType: string | undefined, codeUnit: CodeUnit | undefined): import('../types/search.js').ResultSummary['type'] {
|
|
643
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
644
|
+
if (codeUnit) return codeUnit.type as import('../types/search.js').ResultSummary['type'];
|
|
645
|
+
if (fileType === 'documentation' || fileType === 'documentation-primary') return 'documentation';
|
|
646
|
+
return 'function';
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
private generatePurpose(content: string, query: string): string {
|
|
650
|
+
// Extract first line of JSDoc comment if present
|
|
651
|
+
const docMatch = content.match(/\/\*\*\s*\n\s*\*\s*([^\n]+)/);
|
|
652
|
+
if (docMatch !== null && docMatch[1] !== undefined && docMatch[1] !== '') return docMatch[1].trim();
|
|
653
|
+
|
|
654
|
+
const lines = content.split('\n');
|
|
655
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter(t => t.length > 2);
|
|
656
|
+
|
|
657
|
+
// Helper to check if line is skippable (imports, declarations)
|
|
658
|
+
const shouldSkip = (cleaned: string): boolean => {
|
|
659
|
+
return cleaned.startsWith('import ') ||
|
|
660
|
+
cleaned.startsWith('export ') ||
|
|
661
|
+
cleaned.startsWith('interface ') ||
|
|
662
|
+
cleaned.startsWith('type ');
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
// Helper to score a line based on query term matches
|
|
666
|
+
const scoreLine = (cleaned: string): number => {
|
|
667
|
+
const lowerLine = cleaned.toLowerCase();
|
|
668
|
+
return queryTerms.filter(term => lowerLine.includes(term)).length;
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
// Helper to check if line is meaningful (length, not a comment)
|
|
672
|
+
const isMeaningful = (cleaned: string): boolean => {
|
|
673
|
+
if (cleaned.length === 0) return false;
|
|
674
|
+
if (cleaned.startsWith('//') || cleaned.startsWith('/*')) return false;
|
|
675
|
+
// Accept Markdown headings
|
|
676
|
+
if (cleaned.startsWith('#') && cleaned.length > 3) return true;
|
|
677
|
+
// Accept lines 15+ chars
|
|
678
|
+
return cleaned.length >= 15;
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
// First pass: find lines with query terms, preferring complete sentences
|
|
682
|
+
let bestLine: string | null = null;
|
|
683
|
+
let bestScore = 0;
|
|
684
|
+
|
|
685
|
+
for (const line of lines) {
|
|
686
|
+
const cleaned = line.trim();
|
|
687
|
+
if (shouldSkip(cleaned) || !isMeaningful(cleaned)) continue;
|
|
688
|
+
|
|
689
|
+
let score = scoreLine(cleaned);
|
|
690
|
+
|
|
691
|
+
// Boost score for complete sentences (end with period, !, ?)
|
|
692
|
+
if (/[.!?]$/.test(cleaned)) {
|
|
693
|
+
score += 0.5;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Boost score for code examples (contains function calls or assignments)
|
|
697
|
+
// Favor complete patterns: function calls WITH arguments, assignments with values
|
|
698
|
+
if (/\w+\([^)]*\)|=\s*\w+\(|=>/.test(cleaned)) {
|
|
699
|
+
score += 0.6; // Enhanced boost to preserve code examples in snippets
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
if (score > bestScore) {
|
|
703
|
+
bestScore = score;
|
|
704
|
+
bestLine = cleaned;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// If we found a line with query terms, use it
|
|
709
|
+
if (bestLine !== null && bestLine !== '' && bestScore > 0) {
|
|
710
|
+
if (bestLine.length > 150) {
|
|
711
|
+
const firstSentence = bestLine.match(/^[^.!?]+[.!?]/);
|
|
712
|
+
if (firstSentence && firstSentence[0].length >= 20 && firstSentence[0].length <= 150) {
|
|
713
|
+
return firstSentence[0].trim();
|
|
714
|
+
}
|
|
715
|
+
return bestLine.substring(0, 147) + '...';
|
|
716
|
+
}
|
|
717
|
+
return bestLine;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// Fallback: first meaningful line (original logic)
|
|
721
|
+
for (const line of lines) {
|
|
722
|
+
const cleaned = line.trim();
|
|
723
|
+
if (shouldSkip(cleaned) || !isMeaningful(cleaned)) continue;
|
|
724
|
+
|
|
725
|
+
if (cleaned.length > 150) {
|
|
726
|
+
const firstSentence = cleaned.match(/^[^.!?]+[.!?]/);
|
|
727
|
+
if (firstSentence && firstSentence[0].length >= 20 && firstSentence[0].length <= 150) {
|
|
728
|
+
return firstSentence[0].trim();
|
|
729
|
+
}
|
|
730
|
+
return cleaned.substring(0, 147) + '...';
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
return cleaned;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
return 'Code related to query';
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
private generateRelevanceReason(result: SearchResult, query: string): string {
|
|
740
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter(t => t.length > 2);
|
|
741
|
+
const contentLower = result.content.toLowerCase();
|
|
742
|
+
|
|
743
|
+
const matchedTerms = queryTerms.filter(term => contentLower.includes(term));
|
|
744
|
+
|
|
745
|
+
if (matchedTerms.length > 0) {
|
|
746
|
+
return `Matches: ${matchedTerms.join(', ')}`;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
return 'Semantically similar to query';
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
private extractInterfaces(content: string): string[] {
|
|
753
|
+
const interfaces: string[] = [];
|
|
754
|
+
const matches = content.matchAll(/interface\s+(\w+)/g);
|
|
755
|
+
for (const match of matches) {
|
|
756
|
+
if (match[1] !== undefined && match[1] !== '') interfaces.push(match[1]);
|
|
757
|
+
}
|
|
758
|
+
return interfaces;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
private extractImports(content: string): string[] {
|
|
762
|
+
const imports: string[] = [];
|
|
763
|
+
const matches = content.matchAll(/import\s+.*?from\s+['"]([^'"]+)['"]/g);
|
|
764
|
+
for (const match of matches) {
|
|
765
|
+
if (match[1] !== undefined && match[1] !== '') imports.push(match[1]);
|
|
766
|
+
}
|
|
767
|
+
return imports.slice(0, 5); // Top 5
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
private extractConcepts(content: string, _query: string): string[] {
|
|
771
|
+
// TODO: Use _query parameter to prioritize query-related concepts in future enhancement
|
|
772
|
+
|
|
773
|
+
// Common stopwords to filter out
|
|
774
|
+
const stopwords = new Set([
|
|
775
|
+
'this', 'that', 'these', 'those', 'from', 'with', 'have', 'will',
|
|
776
|
+
'would', 'should', 'could', 'about', 'been', 'were', 'being',
|
|
777
|
+
'function', 'return', 'const', 'import', 'export', 'default',
|
|
778
|
+
'type', 'interface', 'class', 'extends', 'implements', 'async',
|
|
779
|
+
'await', 'then', 'catch', 'throw', 'error', 'undefined', 'null',
|
|
780
|
+
'true', 'false', 'void', 'number', 'string', 'boolean', 'object',
|
|
781
|
+
'array', 'promise', 'callback', 'resolve', 'reject', 'value',
|
|
782
|
+
'param', 'params', 'args', 'props', 'options', 'config', 'data'
|
|
783
|
+
]);
|
|
784
|
+
|
|
785
|
+
// Simple keyword extraction
|
|
786
|
+
const words = content.toLowerCase().match(/\b[a-z]{4,}\b/g) ?? [];
|
|
787
|
+
const frequency = new Map<string, number>();
|
|
788
|
+
|
|
789
|
+
for (const word of words) {
|
|
790
|
+
// Skip stopwords
|
|
791
|
+
if (stopwords.has(word)) continue;
|
|
792
|
+
|
|
793
|
+
frequency.set(word, (frequency.get(word) ?? 0) + 1);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
return Array.from(frequency.entries())
|
|
797
|
+
.sort((a, b) => b[1] - a[1])
|
|
798
|
+
.slice(0, 5)
|
|
799
|
+
.map(([word]) => word);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
private extractDocumentation(content: string): string {
|
|
803
|
+
const docMatch = content.match(/\/\*\*([\s\S]*?)\*\//);
|
|
804
|
+
if (docMatch !== null && docMatch[1] !== undefined && docMatch[1] !== '') {
|
|
805
|
+
return docMatch[1]
|
|
806
|
+
.split('\n')
|
|
807
|
+
.map(line => line.replace(/^\s*\*\s?/, '').trim())
|
|
808
|
+
.filter(line => line.length > 0)
|
|
809
|
+
.join('\n');
|
|
810
|
+
}
|
|
811
|
+
return '';
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Get usage stats from code graph.
|
|
816
|
+
* Returns default values if no graph is available.
|
|
817
|
+
*/
|
|
818
|
+
private getUsageFromGraph(
|
|
819
|
+
graph: CodeGraph | null,
|
|
820
|
+
filePath: string,
|
|
821
|
+
symbolName: string
|
|
822
|
+
): { calledBy: number; calls: number } {
|
|
823
|
+
if (!graph || symbolName === '' || symbolName === '(anonymous)') {
|
|
824
|
+
return { calledBy: 0, calls: 0 };
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
const nodeId = `${filePath}:${symbolName}`;
|
|
828
|
+
return {
|
|
829
|
+
calledBy: graph.getCalledByCount(nodeId),
|
|
830
|
+
calls: graph.getCallsCount(nodeId)
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Get related code from graph.
|
|
836
|
+
* Returns callers and callees for the symbol.
|
|
837
|
+
*/
|
|
838
|
+
private getRelatedCodeFromGraph(
|
|
839
|
+
graph: CodeGraph | null,
|
|
840
|
+
filePath: string,
|
|
841
|
+
symbolName: string
|
|
842
|
+
): Array<{ file: string; summary: string; relationship: string }> {
|
|
843
|
+
if (!graph || symbolName === '' || symbolName === '(anonymous)') {
|
|
844
|
+
return [];
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
const nodeId = `${filePath}:${symbolName}`;
|
|
848
|
+
const related: Array<{ file: string; summary: string; relationship: string }> = [];
|
|
849
|
+
|
|
850
|
+
// Get callers (incoming edges)
|
|
851
|
+
const incoming = graph.getIncomingEdges(nodeId);
|
|
852
|
+
for (const edge of incoming) {
|
|
853
|
+
if (edge.type === 'calls') {
|
|
854
|
+
// Parse file:symbol from edge.from
|
|
855
|
+
const [file, symbol] = this.parseNodeId(edge.from);
|
|
856
|
+
related.push({
|
|
857
|
+
file,
|
|
858
|
+
summary: symbol ? `${symbol}()` : 'unknown',
|
|
859
|
+
relationship: 'calls this'
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Get callees (outgoing edges)
|
|
865
|
+
const outgoing = graph.getEdges(nodeId);
|
|
866
|
+
for (const edge of outgoing) {
|
|
867
|
+
if (edge.type === 'calls') {
|
|
868
|
+
// Parse file:symbol from edge.to
|
|
869
|
+
const [file, symbol] = this.parseNodeId(edge.to);
|
|
870
|
+
related.push({
|
|
871
|
+
file,
|
|
872
|
+
summary: symbol ? `${symbol}()` : 'unknown',
|
|
873
|
+
relationship: 'called by this'
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// Limit to top 10 related items
|
|
879
|
+
return related.slice(0, 10);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Parse a node ID into file path and symbol name.
|
|
884
|
+
*/
|
|
885
|
+
private parseNodeId(nodeId: string): [string, string] {
|
|
886
|
+
const lastColon = nodeId.lastIndexOf(':');
|
|
887
|
+
if (lastColon === -1) {
|
|
888
|
+
return [nodeId, ''];
|
|
889
|
+
}
|
|
890
|
+
return [nodeId.substring(0, lastColon), nodeId.substring(lastColon + 1)];
|
|
891
|
+
}
|
|
892
|
+
}
|