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
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP smoke test for Track I (post-Track-H features):
|
|
3
|
+
* - seer_external_bundles
|
|
4
|
+
* - seer_contract_diff
|
|
5
|
+
* - seer_preflight
|
|
6
|
+
* - seer_boundaries / seer_boundary_for_file / seer_boundary_dependencies
|
|
7
|
+
* - seer_continuity
|
|
8
|
+
*
|
|
9
|
+
* Spawns `seer mcp` against a tiny fixture monorepo and exercises each tool.
|
|
10
|
+
*
|
|
11
|
+
* Run: npx tsx tests/mcp-tracki.ts
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { spawn } from 'child_process';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
import os from 'os';
|
|
18
|
+
|
|
19
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
20
|
+
const TMP_WS = path.join(os.tmpdir(), `seer-mcp-i-${Date.now()}`);
|
|
21
|
+
const CLI = path.join(ROOT, 'dist/cli/index.js');
|
|
22
|
+
|
|
23
|
+
let passed = 0;
|
|
24
|
+
let failed = 0;
|
|
25
|
+
const ok = (m: string): void => { passed++; console.log(` ✓ ${m}`); };
|
|
26
|
+
const bad = (m: string, x?: unknown): void => {
|
|
27
|
+
failed++;
|
|
28
|
+
console.error(` ✗ ${m}` + (x !== undefined ? ` :: ${JSON.stringify(x).slice(0, 400)}` : ''));
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function write(rel: string, content: string): void {
|
|
32
|
+
const full = path.join(TMP_WS, rel);
|
|
33
|
+
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
34
|
+
fs.writeFileSync(full, content);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function main(): Promise<void> {
|
|
38
|
+
console.log('\nSeer MCP Track-I Smoke');
|
|
39
|
+
console.log('======================\n');
|
|
40
|
+
|
|
41
|
+
fs.mkdirSync(TMP_WS, { recursive: true });
|
|
42
|
+
// Tiny monorepo with one package and one service.
|
|
43
|
+
write('package.json', JSON.stringify({
|
|
44
|
+
name: 'tracki-mcp-fixture', private: true,
|
|
45
|
+
workspaces: ['packages/*', 'services/*'],
|
|
46
|
+
}));
|
|
47
|
+
write('packages/lib/package.json', JSON.stringify({ name: 'lib', version: '0.0.0' }));
|
|
48
|
+
write('packages/lib/src/util.ts', `
|
|
49
|
+
export function makeId(seed: number): string { return 'id-' + seed; }
|
|
50
|
+
`.trimStart());
|
|
51
|
+
write('services/svc/package.json', JSON.stringify({ name: 'svc', version: '0.0.0' }));
|
|
52
|
+
write('services/svc/src/api.ts', `
|
|
53
|
+
import { makeId } from '../../../packages/lib/src/util';
|
|
54
|
+
declare const app: any;
|
|
55
|
+
export function getHandler(req: any, res: any): unknown {
|
|
56
|
+
return res.send({ id: makeId(req.body.seed) });
|
|
57
|
+
}
|
|
58
|
+
app.get('/api/get', getHandler);
|
|
59
|
+
`.trimStart());
|
|
60
|
+
|
|
61
|
+
const proc = spawn(process.execPath,
|
|
62
|
+
[CLI, 'mcp', '--workspace', TMP_WS, '--no-watch', '--no-jit'],
|
|
63
|
+
{ stdio: ['pipe', 'pipe', 'pipe'] });
|
|
64
|
+
proc.stderr.on('data', d => process.stderr.write(`[mcp-stderr] ${d}`));
|
|
65
|
+
|
|
66
|
+
let buf = '';
|
|
67
|
+
const pending = new Map<number, (msg: any) => void>();
|
|
68
|
+
proc.stdout.on('data', (chunk: Buffer) => {
|
|
69
|
+
buf += chunk.toString('utf8');
|
|
70
|
+
let nl: number;
|
|
71
|
+
while ((nl = buf.indexOf('\n')) >= 0) {
|
|
72
|
+
const line = buf.slice(0, nl).trim();
|
|
73
|
+
buf = buf.slice(nl + 1);
|
|
74
|
+
if (!line) continue;
|
|
75
|
+
let msg: any;
|
|
76
|
+
try { msg = JSON.parse(line); } catch { continue; }
|
|
77
|
+
if (msg.id != null && pending.has(msg.id)) {
|
|
78
|
+
pending.get(msg.id)!(msg);
|
|
79
|
+
pending.delete(msg.id);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
let nextId = 1;
|
|
85
|
+
const call = (method: string, params: any): Promise<any> => {
|
|
86
|
+
const id = nextId++;
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
pending.set(id, resolve);
|
|
89
|
+
proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n');
|
|
90
|
+
setTimeout(() => {
|
|
91
|
+
if (pending.has(id)) { pending.delete(id); reject(new Error(`timeout ${method}`)); }
|
|
92
|
+
}, 60_000);
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
let initOk = false;
|
|
97
|
+
for (let i = 0; i < 40; i++) {
|
|
98
|
+
try {
|
|
99
|
+
const r = await call('initialize', {
|
|
100
|
+
protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 't', version: '0' },
|
|
101
|
+
});
|
|
102
|
+
if (r.result) { initOk = true; break; }
|
|
103
|
+
} catch { /* */ }
|
|
104
|
+
await new Promise(r => setTimeout(r, 500));
|
|
105
|
+
}
|
|
106
|
+
if (initOk) ok('initialize');
|
|
107
|
+
else { bad('initialize'); process.exit(1); }
|
|
108
|
+
|
|
109
|
+
const list = await call('tools/list', {});
|
|
110
|
+
const names: string[] = (list.result?.tools ?? []).map((t: any) => t.name);
|
|
111
|
+
for (const n of [
|
|
112
|
+
'seer_external_bundles', 'seer_contract_diff', 'seer_preflight',
|
|
113
|
+
'seer_boundaries', 'seer_boundary_for_file', 'seer_boundary_dependencies',
|
|
114
|
+
'seer_continuity',
|
|
115
|
+
]) {
|
|
116
|
+
if (names.includes(n)) ok(`tools/list advertises ${n}`);
|
|
117
|
+
else bad(`tools/list missing ${n}`, names);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const callTool = async (name: string, args: any = {}): Promise<any> => {
|
|
121
|
+
const r = await call('tools/call', { name, arguments: args });
|
|
122
|
+
return JSON.parse(r.result?.content?.[0]?.text ?? '{}');
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// seer_boundaries
|
|
126
|
+
const boundaries = await callTool('seer_boundaries');
|
|
127
|
+
if (boundaries.total >= 1) ok(`seer_boundaries returned ${boundaries.total} boundaries`);
|
|
128
|
+
else bad('seer_boundaries returned no boundaries', boundaries);
|
|
129
|
+
const labels = (boundaries.items ?? []).map((b: any) => b.label);
|
|
130
|
+
if (labels.includes('lib')) ok('seer_boundaries includes lib');
|
|
131
|
+
else bad('seer_boundaries missing lib', labels);
|
|
132
|
+
if (labels.includes('svc')) ok('seer_boundaries includes svc');
|
|
133
|
+
else bad('seer_boundaries missing svc', labels);
|
|
134
|
+
|
|
135
|
+
// seer_boundary_for_file
|
|
136
|
+
const bf = await callTool('seer_boundary_for_file', {
|
|
137
|
+
file: 'services/svc/src/api.ts',
|
|
138
|
+
});
|
|
139
|
+
if (bf.ok && bf.boundary?.label === 'svc')
|
|
140
|
+
ok('seer_boundary_for_file returns svc for api.ts');
|
|
141
|
+
else bad('seer_boundary_for_file unexpected', bf);
|
|
142
|
+
|
|
143
|
+
// seer_preflight (symbol)
|
|
144
|
+
const pf = await callTool('seer_preflight', { symbol: 'getHandler' });
|
|
145
|
+
if (pf.ok && pf.symbol?.name === 'getHandler')
|
|
146
|
+
ok('seer_preflight symbol mode returns getHandler');
|
|
147
|
+
else bad('seer_preflight symbol mode', pf);
|
|
148
|
+
if (pf.boundaries?.primary?.label === 'svc')
|
|
149
|
+
ok('seer_preflight surfaces boundary');
|
|
150
|
+
else bad('seer_preflight boundary missing', pf.boundaries);
|
|
151
|
+
|
|
152
|
+
// seer_external_bundles (no layers imported — should return total=0)
|
|
153
|
+
const eb = await callTool('seer_external_bundles');
|
|
154
|
+
if (eb.total === 0) ok('seer_external_bundles total=0 when no layers');
|
|
155
|
+
else bad('seer_external_bundles unexpected', eb);
|
|
156
|
+
|
|
157
|
+
// seer_continuity — for getHandler may or may not find candidates, just
|
|
158
|
+
// verify it does not crash.
|
|
159
|
+
const ct = await callTool('seer_continuity', { symbol: 'getHandler' });
|
|
160
|
+
if (ct.ok === true) ok('seer_continuity ok=true');
|
|
161
|
+
else bad('seer_continuity not ok', ct);
|
|
162
|
+
|
|
163
|
+
proc.kill();
|
|
164
|
+
await new Promise(r => setTimeout(r, 200));
|
|
165
|
+
try { fs.rmSync(TMP_WS, { recursive: true, force: true }); } catch { /* */ }
|
|
166
|
+
|
|
167
|
+
console.log(`\nPassed: ${passed} Failed: ${failed}`);
|
|
168
|
+
if (failed > 0) process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
main().catch(err => {
|
|
172
|
+
console.error(err);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watcher-mode MCP test. Runs `seer mcp` with watcher ENABLED and JIT
|
|
3
|
+
* DISABLED, edits a file, then waits for the watcher to fire and queries
|
|
4
|
+
* to see whether the new symbol shows up. This verifies the watcher path
|
|
5
|
+
* works independently of JIT — they're two separate safety nets and the
|
|
6
|
+
* tests should cover them separately.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { spawn } from 'child_process';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import os from 'os';
|
|
13
|
+
|
|
14
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
15
|
+
const FIXTURES = path.join(ROOT, 'tests/fixtures');
|
|
16
|
+
const TMP_WS = path.join(os.tmpdir(), `seer-mcp-watch-${Date.now()}`);
|
|
17
|
+
const CLI = path.join(ROOT, 'dist/cli/index.js');
|
|
18
|
+
|
|
19
|
+
let passed = 0;
|
|
20
|
+
let failed = 0;
|
|
21
|
+
const ok = (label: string) => { passed++; console.log(` ✓ ${label}`); };
|
|
22
|
+
const bad = (label: string, extra?: unknown) => {
|
|
23
|
+
failed++;
|
|
24
|
+
console.error(` ✗ ${label}` + (extra !== undefined ? ` :: ${JSON.stringify(extra)}` : ''));
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
async function main(): Promise<void> {
|
|
28
|
+
console.log('\nSeer MCP Watcher Test\n=======================\n');
|
|
29
|
+
fs.mkdirSync(TMP_WS, { recursive: true });
|
|
30
|
+
for (const f of fs.readdirSync(FIXTURES)) {
|
|
31
|
+
fs.copyFileSync(path.join(FIXTURES, f), path.join(TMP_WS, f));
|
|
32
|
+
}
|
|
33
|
+
console.log(` Workspace: ${TMP_WS}\n`);
|
|
34
|
+
|
|
35
|
+
const proc = spawn(process.execPath, [CLI, 'mcp', '--workspace', TMP_WS, '--no-jit'], {
|
|
36
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
37
|
+
});
|
|
38
|
+
proc.stderr.on('data', (d) => process.stderr.write(`[mcp-stderr] ${d}`));
|
|
39
|
+
|
|
40
|
+
let buf = '';
|
|
41
|
+
const pending = new Map<number, (msg: any) => void>();
|
|
42
|
+
proc.stdout.on('data', (chunk: Buffer) => {
|
|
43
|
+
buf += chunk.toString('utf8');
|
|
44
|
+
let nl: number;
|
|
45
|
+
while ((nl = buf.indexOf('\n')) >= 0) {
|
|
46
|
+
const line = buf.slice(0, nl).trim();
|
|
47
|
+
buf = buf.slice(nl + 1);
|
|
48
|
+
if (!line) continue;
|
|
49
|
+
try {
|
|
50
|
+
const msg = JSON.parse(line);
|
|
51
|
+
if (msg.id != null && pending.has(msg.id)) {
|
|
52
|
+
pending.get(msg.id)!(msg);
|
|
53
|
+
pending.delete(msg.id);
|
|
54
|
+
}
|
|
55
|
+
} catch { /* */ }
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
let nextId = 1;
|
|
60
|
+
const call = (method: string, params: any): Promise<any> => {
|
|
61
|
+
const id = nextId++;
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
pending.set(id, resolve);
|
|
64
|
+
proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n');
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
if (pending.has(id)) { pending.delete(id); reject(new Error(`timeout: ${method}`)); }
|
|
67
|
+
}, 30_000);
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
for (let i = 0; i < 30; i++) {
|
|
72
|
+
try {
|
|
73
|
+
const r = await call('initialize', { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'watch-smoke', version: '0.1.0' } });
|
|
74
|
+
if (r.result) break;
|
|
75
|
+
} catch { /* */ }
|
|
76
|
+
await new Promise(r => setTimeout(r, 500));
|
|
77
|
+
}
|
|
78
|
+
ok('server initialized with watcher on');
|
|
79
|
+
|
|
80
|
+
// Confirm watcher status is reported
|
|
81
|
+
const h = JSON.parse((await call('tools/call', { name: 'seer_health', arguments: {} })).result.content[0].text);
|
|
82
|
+
if (h.watcher && h.watcher.watching) ok('seer_health reports watcher=true');
|
|
83
|
+
else bad('watcher not active', h.watcher);
|
|
84
|
+
|
|
85
|
+
// Give chokidar a beat to finish its initial scan — even with
|
|
86
|
+
// ignoreInitial:true it walks the tree before declaring "ready", and on
|
|
87
|
+
// Windows the walk is noticeably slow for small workspaces.
|
|
88
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
89
|
+
|
|
90
|
+
// Edit sample.ts and wait for the watcher to fire + reindex.
|
|
91
|
+
const samplePath = path.join(TMP_WS, 'sample.ts');
|
|
92
|
+
const original = fs.readFileSync(samplePath, 'utf8');
|
|
93
|
+
fs.writeFileSync(samplePath, original + `\n\nexport function watcherInjected(): void {}\n`);
|
|
94
|
+
process.stderr.write(` (wrote new function to sample.ts)\n`);
|
|
95
|
+
|
|
96
|
+
// Poll up to 15 seconds for the symbol to appear via the watcher (no JIT helping).
|
|
97
|
+
// The watcher has debounceMs=250, awaitWriteFinish stabilityThreshold=100, plus
|
|
98
|
+
// a full reindex of ~15 files (~200ms). So we'd expect detection in well under
|
|
99
|
+
// a second, but Windows file-event latency can be unpredictable.
|
|
100
|
+
let found = false;
|
|
101
|
+
for (let i = 0; i < 75; i++) {
|
|
102
|
+
await new Promise(r => setTimeout(r, 200));
|
|
103
|
+
const q = JSON.parse((await call('tools/call', { name: 'seer_symbols', arguments: { query: 'watcherInjected' } })).result.content[0].text);
|
|
104
|
+
if (q.items.some((it: any) => it.name === 'watcherInjected')) {
|
|
105
|
+
found = true;
|
|
106
|
+
ok(`watcher picked up new symbol after ${(i + 1) * 200}ms`);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!found) bad('watcher never picked up new symbol within 15s');
|
|
111
|
+
|
|
112
|
+
proc.stdin.end();
|
|
113
|
+
proc.kill();
|
|
114
|
+
await new Promise(r => setTimeout(r, 200));
|
|
115
|
+
|
|
116
|
+
try { fs.rmSync(TMP_WS, { recursive: true, force: true }); } catch { /* */ }
|
|
117
|
+
|
|
118
|
+
console.log(`\n══════════════════════════════════════════════════════════════`);
|
|
119
|
+
console.log(` Watcher results: ${passed} passed, ${failed} failed\n`);
|
|
120
|
+
if (failed > 0) process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
main().catch(err => {
|
|
124
|
+
console.error('Watcher smoke crashed:', err);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
});
|
package/tests/optspec.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP test for the AI-agent optimization features:
|
|
3
|
+
* §1 token-budget truncation envelope (deterministic prefix-trim)
|
|
4
|
+
* §2 did-you-mean fuzzy fallback (suggestion-only, never substitute)
|
|
5
|
+
* §3 seer_skeleton (deterministic source elision + focus expansion)
|
|
6
|
+
* §4 seer_batch (multi-tool fan-out in one call)
|
|
7
|
+
* §5a lazy lifecycle (build tools rebranded; dependents auto-build)
|
|
8
|
+
* §5b seer_trace umbrella (scope-dispatch over the seer_trace_* family)
|
|
9
|
+
*
|
|
10
|
+
* Spawns `seer mcp` against fixtures-tracke and drives it over stdio.
|
|
11
|
+
* Run: npx tsx tests/optspec.ts
|
|
12
|
+
*/
|
|
13
|
+
import { spawn } from 'child_process';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import fs from 'fs';
|
|
16
|
+
import os from 'os';
|
|
17
|
+
|
|
18
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
19
|
+
const FIX = path.join(ROOT, 'tests/fixtures-tracke');
|
|
20
|
+
const TMP_WS = path.join(os.tmpdir(), `seer-optspec-${Date.now()}`);
|
|
21
|
+
const CLI = path.join(ROOT, 'dist/cli/index.js');
|
|
22
|
+
|
|
23
|
+
let passed = 0;
|
|
24
|
+
let failed = 0;
|
|
25
|
+
const ok = (m: string): void => { passed++; console.log(` ✓ ${m}`); };
|
|
26
|
+
const bad = (m: string, x?: unknown): void => {
|
|
27
|
+
failed++;
|
|
28
|
+
console.error(` ✗ ${m}` + (x !== undefined ? ` :: ${JSON.stringify(x).slice(0, 240)}` : ''));
|
|
29
|
+
};
|
|
30
|
+
const check = (cond: boolean, m: string, x?: unknown): void => { cond ? ok(m) : bad(m, x); };
|
|
31
|
+
|
|
32
|
+
function copyRecursive(src: string, dst: string): void {
|
|
33
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
34
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
35
|
+
const s = path.join(src, entry.name);
|
|
36
|
+
const d = path.join(dst, entry.name);
|
|
37
|
+
if (entry.isDirectory()) copyRecursive(s, d);
|
|
38
|
+
else fs.copyFileSync(s, d);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function main(): Promise<void> {
|
|
43
|
+
console.log('\nSeer MCP Optimization-Spec Tests\n================================\n');
|
|
44
|
+
copyRecursive(FIX, TMP_WS);
|
|
45
|
+
|
|
46
|
+
const proc = spawn(process.execPath, [CLI, 'mcp', '--workspace', TMP_WS, '--no-watch', '--no-jit'],
|
|
47
|
+
{ stdio: ['pipe', 'pipe', 'pipe'] });
|
|
48
|
+
proc.stderr.on('data', (d) => process.stderr.write(`[mcp-stderr] ${d}`));
|
|
49
|
+
|
|
50
|
+
let buf = '';
|
|
51
|
+
const pending = new Map<number, (msg: any) => void>();
|
|
52
|
+
proc.stdout.on('data', (chunk: Buffer) => {
|
|
53
|
+
buf += chunk.toString('utf8');
|
|
54
|
+
let nl: number;
|
|
55
|
+
while ((nl = buf.indexOf('\n')) >= 0) {
|
|
56
|
+
const line = buf.slice(0, nl).trim();
|
|
57
|
+
buf = buf.slice(nl + 1);
|
|
58
|
+
if (!line) continue;
|
|
59
|
+
let msg: any;
|
|
60
|
+
try { msg = JSON.parse(line); } catch { continue; }
|
|
61
|
+
if (msg.id != null && pending.has(msg.id)) { pending.get(msg.id)!(msg); pending.delete(msg.id); }
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
let nextId = 1;
|
|
66
|
+
const call = (method: string, params: any): Promise<any> => {
|
|
67
|
+
const id = nextId++;
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
pending.set(id, resolve);
|
|
70
|
+
proc.stdin.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n');
|
|
71
|
+
setTimeout(() => { if (pending.has(id)) { pending.delete(id); reject(new Error(`timeout ${method}`)); } }, 30_000);
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
const callTool = async (name: string, args: any = {}): Promise<any> => {
|
|
75
|
+
const r = await call('tools/call', { name, arguments: args });
|
|
76
|
+
return JSON.parse(r.result?.content?.[0]?.text ?? '{}');
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// ── init ──
|
|
80
|
+
let initOk = false;
|
|
81
|
+
for (let i = 0; i < 30; i++) {
|
|
82
|
+
try {
|
|
83
|
+
const r = await call('initialize', { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 't', version: '0' } });
|
|
84
|
+
if (r.result) { initOk = true; break; }
|
|
85
|
+
} catch { /* */ }
|
|
86
|
+
await new Promise(r => setTimeout(r, 500));
|
|
87
|
+
}
|
|
88
|
+
if (initOk) ok('initialize'); else { bad('initialize'); process.exit(1); }
|
|
89
|
+
|
|
90
|
+
// ── tools/list advertises the new surface ──
|
|
91
|
+
const list = await call('tools/list', {});
|
|
92
|
+
const tools: Array<{ name: string; description: string }> = list.result?.tools ?? [];
|
|
93
|
+
const names = tools.map(t => t.name);
|
|
94
|
+
for (const n of ['seer_skeleton', 'seer_trace', 'seer_batch']) {
|
|
95
|
+
check(names.includes(n), `tools/list advertises ${n}`, names);
|
|
96
|
+
}
|
|
97
|
+
// §5a: build tools rebranded as advanced
|
|
98
|
+
for (const n of ['seer_modules_build', 'seer_shape_hash_build', 'seer_symbol_history_build']) {
|
|
99
|
+
const d = tools.find(t => t.name === n)?.description ?? '';
|
|
100
|
+
check(/advanced/i.test(d), `${n} description marked advanced/automatic`, d);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ── §3 seer_skeleton ──────────────────────────────────────────────────
|
|
104
|
+
const sk = await callTool('seer_skeleton', { file: 'auth/AuthService.ts' });
|
|
105
|
+
check(sk.ok === true, 'seer_skeleton resolves file by rel_path fragment', sk);
|
|
106
|
+
check(typeof sk.skeleton === 'string' && sk.skeleton.includes('AuthService'),
|
|
107
|
+
'skeleton shows the class AuthService', sk.skeleton);
|
|
108
|
+
check(/login/.test(sk.skeleton) && /logout/.test(sk.skeleton),
|
|
109
|
+
'skeleton shows nested methods login/logout', sk.skeleton);
|
|
110
|
+
check(/validateCredentials/.test(sk.skeleton), 'skeleton shows free function validateCredentials', sk.skeleton);
|
|
111
|
+
check(/\{ … \d+ lines … \}/.test(sk.skeleton), 'skeleton collapses bodies with exact line-count fold markers', sk.skeleton);
|
|
112
|
+
// Bodies must NOT appear verbatim (no focus): the literal call should be hidden.
|
|
113
|
+
check(!sk.skeleton.includes('invalidateToken(token)'), 'skeleton elides body source (no focus)', sk.skeleton);
|
|
114
|
+
|
|
115
|
+
// Determinism: identical render twice.
|
|
116
|
+
const sk2 = await callTool('seer_skeleton', { file: 'auth/AuthService.ts' });
|
|
117
|
+
check(sk2.skeleton === sk.skeleton, 'seer_skeleton is deterministic (byte-identical re-render)');
|
|
118
|
+
|
|
119
|
+
// Focus expands a single body verbatim.
|
|
120
|
+
const skf = await callTool('seer_skeleton', { file: 'auth/AuthService.ts', focusSymbol: 'login' });
|
|
121
|
+
check(/◀ focus/.test(skf.skeleton) && skf.skeleton.includes('hashPassword(password)'),
|
|
122
|
+
'seer_skeleton focusSymbol expands the target body verbatim', skf.skeleton);
|
|
123
|
+
|
|
124
|
+
const skMiss = await callTool('seer_skeleton', { file: 'does/not/exist.ts' });
|
|
125
|
+
check(skMiss.ok === false, 'seer_skeleton returns ok:false for an unknown file', skMiss);
|
|
126
|
+
|
|
127
|
+
// ── §2 did-you-mean ───────────────────────────────────────────────────
|
|
128
|
+
const exact = await callTool('seer_definition', { name: 'validateCredentials' });
|
|
129
|
+
check((exact.items ?? []).length >= 1 && exact.didYouMean === undefined,
|
|
130
|
+
'seer_definition exact hit carries NO didYouMean', exact);
|
|
131
|
+
|
|
132
|
+
const typo = await callTool('seer_definition', { name: 'validateCredential' }); // missing trailing s
|
|
133
|
+
check((typo.items ?? []).length === 0, 'seer_definition typo returns zero exact items', typo);
|
|
134
|
+
check(Array.isArray(typo.didYouMean) && typo.didYouMean.some((d: any) => d.name === 'validateCredentials'),
|
|
135
|
+
'seer_definition typo surfaces didYouMean → validateCredentials (suggestion-only)', typo.didYouMean);
|
|
136
|
+
|
|
137
|
+
const riskMiss = await callTool('seer_risk', { symbol: 'validateCredential' });
|
|
138
|
+
check(riskMiss.found === false && Array.isArray(riskMiss.didYouMean) && riskMiss.didYouMean.length > 0,
|
|
139
|
+
'seer_risk on a missing symbol returns found:false + didYouMean (never computes on a guess)', riskMiss);
|
|
140
|
+
|
|
141
|
+
// ── §1 token budget ───────────────────────────────────────────────────
|
|
142
|
+
const full = await callTool('seer_symbols', { query: 'a', limit: 200 });
|
|
143
|
+
const tiny = await callTool('seer_symbols', { query: 'a', limit: 200, tokenBudget: 60 });
|
|
144
|
+
check(full.truncated === undefined, 'seer_symbols without tokenBudget is not flagged truncated', full.truncated);
|
|
145
|
+
check(tiny.truncated === true && tiny.returned <= full.returned,
|
|
146
|
+
'seer_symbols tokenBudget trims items and flags truncated', { full: full.returned, tiny: tiny.returned });
|
|
147
|
+
check(tiny.returned >= 1, 'token budget always keeps at least one item', tiny.returned);
|
|
148
|
+
check(JSON.stringify(tiny).length <= JSON.stringify(full).length,
|
|
149
|
+
'budgeted payload is no larger than the full payload', { t: JSON.stringify(tiny).length, f: JSON.stringify(full).length });
|
|
150
|
+
|
|
151
|
+
// ── §5b seer_trace umbrella ───────────────────────────────────────────
|
|
152
|
+
const tr = await callTool('seer_trace', { scope: 'callers', args: { symbol: 'validateCredentials', maxDepth: 4 } });
|
|
153
|
+
const trDirect = await callTool('seer_trace_callers', { symbol: 'validateCredentials', maxDepth: 4 });
|
|
154
|
+
check((tr.total ?? -1) === (trDirect.total ?? -2),
|
|
155
|
+
'seer_trace scope=callers matches seer_trace_callers directly', { umbrella: tr.total, direct: trDirect.total });
|
|
156
|
+
const trFile = await callTool('seer_trace', { scope: 'file', args: { file: 'billing/Billing.ts', maxDepth: 3 } });
|
|
157
|
+
check(trFile.from != null || trFile.found === false, 'seer_trace scope=file delegates to file-dependency trace', trFile);
|
|
158
|
+
const trBad = await callTool('seer_trace', { scope: 'callers', args: {} });
|
|
159
|
+
check(trBad.found === false || trBad.error != null, 'seer_trace passes through delegate errors', trBad);
|
|
160
|
+
|
|
161
|
+
// ── §4 seer_batch ─────────────────────────────────────────────────────
|
|
162
|
+
const batch = await callTool('seer_batch', { calls: [
|
|
163
|
+
{ tool: 'seer_definition', args: { name: 'validateCredentials' } },
|
|
164
|
+
{ tool: 'seer_callers', args: { symbol: 'validateCredentials' } },
|
|
165
|
+
{ tool: 'seer_skeleton', args: { file: 'auth/AuthService.ts' } },
|
|
166
|
+
{ tool: 'seer_definition', args: { name: '__nope__' } },
|
|
167
|
+
] });
|
|
168
|
+
check(batch.batch === true && batch.count === 4, 'seer_batch returns all 4 results', batch.count);
|
|
169
|
+
check(batch.results[0].ok === true && (batch.results[0].result.items ?? []).length >= 1,
|
|
170
|
+
'seer_batch result[0] = definition hit', batch.results[0]);
|
|
171
|
+
check(batch.results[2].ok === true && batch.results[2].result.ok === true,
|
|
172
|
+
'seer_batch result[2] = skeleton ok', batch.results[2]);
|
|
173
|
+
check(batch.results[3].ok === true && (batch.results[3].result.items ?? []).length === 0,
|
|
174
|
+
'seer_batch tolerates a sub-call that finds nothing (still ok:true wrapper)', batch.results[3]);
|
|
175
|
+
|
|
176
|
+
const batchNest = await callTool('seer_batch', { calls: [{ tool: 'seer_batch', args: {} }] });
|
|
177
|
+
check(batchNest.results[0].ok === false && /nested|disallowed/i.test(batchNest.results[0].error),
|
|
178
|
+
'seer_batch refuses to nest', batchNest.results[0]);
|
|
179
|
+
const batchUnknown = await callTool('seer_batch', { calls: [{ tool: 'seer_nonexistent', args: {} }] });
|
|
180
|
+
check(batchUnknown.results[0].ok === false && /unknown/i.test(batchUnknown.results[0].error),
|
|
181
|
+
'seer_batch reports unknown tool without aborting', batchUnknown.results[0]);
|
|
182
|
+
|
|
183
|
+
// ── §5a dependents still serve data (auto-build path doesn't break) ────
|
|
184
|
+
const dup = await callTool('seer_duplicates', {});
|
|
185
|
+
check(typeof dup.clusters === 'number', 'seer_duplicates serves after lazy shape-hash guard', dup);
|
|
186
|
+
const mods = await callTool('seer_modules', {});
|
|
187
|
+
check((mods.total ?? 0) >= 1, 'seer_modules serves after lazy modules guard', mods);
|
|
188
|
+
|
|
189
|
+
proc.kill();
|
|
190
|
+
console.log(`\n${passed} passed, ${failed} failed\n`);
|
|
191
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
main().catch((e) => { console.error(e); process.exit(2); });
|