seer-mcp 0.1.0
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/.vscode/settings.json +3 -0
- package/LICENSE +176 -0
- package/README.md +272 -0
- package/README_dev.md +199 -0
- package/dist/bundle/ci.d.ts +47 -0
- package/dist/bundle/ci.d.ts.map +1 -0
- package/dist/bundle/ci.js +113 -0
- package/dist/bundle/ci.js.map +1 -0
- package/dist/bundle/contract.d.ts +111 -0
- package/dist/bundle/contract.d.ts.map +1 -0
- package/dist/bundle/contract.js +352 -0
- package/dist/bundle/contract.js.map +1 -0
- package/dist/bundle/export.d.ts +36 -0
- package/dist/bundle/export.d.ts.map +1 -0
- package/dist/bundle/export.js +152 -0
- package/dist/bundle/export.js.map +1 -0
- package/dist/bundle/external.d.ts +66 -0
- package/dist/bundle/external.d.ts.map +1 -0
- package/dist/bundle/external.js +238 -0
- package/dist/bundle/external.js.map +1 -0
- package/dist/bundle/format.d.ts +94 -0
- package/dist/bundle/format.d.ts.map +1 -0
- package/dist/bundle/format.js +42 -0
- package/dist/bundle/format.js.map +1 -0
- package/dist/bundle/import.d.ts +49 -0
- package/dist/bundle/import.d.ts.map +1 -0
- package/dist/bundle/import.js +116 -0
- package/dist/bundle/import.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +1402 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +48 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +284 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/db/schema.d.ts +3 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +616 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/store.d.ts +1011 -0
- package/dist/db/store.d.ts.map +1 -0
- package/dist/db/store.js +3888 -0
- package/dist/db/store.js.map +1 -0
- package/dist/graph/pagerank.d.ts +9 -0
- package/dist/graph/pagerank.d.ts.map +1 -0
- package/dist/graph/pagerank.js +47 -0
- package/dist/graph/pagerank.js.map +1 -0
- package/dist/indexer/architecture.d.ts +72 -0
- package/dist/indexer/architecture.d.ts.map +1 -0
- package/dist/indexer/architecture.js +112 -0
- package/dist/indexer/architecture.js.map +1 -0
- package/dist/indexer/behavior.d.ts +75 -0
- package/dist/indexer/behavior.d.ts.map +1 -0
- package/dist/indexer/behavior.js +395 -0
- package/dist/indexer/behavior.js.map +1 -0
- package/dist/indexer/boundaries.d.ts +60 -0
- package/dist/indexer/boundaries.d.ts.map +1 -0
- package/dist/indexer/boundaries.js +366 -0
- package/dist/indexer/boundaries.js.map +1 -0
- package/dist/indexer/churn.d.ts +15 -0
- package/dist/indexer/churn.d.ts.map +1 -0
- package/dist/indexer/churn.js +49 -0
- package/dist/indexer/churn.js.map +1 -0
- package/dist/indexer/classify.d.ts +9 -0
- package/dist/indexer/classify.d.ts.map +1 -0
- package/dist/indexer/classify.js +90 -0
- package/dist/indexer/classify.js.map +1 -0
- package/dist/indexer/context.d.ts +176 -0
- package/dist/indexer/context.d.ts.map +1 -0
- package/dist/indexer/context.js +193 -0
- package/dist/indexer/context.js.map +1 -0
- package/dist/indexer/continuity.d.ts +67 -0
- package/dist/indexer/continuity.d.ts.map +1 -0
- package/dist/indexer/continuity.js +288 -0
- package/dist/indexer/continuity.js.map +1 -0
- package/dist/indexer/detectchanges.d.ts +32 -0
- package/dist/indexer/detectchanges.d.ts.map +1 -0
- package/dist/indexer/detectchanges.js +74 -0
- package/dist/indexer/detectchanges.js.map +1 -0
- package/dist/indexer/discovery.d.ts +37 -0
- package/dist/indexer/discovery.d.ts.map +1 -0
- package/dist/indexer/discovery.js +136 -0
- package/dist/indexer/discovery.js.map +1 -0
- package/dist/indexer/externaldeps.d.ts +18 -0
- package/dist/indexer/externaldeps.d.ts.map +1 -0
- package/dist/indexer/externaldeps.js +288 -0
- package/dist/indexer/externaldeps.js.map +1 -0
- package/dist/indexer/freshness.d.ts +48 -0
- package/dist/indexer/freshness.d.ts.map +1 -0
- package/dist/indexer/freshness.js +128 -0
- package/dist/indexer/freshness.js.map +1 -0
- package/dist/indexer/git.d.ts +144 -0
- package/dist/indexer/git.d.ts.map +1 -0
- package/dist/indexer/git.js +444 -0
- package/dist/indexer/git.js.map +1 -0
- package/dist/indexer/index.d.ts +145 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +930 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/modules.d.ts +62 -0
- package/dist/indexer/modules.d.ts.map +1 -0
- package/dist/indexer/modules.js +293 -0
- package/dist/indexer/modules.js.map +1 -0
- package/dist/indexer/preflight.d.ts +154 -0
- package/dist/indexer/preflight.d.ts.map +1 -0
- package/dist/indexer/preflight.js +399 -0
- package/dist/indexer/preflight.js.map +1 -0
- package/dist/indexer/protoScanner.d.ts +34 -0
- package/dist/indexer/protoScanner.d.ts.map +1 -0
- package/dist/indexer/protoScanner.js +133 -0
- package/dist/indexer/protoScanner.js.map +1 -0
- package/dist/indexer/risk.d.ts +115 -0
- package/dist/indexer/risk.d.ts.map +1 -0
- package/dist/indexer/risk.js +194 -0
- package/dist/indexer/risk.js.map +1 -0
- package/dist/indexer/serviceHostScanner.d.ts +25 -0
- package/dist/indexer/serviceHostScanner.d.ts.map +1 -0
- package/dist/indexer/serviceHostScanner.js +95 -0
- package/dist/indexer/serviceHostScanner.js.map +1 -0
- package/dist/indexer/serviceLinks.d.ts +105 -0
- package/dist/indexer/serviceLinks.d.ts.map +1 -0
- package/dist/indexer/serviceLinks.js +509 -0
- package/dist/indexer/serviceLinks.js.map +1 -0
- package/dist/indexer/shapehash.d.ts +98 -0
- package/dist/indexer/shapehash.d.ts.map +1 -0
- package/dist/indexer/shapehash.js +354 -0
- package/dist/indexer/shapehash.js.map +1 -0
- package/dist/indexer/skeleton.d.ts +15 -0
- package/dist/indexer/skeleton.d.ts.map +1 -0
- package/dist/indexer/skeleton.js +136 -0
- package/dist/indexer/skeleton.js.map +1 -0
- package/dist/indexer/symbolhistory.d.ts +41 -0
- package/dist/indexer/symbolhistory.d.ts.map +1 -0
- package/dist/indexer/symbolhistory.js +124 -0
- package/dist/indexer/symbolhistory.js.map +1 -0
- package/dist/indexer/watcher.d.ts +68 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +179 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/mcp/server.d.ts +80 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +1610 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/parser/index.d.ts +8 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +33 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/languages/cpp.d.ts +3 -0
- package/dist/parser/languages/cpp.d.ts.map +1 -0
- package/dist/parser/languages/cpp.js +350 -0
- package/dist/parser/languages/cpp.js.map +1 -0
- package/dist/parser/languages/csharp.d.ts +3 -0
- package/dist/parser/languages/csharp.d.ts.map +1 -0
- package/dist/parser/languages/csharp.js +239 -0
- package/dist/parser/languages/csharp.js.map +1 -0
- package/dist/parser/languages/go.d.ts +3 -0
- package/dist/parser/languages/go.d.ts.map +1 -0
- package/dist/parser/languages/go.js +259 -0
- package/dist/parser/languages/go.js.map +1 -0
- package/dist/parser/languages/java.d.ts +3 -0
- package/dist/parser/languages/java.d.ts.map +1 -0
- package/dist/parser/languages/java.js +391 -0
- package/dist/parser/languages/java.js.map +1 -0
- package/dist/parser/languages/python.d.ts +3 -0
- package/dist/parser/languages/python.d.ts.map +1 -0
- package/dist/parser/languages/python.js +396 -0
- package/dist/parser/languages/python.js.map +1 -0
- package/dist/parser/languages/rust.d.ts +3 -0
- package/dist/parser/languages/rust.d.ts.map +1 -0
- package/dist/parser/languages/rust.js +159 -0
- package/dist/parser/languages/rust.js.map +1 -0
- package/dist/parser/languages/typescript.d.ts +3 -0
- package/dist/parser/languages/typescript.d.ts.map +1 -0
- package/dist/parser/languages/typescript.js +1442 -0
- package/dist/parser/languages/typescript.js.map +1 -0
- package/dist/parser/parserContext.d.ts +77 -0
- package/dist/parser/parserContext.d.ts.map +1 -0
- package/dist/parser/parserContext.js +354 -0
- package/dist/parser/parserContext.js.map +1 -0
- package/dist/parser/walker.d.ts +81 -0
- package/dist/parser/walker.d.ts.map +1 -0
- package/dist/parser/walker.js +217 -0
- package/dist/parser/walker.js.map +1 -0
- package/dist/parser/worker.d.ts +66 -0
- package/dist/parser/worker.d.ts.map +1 -0
- package/dist/parser/worker.js +129 -0
- package/dist/parser/worker.js.map +1 -0
- package/dist/parser/workerpool.d.ts +107 -0
- package/dist/parser/workerpool.d.ts.map +1 -0
- package/dist/parser/workerpool.js +383 -0
- package/dist/parser/workerpool.js.map +1 -0
- package/dist/scip/format.d.ts +87 -0
- package/dist/scip/format.d.ts.map +1 -0
- package/dist/scip/format.js +31 -0
- package/dist/scip/format.js.map +1 -0
- package/dist/scip/import.d.ts +37 -0
- package/dist/scip/import.d.ts.map +1 -0
- package/dist/scip/import.js +180 -0
- package/dist/scip/import.js.map +1 -0
- package/dist/types.d.ts +392 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/docs/architecture.md +105 -0
- package/docs/benchmarks/methodology.md +134 -0
- package/docs/benchmarks/raw-results.md +71 -0
- package/docs/benchmarks.md +74 -0
- package/docs/cli.md +148 -0
- package/docs/examples/behavior-tests.md +70 -0
- package/docs/examples/change-history.md +85 -0
- package/docs/examples/pre-edit-context.md +81 -0
- package/docs/examples/service-links.md +88 -0
- package/docs/examples.md +80 -0
- package/docs/faq.md +70 -0
- package/docs/internals.md +104 -0
- package/docs/languages.md +70 -0
- package/docs/limits.md +52 -0
- package/docs/mcp.md +199 -0
- package/docs/quickstart.md +119 -0
- package/docs/testing.md +123 -0
- package/docs/tools.md +115 -0
- package/package.json +52 -0
- package/research-codebase.md +578 -0
- package/seer-cli-docs.md +326 -0
- package/seer-master-guide.md +246 -0
- package/src/bundle/ci.ts +141 -0
- package/src/bundle/contract.ts +387 -0
- package/src/bundle/export.ts +175 -0
- package/src/bundle/external.ts +285 -0
- package/src/bundle/format.ts +92 -0
- package/src/bundle/import.ts +157 -0
- package/src/cli/index.ts +1249 -0
- package/src/cli/init.ts +389 -0
- package/src/db/schema.ts +614 -0
- package/src/db/store.ts +4306 -0
- package/src/graph/pagerank.ts +53 -0
- package/src/indexer/architecture.ts +148 -0
- package/src/indexer/behavior.ts +466 -0
- package/src/indexer/boundaries.ts +374 -0
- package/src/indexer/churn.ts +58 -0
- package/src/indexer/classify.ts +96 -0
- package/src/indexer/context.ts +340 -0
- package/src/indexer/continuity.ts +322 -0
- package/src/indexer/detectchanges.ts +94 -0
- package/src/indexer/discovery.ts +176 -0
- package/src/indexer/externaldeps.ts +243 -0
- package/src/indexer/freshness.ts +166 -0
- package/src/indexer/git.ts +453 -0
- package/src/indexer/index.ts +1092 -0
- package/src/indexer/modules.ts +358 -0
- package/src/indexer/preflight.ts +548 -0
- package/src/indexer/protoScanner.ts +147 -0
- package/src/indexer/risk.ts +304 -0
- package/src/indexer/serviceHostScanner.ts +92 -0
- package/src/indexer/serviceLinks.ts +543 -0
- package/src/indexer/shapehash.ts +370 -0
- package/src/indexer/skeleton.ts +169 -0
- package/src/indexer/symbolhistory.ts +172 -0
- package/src/indexer/watcher.ts +206 -0
- package/src/mcp/server.ts +1659 -0
- package/src/parser/index.ts +37 -0
- package/src/parser/languages/cpp.ts +361 -0
- package/src/parser/languages/csharp.ts +235 -0
- package/src/parser/languages/go.ts +259 -0
- package/src/parser/languages/java.ts +382 -0
- package/src/parser/languages/python.ts +370 -0
- package/src/parser/languages/rust.ts +164 -0
- package/src/parser/languages/typescript.ts +1435 -0
- package/src/parser/parserContext.ts +392 -0
- package/src/parser/walker.ts +306 -0
- package/src/parser/worker.ts +181 -0
- package/src/parser/workerpool.ts +448 -0
- package/src/scip/format.ts +83 -0
- package/src/scip/import.ts +216 -0
- package/src/types.ts +457 -0
- package/tests/benchmark-service-links.ts +244 -0
- package/tests/bug-regressions.ts +626 -0
- package/tests/filters.ts +264 -0
- package/tests/fixtures/Counter.tsx +38 -0
- package/tests/fixtures/caller.ts +7 -0
- package/tests/fixtures/collisions.ts +23 -0
- package/tests/fixtures/local_helper.ts +5 -0
- package/tests/fixtures/overloads.java +17 -0
- package/tests/fixtures/remote_helper.ts +4 -0
- package/tests/fixtures/sample.c +15 -0
- package/tests/fixtures/sample.cpp +47 -0
- package/tests/fixtures/sample.cs +62 -0
- package/tests/fixtures/sample.go +68 -0
- package/tests/fixtures/sample.h +30 -0
- package/tests/fixtures/sample.java +85 -0
- package/tests/fixtures/sample.py +46 -0
- package/tests/fixtures/sample.rs +78 -0
- package/tests/fixtures/sample.ts +76 -0
- package/tests/fixtures-service/HttpClients.cs +30 -0
- package/tests/fixtures-service/HttpClients.java +24 -0
- package/tests/fixtures-service/billing.ts +15 -0
- package/tests/fixtures-service/docker-compose.yml +15 -0
- package/tests/fixtures-service/gateway.ts +10 -0
- package/tests/fixtures-service/get_user.ts +11 -0
- package/tests/fixtures-service/graphql_client.ts +63 -0
- package/tests/fixtures-service/graphql_server.ts +30 -0
- package/tests/fixtures-service/grpc_client.go +30 -0
- package/tests/fixtures-service/http_clients.go +23 -0
- package/tests/fixtures-service/http_clients.py +38 -0
- package/tests/fixtures-service/http_clients.ts +49 -0
- package/tests/fixtures-service/k8s/payment-service.yaml +22 -0
- package/tests/fixtures-service/k8s_calls.ts +20 -0
- package/tests/fixtures-service/messaging.ts +87 -0
- package/tests/fixtures-service/trpc_client.ts +39 -0
- package/tests/fixtures-service/trpc_server.ts +39 -0
- package/tests/fixtures-service/user_service.proto +33 -0
- package/tests/fixtures-trackcd/Cargo.toml +11 -0
- package/tests/fixtures-trackcd/SpringController.java +36 -0
- package/tests/fixtures-trackcd/auth_service.ts +19 -0
- package/tests/fixtures-trackcd/complex_module.py +50 -0
- package/tests/fixtures-trackcd/express_app.js +30 -0
- package/tests/fixtures-trackcd/fastapi_app.py +49 -0
- package/tests/fixtures-trackcd/fastify_object_routes.js +32 -0
- package/tests/fixtures-trackcd/go.mod +8 -0
- package/tests/fixtures-trackcd/package.json +15 -0
- package/tests/fixtures-trackcd/requirements.txt +4 -0
- package/tests/fixtures-trackcd/tests/auth_service.test.ts +13 -0
- package/tests/fixtures-tracke/auth/AuthService.ts +23 -0
- package/tests/fixtures-tracke/auth/crypto.ts +7 -0
- package/tests/fixtures-tracke/billing/Billing.ts +20 -0
- package/tests/fixtures-tracke/billing/Invoice.ts +10 -0
- package/tests/fixtures-tracke/billing/server.ts +17 -0
- package/tests/fixtures-tracke/package.json +7 -0
- package/tests/fixtures-tracke/tests/auth.test.ts +23 -0
- package/tests/fixtures-tracke/tests/billing.test.ts +14 -0
- package/tests/fixtures-trackf/package.json +5 -0
- package/tests/fixtures-trackf/src/auth.ts +26 -0
- package/tests/fixtures-trackf/src/handlers.ts +35 -0
- package/tests/fixtures-tracki/billing/routes.ts +12 -0
- package/tests/fixtures-tracki/gateway/client.ts +13 -0
- package/tests/git-features.ts +267 -0
- package/tests/init.ts +141 -0
- package/tests/mcp-jit.ts +130 -0
- package/tests/mcp-smoke.ts +191 -0
- package/tests/mcp-trackcd.ts +169 -0
- package/tests/mcp-tracke.ts +229 -0
- package/tests/mcp-trackf.ts +330 -0
- package/tests/mcp-trackg.ts +219 -0
- package/tests/mcp-tracki.ts +174 -0
- package/tests/mcp-watcher.ts +126 -0
- package/tests/optspec.ts +194 -0
- package/tests/parallel-index.ts +333 -0
- package/tests/parallel-read.ts +125 -0
- package/tests/parallel-recovery.ts +241 -0
- package/tests/perf-callers.ts +145 -0
- package/tests/query-parity.ts +184 -0
- package/tests/query-perf.ts +55 -0
- package/tests/scale-parallel-parity.ts +225 -0
- package/tests/scale-test.ts +523 -0
- package/tests/smoke.ts +396 -0
- package/tests/trackcd.ts +325 -0
- package/tests/tracke-collisions.ts +255 -0
- package/tests/tracke.ts +314 -0
- package/tests/trackf-bugs.ts +406 -0
- package/tests/trackf.ts +390 -0
- package/tests/trackg.ts +1372 -0
- package/tests/tracki-boundaries.ts +202 -0
- package/tests/tracki-continuity.ts +253 -0
- package/tests/tracki-contract-diff.ts +249 -0
- package/tests/tracki-external-bundles.ts +341 -0
- package/tests/tracki-preflight.ts +251 -0
- package/tests/verify-roles.ts +51 -0
- package/tests/worker-parity.ts +286 -0
- package/tests/worker-pool.ts +262 -0
- package/tsconfig.json +20 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
// Core shared types for the Seer indexer
|
|
2
|
+
|
|
3
|
+
export type Language =
|
|
4
|
+
| 'python'
|
|
5
|
+
| 'javascript'
|
|
6
|
+
| 'typescript'
|
|
7
|
+
| 'go'
|
|
8
|
+
| 'java'
|
|
9
|
+
| 'rust'
|
|
10
|
+
| 'c'
|
|
11
|
+
| 'cpp'
|
|
12
|
+
| 'csharp'
|
|
13
|
+
// v9 Track-H — proto files contribute routes (gRPC) but no symbols.
|
|
14
|
+
// They go through a regex scanner in `protoScanner.ts`, not tree-sitter.
|
|
15
|
+
| 'proto';
|
|
16
|
+
|
|
17
|
+
export type SymbolKind =
|
|
18
|
+
| 'function'
|
|
19
|
+
| 'class'
|
|
20
|
+
| 'method'
|
|
21
|
+
| 'interface'
|
|
22
|
+
| 'struct'
|
|
23
|
+
| 'enum'
|
|
24
|
+
| 'type'
|
|
25
|
+
| 'constructor'
|
|
26
|
+
| 'variable';
|
|
27
|
+
|
|
28
|
+
export type EdgeKind = 'call' | 'import' | 'inherits' | 'implements' | 'tests';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* What variety of symbol this row represents.
|
|
32
|
+
* - 'definition' — the canonical, body-bearing definition site. The default
|
|
33
|
+
* and the only role indexed by every extractor on every
|
|
34
|
+
* symbol historically. Rankable when the kind allows it.
|
|
35
|
+
* - 'declaration' — a forward declaration or prototype (no body). C/C++
|
|
36
|
+
* class-body method declarations and forward declarations
|
|
37
|
+
* fall here. Not rankable; excluded from agent-facing
|
|
38
|
+
* defaults unless `includeDeclarations=true`.
|
|
39
|
+
* - 'type_ref' — a bare use of a type name (no body, no declaration).
|
|
40
|
+
* Not yet emitted by any extractor — the slot exists so a
|
|
41
|
+
* future indexing mode can store reference sites without
|
|
42
|
+
* re-shaping the schema.
|
|
43
|
+
*/
|
|
44
|
+
export type SymbolRole = 'definition' | 'declaration' | 'type_ref';
|
|
45
|
+
|
|
46
|
+
// A symbol definition extracted from source
|
|
47
|
+
export interface SymbolDef {
|
|
48
|
+
name: string;
|
|
49
|
+
/**
|
|
50
|
+
* Dotted path including all enclosing class/struct/impl scopes.
|
|
51
|
+
* Computed by the walker from the def stack — extractors should not set it.
|
|
52
|
+
* E.g. `Alpha.run`, `AuthService.login`, `PaymentService.process_payment`.
|
|
53
|
+
* Equals `name` for top-level definitions.
|
|
54
|
+
*/
|
|
55
|
+
qualifiedName?: string;
|
|
56
|
+
kind: SymbolKind;
|
|
57
|
+
lineStart: number; // 0-indexed row
|
|
58
|
+
lineEnd: number;
|
|
59
|
+
colStart: number;
|
|
60
|
+
colEnd: number;
|
|
61
|
+
signature?: string; // first line of the definition, truncated
|
|
62
|
+
/**
|
|
63
|
+
* Complexity metrics, populated by language extractors via the walker.
|
|
64
|
+
* `loc`/`cyclomatic`/`cognitive`/`maxNesting` are non-null only for
|
|
65
|
+
* function-like symbols (function, method, constructor) where they make
|
|
66
|
+
* sense. For classes/structs/enums/types they stay null.
|
|
67
|
+
*/
|
|
68
|
+
loc?: number;
|
|
69
|
+
cyclomatic?: number;
|
|
70
|
+
cognitive?: number;
|
|
71
|
+
maxNesting?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Optional. When omitted, the Store treats this as `'definition'` —
|
|
74
|
+
* matches all pre-existing extractor behavior. C/C++ field_declaration
|
|
75
|
+
* (class-body method declarations) and forward declarations set this to
|
|
76
|
+
* `'declaration'` so default agent-facing queries can hide them.
|
|
77
|
+
*/
|
|
78
|
+
symbolRole?: SymbolRole;
|
|
79
|
+
/**
|
|
80
|
+
* Extra owning-scope segments that are NOT on the lexical definition stack.
|
|
81
|
+
* Used for out-of-line definitions whose declarator names a qualifier that
|
|
82
|
+
* the walker can't see lexically — e.g. a C++ method defined at namespace
|
|
83
|
+
* scope as `T Vec<T>::dot(...) { ... }` sets `scopePath = ['Vec']` so its
|
|
84
|
+
* qualified name becomes `geo.Vec.dot` (the true owner) instead of `geo.dot`
|
|
85
|
+
* (which reads like a free function). The walker folds these segments into
|
|
86
|
+
* the qualified name and keys overload disambiguation on (scope + name), so
|
|
87
|
+
* `Foo::bar` and `Baz::bar` stay distinct instead of collapsing to bar / bar#1.
|
|
88
|
+
* Extractors set short names only; this is the one sanctioned scope hint.
|
|
89
|
+
*/
|
|
90
|
+
scopePath?: string[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// A reference (call/usage) extracted from source
|
|
94
|
+
export interface SymbolRef {
|
|
95
|
+
calleeName: string; // the name being called/referenced
|
|
96
|
+
callerName: string; // name of the enclosing function/method, or '' for module level
|
|
97
|
+
kind: EdgeKind;
|
|
98
|
+
line: number; // 0-indexed row
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* v9 Track-H — protocols supported by the service-link layer. HTTP was the
|
|
103
|
+
* only protocol at v8; v9 generalizes to RPC/messaging/streaming protocols.
|
|
104
|
+
* Protocol-specific fields are stored sparsely on the same row.
|
|
105
|
+
*/
|
|
106
|
+
export type ServiceProtocol =
|
|
107
|
+
| 'http'
|
|
108
|
+
| 'trpc'
|
|
109
|
+
| 'graphql'
|
|
110
|
+
| 'grpc'
|
|
111
|
+
| 'kafka'
|
|
112
|
+
| 'sqs'
|
|
113
|
+
| 'sns'
|
|
114
|
+
| 'rabbitmq'
|
|
115
|
+
| 'nats'
|
|
116
|
+
| 'redis_pubsub'
|
|
117
|
+
| 'websocket'
|
|
118
|
+
| 'sse';
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* One route / endpoint detected during parsing.
|
|
122
|
+
*
|
|
123
|
+
* For HTTP (default): Express/Fastify/FastAPI/Flask/Spring routes. `method` +
|
|
124
|
+
* `path` carry the matchable contract; `framework` records the library.
|
|
125
|
+
*
|
|
126
|
+
* v9 Track-H: the same row shape now represents tRPC procedures, GraphQL
|
|
127
|
+
* resolvers, gRPC service methods, Kafka/SQS/RabbitMQ consumers, etc. The
|
|
128
|
+
* protocol-specific fields (operation/topic/queue/exchange/service/broker)
|
|
129
|
+
* are populated by the protocol's extractor and left undefined elsewhere.
|
|
130
|
+
*
|
|
131
|
+
* The handler is named when the route maps to a local function; the post-pass
|
|
132
|
+
* resolves `handlerName` → a `symbol_id` after all definitions are inserted.
|
|
133
|
+
*/
|
|
134
|
+
export interface RouteDef {
|
|
135
|
+
method: string;
|
|
136
|
+
path: string;
|
|
137
|
+
framework: string;
|
|
138
|
+
handlerName?: string;
|
|
139
|
+
line: number;
|
|
140
|
+
/** v9 Track-H. Defaults to 'http' when omitted (every pre-v9 RouteDef). */
|
|
141
|
+
protocol?: ServiceProtocol;
|
|
142
|
+
/** tRPC procedure path ('user.getById'), GraphQL operation name, gRPC method. */
|
|
143
|
+
operation?: string;
|
|
144
|
+
/** Kafka / pub-sub topic the consumer subscribes to. */
|
|
145
|
+
topic?: string;
|
|
146
|
+
/** SQS / RabbitMQ queue the consumer reads from. */
|
|
147
|
+
queue?: string;
|
|
148
|
+
/** RabbitMQ exchange. */
|
|
149
|
+
exchange?: string;
|
|
150
|
+
/** gRPC service name; k8s service hostname for HTTP routes inside a service module. */
|
|
151
|
+
service?: string;
|
|
152
|
+
/** Broker host / cluster identifier (kafka:9092, sqs.us-east-1, etc.). */
|
|
153
|
+
broker?: string;
|
|
154
|
+
/** Protocol-specific catch-all already serialized as JSON. */
|
|
155
|
+
metadataJson?: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** A static read of an environment variable or config key. */
|
|
159
|
+
export interface ConfigKeyRead {
|
|
160
|
+
key: string;
|
|
161
|
+
source: 'env' | 'config';
|
|
162
|
+
callerName?: string; // enclosing symbol qualified name, '' for module-level
|
|
163
|
+
line: number;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* One outbound HTTP client call detected during parsing — fetch / axios /
|
|
168
|
+
* requests / http.Get / HttpClient.GetAsync / etc.
|
|
169
|
+
*
|
|
170
|
+
* Routes are HANDLERS (registered with the framework so an incoming request
|
|
171
|
+
* lands on a function); ServiceCalls are CLIENTS (your code dialing OUT to
|
|
172
|
+
* another service). They are deliberately separate concepts; the post-index
|
|
173
|
+
* resolver rendezvous-matches calls to routes to build service_links.
|
|
174
|
+
*
|
|
175
|
+
* `rawTarget` always carries the literal/expression as written — if the path
|
|
176
|
+
* can't be confidently extracted, normalizedPath stays undefined but the call
|
|
177
|
+
* is still recorded so seer can show "this code calls something via fetch()"
|
|
178
|
+
* even when the target can't be resolved.
|
|
179
|
+
*
|
|
180
|
+
* `callerName` is the enclosing function/method's qualified name at the call
|
|
181
|
+
* site; the walker sets it from the def stack, and the indexer backfills the
|
|
182
|
+
* resolved symbol id from the symbolIdMap.
|
|
183
|
+
*/
|
|
184
|
+
export interface ServiceCallDef {
|
|
185
|
+
/** v9 Track-H — HTTP at v8; v9 generalizes to RPC / messaging / streaming. */
|
|
186
|
+
protocol: ServiceProtocol;
|
|
187
|
+
/** Upper-cased HTTP method when known: 'GET' | 'POST' | … | 'ANY' if unknown.
|
|
188
|
+
* For non-HTTP protocols, may carry the operation kind ('query'/'mutation'/'publish'). */
|
|
189
|
+
method?: string;
|
|
190
|
+
/** Original literal/expression text at the call site (truncated to 240 chars) */
|
|
191
|
+
rawTarget: string;
|
|
192
|
+
/** /api/users when extractable; undefined when dynamic and not recoverable */
|
|
193
|
+
normalizedPath?: string;
|
|
194
|
+
/** Hostname / service name (e.g. "payment-service") when present in the URL */
|
|
195
|
+
hostHint?: string;
|
|
196
|
+
/** Env-variable name used in URL building (e.g. "PAYMENT_URL") when seen */
|
|
197
|
+
envKey?: string;
|
|
198
|
+
/** Library that emitted this call: 'fetch' / 'axios' / 'requests' / 'http.Get' / 'trpc' / 'apollo' / … */
|
|
199
|
+
framework: string;
|
|
200
|
+
/** Enclosing symbol qualified name; '' for module-level reads */
|
|
201
|
+
callerName?: string;
|
|
202
|
+
line: number;
|
|
203
|
+
/**
|
|
204
|
+
* Extractor confidence (0..1). High (≥0.9) for unambiguous literal-path
|
|
205
|
+
* calls; lower when only a host or env key was recovered.
|
|
206
|
+
*/
|
|
207
|
+
confidence: number;
|
|
208
|
+
// ── v9 Track-H protocol-specific fields. All optional; only set the ones
|
|
209
|
+
// that apply to the protocol you're emitting.
|
|
210
|
+
/** tRPC procedure path ('user.getById'), GraphQL operation name, gRPC method. */
|
|
211
|
+
operation?: string;
|
|
212
|
+
/** Kafka / pub-sub topic this call publishes to. */
|
|
213
|
+
topic?: string;
|
|
214
|
+
/** SQS / RabbitMQ queue this call publishes to. */
|
|
215
|
+
queue?: string;
|
|
216
|
+
/** RabbitMQ exchange. */
|
|
217
|
+
exchange?: string;
|
|
218
|
+
/** gRPC service name; k8s service hostname for outbound HTTP. */
|
|
219
|
+
service?: string;
|
|
220
|
+
/** Broker host / cluster identifier. */
|
|
221
|
+
broker?: string;
|
|
222
|
+
/** Protocol-specific catch-all (serialized JSON object). */
|
|
223
|
+
metadataJson?: string;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Everything extracted from one file
|
|
227
|
+
export interface FileExtraction {
|
|
228
|
+
language: Language;
|
|
229
|
+
definitions: SymbolDef[];
|
|
230
|
+
references: SymbolRef[];
|
|
231
|
+
importedModules: string[]; // raw module/file paths imported
|
|
232
|
+
routes?: RouteDef[];
|
|
233
|
+
configKeys?: ConfigKeyRead[];
|
|
234
|
+
/** v8 Track G — HTTP/etc. client calls (outbound). Optional so legacy
|
|
235
|
+
* extractors that don't implement detection produce undefined / []. */
|
|
236
|
+
serviceCalls?: ServiceCallDef[];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ── DB result types ────────────────────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
export interface SymbolRow {
|
|
242
|
+
id: number;
|
|
243
|
+
name: string;
|
|
244
|
+
qualifiedName: string | null;
|
|
245
|
+
kind: string;
|
|
246
|
+
fileId: number;
|
|
247
|
+
filePath: string;
|
|
248
|
+
lineStart: number;
|
|
249
|
+
lineEnd: number;
|
|
250
|
+
signature: string | null;
|
|
251
|
+
pagerank: number;
|
|
252
|
+
loc?: number | null;
|
|
253
|
+
cyclomatic?: number | null;
|
|
254
|
+
cognitive?: number | null;
|
|
255
|
+
maxNesting?: number | null;
|
|
256
|
+
/**
|
|
257
|
+
* Stored variety of symbol. Null on pre-v5 DBs that haven't yet been
|
|
258
|
+
* re-indexed; the Store treats null as `'definition'` for filter logic.
|
|
259
|
+
*/
|
|
260
|
+
symbolRole?: SymbolRole | null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface CallerRow {
|
|
264
|
+
callerName: string;
|
|
265
|
+
callerQualifiedName: string | null;
|
|
266
|
+
callerKind: string;
|
|
267
|
+
callerFile: string;
|
|
268
|
+
callerLine: number;
|
|
269
|
+
edgeKind: string;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface CalleeRow {
|
|
273
|
+
calleeName: string;
|
|
274
|
+
calleeKind: string | null;
|
|
275
|
+
calleeFile: string | null;
|
|
276
|
+
calleeLineStart: number | null;
|
|
277
|
+
edgeKind: string;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface RouteRow {
|
|
281
|
+
id: number;
|
|
282
|
+
method: string;
|
|
283
|
+
path: string;
|
|
284
|
+
framework: string;
|
|
285
|
+
handlerName: string | null;
|
|
286
|
+
handlerId: number | null;
|
|
287
|
+
handlerSymbol: string | null;
|
|
288
|
+
handlerFile: string | null;
|
|
289
|
+
filePath: string;
|
|
290
|
+
line: number;
|
|
291
|
+
// v9 Track-H — NULL on pre-v9 DBs.
|
|
292
|
+
protocol?: string | null;
|
|
293
|
+
operation?: string | null;
|
|
294
|
+
topic?: string | null;
|
|
295
|
+
queue?: string | null;
|
|
296
|
+
exchange?: string | null;
|
|
297
|
+
service?: string | null;
|
|
298
|
+
broker?: string | null;
|
|
299
|
+
metadataJson?: string | null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export interface ExternalDepRow {
|
|
303
|
+
id: number;
|
|
304
|
+
ecosystem: string;
|
|
305
|
+
name: string;
|
|
306
|
+
versionRange: string | null;
|
|
307
|
+
manifestPath: string;
|
|
308
|
+
isDev: number;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export interface ConfigKeyRow {
|
|
312
|
+
id: number;
|
|
313
|
+
key: string;
|
|
314
|
+
source: string;
|
|
315
|
+
filePath: string;
|
|
316
|
+
symbolId: number | null;
|
|
317
|
+
symbolName: string | null;
|
|
318
|
+
line: number;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export interface FileChurnRow {
|
|
322
|
+
fileId: number;
|
|
323
|
+
filePath: string;
|
|
324
|
+
commitCount: number;
|
|
325
|
+
lastCommitSha: string | null;
|
|
326
|
+
lastCommitAt: number | null;
|
|
327
|
+
topAuthor: string | null;
|
|
328
|
+
secondAuthor: string | null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export interface SymbolHistoryRow {
|
|
332
|
+
id: number;
|
|
333
|
+
symbolId: number;
|
|
334
|
+
symbolKey: string;
|
|
335
|
+
commitSha: string;
|
|
336
|
+
authorName: string | null;
|
|
337
|
+
authorEmail: string | null;
|
|
338
|
+
committedAt: number;
|
|
339
|
+
message: string | null;
|
|
340
|
+
linesAdded: number;
|
|
341
|
+
linesRemoved: number;
|
|
342
|
+
prNumber: number | null;
|
|
343
|
+
prUrl: string | null;
|
|
344
|
+
matchStrategy: string;
|
|
345
|
+
confidence: number;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* v8 Track G — row returned by Store.listServiceCalls(). The caller is the
|
|
350
|
+
* AST-attributed enclosing function/method; the call always carries the raw
|
|
351
|
+
* literal/expression text as written.
|
|
352
|
+
*/
|
|
353
|
+
export interface ServiceCallRow {
|
|
354
|
+
id: number;
|
|
355
|
+
protocol: string;
|
|
356
|
+
method: string | null;
|
|
357
|
+
rawTarget: string;
|
|
358
|
+
normalizedPath: string | null;
|
|
359
|
+
hostHint: string | null;
|
|
360
|
+
envKey: string | null;
|
|
361
|
+
framework: string;
|
|
362
|
+
line: number;
|
|
363
|
+
confidence: number;
|
|
364
|
+
filePath: string;
|
|
365
|
+
callerSymbolId: number | null;
|
|
366
|
+
callerName: string | null;
|
|
367
|
+
callerQualifiedName: string | null;
|
|
368
|
+
callerKind: string | null;
|
|
369
|
+
// v9 Track-H — null on HTTP rows and pre-v9 DBs.
|
|
370
|
+
operation: string | null;
|
|
371
|
+
topic: string | null;
|
|
372
|
+
queue: string | null;
|
|
373
|
+
exchange: string | null;
|
|
374
|
+
service: string | null;
|
|
375
|
+
broker: string | null;
|
|
376
|
+
metadataJson: string | null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* v8 Track G — row returned by Store.listServiceLinks(). Each link rendezvous-
|
|
381
|
+
* matches one service_call (the caller side) with one route (the handler side)
|
|
382
|
+
* and carries the deterministic match_kind + confidence.
|
|
383
|
+
*/
|
|
384
|
+
export interface ServiceLinkRow {
|
|
385
|
+
id: number;
|
|
386
|
+
callId: number;
|
|
387
|
+
routeId: number | null;
|
|
388
|
+
protocol: string;
|
|
389
|
+
matchKind: string;
|
|
390
|
+
confidence: number;
|
|
391
|
+
evidenceJson: string;
|
|
392
|
+
// Caller side (snapshot from service_calls.symbol_id)
|
|
393
|
+
callerSymbolId: number | null;
|
|
394
|
+
callerName: string | null;
|
|
395
|
+
callerQualifiedName: string | null;
|
|
396
|
+
callerFile: string | null;
|
|
397
|
+
callerLine: number;
|
|
398
|
+
// Call details (forwarded from service_calls so consumers don't have to
|
|
399
|
+
// re-join twice)
|
|
400
|
+
callMethod: string | null;
|
|
401
|
+
callRawTarget: string;
|
|
402
|
+
callNormalizedPath: string | null;
|
|
403
|
+
callFramework: string;
|
|
404
|
+
callEnvKey: string | null;
|
|
405
|
+
callHostHint: string | null;
|
|
406
|
+
// Handler side (route.handler_id resolved to symbol)
|
|
407
|
+
handlerSymbolId: number | null;
|
|
408
|
+
handlerName: string | null;
|
|
409
|
+
handlerQualifiedName: string | null;
|
|
410
|
+
handlerFile: string | null;
|
|
411
|
+
handlerLine: number | null;
|
|
412
|
+
// Route details
|
|
413
|
+
routeMethod: string | null;
|
|
414
|
+
routePath: string | null;
|
|
415
|
+
routeFramework: string | null;
|
|
416
|
+
// v9 Track-H — protocol-specific fields on both sides of the link, null when N/A.
|
|
417
|
+
callOperation: string | null;
|
|
418
|
+
callTopic: string | null;
|
|
419
|
+
callQueue: string | null;
|
|
420
|
+
callService: string | null;
|
|
421
|
+
routeOperation: string | null;
|
|
422
|
+
routeTopic: string | null;
|
|
423
|
+
routeQueue: string | null;
|
|
424
|
+
routeService: string | null;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export interface StatsRow {
|
|
428
|
+
files: number;
|
|
429
|
+
symbols: number;
|
|
430
|
+
edges: number;
|
|
431
|
+
resolvedEdges: number;
|
|
432
|
+
languages: Record<string, number>;
|
|
433
|
+
roles?: { project: number; vendor: number; generated: number; test: number };
|
|
434
|
+
routes?: number;
|
|
435
|
+
externalDependencies?: number;
|
|
436
|
+
configKeys?: number;
|
|
437
|
+
symbolHistory?: number;
|
|
438
|
+
/** Number of clustered modules; 0 if the clustering pass hasn't run. */
|
|
439
|
+
modules?: number;
|
|
440
|
+
/** v7: SCIP files imported into this DB; 0 on pre-v7. */
|
|
441
|
+
scipImports?: number;
|
|
442
|
+
/** v7: symbols with a non-null structural shape_hash. */
|
|
443
|
+
shapeHashed?: number;
|
|
444
|
+
/**
|
|
445
|
+
* v7: symbol + edge counts grouped by provenance. Always present at v7;
|
|
446
|
+
* agents can use it to see how much precision SCIP contributed vs the
|
|
447
|
+
* tree-sitter baseline.
|
|
448
|
+
*/
|
|
449
|
+
provenance?: {
|
|
450
|
+
symbols: Record<string, number>;
|
|
451
|
+
edges: Record<string, number>;
|
|
452
|
+
};
|
|
453
|
+
/** v8 Track G — total service_calls rows (outbound HTTP/etc. clients). */
|
|
454
|
+
serviceCalls?: number;
|
|
455
|
+
/** v8 Track G — total service_links rows (caller↔handler rendezvous). */
|
|
456
|
+
serviceLinks?: number;
|
|
457
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SeerBench — service-link benchmark.
|
|
3
|
+
*
|
|
4
|
+
* Each task is a deterministic question over the fixtures-service workspace.
|
|
5
|
+
* The runner indexes the fixtures once, then for each task computes:
|
|
6
|
+
* - actual: the result returned by Seer-Core (no AI)
|
|
7
|
+
* - expected: the JSON answer we hand-wrote per task
|
|
8
|
+
* - precision: |actual ∩ expected| / |actual| (0 if actual empty when expected non-empty)
|
|
9
|
+
* - recall: |actual ∩ expected| / |expected|
|
|
10
|
+
*
|
|
11
|
+
* The suite fails (exit 1) when:
|
|
12
|
+
* - precision < 0.9 OR recall < 0.9 on any task
|
|
13
|
+
* - latency over the full suite exceeds the cap (5s — generous for fixtures)
|
|
14
|
+
* - any task throws
|
|
15
|
+
*
|
|
16
|
+
* This is a tiny benchmark; its purpose is to catch regressions in the
|
|
17
|
+
* service-link resolver (precision/recall drops) and to demonstrate that the
|
|
18
|
+
* answers Seer produces for these specific questions are stable.
|
|
19
|
+
*
|
|
20
|
+
* Run: npx tsx tests/benchmark-service-links.ts
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import path from 'path';
|
|
24
|
+
import fs from 'fs';
|
|
25
|
+
import os from 'os';
|
|
26
|
+
import { Indexer } from '../src/indexer/index';
|
|
27
|
+
import { Store } from '../src/db/store';
|
|
28
|
+
|
|
29
|
+
const FIX = path.join(__dirname, 'fixtures-service');
|
|
30
|
+
const TMP = path.join(os.tmpdir(), `seer-bench-${Date.now()}`);
|
|
31
|
+
fs.mkdirSync(TMP, { recursive: true });
|
|
32
|
+
const DB = path.join(TMP, 'bench.db');
|
|
33
|
+
|
|
34
|
+
interface BenchTask {
|
|
35
|
+
id: string;
|
|
36
|
+
question: string;
|
|
37
|
+
expected: Set<string>; // set of expected answer items (e.g. handler qnames)
|
|
38
|
+
run(store: Store): Set<string>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const tasks: BenchTask[] = [
|
|
42
|
+
{
|
|
43
|
+
id: 'http-handler-for-checkout-charge',
|
|
44
|
+
question: 'What handler receives the gateway service\'s POST /api/charge call?',
|
|
45
|
+
expected: new Set(['chargeHandler']),
|
|
46
|
+
run(store) {
|
|
47
|
+
const rows = store.rawDb().prepare(
|
|
48
|
+
`SELECT sh.qualified_name AS qn
|
|
49
|
+
FROM service_links sl
|
|
50
|
+
JOIN routes r ON r.id = sl.route_id
|
|
51
|
+
JOIN service_calls sc ON sc.id = sl.call_id
|
|
52
|
+
LEFT JOIN symbols sh ON sh.id = sl.handler_symbol_id
|
|
53
|
+
WHERE r.path = '/api/charge' AND sc.method = 'POST'`,
|
|
54
|
+
).all() as Array<{ qn: string }>;
|
|
55
|
+
return new Set(rows.map(r => r.qn).filter(Boolean));
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'trpc-handler-for-user-getbyid',
|
|
60
|
+
question: 'Which handler receives the trpc.user.getById.query() call?',
|
|
61
|
+
expected: new Set(['getUserById']),
|
|
62
|
+
run(store) {
|
|
63
|
+
const rows = store.rawDb().prepare(
|
|
64
|
+
`SELECT sh.qualified_name AS qn
|
|
65
|
+
FROM service_links sl
|
|
66
|
+
JOIN service_calls sc ON sc.id = sl.call_id
|
|
67
|
+
JOIN routes r ON r.id = sl.route_id
|
|
68
|
+
LEFT JOIN symbols sh ON sh.id = sl.handler_symbol_id
|
|
69
|
+
WHERE sl.protocol = 'trpc' AND r.operation = 'getById'`,
|
|
70
|
+
).all() as Array<{ qn: string }>;
|
|
71
|
+
return new Set(rows.map(r => r.qn).filter(Boolean));
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'graphql-resolver-for-user-query',
|
|
76
|
+
question: 'Which resolver receives the GraphQL "user" query operation?',
|
|
77
|
+
expected: new Set(['userResolver']),
|
|
78
|
+
run(store) {
|
|
79
|
+
const rows = store.rawDb().prepare(
|
|
80
|
+
`SELECT sh.qualified_name AS qn
|
|
81
|
+
FROM service_links sl
|
|
82
|
+
JOIN routes r ON r.id = sl.route_id
|
|
83
|
+
LEFT JOIN symbols sh ON sh.id = sl.handler_symbol_id
|
|
84
|
+
WHERE sl.protocol = 'graphql' AND r.operation = 'user'`,
|
|
85
|
+
).all() as Array<{ qn: string }>;
|
|
86
|
+
return new Set(rows.map(r => r.qn).filter(Boolean));
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'grpc-method-for-userservice-getuser',
|
|
91
|
+
question: 'Which gRPC rpc receives the UserService.GetUser client call?',
|
|
92
|
+
expected: new Set(['UserService/GetUser']),
|
|
93
|
+
run(store) {
|
|
94
|
+
const rows = store.rawDb().prepare(
|
|
95
|
+
`SELECT r.operation AS op
|
|
96
|
+
FROM service_links sl
|
|
97
|
+
JOIN routes r ON r.id = sl.route_id
|
|
98
|
+
WHERE sl.protocol = 'grpc' AND r.operation = 'UserService/GetUser'`,
|
|
99
|
+
).all() as Array<{ op: string }>;
|
|
100
|
+
return new Set(rows.map(r => r.op));
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: 'kafka-producers-for-orders-topic',
|
|
105
|
+
question: 'Which functions publish to the Kafka "orders" topic?',
|
|
106
|
+
expected: new Set(['produceOrders']),
|
|
107
|
+
run(store) {
|
|
108
|
+
const rows = store.rawDb().prepare(
|
|
109
|
+
`SELECT s.qualified_name AS qn
|
|
110
|
+
FROM service_calls sc
|
|
111
|
+
LEFT JOIN symbols s ON s.id = sc.symbol_id
|
|
112
|
+
WHERE sc.protocol = 'kafka' AND sc.topic = 'orders'`,
|
|
113
|
+
).all() as Array<{ qn: string }>;
|
|
114
|
+
return new Set(rows.map(r => r.qn).filter(Boolean));
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: 'kafka-consumers-for-orders-topic',
|
|
119
|
+
question: 'Which functions consume the Kafka "orders" topic?',
|
|
120
|
+
expected: new Set(['subscribeOrders']),
|
|
121
|
+
run(store) {
|
|
122
|
+
// Consumers register a route; we want the file/symbol that calls
|
|
123
|
+
// consumer.subscribe(...). We approximate by finding any symbol whose
|
|
124
|
+
// qualified name matches the file's known consumer.
|
|
125
|
+
const rows = store.rawDb().prepare(
|
|
126
|
+
`SELECT s.qualified_name AS qn
|
|
127
|
+
FROM routes r
|
|
128
|
+
JOIN files f ON f.id = r.file_id
|
|
129
|
+
JOIN symbols s ON s.file_id = r.file_id
|
|
130
|
+
AND s.line_start <= r.line
|
|
131
|
+
AND s.line_end >= r.line
|
|
132
|
+
WHERE r.protocol = 'kafka' AND r.topic = 'orders'
|
|
133
|
+
AND s.kind IN ('function','method')
|
|
134
|
+
ORDER BY (r.line - s.line_start) ASC LIMIT 1`,
|
|
135
|
+
).all() as Array<{ qn: string }>;
|
|
136
|
+
return new Set(rows.map(r => r.qn).filter(Boolean));
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: 'sqs-consumers-for-job-queue',
|
|
141
|
+
question: 'Which consumers handle the "job-queue" SQS queue?',
|
|
142
|
+
expected: new Set(['consumeJob']),
|
|
143
|
+
run(store) {
|
|
144
|
+
const rows = store.rawDb().prepare(
|
|
145
|
+
`SELECT s.qualified_name AS qn
|
|
146
|
+
FROM routes r
|
|
147
|
+
JOIN files f ON f.id = r.file_id
|
|
148
|
+
JOIN symbols s ON s.file_id = r.file_id
|
|
149
|
+
AND s.line_start <= r.line
|
|
150
|
+
AND s.line_end >= r.line
|
|
151
|
+
WHERE r.protocol = 'sqs' AND r.queue = 'job-queue'
|
|
152
|
+
AND s.kind IN ('function','method')
|
|
153
|
+
ORDER BY (r.line - s.line_start) ASC LIMIT 1`,
|
|
154
|
+
).all() as Array<{ qn: string }>;
|
|
155
|
+
return new Set(rows.map(r => r.qn).filter(Boolean));
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: 'service-host-link-payment',
|
|
160
|
+
question: 'Which calls were classified as service_host matches via the payment-service k8s host?',
|
|
161
|
+
expected: new Set(['paymentCall']),
|
|
162
|
+
run(store) {
|
|
163
|
+
const rows = store.rawDb().prepare(
|
|
164
|
+
`SELECT sc.qualified_name AS qn
|
|
165
|
+
FROM service_links sl
|
|
166
|
+
JOIN service_calls c ON c.id = sl.call_id
|
|
167
|
+
LEFT JOIN symbols sc ON sc.id = sl.caller_symbol_id
|
|
168
|
+
WHERE sl.match_kind = 'service_host' AND c.host_hint = 'payment-service'`,
|
|
169
|
+
).all() as Array<{ qn: string }>;
|
|
170
|
+
return new Set(rows.map(r => r.qn).filter(Boolean));
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
function intersect(a: Set<string>, b: Set<string>): Set<string> {
|
|
176
|
+
const out = new Set<string>();
|
|
177
|
+
for (const x of a) if (b.has(x)) out.add(x);
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function main(): Promise<void> {
|
|
182
|
+
console.log('\nSeerBench — service-link benchmark');
|
|
183
|
+
console.log('===================================\n');
|
|
184
|
+
const startSetup = Date.now();
|
|
185
|
+
const store = new Store(DB);
|
|
186
|
+
await new Indexer(store).indexDirectory(FIX, { quiet: true });
|
|
187
|
+
const setupMs = Date.now() - startSetup;
|
|
188
|
+
console.log(` setup: indexed fixtures-service in ${setupMs}ms\n`);
|
|
189
|
+
|
|
190
|
+
let totalLatency = 0;
|
|
191
|
+
let regressions = 0;
|
|
192
|
+
let toolCalls = 0;
|
|
193
|
+
let bytes = 0;
|
|
194
|
+
|
|
195
|
+
for (const t of tasks) {
|
|
196
|
+
const start = Date.now();
|
|
197
|
+
let actual: Set<string> = new Set();
|
|
198
|
+
let err: unknown = null;
|
|
199
|
+
try { actual = t.run(store); } catch (e) { err = e; }
|
|
200
|
+
const latency = Date.now() - start;
|
|
201
|
+
totalLatency += latency;
|
|
202
|
+
toolCalls += 1;
|
|
203
|
+
const actualJson = JSON.stringify(Array.from(actual).sort());
|
|
204
|
+
bytes += actualJson.length;
|
|
205
|
+
const inter = intersect(actual, t.expected);
|
|
206
|
+
const precision = actual.size === 0 ? (t.expected.size === 0 ? 1 : 0) : inter.size / actual.size;
|
|
207
|
+
const recall = t.expected.size === 0 ? 1 : inter.size / t.expected.size;
|
|
208
|
+
const okPrec = precision >= 0.9;
|
|
209
|
+
const okRec = recall >= 0.9;
|
|
210
|
+
const mark = (okPrec && okRec && !err) ? '✓' : '✗';
|
|
211
|
+
console.log(` ${mark} [${t.id}] precision=${precision.toFixed(2)} recall=${recall.toFixed(2)} latency=${latency}ms`);
|
|
212
|
+
if (err) {
|
|
213
|
+
console.log(` ! threw: ${err}`);
|
|
214
|
+
regressions++;
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (!okPrec || !okRec) {
|
|
218
|
+
console.log(` expected=${JSON.stringify([...t.expected])} actual=${actualJson}`);
|
|
219
|
+
regressions++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
console.log(`\nSummary:`);
|
|
224
|
+
console.log(` tasks: ${tasks.length}`);
|
|
225
|
+
console.log(` regressions: ${regressions}`);
|
|
226
|
+
console.log(` total latency: ${totalLatency}ms`);
|
|
227
|
+
console.log(` tool calls: ${toolCalls}`);
|
|
228
|
+
console.log(` output bytes: ${bytes}`);
|
|
229
|
+
|
|
230
|
+
store.close();
|
|
231
|
+
try { fs.rmSync(TMP, { recursive: true, force: true }); } catch { /* */ }
|
|
232
|
+
|
|
233
|
+
// Latency cap: 5 seconds for the full suite over a tiny fixture set is
|
|
234
|
+
// very generous; if we ever blow past it, something pathological has
|
|
235
|
+
// happened in the resolver.
|
|
236
|
+
if (totalLatency > 5000) {
|
|
237
|
+
console.error(`✗ total latency ${totalLatency}ms > 5000ms cap`);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
if (regressions > 0) process.exit(1);
|
|
241
|
+
console.log(`\n ✓ all ${tasks.length} bench tasks within precision/recall ≥ 0.9`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
main().catch(err => { console.error('benchmark crashed:', err); process.exit(1); });
|