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/tests/smoke.ts
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smoke test — run with: npm test (or: npx tsx tests/smoke.ts)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
import { Indexer } from '../src/indexer/index';
|
|
9
|
+
import { Store } from '../src/db/store';
|
|
10
|
+
|
|
11
|
+
const FIXTURES_DIR = path.join(__dirname, 'fixtures');
|
|
12
|
+
const TMP_DB = path.join(os.tmpdir(), `seer-smoke-${Date.now()}.db`);
|
|
13
|
+
|
|
14
|
+
let passed = 0;
|
|
15
|
+
let failed = 0;
|
|
16
|
+
|
|
17
|
+
function assert(condition: boolean, message: string): void {
|
|
18
|
+
if (condition) {
|
|
19
|
+
console.log(` ✓ ${message}`);
|
|
20
|
+
passed++;
|
|
21
|
+
} else {
|
|
22
|
+
console.error(` ✗ ${message}`);
|
|
23
|
+
failed++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function assertGte(actual: number, min: number, label: string): void {
|
|
28
|
+
assert(actual >= min, `${label}: ${actual} >= ${min}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function run(): Promise<void> {
|
|
32
|
+
console.log('\nSeer Smoke Test');
|
|
33
|
+
console.log('=================\n');
|
|
34
|
+
|
|
35
|
+
const store = new Store(TMP_DB);
|
|
36
|
+
const indexer = new Indexer(store);
|
|
37
|
+
|
|
38
|
+
console.log(`Indexing ${FIXTURES_DIR}...\n`);
|
|
39
|
+
const result = await indexer.indexDirectory(FIXTURES_DIR, { verbose: true });
|
|
40
|
+
|
|
41
|
+
console.log('\n── Indexing results ──────────────────────────────────────────\n');
|
|
42
|
+
assertGte(result.filesIndexed, 5, 'indexed 5+ fixture files');
|
|
43
|
+
assertGte(result.symbols, 20, 'extracted 20+ symbols');
|
|
44
|
+
assertGte(result.edges, 5, 'found 5+ call edges');
|
|
45
|
+
assertGte(result.resolvedEdges, 1, 'resolved 1+ edges');
|
|
46
|
+
|
|
47
|
+
// ── Per-language checks ──────────────────────────────────────────────────────
|
|
48
|
+
console.log('\n── Per-language checks ───────────────────────────────────────\n');
|
|
49
|
+
const stats = store.getStats();
|
|
50
|
+
assert('python' in stats.languages, 'Python indexed');
|
|
51
|
+
assert('typescript' in stats.languages, 'TypeScript indexed');
|
|
52
|
+
assert('go' in stats.languages, 'Go indexed');
|
|
53
|
+
assert('java' in stats.languages, 'Java indexed');
|
|
54
|
+
assert('rust' in stats.languages, 'Rust indexed');
|
|
55
|
+
assert('c' in stats.languages, 'C indexed');
|
|
56
|
+
assert('cpp' in stats.languages, 'C++ indexed');
|
|
57
|
+
assert('csharp' in stats.languages, 'C# indexed');
|
|
58
|
+
|
|
59
|
+
// ── Symbol queries ───────────────────────────────────────────────────────────
|
|
60
|
+
console.log('\n── Symbol queries ────────────────────────────────────────────\n');
|
|
61
|
+
|
|
62
|
+
const pyClass = store.findSymbols('PaymentService');
|
|
63
|
+
assert(pyClass.length >= 1, `findSymbols('PaymentService') → ${pyClass.length}`);
|
|
64
|
+
|
|
65
|
+
const validateFn = store.findSymbols('validate_amount');
|
|
66
|
+
assert(validateFn.length >= 1, `findSymbols('validate_amount') → ${validateFn.length}`);
|
|
67
|
+
|
|
68
|
+
const authSvc = store.findSymbols('AuthService');
|
|
69
|
+
assert(authSvc.length >= 1, `findSymbols('AuthService') → ${authSvc.length}`);
|
|
70
|
+
|
|
71
|
+
const userRepo = store.findSymbols('UserRepository');
|
|
72
|
+
assert(userRepo.length >= 1, `findSymbols('UserRepository') → ${userRepo.length}`);
|
|
73
|
+
|
|
74
|
+
const orderProc = store.findSymbols('OrderProcessor');
|
|
75
|
+
assert(orderProc.length >= 1, `findSymbols('OrderProcessor') → ${orderProc.length}`);
|
|
76
|
+
|
|
77
|
+
// ── Caller / callee queries ──────────────────────────────────────────────────
|
|
78
|
+
console.log('\n── Call-graph queries ────────────────────────────────────────\n');
|
|
79
|
+
|
|
80
|
+
const callers = store.findCallers('validate_amount');
|
|
81
|
+
console.log(` findCallers('validate_amount'): ${callers.length} caller(s)`);
|
|
82
|
+
for (const c of callers) {
|
|
83
|
+
console.log(` ${c.callerName} (${c.callerKind}) in ${path.basename(c.callerFile)}`);
|
|
84
|
+
}
|
|
85
|
+
assert(callers.length >= 1, 'validate_amount has ≥1 caller');
|
|
86
|
+
|
|
87
|
+
const callees = store.findCallees('process_payment');
|
|
88
|
+
console.log(`\n findCallees('process_payment'): ${callees.length} callee(s)`);
|
|
89
|
+
for (const c of callees) {
|
|
90
|
+
const loc = c.calleeFile ? path.basename(c.calleeFile) : 'unresolved';
|
|
91
|
+
console.log(` → ${c.calleeName} (${loc})`);
|
|
92
|
+
}
|
|
93
|
+
assert(callees.length >= 1, 'process_payment has ≥1 callee');
|
|
94
|
+
|
|
95
|
+
// ── Fix B: `new X()` constructor calls ───────────────────────────────────────
|
|
96
|
+
console.log('\n── new_expression tracking ──────────────────────────────────\n');
|
|
97
|
+
|
|
98
|
+
const authCtorCallers = store.findCallers('AuthService');
|
|
99
|
+
console.log(` findCallers('AuthService'): ${authCtorCallers.length} caller(s)`);
|
|
100
|
+
for (const c of authCtorCallers) {
|
|
101
|
+
console.log(` ${c.callerName} (${c.callerKind}) in ${path.basename(c.callerFile)}`);
|
|
102
|
+
}
|
|
103
|
+
assert(
|
|
104
|
+
authCtorCallers.some(c => c.callerName === 'createAuthService'),
|
|
105
|
+
'createAuthService is recorded as caller of AuthService (new_expression tracked)',
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// ── Fix C: qualified names disambiguate colliding method names ───────────────
|
|
109
|
+
console.log('\n── Qualified names / method collisions ──────────────────────\n');
|
|
110
|
+
|
|
111
|
+
const runSyms = store.findSymbols('run').filter(s => s.kind === 'method');
|
|
112
|
+
console.log(` findSymbols('run') methods: ${runSyms.length}`);
|
|
113
|
+
for (const s of runSyms) {
|
|
114
|
+
console.log(` ${s.name} qualified=${s.qualifiedName} in ${path.basename(s.filePath)}`);
|
|
115
|
+
}
|
|
116
|
+
const collisionMethods = runSyms.filter(s => s.filePath.endsWith('collisions.ts'));
|
|
117
|
+
assert(collisionMethods.length === 2, 'collisions.ts has exactly 2 `run` methods');
|
|
118
|
+
|
|
119
|
+
const qualified = collisionMethods.map(s => s.qualifiedName).sort();
|
|
120
|
+
assert(
|
|
121
|
+
qualified[0] === 'Alpha.run' && qualified[1] === 'Beta.run',
|
|
122
|
+
`qualified names are 'Alpha.run' and 'Beta.run' (got ${JSON.stringify(qualified)})`,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Rust impl-block context should also be reflected in qualified names
|
|
126
|
+
const loginSyms = store.findSymbols('login').filter(s => s.filePath.endsWith('sample.rs'));
|
|
127
|
+
assert(
|
|
128
|
+
loginSyms.some(s => s.qualifiedName === 'AuthService.login'),
|
|
129
|
+
`Rust impl method qualified as 'AuthService.login' (got ${loginSyms.map(s => s.qualifiedName).join(', ')})`,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Call-graph attribution: alphaOnly() must be attributed to Alpha.run, not Beta.run.
|
|
133
|
+
// betaOnly() must be attributed to Beta.run, not Alpha.run.
|
|
134
|
+
// Bug: walker used defStack.last (short name), so both 'run' methods shared one symbolIdMap entry.
|
|
135
|
+
const alphaOnlyCallers = store.findCallers('alphaOnly');
|
|
136
|
+
console.log(` findCallers('alphaOnly'): ${alphaOnlyCallers.length}`);
|
|
137
|
+
for (const c of alphaOnlyCallers) {
|
|
138
|
+
console.log(` ${c.callerQualifiedName ?? c.callerName} in ${path.basename(c.callerFile)}`);
|
|
139
|
+
}
|
|
140
|
+
assert(
|
|
141
|
+
alphaOnlyCallers.some(c => c.callerQualifiedName === 'Alpha.run'),
|
|
142
|
+
`alphaOnly() attributed to Alpha.run (got ${alphaOnlyCallers.map(c => c.callerQualifiedName).join(', ')})`,
|
|
143
|
+
);
|
|
144
|
+
assert(
|
|
145
|
+
!alphaOnlyCallers.some(c => c.callerQualifiedName === 'Beta.run'),
|
|
146
|
+
'alphaOnly() not attributed to Beta.run',
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const betaOnlyCallers = store.findCallers('betaOnly');
|
|
150
|
+
console.log(` findCallers('betaOnly'): ${betaOnlyCallers.length}`);
|
|
151
|
+
for (const c of betaOnlyCallers) {
|
|
152
|
+
console.log(` ${c.callerQualifiedName ?? c.callerName} in ${path.basename(c.callerFile)}`);
|
|
153
|
+
}
|
|
154
|
+
assert(
|
|
155
|
+
betaOnlyCallers.some(c => c.callerQualifiedName === 'Beta.run'),
|
|
156
|
+
`betaOnly() attributed to Beta.run (got ${betaOnlyCallers.map(c => c.callerQualifiedName).join(', ')})`,
|
|
157
|
+
);
|
|
158
|
+
assert(
|
|
159
|
+
!betaOnlyCallers.some(c => c.callerQualifiedName === 'Alpha.run'),
|
|
160
|
+
'betaOnly() not attributed to Alpha.run',
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// ── Overload disambiguation ───────────────────────────────────────────────────
|
|
164
|
+
console.log('\n── Overload disambiguation ──────────────────────────────────\n');
|
|
165
|
+
|
|
166
|
+
// In overloads.java: Overload.run(int) calls javaOnly1, Overload.run(String) calls javaOnly2.
|
|
167
|
+
// Both have qualified name Overload.run before the fix; the second becomes Overload.run#1 after.
|
|
168
|
+
const javaOnly1Callers = store.findCallers('javaOnly1');
|
|
169
|
+
console.log(` findCallers('javaOnly1'): ${javaOnly1Callers.length}`);
|
|
170
|
+
for (const c of javaOnly1Callers) {
|
|
171
|
+
console.log(` ${c.callerQualifiedName ?? c.callerName} in ${path.basename(c.callerFile)}`);
|
|
172
|
+
}
|
|
173
|
+
assert(
|
|
174
|
+
javaOnly1Callers.some(c => c.callerQualifiedName === 'Overload.run'),
|
|
175
|
+
`javaOnly1 attributed to Overload.run (first overload) (got ${javaOnly1Callers.map(c => c.callerQualifiedName).join(', ')})`,
|
|
176
|
+
);
|
|
177
|
+
assert(
|
|
178
|
+
!javaOnly1Callers.some(c => c.callerQualifiedName === 'Overload.run#1'),
|
|
179
|
+
'javaOnly1 not attributed to Overload.run#1',
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const javaOnly2Callers = store.findCallers('javaOnly2');
|
|
183
|
+
console.log(` findCallers('javaOnly2'): ${javaOnly2Callers.length}`);
|
|
184
|
+
for (const c of javaOnly2Callers) {
|
|
185
|
+
console.log(` ${c.callerQualifiedName ?? c.callerName} in ${path.basename(c.callerFile)}`);
|
|
186
|
+
}
|
|
187
|
+
assert(
|
|
188
|
+
javaOnly2Callers.some(c => c.callerQualifiedName === 'Overload.run#1'),
|
|
189
|
+
`javaOnly2 attributed to Overload.run#1 (second overload) (got ${javaOnly2Callers.map(c => c.callerQualifiedName).join(', ')})`,
|
|
190
|
+
);
|
|
191
|
+
assert(
|
|
192
|
+
!javaOnly2Callers.some(c => c.callerQualifiedName === 'Overload.run'),
|
|
193
|
+
'javaOnly2 not attributed to Overload.run',
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
// ── Fix A: scope-aware (import-based) resolution ─────────────────────────────
|
|
197
|
+
console.log('\n── Scope-aware edge resolution ──────────────────────────────\n');
|
|
198
|
+
|
|
199
|
+
const callCheckCallees = store.findCallees('callCheck');
|
|
200
|
+
console.log(` findCallees('callCheck'): ${callCheckCallees.length} callee(s)`);
|
|
201
|
+
for (const c of callCheckCallees) {
|
|
202
|
+
console.log(` → ${c.calleeName} in ${c.calleeFile ? path.basename(c.calleeFile) : 'unresolved'}`);
|
|
203
|
+
}
|
|
204
|
+
const checkCallee = callCheckCallees.find(c => c.calleeName === 'check');
|
|
205
|
+
assert(checkCallee !== undefined, "callCheck has a 'check' callee");
|
|
206
|
+
assert(
|
|
207
|
+
checkCallee?.calleeFile?.endsWith('remote_helper.ts') ?? false,
|
|
208
|
+
`'check' resolved to remote_helper.ts, not local_helper.ts (got ${checkCallee?.calleeFile})`,
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
// ── Resolution breakdown summary ─────────────────────────────────────────────
|
|
212
|
+
console.log('\n Edge resolution breakdown:');
|
|
213
|
+
console.log(` same-file: ${result.edgeResolution.sameFile}`);
|
|
214
|
+
console.log(` imported: ${result.edgeResolution.imported}`);
|
|
215
|
+
console.log(` global: ${result.edgeResolution.global}`);
|
|
216
|
+
console.log(` imports resolved to files: ${result.resolvedImports}`);
|
|
217
|
+
assert(result.edgeResolution.imported >= 1, 'at least one edge resolved via import scope');
|
|
218
|
+
assert(result.resolvedImports >= 1, 'at least one file_import resolved to a file');
|
|
219
|
+
|
|
220
|
+
// ── C source files ──────────────────────────────────────────────────────────
|
|
221
|
+
console.log('\n── C source files ───────────────────────────────────────\n');
|
|
222
|
+
|
|
223
|
+
const cEntry = store.findSymbols('c_entrypoint');
|
|
224
|
+
assert(
|
|
225
|
+
cEntry.some(s => s.filePath.endsWith('sample.c')),
|
|
226
|
+
'C .c file parsed — c_entrypoint symbol present',
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const cHelperCallers = store.findCallers('c_helper');
|
|
230
|
+
console.log(` findCallers('c_helper'): ${cHelperCallers.length}`);
|
|
231
|
+
for (const c of cHelperCallers) {
|
|
232
|
+
console.log(` ${c.callerName} in ${path.basename(c.callerFile)}`);
|
|
233
|
+
}
|
|
234
|
+
assert(
|
|
235
|
+
cHelperCallers.some(c => c.callerName === 'c_entrypoint'),
|
|
236
|
+
'C call c_helper() attributed to c_entrypoint',
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
// ── C++ (Unreal-style) ───────────────────────────────────────────────────────
|
|
240
|
+
console.log('\n── C++ (Unreal-style) ───────────────────────────────────────\n');
|
|
241
|
+
|
|
242
|
+
const pickupClass = store.findSymbols('APickupItem');
|
|
243
|
+
assert(
|
|
244
|
+
pickupClass.some(s => s.kind === 'class'),
|
|
245
|
+
'C++ class APickupItem extracted',
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
// Out-of-line method definition `APickupItem::OnPickedUp` should be picked up
|
|
249
|
+
const onPickedUp = store.findSymbols('OnPickedUp');
|
|
250
|
+
assert(
|
|
251
|
+
onPickedUp.length >= 1,
|
|
252
|
+
`C++ out-of-line method 'OnPickedUp' extracted (got ${onPickedUp.length})`,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
// PlayPickupSound is called twice (BeginPlay + OnPickedUp) — should have ≥2 callers
|
|
256
|
+
const playSoundCallers = store.findCallers('PlayPickupSound');
|
|
257
|
+
console.log(` findCallers('PlayPickupSound'): ${playSoundCallers.length}`);
|
|
258
|
+
for (const c of playSoundCallers) {
|
|
259
|
+
console.log(` ${c.callerName} (${c.callerKind})`);
|
|
260
|
+
}
|
|
261
|
+
assert(
|
|
262
|
+
playSoundCallers.length >= 2,
|
|
263
|
+
`PlayPickupSound has ≥2 callers (BeginPlay + OnPickedUp) — got ${playSoundCallers.length}`,
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
// qualified_identifier call: `UGameplayStatics::PlaySound2D` — the callee
|
|
267
|
+
// name should be `PlaySound2D`, attributed to the enclosing method
|
|
268
|
+
const playSound2DCallers = store.findCallers('PlaySound2D');
|
|
269
|
+
assert(
|
|
270
|
+
playSound2DCallers.some(c => c.callerName === 'PlayPickupSound'),
|
|
271
|
+
'qualified call UGameplayStatics::PlaySound2D attributed to PlayPickupSound',
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
// ── C# (Godot-style) ─────────────────────────────────────────────────────────
|
|
275
|
+
console.log('\n── C# (Godot-style) ─────────────────────────────────────────\n');
|
|
276
|
+
|
|
277
|
+
const playerClass = store.findSymbols('Player').filter(s => s.kind === 'class');
|
|
278
|
+
assert(playerClass.length >= 1, 'C# Player class extracted');
|
|
279
|
+
|
|
280
|
+
// `new InventoryService()` inside _Ready should be tracked as a call edge
|
|
281
|
+
const invSvcCallers = store.findCallers('InventoryService');
|
|
282
|
+
console.log(` findCallers('InventoryService'): ${invSvcCallers.length}`);
|
|
283
|
+
for (const c of invSvcCallers) {
|
|
284
|
+
console.log(` ${c.callerName} (${c.callerKind})`);
|
|
285
|
+
}
|
|
286
|
+
assert(
|
|
287
|
+
invSvcCallers.some(c => c.callerName === '_Ready'),
|
|
288
|
+
'C# `new InventoryService()` recorded as caller from _Ready',
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
// Cross-class method call: ResetState calls inventory.Clear()
|
|
292
|
+
const clearCallers = store.findCallers('Clear');
|
|
293
|
+
assert(
|
|
294
|
+
clearCallers.some(c => c.callerName === 'ResetState'),
|
|
295
|
+
'C# member access call Clear() attributed to ResetState',
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
// ── React (TSX with JSX) — Counter.tsx ───────────────────────────────────────
|
|
299
|
+
console.log('\n── React (TSX with JSX) ─────────────────────────────────────\n');
|
|
300
|
+
|
|
301
|
+
// If TSX grammar routing is broken, the file silently fails to parse and
|
|
302
|
+
// these symbols won't exist at all.
|
|
303
|
+
const counterFn = store.findSymbols('Counter').filter(
|
|
304
|
+
s => s.filePath.endsWith('Counter.tsx'),
|
|
305
|
+
);
|
|
306
|
+
assert(counterFn.length >= 1, 'TSX file parsed — Counter symbol present');
|
|
307
|
+
|
|
308
|
+
const dashboardFn = store.findSymbols('Dashboard').filter(
|
|
309
|
+
s => s.filePath.endsWith('Counter.tsx'),
|
|
310
|
+
);
|
|
311
|
+
assert(dashboardFn.length >= 1, 'TSX file parsed — Dashboard symbol present');
|
|
312
|
+
|
|
313
|
+
// formatLabel called inside the JSX body — should still be tracked as a call
|
|
314
|
+
const formatLabelCallers = store.findCallers('formatLabel');
|
|
315
|
+
console.log(` findCallers('formatLabel'): ${formatLabelCallers.length}`);
|
|
316
|
+
for (const c of formatLabelCallers) {
|
|
317
|
+
console.log(` ${c.callerName} in ${path.basename(c.callerFile)}`);
|
|
318
|
+
}
|
|
319
|
+
assert(
|
|
320
|
+
formatLabelCallers.some(c => c.callerName === 'Counter'),
|
|
321
|
+
'formatLabel call inside JSX attributed to Counter',
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
// ── PageRank ─────────────────────────────────────────────────────────────────
|
|
325
|
+
console.log('\n── PageRank ──────────────────────────────────────────────────\n');
|
|
326
|
+
|
|
327
|
+
const topSyms = store.getTopSymbols(10);
|
|
328
|
+
console.log(' Top 10 symbols by PageRank:');
|
|
329
|
+
for (const s of topSyms) {
|
|
330
|
+
console.log(` ${s.pagerank.toFixed(5)} ${s.name.padEnd(28)} (${s.kind})`);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const pagerankValues = topSyms.map(s => s.pagerank);
|
|
334
|
+
const hasVariance = new Set(pagerankValues.map(v => v.toFixed(5))).size > 1;
|
|
335
|
+
assert(hasVariance, 'PageRank values differ between symbols');
|
|
336
|
+
assertGte(topSyms.length, 5, '5+ symbols ranked');
|
|
337
|
+
|
|
338
|
+
// First-run pagerank MUST have been computed (we just built the graph).
|
|
339
|
+
assert(result.pagerankRecomputed === true, 'fresh index recomputed PageRank');
|
|
340
|
+
|
|
341
|
+
// ── findCallers limit + countCallers ─────────────────────────────────────────
|
|
342
|
+
// Regression net for the perf fix: pushing LIMIT into SQL must produce a
|
|
343
|
+
// strict subset of the unbounded result, and countCallers must agree with
|
|
344
|
+
// the unbounded length. Fixtures don't have 100k-fan-in symbols, but the
|
|
345
|
+
// semantic checks here catch the contract; the high-fan-in perf is verified
|
|
346
|
+
// out-of-band against the scale-test DBs.
|
|
347
|
+
console.log('\n── findCallers limit + countCallers ────────────────────────\n');
|
|
348
|
+
|
|
349
|
+
const allClearCallers = store.findCallers('Clear');
|
|
350
|
+
const clearCount = store.countCallers('Clear');
|
|
351
|
+
console.log(` countCallers('Clear') = ${clearCount}, findCallers length = ${allClearCallers.length}`);
|
|
352
|
+
assert(
|
|
353
|
+
clearCount === allClearCallers.length,
|
|
354
|
+
`countCallers matches unbounded findCallers (${clearCount} vs ${allClearCallers.length})`,
|
|
355
|
+
);
|
|
356
|
+
if (allClearCallers.length >= 1) {
|
|
357
|
+
const limited = store.findCallers('Clear', 1);
|
|
358
|
+
assert(limited.length === 1, `findCallers respects LIMIT=1 (got ${limited.length})`);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ── Cached re-index: PageRank must be skipped ────────────────────────────────
|
|
362
|
+
// The CLI bug we just fixed printed "✓ PageRank computed" even when the
|
|
363
|
+
// indexer correctly logged "Skipping PageRank (graph unchanged)". Lock in
|
|
364
|
+
// the underlying signal: re-indexing the same tree with no changes must
|
|
365
|
+
// report `pagerankRecomputed === false`.
|
|
366
|
+
console.log('\n── Cached re-index PageRank reuse ───────────────────────────\n');
|
|
367
|
+
const second = await indexer.indexDirectory(FIXTURES_DIR, { quiet: true });
|
|
368
|
+
console.log(` second-run filesReusedFromCache=${second.filesReusedFromCache}, pagerankRecomputed=${second.pagerankRecomputed}`);
|
|
369
|
+
assert(
|
|
370
|
+
second.filesReusedFromCache === result.filesIndexed,
|
|
371
|
+
`second run reused every fresh-indexed file (${second.filesReusedFromCache} vs ${result.filesIndexed})`,
|
|
372
|
+
);
|
|
373
|
+
assert(
|
|
374
|
+
second.pagerankRecomputed === false,
|
|
375
|
+
'cached re-index skips PageRank (graph unchanged)',
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
// ── Cleanup ──────────────────────────────────────────────────────────────────
|
|
379
|
+
store.close();
|
|
380
|
+
if (fs.existsSync(TMP_DB)) fs.unlinkSync(TMP_DB);
|
|
381
|
+
|
|
382
|
+
console.log('\n══════════════════════════════════════════════════════════════');
|
|
383
|
+
console.log(` Results: ${passed} passed, ${failed} failed`);
|
|
384
|
+
|
|
385
|
+
if (failed > 0) {
|
|
386
|
+
console.error('\n SMOKE TEST FAILED\n');
|
|
387
|
+
process.exit(1);
|
|
388
|
+
} else {
|
|
389
|
+
console.log('\n All smoke tests passed! ✓\n');
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
run().catch(err => {
|
|
394
|
+
console.error('Smoke test threw:', err);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
});
|