bluera-knowledge 0.14.0 → 0.14.2
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-plugin/plugin.json +1 -1
- package/CHANGELOG.md +14 -0
- package/dist/{chunk-AIS5S77C.js → chunk-X7E4RYJE.js} +51 -9
- package/dist/{chunk-AIS5S77C.js.map → chunk-X7E4RYJE.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/workers/background-worker-cli.js +1 -1
- package/package.json +12 -1
- package/.claude/commands/code-review.md +0 -15
- package/.claude/commands/commit.md +0 -34
- package/.claude/council-cache/1a43ed5977b8f29afc79a9bf5c4082ee5ad8338c42ab991a4241a48f80c1e46d.json +0 -7
- package/.claude/hooks/post-edit-check.sh +0 -40
- package/.claude/rules/code-quality.md +0 -12
- package/.claude/rules/git.md +0 -5
- package/.claude/rules/versioning.md +0 -7
- package/.claude/settings.local.json.example +0 -45
- package/.claude/skills/atomic-commits/SKILL.md +0 -61
- package/.claude/skills/code-review-repo/skill.md +0 -62
- package/.editorconfig +0 -15
- package/.env.example +0 -21
- package/.github/workflows/auto-release.yml +0 -64
- package/.github/workflows/ci.yml +0 -168
- package/.github/workflows/release.yml +0 -74
- package/.github/workflows/update-marketplace.yml +0 -96
- package/.husky/pre-commit +0 -48
- package/.husky/pre-push +0 -39
- package/.mcp.json +0 -11
- package/.prettierrc +0 -9
- package/.versionrc.json +0 -24
- package/CLAUDE.md +0 -110
- package/CONTRIBUTING.md +0 -307
- package/NOTICE +0 -47
- package/SECURITY.md +0 -65
- package/bun.lock +0 -2036
- package/docs/claude-code-best-practices.md +0 -458
- package/docs/cli.md +0 -170
- package/docs/commands.md +0 -392
- package/docs/crawler-architecture.md +0 -89
- package/docs/mcp-integration.md +0 -130
- package/docs/token-efficiency.md +0 -91
- package/eslint-rules/require-skip-comment.js +0 -81
- package/eslint.config.js +0 -103
- package/knip.json +0 -43
- package/scripts/test-mcp-dev.js +0 -260
- package/scripts/validate-npm-release.sh +0 -314
- package/src/analysis/adapter-registry.test.ts +0 -211
- package/src/analysis/adapter-registry.ts +0 -155
- package/src/analysis/ast-parser.test.ts +0 -470
- package/src/analysis/ast-parser.ts +0 -198
- package/src/analysis/code-graph.test.ts +0 -718
- package/src/analysis/code-graph.ts +0 -249
- package/src/analysis/dependency-usage-analyzer.test.ts +0 -619
- package/src/analysis/dependency-usage-analyzer.ts +0 -433
- package/src/analysis/go-ast-parser.test.ts +0 -531
- package/src/analysis/go-ast-parser.ts +0 -471
- package/src/analysis/language-adapter.ts +0 -127
- package/src/analysis/parser-factory.test.ts +0 -210
- package/src/analysis/parser-factory.ts +0 -52
- package/src/analysis/python-ast-parser.test.ts +0 -210
- package/src/analysis/python-ast-parser.ts +0 -34
- package/src/analysis/repo-url-resolver.test.ts +0 -533
- package/src/analysis/repo-url-resolver.ts +0 -233
- package/src/analysis/rust-ast-parser.test.ts +0 -568
- package/src/analysis/rust-ast-parser.ts +0 -467
- package/src/analysis/tree-sitter-parser.test.ts +0 -297
- package/src/analysis/tree-sitter-parser.ts +0 -217
- package/src/analysis/zil/index.ts +0 -34
- package/src/analysis/zil/zil-adapter.test.ts +0 -187
- package/src/analysis/zil/zil-adapter.ts +0 -121
- package/src/analysis/zil/zil-lexer.test.ts +0 -222
- package/src/analysis/zil/zil-lexer.ts +0 -239
- package/src/analysis/zil/zil-parser.test.ts +0 -210
- package/src/analysis/zil/zil-parser.ts +0 -360
- package/src/analysis/zil/zil-special-forms.ts +0 -193
- package/src/cli/commands/crawl.test.ts +0 -1086
- package/src/cli/commands/crawl.ts +0 -220
- package/src/cli/commands/index-cmd.test.ts +0 -733
- package/src/cli/commands/index-cmd.ts +0 -128
- package/src/cli/commands/mcp.test.ts +0 -218
- package/src/cli/commands/mcp.ts +0 -18
- package/src/cli/commands/plugin-api.test.ts +0 -373
- package/src/cli/commands/plugin-api.ts +0 -82
- package/src/cli/commands/search.test.ts +0 -1047
- package/src/cli/commands/search.ts +0 -197
- package/src/cli/commands/serve.test.ts +0 -371
- package/src/cli/commands/serve.ts +0 -43
- package/src/cli/commands/setup.test.ts +0 -895
- package/src/cli/commands/setup.ts +0 -176
- package/src/cli/commands/store.test.ts +0 -1370
- package/src/cli/commands/store.ts +0 -229
- package/src/cli/commands/sync.test.ts +0 -54
- package/src/cli/commands/sync.ts +0 -313
- package/src/cli/index.ts +0 -8
- package/src/cli/program.ts +0 -59
- package/src/crawl/article-converter.test.ts +0 -576
- package/src/crawl/article-converter.ts +0 -142
- package/src/crawl/bridge.test.ts +0 -796
- package/src/crawl/bridge.ts +0 -349
- package/src/crawl/claude-client.test.ts +0 -902
- package/src/crawl/claude-client.ts +0 -261
- package/src/crawl/intelligent-crawler.test.ts +0 -1028
- package/src/crawl/intelligent-crawler.ts +0 -478
- package/src/crawl/markdown-utils.test.ts +0 -703
- package/src/crawl/markdown-utils.ts +0 -225
- package/src/crawl/schemas.ts +0 -114
- package/src/db/embeddings.test.ts +0 -79
- package/src/db/embeddings.ts +0 -78
- package/src/db/index.ts +0 -2
- package/src/db/lance.test.ts +0 -479
- package/src/db/lance.ts +0 -190
- package/src/defaults/repos.ts +0 -67
- package/src/index.ts +0 -124
- package/src/logging/index.ts +0 -25
- package/src/logging/logger.test.ts +0 -75
- package/src/logging/logger.ts +0 -145
- package/src/logging/payload.test.ts +0 -152
- package/src/logging/payload.ts +0 -119
- package/src/mcp/cache.test.ts +0 -202
- package/src/mcp/cache.ts +0 -103
- package/src/mcp/commands/index.ts +0 -24
- package/src/mcp/commands/job.commands.ts +0 -48
- package/src/mcp/commands/meta.commands.ts +0 -54
- package/src/mcp/commands/registry.ts +0 -180
- package/src/mcp/commands/store.commands.ts +0 -75
- package/src/mcp/commands/sync.commands.test.ts +0 -371
- package/src/mcp/commands/sync.commands.ts +0 -263
- package/src/mcp/commands/uninstall.commands.test.ts +0 -37
- package/src/mcp/commands/uninstall.commands.ts +0 -29
- package/src/mcp/handlers/execute.handler.test.ts +0 -179
- package/src/mcp/handlers/execute.handler.ts +0 -23
- package/src/mcp/handlers/index.ts +0 -39
- package/src/mcp/handlers/job.handler.test.ts +0 -189
- package/src/mcp/handlers/job.handler.ts +0 -118
- package/src/mcp/handlers/search.handler.test.ts +0 -324
- package/src/mcp/handlers/search.handler.ts +0 -287
- package/src/mcp/handlers/store.handler.test.ts +0 -408
- package/src/mcp/handlers/store.handler.ts +0 -318
- package/src/mcp/handlers/uninstall.handler.test.ts +0 -194
- package/src/mcp/handlers/uninstall.handler.ts +0 -142
- package/src/mcp/plugin-mcp-config.test.ts +0 -71
- package/src/mcp/schemas/index.test.ts +0 -356
- package/src/mcp/schemas/index.ts +0 -155
- package/src/mcp/server.test.ts +0 -91
- package/src/mcp/server.ts +0 -235
- package/src/mcp/types.ts +0 -41
- package/src/plugin/commands.test.ts +0 -925
- package/src/plugin/commands.ts +0 -311
- package/src/plugin/dependency-analyzer.test.ts +0 -380
- package/src/plugin/dependency-analyzer.ts +0 -210
- package/src/plugin/git-clone.test.ts +0 -387
- package/src/plugin/git-clone.ts +0 -57
- package/src/scripts/validate-npm-release.test.ts +0 -70
- package/src/server/app.test.ts +0 -752
- package/src/server/app.ts +0 -128
- package/src/server/index.test.ts +0 -475
- package/src/server/index.ts +0 -1
- package/src/services/chunking.service.test.ts +0 -363
- package/src/services/chunking.service.ts +0 -380
- package/src/services/code-graph.service.test.ts +0 -298
- package/src/services/code-graph.service.ts +0 -326
- package/src/services/code-unit.service.test.ts +0 -693
- package/src/services/code-unit.service.ts +0 -234
- package/src/services/config.service.test.ts +0 -146
- package/src/services/config.service.ts +0 -92
- package/src/services/gitignore.service.test.ts +0 -157
- package/src/services/gitignore.service.ts +0 -132
- package/src/services/index.service.test.ts +0 -2301
- package/src/services/index.service.ts +0 -442
- package/src/services/index.ts +0 -119
- package/src/services/job.service.test.ts +0 -531
- package/src/services/job.service.ts +0 -298
- package/src/services/project-root.service.test.ts +0 -504
- package/src/services/project-root.service.ts +0 -112
- package/src/services/search.service.test.ts +0 -2263
- package/src/services/search.service.ts +0 -1341
- package/src/services/services.test.ts +0 -108
- package/src/services/snippet.service.test.ts +0 -213
- package/src/services/snippet.service.ts +0 -193
- package/src/services/store-definition.service.test.ts +0 -440
- package/src/services/store-definition.service.ts +0 -198
- package/src/services/store.service.test.ts +0 -843
- package/src/services/store.service.ts +0 -363
- package/src/services/token.service.test.ts +0 -45
- package/src/services/token.service.ts +0 -33
- package/src/services/watch.service.test.ts +0 -600
- package/src/services/watch.service.ts +0 -84
- package/src/types/brands.test.ts +0 -47
- package/src/types/brands.ts +0 -32
- package/src/types/config.ts +0 -79
- package/src/types/document.ts +0 -54
- package/src/types/index.ts +0 -73
- package/src/types/job.ts +0 -61
- package/src/types/progress.ts +0 -9
- package/src/types/result.test.ts +0 -54
- package/src/types/result.ts +0 -41
- package/src/types/search.ts +0 -105
- package/src/types/store-definition.test.ts +0 -492
- package/src/types/store-definition.ts +0 -129
- package/src/types/store.test.ts +0 -69
- package/src/types/store.ts +0 -47
- package/src/utils/type-guards.test.ts +0 -351
- package/src/utils/type-guards.ts +0 -61
- package/src/workers/background-worker-cli.test.ts +0 -35
- package/src/workers/background-worker-cli.ts +0 -149
- package/src/workers/background-worker.test.ts +0 -222
- package/src/workers/background-worker.ts +0 -322
- package/src/workers/pid-file.test.ts +0 -167
- package/src/workers/pid-file.ts +0 -82
- package/src/workers/spawn-worker.test.ts +0 -194
- package/src/workers/spawn-worker.ts +0 -70
- package/tests/analysis/ast-parser.test.ts +0 -98
- package/tests/analysis/code-graph.test.ts +0 -60
- package/tests/fixtures/README.md +0 -114
- package/tests/fixtures/code-snippets/api/error-handling.ts +0 -256
- package/tests/fixtures/code-snippets/api/rest-controller.ts +0 -297
- package/tests/fixtures/code-snippets/auth/jwt-auth.ts +0 -197
- package/tests/fixtures/code-snippets/auth/oauth-flow.ts +0 -245
- package/tests/fixtures/code-snippets/database/repository-pattern.ts +0 -280
- package/tests/fixtures/corpus/VERSION.md +0 -25
- package/tests/fixtures/corpus/articles/jwt-authentication.md +0 -97
- package/tests/fixtures/corpus/articles/react-hooks-patterns.md +0 -127
- package/tests/fixtures/corpus/articles/typescript-generics.md +0 -111
- package/tests/fixtures/corpus/documentation/express-middleware.md +0 -71
- package/tests/fixtures/corpus/documentation/express-routing.md +0 -83
- package/tests/fixtures/corpus/documentation/node-streams.md +0 -78
- package/tests/fixtures/corpus/oss-repos/express/History.md +0 -3871
- package/tests/fixtures/corpus/oss-repos/express/LICENSE +0 -24
- package/tests/fixtures/corpus/oss-repos/express/README.md +0 -276
- package/tests/fixtures/corpus/oss-repos/express/SECURITY.md +0 -56
- package/tests/fixtures/corpus/oss-repos/express/benchmarks/Makefile +0 -17
- package/tests/fixtures/corpus/oss-repos/express/benchmarks/README.md +0 -34
- package/tests/fixtures/corpus/oss-repos/express/benchmarks/middleware.js +0 -20
- package/tests/fixtures/corpus/oss-repos/express/benchmarks/run +0 -18
- package/tests/fixtures/corpus/oss-repos/express/examples/README.md +0 -29
- package/tests/fixtures/corpus/oss-repos/express/examples/auth/index.js +0 -134
- package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/foot.ejs +0 -2
- package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/head.ejs +0 -20
- package/tests/fixtures/corpus/oss-repos/express/examples/auth/views/login.ejs +0 -21
- package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/db.js +0 -9
- package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/index.js +0 -46
- package/tests/fixtures/corpus/oss-repos/express/examples/content-negotiation/users.js +0 -19
- package/tests/fixtures/corpus/oss-repos/express/examples/cookie-sessions/index.js +0 -25
- package/tests/fixtures/corpus/oss-repos/express/examples/cookies/index.js +0 -53
- 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 +0 -2
- package/tests/fixtures/corpus/oss-repos/express/examples/downloads/files/amazing.txt +0 -1
- package/tests/fixtures/corpus/oss-repos/express/examples/downloads/files/notes/groceries.txt +0 -3
- package/tests/fixtures/corpus/oss-repos/express/examples/downloads/index.js +0 -40
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/index.js +0 -57
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/public/stylesheets/style.css +0 -4
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/footer.html +0 -2
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/header.html +0 -9
- package/tests/fixtures/corpus/oss-repos/express/examples/ejs/views/users.html +0 -10
- package/tests/fixtures/corpus/oss-repos/express/examples/error/index.js +0 -53
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/index.js +0 -103
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/404.ejs +0 -3
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/500.ejs +0 -8
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/error_header.ejs +0 -10
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/footer.ejs +0 -2
- package/tests/fixtures/corpus/oss-repos/express/examples/error-pages/views/index.ejs +0 -20
- package/tests/fixtures/corpus/oss-repos/express/examples/hello-world/index.js +0 -15
- package/tests/fixtures/corpus/oss-repos/express/examples/markdown/index.js +0 -44
- package/tests/fixtures/corpus/oss-repos/express/examples/markdown/views/index.md +0 -4
- package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/controllers/api_v1.js +0 -15
- package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/controllers/api_v2.js +0 -15
- package/tests/fixtures/corpus/oss-repos/express/examples/multi-router/index.js +0 -18
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/main/index.js +0 -5
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/index.js +0 -31
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/views/edit.ejs +0 -17
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/pet/views/show.ejs +0 -15
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/index.js +0 -41
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/edit.hbs +0 -27
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/list.hbs +0 -18
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user/views/show.hbs +0 -31
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/controllers/user-pet/index.js +0 -22
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/db.js +0 -16
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/index.js +0 -95
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/lib/boot.js +0 -83
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/public/style.css +0 -14
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/views/404.ejs +0 -13
- package/tests/fixtures/corpus/oss-repos/express/examples/mvc/views/5xx.ejs +0 -13
- package/tests/fixtures/corpus/oss-repos/express/examples/online/index.js +0 -61
- package/tests/fixtures/corpus/oss-repos/express/examples/params/index.js +0 -74
- package/tests/fixtures/corpus/oss-repos/express/examples/resource/index.js +0 -95
- package/tests/fixtures/corpus/oss-repos/express/examples/route-map/index.js +0 -75
- package/tests/fixtures/corpus/oss-repos/express/examples/route-middleware/index.js +0 -90
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/index.js +0 -55
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/post.js +0 -13
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/public/style.css +0 -24
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/site.js +0 -5
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/user.js +0 -47
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/footer.ejs +0 -2
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/header.ejs +0 -9
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/index.ejs +0 -10
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/posts/index.ejs +0 -12
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/edit.ejs +0 -23
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/index.ejs +0 -14
- package/tests/fixtures/corpus/oss-repos/express/examples/route-separation/views/users/view.ejs +0 -9
- package/tests/fixtures/corpus/oss-repos/express/examples/search/index.js +0 -61
- package/tests/fixtures/corpus/oss-repos/express/examples/search/public/client.js +0 -15
- package/tests/fixtures/corpus/oss-repos/express/examples/search/public/index.html +0 -21
- package/tests/fixtures/corpus/oss-repos/express/examples/session/index.js +0 -37
- package/tests/fixtures/corpus/oss-repos/express/examples/session/redis.js +0 -39
- package/tests/fixtures/corpus/oss-repos/express/examples/static-files/index.js +0 -43
- package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/css/style.css +0 -3
- package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/hello.txt +0 -1
- package/tests/fixtures/corpus/oss-repos/express/examples/static-files/public/js/app.js +0 -1
- package/tests/fixtures/corpus/oss-repos/express/examples/vhost/index.js +0 -53
- package/tests/fixtures/corpus/oss-repos/express/examples/view-constructor/github-view.js +0 -53
- package/tests/fixtures/corpus/oss-repos/express/examples/view-constructor/index.js +0 -48
- package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/index.js +0 -155
- package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/user.js +0 -36
- package/tests/fixtures/corpus/oss-repos/express/examples/view-locals/views/index.ejs +0 -20
- package/tests/fixtures/corpus/oss-repos/express/examples/web-service/index.js +0 -117
- package/tests/fixtures/corpus/oss-repos/express/index.js +0 -11
- package/tests/fixtures/corpus/oss-repos/express/lib/application.js +0 -631
- package/tests/fixtures/corpus/oss-repos/express/lib/express.js +0 -81
- package/tests/fixtures/corpus/oss-repos/express/lib/request.js +0 -514
- package/tests/fixtures/corpus/oss-repos/express/lib/response.js +0 -1053
- package/tests/fixtures/corpus/oss-repos/express/lib/utils.js +0 -271
- package/tests/fixtures/corpus/oss-repos/express/lib/view.js +0 -205
- package/tests/fixtures/corpus/oss-repos/express/package.json +0 -99
- package/tests/fixtures/corpus/oss-repos/express/test/Route.js +0 -274
- package/tests/fixtures/corpus/oss-repos/express/test/Router.js +0 -636
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/auth.js +0 -117
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/content-negotiation.js +0 -49
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/cookie-sessions.js +0 -38
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/cookies.js +0 -71
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/downloads.js +0 -47
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/ejs.js +0 -17
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/error-pages.js +0 -99
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/error.js +0 -29
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/hello-world.js +0 -21
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/markdown.js +0 -21
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/multi-router.js +0 -44
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/mvc.js +0 -132
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/params.js +0 -44
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/resource.js +0 -68
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/route-map.js +0 -45
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/route-separation.js +0 -97
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/vhost.js +0 -46
- package/tests/fixtures/corpus/oss-repos/express/test/acceptance/web-service.js +0 -105
- package/tests/fixtures/corpus/oss-repos/express/test/app.all.js +0 -38
- package/tests/fixtures/corpus/oss-repos/express/test/app.engine.js +0 -83
- package/tests/fixtures/corpus/oss-repos/express/test/app.head.js +0 -66
- package/tests/fixtures/corpus/oss-repos/express/test/app.js +0 -120
- package/tests/fixtures/corpus/oss-repos/express/test/app.listen.js +0 -55
- package/tests/fixtures/corpus/oss-repos/express/test/app.locals.js +0 -26
- package/tests/fixtures/corpus/oss-repos/express/test/app.options.js +0 -116
- package/tests/fixtures/corpus/oss-repos/express/test/app.param.js +0 -323
- package/tests/fixtures/corpus/oss-repos/express/test/app.render.js +0 -374
- package/tests/fixtures/corpus/oss-repos/express/test/app.request.js +0 -143
- package/tests/fixtures/corpus/oss-repos/express/test/app.response.js +0 -143
- package/tests/fixtures/corpus/oss-repos/express/test/app.route.js +0 -197
- package/tests/fixtures/corpus/oss-repos/express/test/app.router.js +0 -1217
- package/tests/fixtures/corpus/oss-repos/express/test/app.routes.error.js +0 -62
- package/tests/fixtures/corpus/oss-repos/express/test/app.use.js +0 -542
- package/tests/fixtures/corpus/oss-repos/express/test/config.js +0 -207
- package/tests/fixtures/corpus/oss-repos/express/test/exports.js +0 -82
- package/tests/fixtures/corpus/oss-repos/express/test/express.json.js +0 -755
- package/tests/fixtures/corpus/oss-repos/express/test/express.raw.js +0 -513
- package/tests/fixtures/corpus/oss-repos/express/test/express.static.js +0 -815
- package/tests/fixtures/corpus/oss-repos/express/test/express.text.js +0 -566
- package/tests/fixtures/corpus/oss-repos/express/test/express.urlencoded.js +0 -828
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/% of dogs.txt +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/.name +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/blog/index.html +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/blog/post/index.tmpl +0 -1
- 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 +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/default_layout/user.tmpl +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/email.tmpl +0 -1
- 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 +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/name.tmpl +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/name.txt +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/nums.txt +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/pets/names.txt +0 -1
- 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 +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/todo.txt +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/user.html +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/user.tmpl +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/users/index.html +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/fixtures/users/tobi.txt +0 -1
- package/tests/fixtures/corpus/oss-repos/express/test/middleware.basic.js +0 -42
- package/tests/fixtures/corpus/oss-repos/express/test/regression.js +0 -20
- package/tests/fixtures/corpus/oss-repos/express/test/req.accepts.js +0 -125
- package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsCharsets.js +0 -50
- package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsEncodings.js +0 -39
- package/tests/fixtures/corpus/oss-repos/express/test/req.acceptsLanguages.js +0 -57
- package/tests/fixtures/corpus/oss-repos/express/test/req.baseUrl.js +0 -88
- package/tests/fixtures/corpus/oss-repos/express/test/req.fresh.js +0 -70
- package/tests/fixtures/corpus/oss-repos/express/test/req.get.js +0 -60
- package/tests/fixtures/corpus/oss-repos/express/test/req.host.js +0 -156
- package/tests/fixtures/corpus/oss-repos/express/test/req.hostname.js +0 -188
- package/tests/fixtures/corpus/oss-repos/express/test/req.ip.js +0 -113
- package/tests/fixtures/corpus/oss-repos/express/test/req.ips.js +0 -71
- package/tests/fixtures/corpus/oss-repos/express/test/req.is.js +0 -169
- package/tests/fixtures/corpus/oss-repos/express/test/req.path.js +0 -20
- package/tests/fixtures/corpus/oss-repos/express/test/req.protocol.js +0 -113
- package/tests/fixtures/corpus/oss-repos/express/test/req.query.js +0 -106
- package/tests/fixtures/corpus/oss-repos/express/test/req.range.js +0 -104
- package/tests/fixtures/corpus/oss-repos/express/test/req.route.js +0 -28
- package/tests/fixtures/corpus/oss-repos/express/test/req.secure.js +0 -101
- package/tests/fixtures/corpus/oss-repos/express/test/req.signedCookies.js +0 -37
- package/tests/fixtures/corpus/oss-repos/express/test/req.stale.js +0 -50
- package/tests/fixtures/corpus/oss-repos/express/test/req.subdomains.js +0 -173
- package/tests/fixtures/corpus/oss-repos/express/test/req.xhr.js +0 -42
- package/tests/fixtures/corpus/oss-repos/express/test/res.append.js +0 -116
- package/tests/fixtures/corpus/oss-repos/express/test/res.attachment.js +0 -79
- package/tests/fixtures/corpus/oss-repos/express/test/res.clearCookie.js +0 -62
- package/tests/fixtures/corpus/oss-repos/express/test/res.cookie.js +0 -295
- package/tests/fixtures/corpus/oss-repos/express/test/res.download.js +0 -487
- package/tests/fixtures/corpus/oss-repos/express/test/res.format.js +0 -248
- package/tests/fixtures/corpus/oss-repos/express/test/res.get.js +0 -21
- package/tests/fixtures/corpus/oss-repos/express/test/res.json.js +0 -186
- package/tests/fixtures/corpus/oss-repos/express/test/res.jsonp.js +0 -344
- package/tests/fixtures/corpus/oss-repos/express/test/res.links.js +0 -65
- package/tests/fixtures/corpus/oss-repos/express/test/res.locals.js +0 -40
- package/tests/fixtures/corpus/oss-repos/express/test/res.location.js +0 -316
- package/tests/fixtures/corpus/oss-repos/express/test/res.redirect.js +0 -214
- package/tests/fixtures/corpus/oss-repos/express/test/res.render.js +0 -367
- package/tests/fixtures/corpus/oss-repos/express/test/res.send.js +0 -569
- package/tests/fixtures/corpus/oss-repos/express/test/res.sendFile.js +0 -913
- package/tests/fixtures/corpus/oss-repos/express/test/res.sendStatus.js +0 -44
- package/tests/fixtures/corpus/oss-repos/express/test/res.set.js +0 -124
- package/tests/fixtures/corpus/oss-repos/express/test/res.status.js +0 -206
- package/tests/fixtures/corpus/oss-repos/express/test/res.type.js +0 -46
- package/tests/fixtures/corpus/oss-repos/express/test/res.vary.js +0 -90
- package/tests/fixtures/corpus/oss-repos/express/test/support/env.js +0 -3
- package/tests/fixtures/corpus/oss-repos/express/test/support/tmpl.js +0 -36
- package/tests/fixtures/corpus/oss-repos/express/test/support/utils.js +0 -86
- package/tests/fixtures/corpus/oss-repos/express/test/utils.js +0 -83
- package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/Dockerfile +0 -11
- package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/devcontainer.json +0 -21
- package/tests/fixtures/corpus/oss-repos/hono/.devcontainer/docker-compose.yml +0 -18
- package/tests/fixtures/corpus/oss-repos/hono/.eslintignore +0 -1
- package/tests/fixtures/corpus/oss-repos/hono/.eslintrc.cjs +0 -9
- package/tests/fixtures/corpus/oss-repos/hono/.gitpod.yml +0 -9
- package/tests/fixtures/corpus/oss-repos/hono/.prettierrc +0 -9
- package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/jsx-runtime-default.ts +0 -15
- package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/jsx-runtime-dom.ts +0 -15
- package/tests/fixtures/corpus/oss-repos/hono/.vitest.config/setup-vitest.ts +0 -47
- package/tests/fixtures/corpus/oss-repos/hono/LICENSE +0 -21
- package/tests/fixtures/corpus/oss-repos/hono/README.md +0 -91
- package/tests/fixtures/corpus/oss-repos/hono/build.ts +0 -80
- package/tests/fixtures/corpus/oss-repos/hono/bun.lockb +0 -0
- package/tests/fixtures/corpus/oss-repos/hono/bunfig.toml +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/codecov.yml +0 -13
- package/tests/fixtures/corpus/oss-repos/hono/docs/CODE_OF_CONDUCT.md +0 -128
- package/tests/fixtures/corpus/oss-repos/hono/docs/CONTRIBUTING.md +0 -62
- package/tests/fixtures/corpus/oss-repos/hono/docs/MIGRATION.md +0 -295
- 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 +0 -6
- 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 +0 -119
- package/tests/fixtures/corpus/oss-repos/hono/package.cjs.json +0 -3
- package/tests/fixtures/corpus/oss-repos/hono/package.json +0 -650
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +0 -492
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/index.ts +0 -13
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/types.ts +0 -144
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/conninfo.ts +0 -28
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/index.ts +0 -9
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/serve-static.ts +0 -35
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/server.ts +0 -30
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/ssg.ts +0 -27
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/bun/websocket.ts +0 -110
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +0 -120
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/index.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/conninfo.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/index.ts +0 -8
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static-module.ts +0 -12
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +0 -39
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/utils.ts +0 -50
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/websocket.ts +0 -50
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/conninfo.ts +0 -17
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/deno.d.ts +0 -28
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/index.ts +0 -9
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/serve-static.ts +0 -40
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/ssg.ts +0 -27
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/deno/websocket.ts +0 -51
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/conninfo.ts +0 -15
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/handler.ts +0 -189
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/lambda-edge/index.ts +0 -14
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/handler.ts +0 -10
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/index.ts +0 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/netlify/mod.ts +0 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/handler.ts +0 -34
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/index.ts +0 -5
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/service-worker/types.ts +0 -14
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/conninfo.ts +0 -8
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/handler.ts +0 -9
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/vercel/index.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +0 -214
- package/tests/fixtures/corpus/oss-repos/hono/src/client/index.ts +0 -14
- package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +0 -182
- package/tests/fixtures/corpus/oss-repos/hono/src/client/utils.ts +0 -54
- package/tests/fixtures/corpus/oss-repos/hono/src/compose.ts +0 -94
- package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +0 -917
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +0 -84
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/index.ts +0 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +0 -85
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/conninfo/index.ts +0 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/conninfo/types.ts +0 -45
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/cookie/index.ts +0 -130
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/common.ts +0 -243
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +0 -220
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/dev/index.ts +0 -79
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +0 -246
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/html/index.ts +0 -56
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/index.ts +0 -13
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/middleware.ts +0 -79
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +0 -388
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/utils.ts +0 -71
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/index.ts +0 -9
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/sse.ts +0 -89
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/stream.ts +0 -36
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/streaming/text.ts +0 -15
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/testing/index.ts +0 -26
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/websocket/index.ts +0 -57
- package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +0 -523
- package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +0 -34
- package/tests/fixtures/corpus/oss-repos/hono/src/http-exception.ts +0 -78
- package/tests/fixtures/corpus/oss-repos/hono/src/index.ts +0 -51
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/base.ts +0 -419
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/children.ts +0 -20
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/components.ts +0 -195
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/constants.ts +0 -5
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/context.ts +0 -50
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/client.ts +0 -89
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/components.ts +0 -39
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/context.ts +0 -52
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +0 -246
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/hooks/index.ts +0 -91
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/index.ts +0 -159
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +0 -398
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/jsx-dev-runtime.ts +0 -22
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/jsx-runtime.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +0 -772
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/server.ts +0 -70
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/utils.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +0 -426
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/index.ts +0 -114
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/common.ts +0 -11
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +0 -196
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-elements.ts +0 -924
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/jsx-dev-runtime.ts +0 -26
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/jsx-runtime.ts +0 -18
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/streaming.ts +0 -184
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/types.ts +0 -41
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +0 -36
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/basic-auth/index.ts +0 -128
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/bearer-auth/index.ts +0 -159
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/body-limit/index.ts +0 -115
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/cache/index.ts +0 -127
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/combine/index.ts +0 -153
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/compress/index.ts +0 -79
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/context-storage/index.ts +0 -55
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/cors/index.ts +0 -141
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/csrf/index.ts +0 -90
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/etag/index.ts +0 -88
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/ip-restriction/index.ts +0 -178
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +0 -158
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jwt/index.ts +0 -8
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jwt/jwt.ts +0 -159
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/logger/index.ts +0 -93
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/method-override/index.ts +0 -146
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/powered-by/index.ts +0 -13
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/pretty-json/index.ts +0 -50
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/request-id/index.ts +0 -8
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/request-id/request-id.ts +0 -59
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/index.ts +0 -8
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/permissions-policy.ts +0 -86
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/secure-headers/secure-headers.ts +0 -319
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +0 -140
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timeout/index.ts +0 -58
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timing/index.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/timing/timing.ts +0 -225
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/trailing-slash/index.ts +0 -71
- package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +0 -24
- package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +0 -20
- package/tests/fixtures/corpus/oss-repos/hono/src/request.ts +0 -403
- package/tests/fixtures/corpus/oss-repos/hono/src/router/linear-router/index.ts +0 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/router/linear-router/router.ts +0 -132
- package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/index.ts +0 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +0 -54
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/index.ts +0 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +0 -159
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +0 -274
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/trie.ts +0 -74
- package/tests/fixtures/corpus/oss-repos/hono/src/router/smart-router/index.ts +0 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/router/smart-router/router.ts +0 -69
- package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/index.ts +0 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +0 -205
- package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/router.ts +0 -28
- package/tests/fixtures/corpus/oss-repos/hono/src/router.ts +0 -103
- package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +0 -2006
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/basic-auth.ts +0 -26
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +0 -225
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/buffer.ts +0 -65
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +0 -26
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/concurrent.ts +0 -55
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +0 -230
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/crypto.ts +0 -65
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +0 -34
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/filepath.ts +0 -56
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/handler.ts +0 -15
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/html.ts +0 -182
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/http-status.ts +0 -69
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/ipaddr.ts +0 -113
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/index.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jwa.ts +0 -23
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jws.ts +0 -226
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/jwt.ts +0 -114
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/types.ts +0 -83
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/jwt/utf8.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/mime.ts +0 -142
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/stream.ts +0 -96
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +0 -102
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/url.ts +0 -310
- package/tests/fixtures/corpus/oss-repos/hono/src/validator/index.ts +0 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +0 -151
- package/tests/fixtures/corpus/oss-repos/hono/tsconfig.build.json +0 -23
- package/tests/fixtures/corpus/oss-repos/hono/tsconfig.json +0 -28
- package/tests/fixtures/corpus/oss-repos/hono/vitest.config.ts +0 -34
- package/tests/fixtures/corpus/oss-repos/hono/yarn.lock +0 -6232
- package/tests/fixtures/documentation/api-reference.md +0 -412
- package/tests/fixtures/documentation/architecture.md +0 -214
- package/tests/fixtures/documentation/deployment-guide.md +0 -420
- package/tests/fixtures/github-readmes/express.md +0 -133
- package/tests/fixtures/github-readmes/nextjs.md +0 -106
- package/tests/fixtures/github-readmes/react.md +0 -74
- package/tests/fixtures/github-readmes/typescript.md +0 -93
- package/tests/fixtures/github-readmes/vite.md +0 -79
- package/tests/fixtures/queries/core.json +0 -125
- package/tests/fixtures/queries/extended.json +0 -427
- package/tests/fixtures/queries/generated/.gitkeep +0 -0
- package/tests/fixtures/test-server.ts +0 -268
- package/tests/helpers/performance-metrics.ts +0 -370
- package/tests/helpers/search-relevance.ts +0 -326
- package/tests/integration/cli-consistency.test.ts +0 -298
- package/tests/integration/cli.test.ts +0 -69
- package/tests/integration/e2e-workflow.test.ts +0 -614
- package/tests/integration/mcp.test.ts +0 -250
- package/tests/integration/python-bridge.test.ts +0 -193
- package/tests/integration/search-quality.test.ts +0 -720
- package/tests/integration/serve.test.ts +0 -260
- package/tests/integration/stress.test.ts +0 -326
- package/tests/mcp/server.test.ts +0 -15
- package/tests/scripts/schemas/evaluation.json +0 -44
- package/tests/scripts/schemas/query-generation.json +0 -21
- package/tests/services/code-unit.service.test.ts +0 -95
- package/tests/services/job.service.test.ts +0 -124
- package/tests/services/search.progressive-context.test.ts +0 -35
- package/tsconfig.json +0 -34
- package/tsup.config.ts +0 -15
- package/turndown-plugin-gfm.d.ts +0 -29
- package/vitest.config.ts +0 -90
|
@@ -1,1341 +0,0 @@
|
|
|
1
|
-
import { CodeUnitService } from './code-unit.service.js';
|
|
2
|
-
import { createLogger } from '../logging/index.js';
|
|
3
|
-
import type { CodeGraphService } from './code-graph.service.js';
|
|
4
|
-
import type { CodeGraph } from '../analysis/code-graph.js';
|
|
5
|
-
import type { EmbeddingEngine } from '../db/embeddings.js';
|
|
6
|
-
import type { LanceStore } from '../db/lance.js';
|
|
7
|
-
import type { StoreId } from '../types/brands.js';
|
|
8
|
-
import type {
|
|
9
|
-
SearchQuery,
|
|
10
|
-
SearchResponse,
|
|
11
|
-
SearchResult,
|
|
12
|
-
SearchConfidence,
|
|
13
|
-
DetailLevel,
|
|
14
|
-
CodeUnit,
|
|
15
|
-
} from '../types/search.js';
|
|
16
|
-
|
|
17
|
-
const logger = createLogger('search-service');
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Query intent classification for context-aware ranking.
|
|
21
|
-
* Different intents prioritize different content types.
|
|
22
|
-
*/
|
|
23
|
-
export type QueryIntent = 'how-to' | 'implementation' | 'conceptual' | 'comparison' | 'debugging';
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Classified intent with confidence score for multi-intent queries.
|
|
27
|
-
*/
|
|
28
|
-
export interface ClassifiedIntent {
|
|
29
|
-
intent: QueryIntent;
|
|
30
|
-
confidence: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Intent-based file type multipliers - CONSERVATIVE version.
|
|
35
|
-
* Applied on top of base file-type boosts.
|
|
36
|
-
* Lessons learned: Too-aggressive penalties hurt when corpus lacks ideal content.
|
|
37
|
-
* These values provide gentle guidance rather than dramatic reranking.
|
|
38
|
-
*/
|
|
39
|
-
const INTENT_FILE_BOOSTS: Record<QueryIntent, Record<string, number>> = {
|
|
40
|
-
'how-to': {
|
|
41
|
-
'documentation-primary': 1.3, // Strong boost for docs
|
|
42
|
-
documentation: 1.2,
|
|
43
|
-
example: 1.5, // Examples are ideal for "how to"
|
|
44
|
-
source: 0.85, // Moderate penalty - source might still have good content
|
|
45
|
-
'source-internal': 0.7, // Stronger penalty - internal code less useful
|
|
46
|
-
test: 0.8,
|
|
47
|
-
config: 0.7,
|
|
48
|
-
other: 0.9,
|
|
49
|
-
},
|
|
50
|
-
implementation: {
|
|
51
|
-
'documentation-primary': 0.95,
|
|
52
|
-
documentation: 1.0,
|
|
53
|
-
example: 1.0,
|
|
54
|
-
source: 1.1, // Slight boost for source code
|
|
55
|
-
'source-internal': 1.05, // Internal code can be relevant
|
|
56
|
-
test: 1.0,
|
|
57
|
-
config: 0.95,
|
|
58
|
-
other: 1.0,
|
|
59
|
-
},
|
|
60
|
-
conceptual: {
|
|
61
|
-
'documentation-primary': 1.1,
|
|
62
|
-
documentation: 1.05,
|
|
63
|
-
example: 1.0,
|
|
64
|
-
source: 0.95,
|
|
65
|
-
'source-internal': 0.9,
|
|
66
|
-
test: 0.9,
|
|
67
|
-
config: 0.85,
|
|
68
|
-
other: 0.95,
|
|
69
|
-
},
|
|
70
|
-
comparison: {
|
|
71
|
-
'documentation-primary': 1.15,
|
|
72
|
-
documentation: 1.1,
|
|
73
|
-
example: 1.05,
|
|
74
|
-
source: 0.9,
|
|
75
|
-
'source-internal': 0.85,
|
|
76
|
-
test: 0.9,
|
|
77
|
-
config: 0.85,
|
|
78
|
-
other: 0.95,
|
|
79
|
-
},
|
|
80
|
-
debugging: {
|
|
81
|
-
'documentation-primary': 1.0,
|
|
82
|
-
documentation: 1.0,
|
|
83
|
-
example: 1.05,
|
|
84
|
-
source: 1.0, // Source code helps with debugging
|
|
85
|
-
'source-internal': 0.95,
|
|
86
|
-
test: 1.05, // Tests can show expected behavior
|
|
87
|
-
config: 0.9,
|
|
88
|
-
other: 1.0,
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
// Known frameworks/technologies for context-aware boosting
|
|
93
|
-
const FRAMEWORK_PATTERNS: Array<{ pattern: RegExp; terms: string[] }> = [
|
|
94
|
-
{ pattern: /\bexpress\b/i, terms: ['express', 'expressjs', 'express.js'] },
|
|
95
|
-
{ pattern: /\bhono\b/i, terms: ['hono'] },
|
|
96
|
-
{ pattern: /\bzod\b/i, terms: ['zod'] },
|
|
97
|
-
{ pattern: /\breact\b/i, terms: ['react', 'reactjs', 'react.js'] },
|
|
98
|
-
{ pattern: /\bvue\b/i, terms: ['vue', 'vuejs', 'vue.js', 'vue3'] },
|
|
99
|
-
{ pattern: /\bnode\b/i, terms: ['node', 'nodejs', 'node.js'] },
|
|
100
|
-
{ pattern: /\btypescript\b/i, terms: ['typescript', 'ts'] },
|
|
101
|
-
{ pattern: /\bjwt\b/i, terms: ['jwt', 'jsonwebtoken', 'json-web-token'] },
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
// Pattern definitions for intent classification
|
|
105
|
-
const HOW_TO_PATTERNS = [
|
|
106
|
-
/how (do|can|should|would) (i|you|we)/i,
|
|
107
|
-
/how to\b/i,
|
|
108
|
-
/what('s| is) the (best |right |correct )?(way|approach) to/i,
|
|
109
|
-
/i (need|want|have) to/i,
|
|
110
|
-
/show me how/i,
|
|
111
|
-
/\bwhat's the syntax\b/i,
|
|
112
|
-
/\bhow do i (use|create|make|set up|configure|implement|add|get)\b/i,
|
|
113
|
-
/\bi'm (trying|building|creating|making)\b/i,
|
|
114
|
-
];
|
|
115
|
-
|
|
116
|
-
const IMPLEMENTATION_PATTERNS = [
|
|
117
|
-
/how (does|is) .* (implemented|work internally)/i,
|
|
118
|
-
/\binternal(ly)?\b/i,
|
|
119
|
-
/\bsource code\b/i,
|
|
120
|
-
/\bunder the hood\b/i,
|
|
121
|
-
/\bimplementation (of|details?)\b/i,
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
const COMPARISON_PATTERNS = [
|
|
125
|
-
/\b(vs\.?|versus)\b/i,
|
|
126
|
-
/\bdifference(s)? between\b/i,
|
|
127
|
-
/\bcompare\b/i,
|
|
128
|
-
/\bshould (i|we) use .* or\b/i,
|
|
129
|
-
/\bwhat's the difference\b/i,
|
|
130
|
-
/\bwhich (one|is better)\b/i,
|
|
131
|
-
/\bwhen (should|to) use\b/i,
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
const DEBUGGING_PATTERNS = [
|
|
135
|
-
/\b(error|bug|issue|problem|crash|fail|broken|wrong)\b/i,
|
|
136
|
-
/\bdoesn't (work|compile|run)\b/i,
|
|
137
|
-
/\bisn't (working|updating|rendering)\b/i,
|
|
138
|
-
/\bwhy (is|does|doesn't|isn't)\b/i,
|
|
139
|
-
/\bwhat('s| is) (wrong|happening|going on)\b/i,
|
|
140
|
-
/\bwhat am i doing wrong\b/i,
|
|
141
|
-
/\bnot (working|updating|showing)\b/i,
|
|
142
|
-
/\bhow do i (fix|debug|solve|resolve)\b/i,
|
|
143
|
-
];
|
|
144
|
-
|
|
145
|
-
const CONCEPTUAL_PATTERNS = [
|
|
146
|
-
/\bwhat (is|are)\b/i,
|
|
147
|
-
/\bexplain\b/i,
|
|
148
|
-
/\bwhat does .* (mean|do)\b/i,
|
|
149
|
-
/\bhow does .* work\b/i,
|
|
150
|
-
/\bwhat('s| is) the (purpose|point|idea)\b/i,
|
|
151
|
-
];
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Classify query intents with confidence scores.
|
|
155
|
-
* Returns all matching intents, allowing queries to have multiple intents.
|
|
156
|
-
*/
|
|
157
|
-
function classifyQueryIntents(query: string): ClassifiedIntent[] {
|
|
158
|
-
const q = query.toLowerCase();
|
|
159
|
-
const intents: ClassifiedIntent[] = [];
|
|
160
|
-
|
|
161
|
-
// Check all pattern groups and add matching intents with confidence
|
|
162
|
-
if (IMPLEMENTATION_PATTERNS.some((p) => p.test(q))) {
|
|
163
|
-
intents.push({ intent: 'implementation', confidence: 0.9 });
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (DEBUGGING_PATTERNS.some((p) => p.test(q))) {
|
|
167
|
-
intents.push({ intent: 'debugging', confidence: 0.85 });
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (COMPARISON_PATTERNS.some((p) => p.test(q))) {
|
|
171
|
-
intents.push({ intent: 'comparison', confidence: 0.8 });
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (HOW_TO_PATTERNS.some((p) => p.test(q))) {
|
|
175
|
-
intents.push({ intent: 'how-to', confidence: 0.75 });
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (CONCEPTUAL_PATTERNS.some((p) => p.test(q))) {
|
|
179
|
-
intents.push({ intent: 'conceptual', confidence: 0.7 });
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// If no patterns match, use how-to as the baseline intent
|
|
183
|
-
if (intents.length === 0) {
|
|
184
|
-
intents.push({ intent: 'how-to', confidence: 0.5 });
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Sort by confidence descending
|
|
188
|
-
return intents.sort((a, b) => b.confidence - a.confidence);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Get primary intent for logging/display purposes.
|
|
193
|
-
*/
|
|
194
|
-
function getPrimaryIntent(intents: ClassifiedIntent[]): QueryIntent {
|
|
195
|
-
return intents[0]?.intent ?? 'how-to';
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* RRF presets for different content types.
|
|
200
|
-
* Web/docs content uses higher k to reduce noise from repetitive structure.
|
|
201
|
-
*/
|
|
202
|
-
const RRF_PRESETS = {
|
|
203
|
-
code: { k: 20, vectorWeight: 0.6, ftsWeight: 0.4 },
|
|
204
|
-
web: { k: 30, vectorWeight: 0.55, ftsWeight: 0.45 },
|
|
205
|
-
} as const;
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Detect if results are primarily web content (have urls vs file paths).
|
|
209
|
-
*/
|
|
210
|
-
function detectContentType(results: SearchResult[]): 'web' | 'code' {
|
|
211
|
-
const webCount = results.filter((r) => 'url' in r.metadata).length;
|
|
212
|
-
return webCount > results.length / 2 ? 'web' : 'code';
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export class SearchService {
|
|
216
|
-
private readonly lanceStore: LanceStore;
|
|
217
|
-
private readonly embeddingEngine: EmbeddingEngine;
|
|
218
|
-
private readonly codeUnitService: CodeUnitService;
|
|
219
|
-
private readonly codeGraphService: CodeGraphService | undefined;
|
|
220
|
-
private readonly graphCache: Map<string, CodeGraph | null>;
|
|
221
|
-
|
|
222
|
-
constructor(
|
|
223
|
-
lanceStore: LanceStore,
|
|
224
|
-
embeddingEngine: EmbeddingEngine,
|
|
225
|
-
codeGraphService?: CodeGraphService
|
|
226
|
-
) {
|
|
227
|
-
this.lanceStore = lanceStore;
|
|
228
|
-
this.embeddingEngine = embeddingEngine;
|
|
229
|
-
this.codeUnitService = new CodeUnitService();
|
|
230
|
-
this.codeGraphService = codeGraphService;
|
|
231
|
-
this.graphCache = new Map();
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Load code graph for a store, with caching.
|
|
236
|
-
* Returns null if no graph is available.
|
|
237
|
-
*/
|
|
238
|
-
private async loadGraphForStore(storeId: StoreId): Promise<CodeGraph | null> {
|
|
239
|
-
if (!this.codeGraphService) return null;
|
|
240
|
-
|
|
241
|
-
const cached = this.graphCache.get(storeId);
|
|
242
|
-
if (cached !== undefined) return cached;
|
|
243
|
-
|
|
244
|
-
const graph = await this.codeGraphService.loadGraph(storeId);
|
|
245
|
-
const result = graph ?? null;
|
|
246
|
-
this.graphCache.set(storeId, result);
|
|
247
|
-
return result;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Calculate confidence level based on max raw vector similarity score.
|
|
252
|
-
* Configurable via environment variables, with sensible defaults for CLI usage.
|
|
253
|
-
*/
|
|
254
|
-
private calculateConfidence(maxRawScore: number): SearchConfidence {
|
|
255
|
-
const highThreshold = parseFloat(process.env['SEARCH_CONFIDENCE_HIGH'] ?? '0.5');
|
|
256
|
-
const mediumThreshold = parseFloat(process.env['SEARCH_CONFIDENCE_MEDIUM'] ?? '0.3');
|
|
257
|
-
|
|
258
|
-
if (maxRawScore >= highThreshold) return 'high';
|
|
259
|
-
if (maxRawScore >= mediumThreshold) return 'medium';
|
|
260
|
-
return 'low';
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async search(query: SearchQuery): Promise<SearchResponse> {
|
|
264
|
-
const startTime = Date.now();
|
|
265
|
-
const mode = query.mode ?? 'hybrid';
|
|
266
|
-
const limit = query.limit ?? 10;
|
|
267
|
-
const stores = query.stores ?? [];
|
|
268
|
-
const detail = query.detail ?? 'minimal';
|
|
269
|
-
const intents = classifyQueryIntents(query.query);
|
|
270
|
-
const primaryIntent = getPrimaryIntent(intents);
|
|
271
|
-
|
|
272
|
-
logger.debug(
|
|
273
|
-
{
|
|
274
|
-
query: query.query,
|
|
275
|
-
mode,
|
|
276
|
-
limit,
|
|
277
|
-
stores,
|
|
278
|
-
detail,
|
|
279
|
-
intent: primaryIntent,
|
|
280
|
-
intents,
|
|
281
|
-
minRelevance: query.minRelevance,
|
|
282
|
-
},
|
|
283
|
-
'Search query received'
|
|
284
|
-
);
|
|
285
|
-
|
|
286
|
-
let allResults: SearchResult[] = [];
|
|
287
|
-
let maxRawScore = 0;
|
|
288
|
-
|
|
289
|
-
// Fetch more results than needed to allow for deduplication
|
|
290
|
-
const fetchLimit = limit * 3;
|
|
291
|
-
|
|
292
|
-
if (mode === 'vector') {
|
|
293
|
-
// For vector mode, get raw scores first for confidence calculation
|
|
294
|
-
const rawResults = await this.vectorSearchRaw(query.query, stores, fetchLimit);
|
|
295
|
-
maxRawScore = rawResults.length > 0 ? (rawResults[0]?.score ?? 0) : 0;
|
|
296
|
-
allResults = await this.vectorSearch(query.query, stores, fetchLimit, query.threshold);
|
|
297
|
-
} else if (mode === 'fts') {
|
|
298
|
-
// FTS mode doesn't have vector similarity, so no confidence calculation
|
|
299
|
-
allResults = await this.ftsSearch(query.query, stores, fetchLimit);
|
|
300
|
-
} else {
|
|
301
|
-
// Hybrid: combine vector and FTS with RRF, get maxRawScore for confidence
|
|
302
|
-
const hybridResult = await this.hybridSearchWithMetadata(
|
|
303
|
-
query.query,
|
|
304
|
-
stores,
|
|
305
|
-
fetchLimit,
|
|
306
|
-
query.threshold
|
|
307
|
-
);
|
|
308
|
-
allResults = hybridResult.results;
|
|
309
|
-
maxRawScore = hybridResult.maxRawScore;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Apply minRelevance filter - if max raw score is below threshold, return empty
|
|
313
|
-
if (query.minRelevance !== undefined && maxRawScore < query.minRelevance) {
|
|
314
|
-
const timeMs = Date.now() - startTime;
|
|
315
|
-
logger.info(
|
|
316
|
-
{
|
|
317
|
-
query: query.query,
|
|
318
|
-
mode,
|
|
319
|
-
maxRawScore,
|
|
320
|
-
minRelevance: query.minRelevance,
|
|
321
|
-
timeMs,
|
|
322
|
-
},
|
|
323
|
-
'Search filtered by minRelevance - no sufficiently relevant results'
|
|
324
|
-
);
|
|
325
|
-
|
|
326
|
-
return {
|
|
327
|
-
query: query.query,
|
|
328
|
-
mode,
|
|
329
|
-
stores,
|
|
330
|
-
results: [],
|
|
331
|
-
totalResults: 0,
|
|
332
|
-
timeMs,
|
|
333
|
-
confidence: this.calculateConfidence(maxRawScore),
|
|
334
|
-
maxRawScore,
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Deduplicate by source file - keep best chunk per source (considers query relevance)
|
|
339
|
-
const dedupedResults = this.deduplicateBySource(allResults, query.query);
|
|
340
|
-
const resultsToEnhance = dedupedResults.slice(0, limit);
|
|
341
|
-
|
|
342
|
-
// Load code graphs for stores in results (for contextual/full detail levels)
|
|
343
|
-
const graphs = new Map<string, CodeGraph | null>();
|
|
344
|
-
if (detail === 'contextual' || detail === 'full') {
|
|
345
|
-
const storeIds = new Set(resultsToEnhance.map((r) => r.metadata.storeId));
|
|
346
|
-
for (const storeId of storeIds) {
|
|
347
|
-
graphs.set(storeId, await this.loadGraphForStore(storeId));
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Enhance results with progressive context
|
|
352
|
-
const enhancedResults = resultsToEnhance.map((r) => {
|
|
353
|
-
const graph = graphs.get(r.metadata.storeId) ?? null;
|
|
354
|
-
return this.addProgressiveContext(r, query.query, detail, graph);
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
const timeMs = Date.now() - startTime;
|
|
358
|
-
const confidence = mode !== 'fts' ? this.calculateConfidence(maxRawScore) : undefined;
|
|
359
|
-
|
|
360
|
-
logger.info(
|
|
361
|
-
{
|
|
362
|
-
query: query.query,
|
|
363
|
-
mode,
|
|
364
|
-
resultCount: enhancedResults.length,
|
|
365
|
-
dedupedFrom: allResults.length,
|
|
366
|
-
intents: intents.map((i) => `${i.intent}(${i.confidence.toFixed(2)})`),
|
|
367
|
-
maxRawScore: mode !== 'fts' ? maxRawScore : undefined,
|
|
368
|
-
confidence,
|
|
369
|
-
timeMs,
|
|
370
|
-
},
|
|
371
|
-
'Search complete'
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
return {
|
|
375
|
-
query: query.query,
|
|
376
|
-
mode,
|
|
377
|
-
stores,
|
|
378
|
-
results: enhancedResults,
|
|
379
|
-
totalResults: enhancedResults.length,
|
|
380
|
-
timeMs,
|
|
381
|
-
confidence,
|
|
382
|
-
maxRawScore: mode !== 'fts' ? maxRawScore : undefined,
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Deduplicate results by source file path.
|
|
388
|
-
* Keeps the best chunk for each unique source, considering both score and query relevance.
|
|
389
|
-
*/
|
|
390
|
-
private deduplicateBySource(results: SearchResult[], query: string): SearchResult[] {
|
|
391
|
-
const bySource = new Map<string, SearchResult>();
|
|
392
|
-
const queryTerms = query
|
|
393
|
-
.toLowerCase()
|
|
394
|
-
.split(/\s+/)
|
|
395
|
-
.filter((t) => t.length > 2);
|
|
396
|
-
|
|
397
|
-
for (const result of results) {
|
|
398
|
-
// Use file path as the source key (or url for web content, or id as last resort)
|
|
399
|
-
const sourceKey = result.metadata.path ?? result.metadata.url ?? result.id;
|
|
400
|
-
|
|
401
|
-
const existing = bySource.get(sourceKey);
|
|
402
|
-
if (!existing) {
|
|
403
|
-
bySource.set(sourceKey, result);
|
|
404
|
-
} else {
|
|
405
|
-
// Score-weighted relevance: accounts for fileType/framework boosts
|
|
406
|
-
const existingTermCount = this.countQueryTerms(existing.content, queryTerms);
|
|
407
|
-
const newTermCount = this.countQueryTerms(result.content, queryTerms);
|
|
408
|
-
|
|
409
|
-
// Weight term count by score to account for ranking boosts
|
|
410
|
-
const existingRelevance = existingTermCount * existing.score;
|
|
411
|
-
const newRelevance = newTermCount * result.score;
|
|
412
|
-
|
|
413
|
-
if (newRelevance > existingRelevance) {
|
|
414
|
-
bySource.set(sourceKey, result);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Return results sorted by score
|
|
420
|
-
return Array.from(bySource.values()).sort((a, b) => b.score - a.score);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Count how many query terms appear in the content.
|
|
425
|
-
*/
|
|
426
|
-
private countQueryTerms(content: string, queryTerms: string[]): number {
|
|
427
|
-
const lowerContent = content.toLowerCase();
|
|
428
|
-
return queryTerms.filter((term) => lowerContent.includes(term)).length;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* Normalize scores to 0-1 range and optionally filter by threshold.
|
|
433
|
-
* This ensures threshold values match displayed scores (UX consistency).
|
|
434
|
-
*
|
|
435
|
-
* Edge case handling:
|
|
436
|
-
* - If there's only 1 result or all results have the same score, normalization
|
|
437
|
-
* would make them all 1.0. In this case, we keep the raw scores to allow
|
|
438
|
-
* threshold filtering to work meaningfully on absolute quality.
|
|
439
|
-
*/
|
|
440
|
-
private normalizeAndFilterScores(results: SearchResult[], threshold?: number): SearchResult[] {
|
|
441
|
-
if (results.length === 0) return [];
|
|
442
|
-
|
|
443
|
-
// Sort by score descending
|
|
444
|
-
const sorted = [...results].sort((a, b) => b.score - a.score);
|
|
445
|
-
|
|
446
|
-
// Get score range for normalization
|
|
447
|
-
const first = sorted[0];
|
|
448
|
-
const last = sorted[sorted.length - 1];
|
|
449
|
-
if (first === undefined || last === undefined) return [];
|
|
450
|
-
|
|
451
|
-
const maxScore = first.score;
|
|
452
|
-
const minScore = last.score;
|
|
453
|
-
const range = maxScore - minScore;
|
|
454
|
-
|
|
455
|
-
// Only normalize when there's meaningful score variation
|
|
456
|
-
// If all scores are the same (range = 0), keep raw scores for threshold filtering
|
|
457
|
-
const normalized =
|
|
458
|
-
range > 0
|
|
459
|
-
? sorted.map((r) => ({
|
|
460
|
-
...r,
|
|
461
|
-
score: Math.round(((r.score - minScore) / range) * 1000000) / 1000000,
|
|
462
|
-
}))
|
|
463
|
-
: sorted; // Keep raw scores when no variation (allows threshold to filter by quality)
|
|
464
|
-
|
|
465
|
-
// Apply threshold filter on scores
|
|
466
|
-
if (threshold !== undefined) {
|
|
467
|
-
return normalized.filter((r) => r.score >= threshold);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
return normalized;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* Fetch raw vector search results without normalization.
|
|
475
|
-
* Returns results with raw cosine similarity scores [0-1].
|
|
476
|
-
*/
|
|
477
|
-
private async vectorSearchRaw(
|
|
478
|
-
query: string,
|
|
479
|
-
stores: readonly StoreId[],
|
|
480
|
-
limit: number
|
|
481
|
-
): Promise<SearchResult[]> {
|
|
482
|
-
const queryVector = await this.embeddingEngine.embed(query);
|
|
483
|
-
const results: SearchResult[] = [];
|
|
484
|
-
|
|
485
|
-
for (const storeId of stores) {
|
|
486
|
-
const hits = await this.lanceStore.search(storeId, queryVector, limit);
|
|
487
|
-
results.push(
|
|
488
|
-
...hits.map((r) => ({
|
|
489
|
-
id: r.id,
|
|
490
|
-
score: r.score, // Raw cosine similarity (1 - distance)
|
|
491
|
-
content: r.content,
|
|
492
|
-
metadata: r.metadata,
|
|
493
|
-
}))
|
|
494
|
-
);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
private async vectorSearch(
|
|
501
|
-
query: string,
|
|
502
|
-
stores: readonly StoreId[],
|
|
503
|
-
limit: number,
|
|
504
|
-
threshold?: number
|
|
505
|
-
): Promise<SearchResult[]> {
|
|
506
|
-
const results = await this.vectorSearchRaw(query, stores, limit);
|
|
507
|
-
|
|
508
|
-
// Normalize scores and apply threshold filter
|
|
509
|
-
const normalized = this.normalizeAndFilterScores(results, threshold);
|
|
510
|
-
return normalized.slice(0, limit);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
private async ftsSearch(
|
|
514
|
-
query: string,
|
|
515
|
-
stores: readonly StoreId[],
|
|
516
|
-
limit: number
|
|
517
|
-
): Promise<SearchResult[]> {
|
|
518
|
-
const results: SearchResult[] = [];
|
|
519
|
-
|
|
520
|
-
for (const storeId of stores) {
|
|
521
|
-
try {
|
|
522
|
-
const hits = await this.lanceStore.fullTextSearch(storeId, query, limit);
|
|
523
|
-
results.push(
|
|
524
|
-
...hits.map((r) => ({
|
|
525
|
-
id: r.id,
|
|
526
|
-
score: r.score,
|
|
527
|
-
content: r.content,
|
|
528
|
-
metadata: r.metadata,
|
|
529
|
-
}))
|
|
530
|
-
);
|
|
531
|
-
} catch {
|
|
532
|
-
// FTS index may not exist for this store - continue with other stores
|
|
533
|
-
// and rely on vector search results. This is expected behavior since
|
|
534
|
-
// FTS indexing is optional and hybrid search works with vector-only.
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
/**
|
|
542
|
-
* Internal hybrid search result with additional metadata for confidence calculation.
|
|
543
|
-
*/
|
|
544
|
-
private async hybridSearchWithMetadata(
|
|
545
|
-
query: string,
|
|
546
|
-
stores: readonly StoreId[],
|
|
547
|
-
limit: number,
|
|
548
|
-
threshold?: number
|
|
549
|
-
): Promise<{ results: SearchResult[]; maxRawScore: number }> {
|
|
550
|
-
// Classify query intents for context-aware ranking (supports multiple intents)
|
|
551
|
-
const intents = classifyQueryIntents(query);
|
|
552
|
-
|
|
553
|
-
// Get raw vector results (unnormalized) to track raw cosine similarity
|
|
554
|
-
// We use these for both raw score tracking and as the basis for normalized vector results
|
|
555
|
-
const rawVectorResults = await this.vectorSearchRaw(query, stores, limit * 2);
|
|
556
|
-
|
|
557
|
-
// Build map of raw vector scores by document ID
|
|
558
|
-
const rawVectorScores = new Map<string, number>();
|
|
559
|
-
rawVectorResults.forEach((r) => {
|
|
560
|
-
rawVectorScores.set(r.id, r.score);
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
// Track max raw score for confidence calculation
|
|
564
|
-
const maxRawScore = rawVectorResults.length > 0 ? (rawVectorResults[0]?.score ?? 0) : 0;
|
|
565
|
-
|
|
566
|
-
// Normalize raw vector results directly (avoids duplicate embedding call)
|
|
567
|
-
// Don't apply threshold here - it's applied to final RRF-normalized scores at the end
|
|
568
|
-
const vectorResults = this.normalizeAndFilterScores(rawVectorResults);
|
|
569
|
-
|
|
570
|
-
// Get FTS results in parallel (only one call needed now)
|
|
571
|
-
const ftsResults = await this.ftsSearch(query, stores, limit * 2);
|
|
572
|
-
|
|
573
|
-
// Build rank maps
|
|
574
|
-
const vectorRanks = new Map<string, number>();
|
|
575
|
-
const ftsRanks = new Map<string, number>();
|
|
576
|
-
const allDocs = new Map<string, SearchResult>();
|
|
577
|
-
|
|
578
|
-
vectorResults.forEach((r, i) => {
|
|
579
|
-
vectorRanks.set(r.id, i + 1);
|
|
580
|
-
allDocs.set(r.id, r);
|
|
581
|
-
});
|
|
582
|
-
|
|
583
|
-
ftsResults.forEach((r, i) => {
|
|
584
|
-
ftsRanks.set(r.id, i + 1);
|
|
585
|
-
if (!allDocs.has(r.id)) {
|
|
586
|
-
allDocs.set(r.id, r);
|
|
587
|
-
}
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
// Calculate RRF scores with file-type boosting and preserve ranking metadata
|
|
591
|
-
const rrfScores: Array<{
|
|
592
|
-
id: string;
|
|
593
|
-
score: number;
|
|
594
|
-
result: SearchResult;
|
|
595
|
-
rawVectorScore: number | undefined;
|
|
596
|
-
metadata: {
|
|
597
|
-
vectorRank?: number;
|
|
598
|
-
ftsRank?: number;
|
|
599
|
-
vectorRRF: number;
|
|
600
|
-
ftsRRF: number;
|
|
601
|
-
fileTypeBoost: number;
|
|
602
|
-
frameworkBoost: number;
|
|
603
|
-
urlKeywordBoost: number;
|
|
604
|
-
pathKeywordBoost: number;
|
|
605
|
-
rawVectorScore?: number;
|
|
606
|
-
};
|
|
607
|
-
}> = [];
|
|
608
|
-
|
|
609
|
-
// Select RRF config based on content type (web vs code)
|
|
610
|
-
const contentType = detectContentType([...allDocs.values()]);
|
|
611
|
-
const { k, vectorWeight, ftsWeight } = RRF_PRESETS[contentType];
|
|
612
|
-
|
|
613
|
-
for (const [id, result] of allDocs) {
|
|
614
|
-
const vectorRank = vectorRanks.get(id) ?? Infinity;
|
|
615
|
-
const ftsRank = ftsRanks.get(id) ?? Infinity;
|
|
616
|
-
const rawVectorScore = rawVectorScores.get(id);
|
|
617
|
-
|
|
618
|
-
const vectorRRF = vectorRank !== Infinity ? vectorWeight / (k + vectorRank) : 0;
|
|
619
|
-
const ftsRRF = ftsRank !== Infinity ? ftsWeight / (k + ftsRank) : 0;
|
|
620
|
-
|
|
621
|
-
// Apply file-type boost (base + multi-intent-adjusted)
|
|
622
|
-
const fileTypeBoost = this.getFileTypeBoost(
|
|
623
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
624
|
-
result.metadata['fileType'] as string | undefined,
|
|
625
|
-
intents
|
|
626
|
-
);
|
|
627
|
-
|
|
628
|
-
// Apply framework context boost
|
|
629
|
-
const frameworkBoost = this.getFrameworkContextBoost(query, result);
|
|
630
|
-
|
|
631
|
-
// Apply URL keyword boost (helps "troubleshooting" find /troubleshooting pages)
|
|
632
|
-
const urlKeywordBoost = this.getUrlKeywordBoost(query, result);
|
|
633
|
-
|
|
634
|
-
// Apply path keyword boost (helps "dispatcher" find async_dispatcher.py)
|
|
635
|
-
const pathKeywordBoost = this.getPathKeywordBoost(query, result);
|
|
636
|
-
|
|
637
|
-
const metadata: {
|
|
638
|
-
vectorRank?: number;
|
|
639
|
-
ftsRank?: number;
|
|
640
|
-
vectorRRF: number;
|
|
641
|
-
ftsRRF: number;
|
|
642
|
-
fileTypeBoost: number;
|
|
643
|
-
frameworkBoost: number;
|
|
644
|
-
urlKeywordBoost: number;
|
|
645
|
-
pathKeywordBoost: number;
|
|
646
|
-
rawVectorScore?: number;
|
|
647
|
-
} = {
|
|
648
|
-
vectorRRF,
|
|
649
|
-
ftsRRF,
|
|
650
|
-
fileTypeBoost,
|
|
651
|
-
frameworkBoost,
|
|
652
|
-
urlKeywordBoost,
|
|
653
|
-
pathKeywordBoost,
|
|
654
|
-
};
|
|
655
|
-
|
|
656
|
-
if (vectorRank !== Infinity) {
|
|
657
|
-
metadata.vectorRank = vectorRank;
|
|
658
|
-
}
|
|
659
|
-
if (ftsRank !== Infinity) {
|
|
660
|
-
metadata.ftsRank = ftsRank;
|
|
661
|
-
}
|
|
662
|
-
if (rawVectorScore !== undefined) {
|
|
663
|
-
metadata.rawVectorScore = rawVectorScore;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
rrfScores.push({
|
|
667
|
-
id,
|
|
668
|
-
score:
|
|
669
|
-
(vectorRRF + ftsRRF) *
|
|
670
|
-
fileTypeBoost *
|
|
671
|
-
frameworkBoost *
|
|
672
|
-
urlKeywordBoost *
|
|
673
|
-
pathKeywordBoost,
|
|
674
|
-
result,
|
|
675
|
-
rawVectorScore,
|
|
676
|
-
metadata,
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// Sort by RRF score
|
|
681
|
-
const sorted = rrfScores.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
682
|
-
|
|
683
|
-
// Normalize scores to 0-1 range for better interpretability
|
|
684
|
-
let normalizedResults: SearchResult[];
|
|
685
|
-
|
|
686
|
-
if (sorted.length > 0) {
|
|
687
|
-
const first = sorted[0];
|
|
688
|
-
const last = sorted[sorted.length - 1];
|
|
689
|
-
if (first === undefined || last === undefined) {
|
|
690
|
-
normalizedResults = sorted.map((r) => ({
|
|
691
|
-
...r.result,
|
|
692
|
-
score: r.score,
|
|
693
|
-
rankingMetadata: r.metadata,
|
|
694
|
-
}));
|
|
695
|
-
} else {
|
|
696
|
-
const maxScore = first.score;
|
|
697
|
-
const minScore = last.score;
|
|
698
|
-
const range = maxScore - minScore;
|
|
699
|
-
|
|
700
|
-
if (range > 0) {
|
|
701
|
-
// Round to avoid floating point precision issues in threshold comparisons
|
|
702
|
-
normalizedResults = sorted.map((r) => ({
|
|
703
|
-
...r.result,
|
|
704
|
-
score: Math.round(((r.score - minScore) / range) * 1000000) / 1000000,
|
|
705
|
-
rankingMetadata: r.metadata,
|
|
706
|
-
}));
|
|
707
|
-
} else {
|
|
708
|
-
// All same score - keep raw scores (allows threshold to filter by quality)
|
|
709
|
-
normalizedResults = sorted.map((r) => ({
|
|
710
|
-
...r.result,
|
|
711
|
-
score: r.score,
|
|
712
|
-
rankingMetadata: r.metadata,
|
|
713
|
-
}));
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
} else {
|
|
717
|
-
normalizedResults = [];
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// Apply threshold filter on normalized scores (UX consistency)
|
|
721
|
-
if (threshold !== undefined) {
|
|
722
|
-
normalizedResults = normalizedResults.filter((r) => r.score >= threshold);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
return { results: normalizedResults, maxRawScore };
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
async searchAllStores(query: SearchQuery, storeIds: StoreId[]): Promise<SearchResponse> {
|
|
729
|
-
return this.search({
|
|
730
|
-
...query,
|
|
731
|
-
stores: storeIds,
|
|
732
|
-
});
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
/**
|
|
736
|
-
* Get a score multiplier based on file type and query intent.
|
|
737
|
-
* Documentation files get a strong boost to surface them higher.
|
|
738
|
-
* Phase 4: Strengthened boosts for better documentation ranking.
|
|
739
|
-
* Phase 1: Intent-based adjustments for context-aware ranking.
|
|
740
|
-
*/
|
|
741
|
-
private getFileTypeBoost(fileType: string | undefined, intents: ClassifiedIntent[]): number {
|
|
742
|
-
// Base file-type boosts
|
|
743
|
-
let baseBoost: number;
|
|
744
|
-
switch (fileType) {
|
|
745
|
-
case 'documentation-primary':
|
|
746
|
-
baseBoost = 1.8; // README, guides get very strong boost
|
|
747
|
-
break;
|
|
748
|
-
case 'documentation':
|
|
749
|
-
baseBoost = 1.5; // docs/, tutorials/ get strong boost
|
|
750
|
-
break;
|
|
751
|
-
case 'example':
|
|
752
|
-
baseBoost = 1.4; // examples/, demos/ are highly valuable
|
|
753
|
-
break;
|
|
754
|
-
case 'source':
|
|
755
|
-
baseBoost = 1.0; // Source code baseline
|
|
756
|
-
break;
|
|
757
|
-
case 'source-internal':
|
|
758
|
-
baseBoost = 0.75; // Internal implementation files (not too harsh)
|
|
759
|
-
break;
|
|
760
|
-
case 'test':
|
|
761
|
-
baseBoost = parseFloat(process.env['SEARCH_TEST_FILE_BOOST'] ?? '0.5');
|
|
762
|
-
break;
|
|
763
|
-
case 'config':
|
|
764
|
-
baseBoost = 0.5; // Config files rarely answer questions
|
|
765
|
-
break;
|
|
766
|
-
default:
|
|
767
|
-
baseBoost = 1.0;
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
// Blend intent-based multipliers weighted by confidence
|
|
771
|
-
let weightedMultiplier = 0;
|
|
772
|
-
let totalConfidence = 0;
|
|
773
|
-
|
|
774
|
-
for (const { intent, confidence } of intents) {
|
|
775
|
-
const intentBoosts = INTENT_FILE_BOOSTS[intent];
|
|
776
|
-
const multiplier = intentBoosts[fileType ?? 'other'] ?? 1.0;
|
|
777
|
-
weightedMultiplier += multiplier * confidence;
|
|
778
|
-
totalConfidence += confidence;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
const blendedMultiplier = totalConfidence > 0 ? weightedMultiplier / totalConfidence : 1.0;
|
|
782
|
-
const finalBoost = baseBoost * blendedMultiplier;
|
|
783
|
-
|
|
784
|
-
// Cap test file boost to prevent intent multipliers from overriding the penalty
|
|
785
|
-
if (fileType === 'test') {
|
|
786
|
-
return Math.min(finalBoost, 0.6);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
return finalBoost;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
/**
|
|
793
|
-
* Get a score multiplier based on URL keyword matching.
|
|
794
|
-
* Boosts results where URL path contains significant query keywords.
|
|
795
|
-
* This helps queries like "troubleshooting" rank /troubleshooting pages first.
|
|
796
|
-
*/
|
|
797
|
-
private getUrlKeywordBoost(query: string, result: SearchResult): number {
|
|
798
|
-
const url = result.metadata.url;
|
|
799
|
-
if (url === undefined || url === '') return 1.0;
|
|
800
|
-
|
|
801
|
-
// Extract path segments from URL and normalize
|
|
802
|
-
const urlPath = url.toLowerCase().replace(/[^a-z0-9]+/g, ' ');
|
|
803
|
-
|
|
804
|
-
// Common stop words to filter from queries
|
|
805
|
-
const stopWords = new Set([
|
|
806
|
-
'how',
|
|
807
|
-
'to',
|
|
808
|
-
'the',
|
|
809
|
-
'a',
|
|
810
|
-
'an',
|
|
811
|
-
'is',
|
|
812
|
-
'are',
|
|
813
|
-
'what',
|
|
814
|
-
'why',
|
|
815
|
-
'when',
|
|
816
|
-
'where',
|
|
817
|
-
'can',
|
|
818
|
-
'do',
|
|
819
|
-
'does',
|
|
820
|
-
'i',
|
|
821
|
-
'my',
|
|
822
|
-
'your',
|
|
823
|
-
'it',
|
|
824
|
-
'in',
|
|
825
|
-
'on',
|
|
826
|
-
'for',
|
|
827
|
-
'with',
|
|
828
|
-
'this',
|
|
829
|
-
'that',
|
|
830
|
-
'get',
|
|
831
|
-
'use',
|
|
832
|
-
'using',
|
|
833
|
-
]);
|
|
834
|
-
|
|
835
|
-
// Extract meaningful query terms
|
|
836
|
-
const queryTerms = query
|
|
837
|
-
.toLowerCase()
|
|
838
|
-
.split(/\s+/)
|
|
839
|
-
.filter((t) => t.length > 2 && !stopWords.has(t));
|
|
840
|
-
|
|
841
|
-
if (queryTerms.length === 0) return 1.0;
|
|
842
|
-
|
|
843
|
-
// Count matching terms in URL path
|
|
844
|
-
const matchingTerms = queryTerms.filter((term) => urlPath.includes(term));
|
|
845
|
-
|
|
846
|
-
if (matchingTerms.length === 0) return 1.0;
|
|
847
|
-
|
|
848
|
-
// Boost based on proportion of matching terms
|
|
849
|
-
// Single match: ~1.5, all terms match: ~2.0
|
|
850
|
-
const matchRatio = matchingTerms.length / queryTerms.length;
|
|
851
|
-
return 1.0 + 1.0 * matchRatio;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
/**
|
|
855
|
-
* Get a score multiplier based on file path keyword matching.
|
|
856
|
-
* Boosts results where file path contains significant query keywords.
|
|
857
|
-
* This helps queries like "dispatcher" rank async_dispatcher.py higher.
|
|
858
|
-
*/
|
|
859
|
-
private getPathKeywordBoost(query: string, result: SearchResult): number {
|
|
860
|
-
const path = result.metadata.path;
|
|
861
|
-
if (path === undefined || path === '') return 1.0;
|
|
862
|
-
|
|
863
|
-
// Extract path segments and normalize (split on slashes, dots, underscores, etc.)
|
|
864
|
-
const pathSegments = path.toLowerCase().replace(/[^a-z0-9]+/g, ' ');
|
|
865
|
-
|
|
866
|
-
// Common stop words to filter from queries
|
|
867
|
-
const stopWords = new Set([
|
|
868
|
-
'how',
|
|
869
|
-
'to',
|
|
870
|
-
'the',
|
|
871
|
-
'a',
|
|
872
|
-
'an',
|
|
873
|
-
'is',
|
|
874
|
-
'are',
|
|
875
|
-
'what',
|
|
876
|
-
'why',
|
|
877
|
-
'when',
|
|
878
|
-
'where',
|
|
879
|
-
'can',
|
|
880
|
-
'do',
|
|
881
|
-
'does',
|
|
882
|
-
'i',
|
|
883
|
-
'my',
|
|
884
|
-
'your',
|
|
885
|
-
'it',
|
|
886
|
-
'in',
|
|
887
|
-
'on',
|
|
888
|
-
'for',
|
|
889
|
-
'with',
|
|
890
|
-
'this',
|
|
891
|
-
'that',
|
|
892
|
-
'get',
|
|
893
|
-
'use',
|
|
894
|
-
'using',
|
|
895
|
-
]);
|
|
896
|
-
|
|
897
|
-
// Extract meaningful query terms
|
|
898
|
-
const queryTerms = query
|
|
899
|
-
.toLowerCase()
|
|
900
|
-
.split(/\s+/)
|
|
901
|
-
.filter((t) => t.length > 2 && !stopWords.has(t));
|
|
902
|
-
|
|
903
|
-
if (queryTerms.length === 0) return 1.0;
|
|
904
|
-
|
|
905
|
-
// Count matching terms in file path
|
|
906
|
-
const matchingTerms = queryTerms.filter((term) => pathSegments.includes(term));
|
|
907
|
-
|
|
908
|
-
if (matchingTerms.length === 0) return 1.0;
|
|
909
|
-
|
|
910
|
-
// Boost based on proportion of matching terms
|
|
911
|
-
// Single match: ~1.5, all terms match: ~2.0
|
|
912
|
-
const matchRatio = matchingTerms.length / queryTerms.length;
|
|
913
|
-
return 1.0 + 1.0 * matchRatio;
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
/**
|
|
917
|
-
* Get a score multiplier based on framework context.
|
|
918
|
-
* If query mentions a framework, boost results from that framework's files.
|
|
919
|
-
*/
|
|
920
|
-
private getFrameworkContextBoost(query: string, result: SearchResult): number {
|
|
921
|
-
const path = result.metadata.path ?? result.metadata.url ?? '';
|
|
922
|
-
const content = result.content.toLowerCase();
|
|
923
|
-
const pathLower = path.toLowerCase();
|
|
924
|
-
|
|
925
|
-
// Check if query mentions any known frameworks
|
|
926
|
-
for (const { pattern, terms } of FRAMEWORK_PATTERNS) {
|
|
927
|
-
if (pattern.test(query)) {
|
|
928
|
-
// Query mentions this framework - check if result is from that framework
|
|
929
|
-
const resultMatchesFramework = terms.some(
|
|
930
|
-
(term) => pathLower.includes(term) || content.includes(term)
|
|
931
|
-
);
|
|
932
|
-
|
|
933
|
-
if (resultMatchesFramework) {
|
|
934
|
-
return 1.5; // Strong boost for matching framework
|
|
935
|
-
} else {
|
|
936
|
-
return 0.8; // Moderate penalty for non-matching when framework is specified
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
return 1.0; // No framework context in query
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
private addProgressiveContext(
|
|
945
|
-
result: SearchResult,
|
|
946
|
-
query: string,
|
|
947
|
-
detail: DetailLevel,
|
|
948
|
-
graph: CodeGraph | null
|
|
949
|
-
): SearchResult {
|
|
950
|
-
const enhanced = { ...result };
|
|
951
|
-
|
|
952
|
-
// Layer 1: Always add summary
|
|
953
|
-
const path = result.metadata.path ?? result.metadata.url ?? 'unknown';
|
|
954
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
955
|
-
const fileType = result.metadata['fileType'] as string | undefined;
|
|
956
|
-
|
|
957
|
-
// Try to extract code unit
|
|
958
|
-
const codeUnit = this.extractCodeUnitFromResult(result);
|
|
959
|
-
const symbolName = codeUnit?.name ?? this.extractSymbolName(result.content);
|
|
960
|
-
|
|
961
|
-
enhanced.summary = {
|
|
962
|
-
type: this.inferType(fileType, codeUnit),
|
|
963
|
-
name: symbolName,
|
|
964
|
-
signature: codeUnit?.signature ?? '',
|
|
965
|
-
purpose: this.generatePurpose(result.content, query),
|
|
966
|
-
location: `${path}${codeUnit ? `:${String(codeUnit.startLine)}` : ''}`,
|
|
967
|
-
relevanceReason: this.generateRelevanceReason(result, query),
|
|
968
|
-
};
|
|
969
|
-
|
|
970
|
-
// Layer 2: Add context if requested
|
|
971
|
-
if (detail === 'contextual' || detail === 'full') {
|
|
972
|
-
// Get usage stats from code graph if available
|
|
973
|
-
const usage = this.getUsageFromGraph(graph, path, symbolName);
|
|
974
|
-
|
|
975
|
-
enhanced.context = {
|
|
976
|
-
interfaces: this.extractInterfaces(result.content),
|
|
977
|
-
keyImports: this.extractImports(result.content),
|
|
978
|
-
relatedConcepts: this.extractConcepts(result.content, query),
|
|
979
|
-
usage,
|
|
980
|
-
};
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
// Layer 3: Add full context if requested
|
|
984
|
-
if (detail === 'full') {
|
|
985
|
-
// Get related code from graph if available
|
|
986
|
-
const relatedCode = this.getRelatedCodeFromGraph(graph, path, symbolName);
|
|
987
|
-
|
|
988
|
-
enhanced.full = {
|
|
989
|
-
completeCode: codeUnit?.fullContent ?? result.content,
|
|
990
|
-
relatedCode,
|
|
991
|
-
documentation: this.extractDocumentation(result.content),
|
|
992
|
-
tests: undefined,
|
|
993
|
-
};
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
return enhanced;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
private extractCodeUnitFromResult(result: SearchResult): CodeUnit | undefined {
|
|
1000
|
-
const path = result.metadata.path;
|
|
1001
|
-
if (path === undefined || path === '') return undefined;
|
|
1002
|
-
|
|
1003
|
-
const ext = path.split('.').pop() ?? '';
|
|
1004
|
-
const language =
|
|
1005
|
-
ext === 'ts' || ext === 'tsx'
|
|
1006
|
-
? 'typescript'
|
|
1007
|
-
: ext === 'js' || ext === 'jsx'
|
|
1008
|
-
? 'javascript'
|
|
1009
|
-
: ext;
|
|
1010
|
-
|
|
1011
|
-
// Try to find a symbol name in the content
|
|
1012
|
-
const symbolName = this.extractSymbolName(result.content);
|
|
1013
|
-
if (symbolName === '') return undefined;
|
|
1014
|
-
|
|
1015
|
-
return this.codeUnitService.extractCodeUnit(result.content, symbolName, language);
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
private extractSymbolName(content: string): string {
|
|
1019
|
-
// Extract function or class name
|
|
1020
|
-
const funcMatch = content.match(/(?:export\s+)?(?:async\s+)?function\s+(\w+)/);
|
|
1021
|
-
if (funcMatch?.[1] !== undefined && funcMatch[1] !== '') return funcMatch[1];
|
|
1022
|
-
|
|
1023
|
-
const classMatch = content.match(/(?:export\s+)?class\s+(\w+)/);
|
|
1024
|
-
if (classMatch?.[1] !== undefined && classMatch[1] !== '') return classMatch[1];
|
|
1025
|
-
|
|
1026
|
-
const constMatch = content.match(/(?:export\s+)?const\s+(\w+)/);
|
|
1027
|
-
if (constMatch?.[1] !== undefined && constMatch[1] !== '') return constMatch[1];
|
|
1028
|
-
|
|
1029
|
-
// Fallback: return "(anonymous)" for unnamed symbols
|
|
1030
|
-
return '(anonymous)';
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
private inferType(
|
|
1034
|
-
fileType: string | undefined,
|
|
1035
|
-
codeUnit: CodeUnit | undefined
|
|
1036
|
-
): import('../types/search.js').ResultSummary['type'] {
|
|
1037
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
1038
|
-
if (codeUnit) return codeUnit.type as import('../types/search.js').ResultSummary['type'];
|
|
1039
|
-
if (fileType === 'documentation' || fileType === 'documentation-primary')
|
|
1040
|
-
return 'documentation';
|
|
1041
|
-
return 'function';
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
private generatePurpose(content: string, query: string): string {
|
|
1045
|
-
// Extract first line of JSDoc comment if present
|
|
1046
|
-
const docMatch = content.match(/\/\*\*\s*\n\s*\*\s*([^\n]+)/);
|
|
1047
|
-
if (docMatch?.[1] !== undefined && docMatch[1] !== '') return docMatch[1].trim();
|
|
1048
|
-
|
|
1049
|
-
const lines = content.split('\n');
|
|
1050
|
-
const queryTerms = query
|
|
1051
|
-
.toLowerCase()
|
|
1052
|
-
.split(/\s+/)
|
|
1053
|
-
.filter((t) => t.length > 2);
|
|
1054
|
-
|
|
1055
|
-
// Helper to check if line is skippable (imports, declarations)
|
|
1056
|
-
const shouldSkip = (cleaned: string): boolean => {
|
|
1057
|
-
return (
|
|
1058
|
-
cleaned.startsWith('import ') ||
|
|
1059
|
-
cleaned.startsWith('export ') ||
|
|
1060
|
-
cleaned.startsWith('interface ') ||
|
|
1061
|
-
cleaned.startsWith('type ')
|
|
1062
|
-
);
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
|
-
// Helper to score a line based on query term matches
|
|
1066
|
-
const scoreLine = (cleaned: string): number => {
|
|
1067
|
-
const lowerLine = cleaned.toLowerCase();
|
|
1068
|
-
return queryTerms.filter((term) => lowerLine.includes(term)).length;
|
|
1069
|
-
};
|
|
1070
|
-
|
|
1071
|
-
// Helper to check if line is meaningful (length, not a comment)
|
|
1072
|
-
const isMeaningful = (cleaned: string): boolean => {
|
|
1073
|
-
if (cleaned.length === 0) return false;
|
|
1074
|
-
if (cleaned.startsWith('//') || cleaned.startsWith('/*')) return false;
|
|
1075
|
-
// Accept Markdown headings
|
|
1076
|
-
if (cleaned.startsWith('#') && cleaned.length > 3) return true;
|
|
1077
|
-
// Accept lines 15+ chars
|
|
1078
|
-
return cleaned.length >= 15;
|
|
1079
|
-
};
|
|
1080
|
-
|
|
1081
|
-
// First pass: find lines with query terms, preferring complete sentences
|
|
1082
|
-
let bestLine: string | null = null;
|
|
1083
|
-
let bestScore = 0;
|
|
1084
|
-
|
|
1085
|
-
for (const line of lines) {
|
|
1086
|
-
const cleaned = line.trim();
|
|
1087
|
-
if (shouldSkip(cleaned) || !isMeaningful(cleaned)) continue;
|
|
1088
|
-
|
|
1089
|
-
let score = scoreLine(cleaned);
|
|
1090
|
-
|
|
1091
|
-
// Boost score for complete sentences (end with period, !, ?)
|
|
1092
|
-
if (/[.!?]$/.test(cleaned)) {
|
|
1093
|
-
score += 0.5;
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
// Boost score for code examples (contains function calls or assignments)
|
|
1097
|
-
// Favor complete patterns: function calls WITH arguments, assignments with values
|
|
1098
|
-
if (/\w+\([^)]*\)|=\s*\w+\(|=>/.test(cleaned)) {
|
|
1099
|
-
score += 0.6; // Enhanced boost to preserve code examples in snippets
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
if (score > bestScore) {
|
|
1103
|
-
bestScore = score;
|
|
1104
|
-
bestLine = cleaned;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
// If we found a line with query terms, use it
|
|
1109
|
-
if (bestLine !== null && bestLine !== '' && bestScore > 0) {
|
|
1110
|
-
if (bestLine.length > 150) {
|
|
1111
|
-
const firstSentence = bestLine.match(/^[^.!?]+[.!?]/);
|
|
1112
|
-
if (firstSentence && firstSentence[0].length >= 20 && firstSentence[0].length <= 150) {
|
|
1113
|
-
return firstSentence[0].trim();
|
|
1114
|
-
}
|
|
1115
|
-
return `${bestLine.substring(0, 147)}...`;
|
|
1116
|
-
}
|
|
1117
|
-
return bestLine;
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
// Fallback: first meaningful line (original logic)
|
|
1121
|
-
for (const line of lines) {
|
|
1122
|
-
const cleaned = line.trim();
|
|
1123
|
-
if (shouldSkip(cleaned) || !isMeaningful(cleaned)) continue;
|
|
1124
|
-
|
|
1125
|
-
if (cleaned.length > 150) {
|
|
1126
|
-
const firstSentence = cleaned.match(/^[^.!?]+[.!?]/);
|
|
1127
|
-
if (firstSentence && firstSentence[0].length >= 20 && firstSentence[0].length <= 150) {
|
|
1128
|
-
return firstSentence[0].trim();
|
|
1129
|
-
}
|
|
1130
|
-
return `${cleaned.substring(0, 147)}...`;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
return cleaned;
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
return 'Code related to query';
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
private generateRelevanceReason(result: SearchResult, query: string): string {
|
|
1140
|
-
const queryTerms = query
|
|
1141
|
-
.toLowerCase()
|
|
1142
|
-
.split(/\s+/)
|
|
1143
|
-
.filter((t) => t.length > 2);
|
|
1144
|
-
const contentLower = result.content.toLowerCase();
|
|
1145
|
-
|
|
1146
|
-
const matchedTerms = queryTerms.filter((term) => contentLower.includes(term));
|
|
1147
|
-
|
|
1148
|
-
if (matchedTerms.length > 0) {
|
|
1149
|
-
return `Matches: ${matchedTerms.join(', ')}`;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
return 'Semantically similar to query';
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
private extractInterfaces(content: string): string[] {
|
|
1156
|
-
const interfaces: string[] = [];
|
|
1157
|
-
const matches = content.matchAll(/interface\s+(\w+)/g);
|
|
1158
|
-
for (const match of matches) {
|
|
1159
|
-
if (match[1] !== undefined && match[1] !== '') interfaces.push(match[1]);
|
|
1160
|
-
}
|
|
1161
|
-
return interfaces;
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
private extractImports(content: string): string[] {
|
|
1165
|
-
const imports: string[] = [];
|
|
1166
|
-
const matches = content.matchAll(/import\s+.*?from\s+['"]([^'"]+)['"]/g);
|
|
1167
|
-
for (const match of matches) {
|
|
1168
|
-
if (match[1] !== undefined && match[1] !== '') imports.push(match[1]);
|
|
1169
|
-
}
|
|
1170
|
-
return imports.slice(0, 5); // Top 5
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
private extractConcepts(content: string, _query: string): string[] {
|
|
1174
|
-
// TODO: Use _query parameter to prioritize query-related concepts in future enhancement
|
|
1175
|
-
|
|
1176
|
-
// Common stopwords to filter out
|
|
1177
|
-
const stopwords = new Set([
|
|
1178
|
-
'this',
|
|
1179
|
-
'that',
|
|
1180
|
-
'these',
|
|
1181
|
-
'those',
|
|
1182
|
-
'from',
|
|
1183
|
-
'with',
|
|
1184
|
-
'have',
|
|
1185
|
-
'will',
|
|
1186
|
-
'would',
|
|
1187
|
-
'should',
|
|
1188
|
-
'could',
|
|
1189
|
-
'about',
|
|
1190
|
-
'been',
|
|
1191
|
-
'were',
|
|
1192
|
-
'being',
|
|
1193
|
-
'function',
|
|
1194
|
-
'return',
|
|
1195
|
-
'const',
|
|
1196
|
-
'import',
|
|
1197
|
-
'export',
|
|
1198
|
-
'default',
|
|
1199
|
-
'type',
|
|
1200
|
-
'interface',
|
|
1201
|
-
'class',
|
|
1202
|
-
'extends',
|
|
1203
|
-
'implements',
|
|
1204
|
-
'async',
|
|
1205
|
-
'await',
|
|
1206
|
-
'then',
|
|
1207
|
-
'catch',
|
|
1208
|
-
'throw',
|
|
1209
|
-
'error',
|
|
1210
|
-
'undefined',
|
|
1211
|
-
'null',
|
|
1212
|
-
'true',
|
|
1213
|
-
'false',
|
|
1214
|
-
'void',
|
|
1215
|
-
'number',
|
|
1216
|
-
'string',
|
|
1217
|
-
'boolean',
|
|
1218
|
-
'object',
|
|
1219
|
-
'array',
|
|
1220
|
-
'promise',
|
|
1221
|
-
'callback',
|
|
1222
|
-
'resolve',
|
|
1223
|
-
'reject',
|
|
1224
|
-
'value',
|
|
1225
|
-
'param',
|
|
1226
|
-
'params',
|
|
1227
|
-
'args',
|
|
1228
|
-
'props',
|
|
1229
|
-
'options',
|
|
1230
|
-
'config',
|
|
1231
|
-
'data',
|
|
1232
|
-
]);
|
|
1233
|
-
|
|
1234
|
-
// Simple keyword extraction
|
|
1235
|
-
const words = content.toLowerCase().match(/\b[a-z]{4,}\b/g) ?? [];
|
|
1236
|
-
const frequency = new Map<string, number>();
|
|
1237
|
-
|
|
1238
|
-
for (const word of words) {
|
|
1239
|
-
// Skip stopwords
|
|
1240
|
-
if (stopwords.has(word)) continue;
|
|
1241
|
-
|
|
1242
|
-
frequency.set(word, (frequency.get(word) ?? 0) + 1);
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
return Array.from(frequency.entries())
|
|
1246
|
-
.sort((a, b) => b[1] - a[1])
|
|
1247
|
-
.slice(0, 5)
|
|
1248
|
-
.map(([word]) => word);
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
private extractDocumentation(content: string): string {
|
|
1252
|
-
const docMatch = content.match(/\/\*\*([\s\S]*?)\*\//);
|
|
1253
|
-
if (docMatch?.[1] !== undefined && docMatch[1] !== '') {
|
|
1254
|
-
return docMatch[1]
|
|
1255
|
-
.split('\n')
|
|
1256
|
-
.map((line) => line.replace(/^\s*\*\s?/, '').trim())
|
|
1257
|
-
.filter((line) => line.length > 0)
|
|
1258
|
-
.join('\n');
|
|
1259
|
-
}
|
|
1260
|
-
return '';
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
/**
|
|
1264
|
-
* Get usage stats from code graph.
|
|
1265
|
-
* Returns default values if no graph is available.
|
|
1266
|
-
*/
|
|
1267
|
-
private getUsageFromGraph(
|
|
1268
|
-
graph: CodeGraph | null,
|
|
1269
|
-
filePath: string,
|
|
1270
|
-
symbolName: string
|
|
1271
|
-
): { calledBy: number; calls: number } {
|
|
1272
|
-
if (!graph || symbolName === '' || symbolName === '(anonymous)') {
|
|
1273
|
-
return { calledBy: 0, calls: 0 };
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
const nodeId = `${filePath}:${symbolName}`;
|
|
1277
|
-
return {
|
|
1278
|
-
calledBy: graph.getCalledByCount(nodeId),
|
|
1279
|
-
calls: graph.getCallsCount(nodeId),
|
|
1280
|
-
};
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
/**
|
|
1284
|
-
* Get related code from graph.
|
|
1285
|
-
* Returns callers and callees for the symbol.
|
|
1286
|
-
*/
|
|
1287
|
-
private getRelatedCodeFromGraph(
|
|
1288
|
-
graph: CodeGraph | null,
|
|
1289
|
-
filePath: string,
|
|
1290
|
-
symbolName: string
|
|
1291
|
-
): Array<{ file: string; summary: string; relationship: string }> {
|
|
1292
|
-
if (!graph || symbolName === '' || symbolName === '(anonymous)') {
|
|
1293
|
-
return [];
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
const nodeId = `${filePath}:${symbolName}`;
|
|
1297
|
-
const related: Array<{ file: string; summary: string; relationship: string }> = [];
|
|
1298
|
-
|
|
1299
|
-
// Get callers (incoming edges)
|
|
1300
|
-
const incoming = graph.getIncomingEdges(nodeId);
|
|
1301
|
-
for (const edge of incoming) {
|
|
1302
|
-
if (edge.type === 'calls') {
|
|
1303
|
-
// Parse file:symbol from edge.from
|
|
1304
|
-
const [file, symbol] = this.parseNodeId(edge.from);
|
|
1305
|
-
related.push({
|
|
1306
|
-
file,
|
|
1307
|
-
summary: symbol ? `${symbol}()` : 'unknown',
|
|
1308
|
-
relationship: 'calls this',
|
|
1309
|
-
});
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
// Get callees (outgoing edges)
|
|
1314
|
-
const outgoing = graph.getEdges(nodeId);
|
|
1315
|
-
for (const edge of outgoing) {
|
|
1316
|
-
if (edge.type === 'calls') {
|
|
1317
|
-
// Parse file:symbol from edge.to
|
|
1318
|
-
const [file, symbol] = this.parseNodeId(edge.to);
|
|
1319
|
-
related.push({
|
|
1320
|
-
file,
|
|
1321
|
-
summary: symbol ? `${symbol}()` : 'unknown',
|
|
1322
|
-
relationship: 'called by this',
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
// Limit to top 10 related items
|
|
1328
|
-
return related.slice(0, 10);
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
/**
|
|
1332
|
-
* Parse a node ID into file path and symbol name.
|
|
1333
|
-
*/
|
|
1334
|
-
private parseNodeId(nodeId: string): [string, string] {
|
|
1335
|
-
const lastColon = nodeId.lastIndexOf(':');
|
|
1336
|
-
if (lastColon === -1) {
|
|
1337
|
-
return [nodeId, ''];
|
|
1338
|
-
}
|
|
1339
|
-
return [nodeId.substring(0, lastColon), nodeId.substring(lastColon + 1)];
|
|
1340
|
-
}
|
|
1341
|
-
}
|