@spikedpunch/mast 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/LICENSE +21 -0
- package/MAST_SPEC.md +2926 -0
- package/README.md +842 -0
- package/assets/skill.md +45 -0
- package/dist/ast/extract.d.ts +65 -0
- package/dist/ast/extract.d.ts.map +1 -0
- package/dist/ast/extract.js +147 -0
- package/dist/ast/extract.js.map +1 -0
- package/dist/ast/extractor.d.ts +85 -0
- package/dist/ast/extractor.d.ts.map +1 -0
- package/dist/ast/extractor.js +2 -0
- package/dist/ast/extractor.js.map +1 -0
- package/dist/ast/extractors/markdown.d.ts +40 -0
- package/dist/ast/extractors/markdown.d.ts.map +1 -0
- package/dist/ast/extractors/markdown.js +175 -0
- package/dist/ast/extractors/markdown.js.map +1 -0
- package/dist/ast/extractors/typescript.d.ts +179 -0
- package/dist/ast/extractors/typescript.d.ts.map +1 -0
- package/dist/ast/extractors/typescript.js +1439 -0
- package/dist/ast/extractors/typescript.js.map +1 -0
- package/dist/ast/parser.d.ts +5 -0
- package/dist/ast/parser.d.ts.map +1 -0
- package/dist/ast/parser.js +21 -0
- package/dist/ast/parser.js.map +1 -0
- package/dist/ast/types.d.ts +586 -0
- package/dist/ast/types.d.ts.map +1 -0
- package/dist/ast/types.js +3 -0
- package/dist/ast/types.js.map +1 -0
- package/dist/cli/docs-cmd.d.ts +22 -0
- package/dist/cli/docs-cmd.d.ts.map +1 -0
- package/dist/cli/docs-cmd.js +100 -0
- package/dist/cli/docs-cmd.js.map +1 -0
- package/dist/cli/index-cmd.d.ts +72 -0
- package/dist/cli/index-cmd.d.ts.map +1 -0
- package/dist/cli/index-cmd.js +263 -0
- package/dist/cli/index-cmd.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 +4 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +14 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +64 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/install-hooks.d.ts +3 -0
- package/dist/cli/install-hooks.d.ts.map +1 -0
- package/dist/cli/install-hooks.js +34 -0
- package/dist/cli/install-hooks.js.map +1 -0
- package/dist/cli/metrics-cmd.d.ts +3 -0
- package/dist/cli/metrics-cmd.d.ts.map +1 -0
- package/dist/cli/metrics-cmd.js +164 -0
- package/dist/cli/metrics-cmd.js.map +1 -0
- package/dist/cli/program.d.ts +14 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +44 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/query.d.ts +46 -0
- package/dist/cli/query.d.ts.map +1 -0
- package/dist/cli/query.js +153 -0
- package/dist/cli/query.js.map +1 -0
- package/dist/cli/search-cmd.d.ts +33 -0
- package/dist/cli/search-cmd.d.ts.map +1 -0
- package/dist/cli/search-cmd.js +114 -0
- package/dist/cli/search-cmd.js.map +1 -0
- package/dist/cli/serve.d.ts +3 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +19 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/skill-install.d.ts +39 -0
- package/dist/cli/skill-install.d.ts.map +1 -0
- package/dist/cli/skill-install.js +57 -0
- package/dist/cli/skill-install.js.map +1 -0
- package/dist/cli/status.d.ts +35 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +117 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/upgrade-cmd.d.ts +48 -0
- package/dist/cli/upgrade-cmd.d.ts.map +1 -0
- package/dist/cli/upgrade-cmd.js +129 -0
- package/dist/cli/upgrade-cmd.js.map +1 -0
- package/dist/cli/version.d.ts +3 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +19 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/env.d.ts +17 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +17 -0
- package/dist/env.js.map +1 -0
- package/dist/graph/checker-resolver.d.ts +156 -0
- package/dist/graph/checker-resolver.d.ts.map +1 -0
- package/dist/graph/checker-resolver.js +458 -0
- package/dist/graph/checker-resolver.js.map +1 -0
- package/dist/graph/db.d.ts +318 -0
- package/dist/graph/db.d.ts.map +1 -0
- package/dist/graph/db.js +266 -0
- package/dist/graph/db.js.map +1 -0
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +5 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/local-type-env.d.ts +45 -0
- package/dist/graph/local-type-env.d.ts.map +1 -0
- package/dist/graph/local-type-env.js +59 -0
- package/dist/graph/local-type-env.js.map +1 -0
- package/dist/graph/path-range.d.ts +40 -0
- package/dist/graph/path-range.d.ts.map +1 -0
- package/dist/graph/path-range.js +42 -0
- package/dist/graph/path-range.js.map +1 -0
- package/dist/graph/populate.d.ts +263 -0
- package/dist/graph/populate.d.ts.map +1 -0
- package/dist/graph/populate.js +984 -0
- package/dist/graph/populate.js.map +1 -0
- package/dist/graph/queries.d.ts +114 -0
- package/dist/graph/queries.d.ts.map +1 -0
- package/dist/graph/queries.js +415 -0
- package/dist/graph/queries.js.map +1 -0
- package/dist/graph/sqliteBatch.d.ts +48 -0
- package/dist/graph/sqliteBatch.d.ts.map +1 -0
- package/dist/graph/sqliteBatch.js +93 -0
- package/dist/graph/sqliteBatch.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 +72 -0
- package/dist/indexer/freshness.js.map +1 -0
- package/dist/indexer/import-resolver.d.ts +50 -0
- package/dist/indexer/import-resolver.d.ts.map +1 -0
- package/dist/indexer/import-resolver.js +318 -0
- package/dist/indexer/import-resolver.js.map +1 -0
- package/dist/indexer/index.d.ts +249 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +560 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/walker.d.ts +60 -0
- package/dist/indexer/walker.d.ts.map +1 -0
- package/dist/indexer/walker.js +128 -0
- package/dist/indexer/walker.js.map +1 -0
- package/dist/indexer/watcher.d.ts +80 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +151 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/mcp/context.d.ts +23 -0
- package/dist/mcp/context.d.ts.map +1 -0
- package/dist/mcp/context.js +2 -0
- package/dist/mcp/context.js.map +1 -0
- package/dist/mcp/register-tools.d.ts +21 -0
- package/dist/mcp/register-tools.d.ts.map +1 -0
- package/dist/mcp/register-tools.js +42 -0
- package/dist/mcp/register-tools.js.map +1 -0
- package/dist/mcp/server.d.ts +58 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +177 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/staleness.d.ts +72 -0
- package/dist/mcp/staleness.d.ts.map +1 -0
- package/dist/mcp/staleness.js +213 -0
- package/dist/mcp/staleness.js.map +1 -0
- package/dist/mcp/startup.d.ts +40 -0
- package/dist/mcp/startup.d.ts.map +1 -0
- package/dist/mcp/startup.js +114 -0
- package/dist/mcp/startup.js.map +1 -0
- package/dist/mcp/tools/_helpers.d.ts +26 -0
- package/dist/mcp/tools/_helpers.d.ts.map +1 -0
- package/dist/mcp/tools/_helpers.js +54 -0
- package/dist/mcp/tools/_helpers.js.map +1 -0
- package/dist/mcp/tools/callers.d.ts +4 -0
- package/dist/mcp/tools/callers.d.ts.map +1 -0
- package/dist/mcp/tools/callers.js +112 -0
- package/dist/mcp/tools/callers.js.map +1 -0
- package/dist/mcp/tools/dependencies.d.ts +4 -0
- package/dist/mcp/tools/dependencies.d.ts.map +1 -0
- package/dist/mcp/tools/dependencies.js +36 -0
- package/dist/mcp/tools/dependencies.js.map +1 -0
- package/dist/mcp/tools/efficiency.d.ts +4 -0
- package/dist/mcp/tools/efficiency.d.ts.map +1 -0
- package/dist/mcp/tools/efficiency.js +39 -0
- package/dist/mcp/tools/efficiency.js.map +1 -0
- package/dist/mcp/tools/exports.d.ts +4 -0
- package/dist/mcp/tools/exports.d.ts.map +1 -0
- package/dist/mcp/tools/exports.js +56 -0
- package/dist/mcp/tools/exports.js.map +1 -0
- package/dist/mcp/tools/implementors.d.ts +4 -0
- package/dist/mcp/tools/implementors.d.ts.map +1 -0
- package/dist/mcp/tools/implementors.js +47 -0
- package/dist/mcp/tools/implementors.js.map +1 -0
- package/dist/mcp/tools/project-skeleton.d.ts +4 -0
- package/dist/mcp/tools/project-skeleton.d.ts.map +1 -0
- package/dist/mcp/tools/project-skeleton.js +61 -0
- package/dist/mcp/tools/project-skeleton.js.map +1 -0
- package/dist/mcp/tools/reindex.d.ts +14 -0
- package/dist/mcp/tools/reindex.d.ts.map +1 -0
- package/dist/mcp/tools/reindex.js +32 -0
- package/dist/mcp/tools/reindex.js.map +1 -0
- package/dist/mcp/tools/rename-impact.d.ts +4 -0
- package/dist/mcp/tools/rename-impact.d.ts.map +1 -0
- package/dist/mcp/tools/rename-impact.js +124 -0
- package/dist/mcp/tools/rename-impact.js.map +1 -0
- package/dist/mcp/tools/search.d.ts +4 -0
- package/dist/mcp/tools/search.d.ts.map +1 -0
- package/dist/mcp/tools/search.js +69 -0
- package/dist/mcp/tools/search.js.map +1 -0
- package/dist/mcp/tools/signature.d.ts +4 -0
- package/dist/mcp/tools/signature.d.ts.map +1 -0
- package/dist/mcp/tools/signature.js +127 -0
- package/dist/mcp/tools/signature.js.map +1 -0
- package/dist/mcp/tools/status.d.ts +4 -0
- package/dist/mcp/tools/status.d.ts.map +1 -0
- package/dist/mcp/tools/status.js +30 -0
- package/dist/mcp/tools/status.js.map +1 -0
- package/dist/search/declex.d.ts +109 -0
- package/dist/search/declex.d.ts.map +1 -0
- package/dist/search/declex.js +242 -0
- package/dist/search/declex.js.map +1 -0
- package/dist/search/fts.d.ts +77 -0
- package/dist/search/fts.d.ts.map +1 -0
- package/dist/search/fts.js +223 -0
- package/dist/search/fts.js.map +1 -0
- package/dist/search/fused.d.ts +110 -0
- package/dist/search/fused.d.ts.map +1 -0
- package/dist/search/fused.js +323 -0
- package/dist/search/fused.js.map +1 -0
- package/dist/search/potential-matches.d.ts +88 -0
- package/dist/search/potential-matches.d.ts.map +1 -0
- package/dist/search/potential-matches.js +83 -0
- package/dist/search/potential-matches.js.map +1 -0
- package/dist/search/scope.d.ts +66 -0
- package/dist/search/scope.d.ts.map +1 -0
- package/dist/search/scope.js +71 -0
- package/dist/search/scope.js.map +1 -0
- package/dist/store/config.d.ts +57 -0
- package/dist/store/config.d.ts.map +1 -0
- package/dist/store/config.js +208 -0
- package/dist/store/config.js.map +1 -0
- package/dist/store/lock.d.ts +101 -0
- package/dist/store/lock.d.ts.map +1 -0
- package/dist/store/lock.js +182 -0
- package/dist/store/lock.js.map +1 -0
- package/dist/store/lockMetrics.d.ts +52 -0
- package/dist/store/lockMetrics.d.ts.map +1 -0
- package/dist/store/lockMetrics.js +29 -0
- package/dist/store/lockMetrics.js.map +1 -0
- package/dist/store/sqliteChunkStore.d.ts +44 -0
- package/dist/store/sqliteChunkStore.d.ts.map +1 -0
- package/dist/store/sqliteChunkStore.js +135 -0
- package/dist/store/sqliteChunkStore.js.map +1 -0
- package/dist/telemetry/lockMetricsSummary.d.ts +42 -0
- package/dist/telemetry/lockMetricsSummary.d.ts.map +1 -0
- package/dist/telemetry/lockMetricsSummary.js +139 -0
- package/dist/telemetry/lockMetricsSummary.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +140 -0
- package/dist/telemetry/metrics.d.ts.map +1 -0
- package/dist/telemetry/metrics.js +312 -0
- package/dist/telemetry/metrics.js.map +1 -0
- package/dist/telemetry/tokenizer.d.ts +125 -0
- package/dist/telemetry/tokenizer.d.ts.map +1 -0
- package/dist/telemetry/tokenizer.js +174 -0
- package/dist/telemetry/tokenizer.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reindex.js","sourceRoot":"","sources":["../../../src/mcp/tools/reindex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAE,QAAQ,EAAoB,MAAM,wBAAwB,CAAC;AAEpE,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,GAAe;IACpE,MAAM,CAAC,IAAI,CACT,cAAc,EACd,2LAA2L,EAC3L;QACE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mFAAmF,CAAC;KAC3H,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC;QAElF,MAAM,aAAa,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QAC9C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,MAAmB;IACjD,OAAO;QACL,aAAa,EAAI,MAAM,CAAC,YAAY;QACpC,aAAa,EAAI,MAAM,CAAC,YAAY;QACpC,YAAY,EAAK,MAAM,CAAC,WAAW;QACnC,cAAc,EAAG,MAAM,CAAC,aAAa;QACrC,YAAY,EAAK,MAAM,CAAC,WAAW;QACnC,YAAY,EAAK,MAAM,CAAC,WAAW;QACnC,sBAAsB,EAAE,MAAM,CAAC,oBAAoB;QACnD,gBAAgB,EAAE,MAAM,CAAC,eAAe,CAAC,KAAK;QAC9C,WAAW,EAAM,MAAM,CAAC,UAAU;KACnC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename-impact.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/rename-impact.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AA2BhD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CA0HjF"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { buildToolStats, recordToolCall } from '../../telemetry/metrics.js';
|
|
3
|
+
import { countTokens, estimateFullFileBound } from '../../telemetry/tokenizer.js';
|
|
4
|
+
import { querySymbolByName, queryVerifiedCallers, queryBarrelExports } from '../../graph/queries.js';
|
|
5
|
+
import { jitRefreshFile, collectPotentialMatches, isIndexEmpty } from './_helpers.js';
|
|
6
|
+
/**
|
|
7
|
+
* Compose the "N verified sites, M review-required sites, K barrel exports"
|
|
8
|
+
* framing the agent acts on. A sentence rather than only counts so the tool
|
|
9
|
+
* output reads as a checklist even when the agent skims.
|
|
10
|
+
*/
|
|
11
|
+
function buildChecklist(verified, potential, barrels) {
|
|
12
|
+
return [
|
|
13
|
+
`${verified} verified call site(s) to update`,
|
|
14
|
+
`${potential} review-required identifier match(es)`,
|
|
15
|
+
`${barrels} barrel export(s) to update`,
|
|
16
|
+
].join(', ') + '.';
|
|
17
|
+
}
|
|
18
|
+
export function registerRenameImpactTool(server, ctx) {
|
|
19
|
+
server.tool('mast_rename_impact', 'Refactor checklist for renaming a symbol: declaration sites, verified call sites (graph), review-required identifier matches (FTS), and barrel re-exports. Composes mast_callers + graph re-export data in one call. Shares mast_callers\' potential-match semantics, including `mast index --checker` verdict filtering (summary.checker_classified_* report what was dropped).', {
|
|
20
|
+
symbol: z.string().describe('Symbol to be renamed (methods qualified as ClassName.methodName)'),
|
|
21
|
+
file_path: z.string().nullable().optional().describe('File that declares the symbol (disambiguates duplicate names)'),
|
|
22
|
+
}, async (args) => {
|
|
23
|
+
const start = Date.now();
|
|
24
|
+
const filePath = args.file_path ?? null;
|
|
25
|
+
// §9.0 staleness: same JIT policy as mast_callers — refresh the named
|
|
26
|
+
// file so declaration/caller line numbers reflect disk. Busy flag goes
|
|
27
|
+
// at the envelope, not per-VerifiedCaller — see
|
|
28
|
+
// CallersResponse.file_busy_returning_stale_cache for the reasoning
|
|
29
|
+
// (this JITs the declaring file, not each caller's own file).
|
|
30
|
+
let fileBusy = false;
|
|
31
|
+
if (filePath != null) {
|
|
32
|
+
const r = await jitRefreshFile(ctx.db, ctx.config, filePath);
|
|
33
|
+
fileBusy = r.busy;
|
|
34
|
+
}
|
|
35
|
+
const symbols = await querySymbolByName(ctx.db, args.symbol, filePath ?? undefined);
|
|
36
|
+
const declaration_sites = symbols.map((s) => ({
|
|
37
|
+
file_path: s.file_path,
|
|
38
|
+
line: s.line,
|
|
39
|
+
kind: s.kind,
|
|
40
|
+
is_exported: s.is_exported === 1,
|
|
41
|
+
}));
|
|
42
|
+
// Impact is computed against the best declaration match — same
|
|
43
|
+
// first-symbol convention as mast_callers. All declarations are still
|
|
44
|
+
// listed so an ambiguous rename is visible in the checklist.
|
|
45
|
+
const target = symbols[0];
|
|
46
|
+
let verified_callers = [];
|
|
47
|
+
let potential_matches = [];
|
|
48
|
+
let barrel_exports = [];
|
|
49
|
+
let checkerClassifiedNonCallSite = 0;
|
|
50
|
+
let checkerClassifiedDifferentDeclaration = 0;
|
|
51
|
+
let potentialTruncated;
|
|
52
|
+
if (target !== undefined) {
|
|
53
|
+
// Direct callers only — a rename edits call sites, and every call site
|
|
54
|
+
// is a direct caller; transitive callers need no edit (deliberate v1 scope).
|
|
55
|
+
const verifiedRows = await queryVerifiedCallers(ctx.db, target.id, false);
|
|
56
|
+
verified_callers = verifiedRows.map((r) => ({
|
|
57
|
+
file_path: r.file_path,
|
|
58
|
+
line: r.line,
|
|
59
|
+
caller_symbol: r.caller_symbol,
|
|
60
|
+
context: r.context,
|
|
61
|
+
resolution: r.resolution,
|
|
62
|
+
}));
|
|
63
|
+
const potentialResult = await collectPotentialMatches(ctx.db, ctx.chunkStore, target.id, args.symbol, verified_callers);
|
|
64
|
+
potential_matches = potentialResult.matches;
|
|
65
|
+
checkerClassifiedNonCallSite = potentialResult.checkerClassifiedNonCallSite;
|
|
66
|
+
checkerClassifiedDifferentDeclaration = potentialResult.checkerClassifiedDifferentDeclaration;
|
|
67
|
+
potentialTruncated = potentialResult.truncatedMatchCount;
|
|
68
|
+
const barrelRows = await queryBarrelExports(ctx.db, target.id, args.symbol, target.file_id);
|
|
69
|
+
barrel_exports = barrelRows.map((b) => ({
|
|
70
|
+
file_path: b.file_path,
|
|
71
|
+
line: b.line,
|
|
72
|
+
exported_as: b.exported_as,
|
|
73
|
+
via: b.via,
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
const filesReferenced = [
|
|
77
|
+
...new Set([
|
|
78
|
+
...declaration_sites.map((d) => d.file_path),
|
|
79
|
+
...verified_callers.map((c) => c.file_path),
|
|
80
|
+
...potential_matches.map((m) => m.file_path),
|
|
81
|
+
...barrel_exports.map((b) => b.file_path),
|
|
82
|
+
]),
|
|
83
|
+
];
|
|
84
|
+
const body = { declaration_sites, verified_callers, potential_matches, barrel_exports };
|
|
85
|
+
const tokens = countTokens(JSON.stringify(body));
|
|
86
|
+
const tokensFullFileBound = estimateFullFileBound(filesReferenced, ctx.config.resolved_project_root);
|
|
87
|
+
const durationMs = Date.now() - start;
|
|
88
|
+
// M6 (§13.8 item 4): checked ONLY when ALL FOUR sections came back empty.
|
|
89
|
+
const indexEmptyField = declaration_sites.length === 0 &&
|
|
90
|
+
verified_callers.length === 0 &&
|
|
91
|
+
potential_matches.length === 0 &&
|
|
92
|
+
barrel_exports.length === 0 &&
|
|
93
|
+
(await isIndexEmpty(ctx))
|
|
94
|
+
? { index_empty: true }
|
|
95
|
+
: {};
|
|
96
|
+
const response = {
|
|
97
|
+
symbol: args.symbol,
|
|
98
|
+
...body,
|
|
99
|
+
// §9.0 TOCTOU policy: omitted when false, never present-and-false.
|
|
100
|
+
...(fileBusy ? { file_busy_returning_stale_cache: true } : {}),
|
|
101
|
+
...indexEmptyField,
|
|
102
|
+
summary: {
|
|
103
|
+
declaration_count: declaration_sites.length,
|
|
104
|
+
verified_count: verified_callers.length,
|
|
105
|
+
potential_count: potential_matches.length,
|
|
106
|
+
barrel_count: barrel_exports.length,
|
|
107
|
+
checklist: target === undefined
|
|
108
|
+
? `Symbol "${args.symbol}" not found in the index — nothing to rename.`
|
|
109
|
+
: buildChecklist(verified_callers.length, potential_matches.length, barrel_exports.length),
|
|
110
|
+
checker_classified_non_call_site: checkerClassifiedNonCallSite,
|
|
111
|
+
checker_classified_different_declaration: checkerClassifiedDifferentDeclaration,
|
|
112
|
+
// F10: omitted-when-false — present only when the identifier-FTS cap was hit.
|
|
113
|
+
...(potentialTruncated !== undefined ? { potential_truncated: potentialTruncated } : {}),
|
|
114
|
+
},
|
|
115
|
+
_stats: buildToolStats('mast_rename_impact', tokens, tokensFullFileBound, filesReferenced, durationMs),
|
|
116
|
+
};
|
|
117
|
+
void recordToolCall(ctx.db, {
|
|
118
|
+
toolName: 'mast_rename_impact', tokensReturned: tokens, tokensFullFileBound,
|
|
119
|
+
durationMs, sessionId: ctx.sessionId, status: 'ok',
|
|
120
|
+
}).catch(() => { });
|
|
121
|
+
return { content: [{ type: 'text', text: JSON.stringify(response) }] };
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=rename-impact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rename-impact.js","sourceRoot":"","sources":["../../../src/mcp/tools/rename-impact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAQhD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAuE3E"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { buildToolStats, recordToolCall, buildArgsJson, buildResultsJson, buildDeclexJson } from '../../telemetry/metrics.js';
|
|
3
|
+
import { countTokens, estimateFullFileBound } from '../../telemetry/tokenizer.js';
|
|
4
|
+
import { fusedSearch } from '../../search/fused.js';
|
|
5
|
+
import { findStaleFiles } from '../staleness.js';
|
|
6
|
+
import { isIndexEmpty } from './_helpers.js';
|
|
7
|
+
export function registerSearchTool(server, ctx) {
|
|
8
|
+
server.tool('mast_search', 'Lexical BM25 + declaration-exact search over the indexed codebase. Returns chunks (not full files) ranked by relevance. Use this for code discovery — replaces Grep, Glob, and exploratory Read.', {
|
|
9
|
+
query: z.string().describe('Natural language or identifier-based search query'),
|
|
10
|
+
limit: z.number().int().min(1).max(50).optional().describe('Max results to return (default: 10)'),
|
|
11
|
+
language: z.enum(['typescript', 'javascript', 'markdown']).nullable().optional(),
|
|
12
|
+
file_pattern: z.string().nullable().optional().describe('Glob pattern to restrict results to matching files'),
|
|
13
|
+
chunk_type: z.enum(['function', 'method', 'class_shell', 'interface', 'type', 'export', 'block', 'doc']).nullable().optional(),
|
|
14
|
+
only_exported: z.boolean().optional().describe('Restrict to exported symbols only'),
|
|
15
|
+
}, async (args) => {
|
|
16
|
+
const start = Date.now();
|
|
17
|
+
const { results, suggestions, declex } = await fusedSearch(ctx.db, args, { rrf_k: ctx.config.rrf_k, declaration_exact_ranker: ctx.config.declaration_exact_ranker }, ctx.chunkStore);
|
|
18
|
+
const filesReferenced = [...new Set(results.map((r) => r.file_path))];
|
|
19
|
+
// F7/C1: stat-and-flag, not JIT refresh — surfaced as `stale`, not
|
|
20
|
+
// `file_busy_returning_stale_cache` (that name is reserved for the
|
|
21
|
+
// JIT-refresh tools, where a refresh is actually attempted). See
|
|
22
|
+
// staleness.ts's `findStaleFiles` WHY-comment. Computed against the
|
|
23
|
+
// ranking fusedSearch already produced; flagged results are what gets
|
|
24
|
+
// token-counted and returned below.
|
|
25
|
+
const staleFiles = await findStaleFiles(ctx.db, ctx.config, filesReferenced);
|
|
26
|
+
const flaggedResults = staleFiles.size === 0
|
|
27
|
+
? results
|
|
28
|
+
: results.map((r) => ({
|
|
29
|
+
...r,
|
|
30
|
+
...(staleFiles.has(r.file_path) ? { stale: true } : {}),
|
|
31
|
+
}));
|
|
32
|
+
// `suggestions` is present (possibly empty) only on the zero-result assist
|
|
33
|
+
// path; conditional spread keeps it out of the payload otherwise.
|
|
34
|
+
const suggestionsField = suggestions !== undefined ? { suggestions } : {};
|
|
35
|
+
const text = JSON.stringify({ results: flaggedResults, ...suggestionsField });
|
|
36
|
+
const tokens = countTokens(text);
|
|
37
|
+
const tokensFullFileBound = estimateFullFileBound(filesReferenced, ctx.config.resolved_project_root);
|
|
38
|
+
const durationMs = Date.now() - start;
|
|
39
|
+
// M6 (§13.8 item 4): checked ONLY on the empty-result path — a
|
|
40
|
+
// populated response never pays the chunkCount() query.
|
|
41
|
+
const indexEmptyField = flaggedResults.length === 0 && await isIndexEmpty(ctx)
|
|
42
|
+
? { index_empty: true }
|
|
43
|
+
: {};
|
|
44
|
+
const response = {
|
|
45
|
+
results: flaggedResults,
|
|
46
|
+
...suggestionsField,
|
|
47
|
+
...indexEmptyField,
|
|
48
|
+
_stats: buildToolStats('mast_search', tokens, tokensFullFileBound, filesReferenced, durationMs),
|
|
49
|
+
};
|
|
50
|
+
// Identity pairs in rank order — the "did a later chain-analysis call
|
|
51
|
+
// target something this search returned?" evidence for the capsule
|
|
52
|
+
// instrumentation decision (IMPLEMENTATION_PLAN_VEXP.md §P, 2026-07-15).
|
|
53
|
+
const resultIdentities = results.map((r) => ({ file_path: r.file_path, symbol_name: r.symbol_name }));
|
|
54
|
+
// Stage 6.3 — D-fire telemetry (M2 decision memo condition 3). Present
|
|
55
|
+
// only when ranker D actually fired (fusedSearch's own contract);
|
|
56
|
+
// never threaded into `response`/`text` above, per this feature's
|
|
57
|
+
// no-leak requirement.
|
|
58
|
+
const declexJsonField = declex !== undefined ? { declexJson: buildDeclexJson(declex) } : {};
|
|
59
|
+
void recordToolCall(ctx.db, {
|
|
60
|
+
toolName: 'mast_search', tokensReturned: tokens, tokensFullFileBound,
|
|
61
|
+
durationMs, sessionId: ctx.sessionId, status: 'ok',
|
|
62
|
+
argsJson: buildArgsJson(args),
|
|
63
|
+
resultsJson: buildResultsJson(resultIdentities),
|
|
64
|
+
...declexJsonField,
|
|
65
|
+
}).catch(() => { });
|
|
66
|
+
return { content: [{ type: 'text', text: JSON.stringify(response) }] };
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/mcp/tools/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/signature.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAgChD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAgH9E"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { buildToolStats, recordToolCall, buildArgsJson, buildResultsJson } from '../../telemetry/metrics.js';
|
|
4
|
+
import { countTokens, estimateFullFileBound } from '../../telemetry/tokenizer.js';
|
|
5
|
+
import { querySymbolByName, resolveTypeContext } from '../../graph/queries.js';
|
|
6
|
+
import { extractFileSignatures } from '../../ast/extract.js';
|
|
7
|
+
import { jitRefreshFile, isIndexEmpty } from './_helpers.js';
|
|
8
|
+
// TypeScript built-in types that are never worth resolving as user-defined types.
|
|
9
|
+
const BUILTIN_TYPES = new Set([
|
|
10
|
+
'string', 'number', 'boolean', 'void', 'null', 'undefined', 'never', 'any',
|
|
11
|
+
'unknown', 'object', 'symbol', 'bigint', 'Function', 'Object', 'Promise',
|
|
12
|
+
'Array', 'Map', 'Set', 'WeakMap', 'WeakSet', 'Record', 'Partial', 'Required',
|
|
13
|
+
'Readonly', 'Pick', 'Omit', 'Exclude', 'Extract', 'NonNullable', 'ReturnType',
|
|
14
|
+
'InstanceType', 'Parameters', 'ConstructorParameters', 'Error',
|
|
15
|
+
]);
|
|
16
|
+
/**
|
|
17
|
+
* Extract user-defined PascalCase type names from a TypeScript signature.
|
|
18
|
+
* Used to populate `type_context` in `mast_signature` responses.
|
|
19
|
+
*/
|
|
20
|
+
function extractTypeNames(signature) {
|
|
21
|
+
const re = /\b([A-Z][A-Za-z0-9]*)\b/g;
|
|
22
|
+
const names = new Set();
|
|
23
|
+
let m;
|
|
24
|
+
while ((m = re.exec(signature)) !== null) {
|
|
25
|
+
const name = m[1];
|
|
26
|
+
if (!BUILTIN_TYPES.has(name))
|
|
27
|
+
names.add(name);
|
|
28
|
+
}
|
|
29
|
+
return [...names];
|
|
30
|
+
}
|
|
31
|
+
export function registerSignatureTool(server, ctx) {
|
|
32
|
+
server.tool('mast_signature', 'Declaration, TSDoc, and resolved parameter type context for a named symbol. Returns an array — always pass file_path to disambiguate when you expect a single result.', {
|
|
33
|
+
symbol: z.string().describe('Symbol name to look up (e.g. "handleLogin", "AuthService")'),
|
|
34
|
+
file_path: z.string().nullable().optional().describe('Narrow to a specific file; omit to search across the whole codebase'),
|
|
35
|
+
}, async (args) => {
|
|
36
|
+
const start = Date.now();
|
|
37
|
+
const filePath = args.file_path ?? null;
|
|
38
|
+
// §9.0 TOCTOU policy. When `file_path` narrows the query, every result
|
|
39
|
+
// necessarily comes from that one file, so a single busy check up front
|
|
40
|
+
// covers all of them (`topLevelBusy` below). When omitted, results can
|
|
41
|
+
// span many files and each gets its own JIT call inside the loop.
|
|
42
|
+
let topLevelBusy = false;
|
|
43
|
+
if (filePath != null) {
|
|
44
|
+
const r = await jitRefreshFile(ctx.db, ctx.config, filePath);
|
|
45
|
+
topLevelBusy = r.busy;
|
|
46
|
+
}
|
|
47
|
+
const symbols = await querySymbolByName(ctx.db, args.symbol, filePath ?? undefined);
|
|
48
|
+
// Parse each referenced file at most once for its signatures.
|
|
49
|
+
const sigsByFile = new Map();
|
|
50
|
+
const sigsFor = (relPath) => {
|
|
51
|
+
let s = sigsByFile.get(relPath);
|
|
52
|
+
if (s === undefined) {
|
|
53
|
+
s = extractFileSignatures(join(ctx.config.resolved_project_root, relPath));
|
|
54
|
+
sigsByFile.set(relPath, s);
|
|
55
|
+
}
|
|
56
|
+
return s;
|
|
57
|
+
};
|
|
58
|
+
const results = [];
|
|
59
|
+
for (const sym of symbols) {
|
|
60
|
+
// Per-result busy flag: when file_path is omitted, each symbol's own
|
|
61
|
+
// file is JIT-refreshed independently, so its busy status must not
|
|
62
|
+
// leak onto results from other (unaffected) files.
|
|
63
|
+
let resultBusy = topLevelBusy;
|
|
64
|
+
if (filePath == null) {
|
|
65
|
+
const r = await jitRefreshFile(ctx.db, ctx.config, sym.file_path);
|
|
66
|
+
resultBusy = r.busy;
|
|
67
|
+
}
|
|
68
|
+
const sigs = sigsFor(sym.file_path);
|
|
69
|
+
// Prefer an exact name+line match; fall back to name only.
|
|
70
|
+
const sig = sigs.find((s) => s.name === sym.name && s.line === sym.line) ??
|
|
71
|
+
sigs.find((s) => s.name === sym.name);
|
|
72
|
+
const params = sig?.params ?? [];
|
|
73
|
+
const returnType = sig?.returnType ?? null;
|
|
74
|
+
// type_context is resolved from the parameter/return TYPES only — not
|
|
75
|
+
// the body — so it no longer pulls in unrelated identifiers (§9).
|
|
76
|
+
const typeNames = extractTypeNames([...params.map((p) => p.type), returnType ?? ''].join(' '));
|
|
77
|
+
const typeContext = await resolveTypeContext(ctx.db, typeNames, sym.file_path);
|
|
78
|
+
results.push({
|
|
79
|
+
symbol: sym.name,
|
|
80
|
+
file_path: sym.file_path,
|
|
81
|
+
line: sym.line,
|
|
82
|
+
signature: sig?.signature ?? '',
|
|
83
|
+
doc: sig?.doc ?? null,
|
|
84
|
+
params,
|
|
85
|
+
return_type: returnType,
|
|
86
|
+
type_context: typeContext,
|
|
87
|
+
// §9.0 TOCTOU policy: omitted when false, never present-and-false.
|
|
88
|
+
...(resultBusy ? { file_busy_returning_stale_cache: true } : {}),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const filesReferenced = [...new Set(results.map((r) => r.file_path))];
|
|
92
|
+
const text = JSON.stringify(results);
|
|
93
|
+
const tokens = countTokens(text);
|
|
94
|
+
const tokensFullFileBound = estimateFullFileBound(filesReferenced, ctx.config.resolved_project_root);
|
|
95
|
+
const durationMs = Date.now() - start;
|
|
96
|
+
// M6 (§13.8 item 4): checked ONLY on the empty-result path. Independent
|
|
97
|
+
// of the F14 busy-envelope flag above — both name different failure
|
|
98
|
+
// modes ("busy, can't tell you" vs "nothing indexed") and either, both,
|
|
99
|
+
// or neither may fire on the same empty response.
|
|
100
|
+
const indexEmptyField = results.length === 0 && await isIndexEmpty(ctx)
|
|
101
|
+
? { index_empty: true }
|
|
102
|
+
: {};
|
|
103
|
+
const response = {
|
|
104
|
+
results,
|
|
105
|
+
// F14: with zero results the per-result busy carrier vanishes, and a
|
|
106
|
+
// stale index would read as "symbol doesn't exist" — surface the
|
|
107
|
+
// top-level busy signal on the envelope in exactly that case.
|
|
108
|
+
...(topLevelBusy && results.length === 0
|
|
109
|
+
? { file_busy_returning_stale_cache: true }
|
|
110
|
+
: {}),
|
|
111
|
+
...indexEmptyField,
|
|
112
|
+
_stats: buildToolStats('mast_signature', tokens, tokensFullFileBound, filesReferenced, durationMs),
|
|
113
|
+
};
|
|
114
|
+
// Identity pairs — the "did this signature call target a symbol/file
|
|
115
|
+
// an earlier search surfaced?" evidence for the capsule instrumentation
|
|
116
|
+
// decision (IMPLEMENTATION_PLAN_VEXP.md §P, 2026-07-15).
|
|
117
|
+
const resultIdentities = results.map((r) => ({ file_path: r.file_path, symbol_name: r.symbol }));
|
|
118
|
+
void recordToolCall(ctx.db, {
|
|
119
|
+
toolName: 'mast_signature', tokensReturned: tokens, tokensFullFileBound,
|
|
120
|
+
durationMs, sessionId: ctx.sessionId, status: 'ok',
|
|
121
|
+
argsJson: buildArgsJson(args),
|
|
122
|
+
resultsJson: buildResultsJson(resultIdentities),
|
|
123
|
+
}).catch(() => { });
|
|
124
|
+
return { content: [{ type: 'text', text: JSON.stringify(response) }] };
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=signature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../../../src/mcp/tools/signature.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAMhD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CA6B3E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { loadIndexMeta, freshnessCause } from '../../indexer/index.js';
|
|
2
|
+
import { measureFreshness } from '../../indexer/freshness.js';
|
|
3
|
+
import { CURRENT_SCHEMA_VERSION } from '../../store/config.js';
|
|
4
|
+
export function registerStatusTool(server, ctx) {
|
|
5
|
+
server.tool('mast_status', 'Index health summary: last-indexed time, file/chunk counts, stale file count, freshness cause.',
|
|
6
|
+
// No input parameters.
|
|
7
|
+
{}, async (_args) => {
|
|
8
|
+
const meta = loadIndexMeta(ctx.config.resolved_state_dir);
|
|
9
|
+
// The same producer `mast status` uses — the two surfaces answer one
|
|
10
|
+
// question and must not compute it twice
|
|
11
|
+
// (`mcp/tools/__tests__/status-surface-parity.test.ts`).
|
|
12
|
+
const stale_files = (await measureFreshness(ctx.config, ctx.db)).total;
|
|
13
|
+
const result = {
|
|
14
|
+
state_dir: ctx.config.resolved_state_dir,
|
|
15
|
+
// From the binary, never from index.json — see StatusResult.schema_version.
|
|
16
|
+
schema_version: CURRENT_SCHEMA_VERSION,
|
|
17
|
+
last_indexed: meta?.last_indexed ?? null,
|
|
18
|
+
indexed_files: meta?.file_count ?? 0,
|
|
19
|
+
chunk_count: meta?.chunk_count ?? 0,
|
|
20
|
+
stale_files,
|
|
21
|
+
parse_errors: meta?.parse_errors ?? 0,
|
|
22
|
+
write_errors: meta?.write_errors ?? 0,
|
|
23
|
+
index_fresh: meta !== null && stale_files === 0,
|
|
24
|
+
freshness_cause: freshnessCause(stale_files),
|
|
25
|
+
seed_commit: meta?.seed_commit,
|
|
26
|
+
};
|
|
27
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/mcp/tools/status.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,GAAe;IACnE,MAAM,CAAC,IAAI,CACT,aAAa,EACb,gGAAgG;IAChG,uBAAuB;IACvB,EAAE,EACF,KAAK,EAAE,KAAK,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAC1D,qEAAqE;QACrE,yCAAyC;QACzC,yDAAyD;QACzD,MAAM,WAAW,GAAG,CAAC,MAAM,gBAAgB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACvE,MAAM,MAAM,GAAiB;YAC3B,SAAS,EAAO,GAAG,CAAC,MAAM,CAAC,kBAAkB;YAC7C,4EAA4E;YAC5E,cAAc,EAAE,sBAAsB;YACtC,YAAY,EAAI,IAAI,EAAE,YAAY,IAAI,IAAI;YAC1C,aAAa,EAAG,IAAI,EAAE,UAAU,IAAI,CAAC;YACrC,WAAW,EAAK,IAAI,EAAE,WAAW,IAAI,CAAC;YACtC,WAAW;YACX,YAAY,EAAI,IAAI,EAAE,YAAY,IAAI,CAAC;YACvC,YAAY,EAAI,IAAI,EAAE,YAAY,IAAI,CAAC;YACvC,WAAW,EAAK,IAAI,KAAK,IAAI,IAAI,WAAW,KAAK,CAAC;YAClD,eAAe,EAAE,cAAc,CAAC,WAAW,CAAC;YAC5C,WAAW,EAAK,IAAI,EAAE,WAAW;SAClC,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;IAChF,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ranker D — the declaration-exact ranker: a match against `chunks.symbol_name`
|
|
3
|
+
* (full-name or final-dot-segment), case-insensitive, deterministically
|
|
4
|
+
* ordered.
|
|
5
|
+
*
|
|
6
|
+
* Ported from `eval/declex-ranker.mjs`, the Q1/DECLEX-measured construction
|
|
7
|
+
* (IMPLEMENTATION_PLAN.md § "Q1/DECLEX — the declaration-exact ranker" +
|
|
8
|
+
* AMENDMENT 1, commit dd10796; Stage 6 of the productization plan). PRIMARY
|
|
9
|
+
* ARM ONLY — this file intentionally does NOT port the escape variant
|
|
10
|
+
* (`escape`/`escapeCap` options, `escapeEligibleTerms`/
|
|
11
|
+
* `lowercaseTokenMatchCounts` diagnostics) or `classifyTargetReach`
|
|
12
|
+
* (instrument-analysis machinery, not product). The escape variant was
|
|
13
|
+
* measured harmful off-stratum (M2 decision memo) and is barred from
|
|
14
|
+
* shipping without a fresh pre-registration.
|
|
15
|
+
*
|
|
16
|
+
* Ranker D queries the `chunks` table DIRECTLY (not `chunk_fts`/
|
|
17
|
+
* `identifier_fts`): `chunk_fts.symbol_name` is stored UNINDEXED
|
|
18
|
+
* (`src/graph/db.ts`) — not reachable via FTS5 MATCH — and the registered
|
|
19
|
+
* match rule ("equals the chunk's own symbol_name OR its final dot-segment")
|
|
20
|
+
* is a structural string comparison, not a full-text match, so a direct SQL
|
|
21
|
+
* predicate against `chunks.symbol_name` is the correct primitive.
|
|
22
|
+
*/
|
|
23
|
+
import type { Db } from '../graph/db.js';
|
|
24
|
+
import { type SearchScope } from './scope.js';
|
|
25
|
+
/**
|
|
26
|
+
* Ranker D's candidate pool multiplier — 4x the caller's own `limit`, the
|
|
27
|
+
* SAME convention as ranker I (`eval/idfuse-ranker.mjs`, AMENDMENT 1 F8) and
|
|
28
|
+
* the pre-Stage-7 vector search helper: the caller multiplies by 4 and passes
|
|
29
|
+
* the already-multiplied limit directly; `searchRankerD` applies no further
|
|
30
|
+
* internal multiplication.
|
|
31
|
+
*/
|
|
32
|
+
export declare const RANKER_D_POOL_MULTIPLIER = 4;
|
|
33
|
+
/** Raw token split — identical character class to ranker I's own derivation
|
|
34
|
+
* (`eval/idfuse-ranker.mjs`); no camelCase split, no lowercasing. `Class.method`
|
|
35
|
+
* splits into two independent terms (the dot is not in the character class). */
|
|
36
|
+
export declare function deriveRankerDTerms(query: string): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Symbol-shaped eligibility predicate for ranker D's PRIMARY arm — reproduces
|
|
39
|
+
* `isSymbolShapedTerm` (`eval/idfuse-ranker.mjs`) MINUS the dead
|
|
40
|
+
* `term.includes('.')` clause (registration: "the implementation also tests
|
|
41
|
+
* term.includes('.'), but the upstream split character class
|
|
42
|
+
* `/[A-Za-z0-9_$]+/` never includes `.` in any surviving token ... Ranker D's
|
|
43
|
+
* eligibility gate reproduces this predicate but drops the dead clause rather
|
|
44
|
+
* than reimplementing dead code"). A term qualifies if it contains an
|
|
45
|
+
* uppercase letter, an underscore, a dollar sign, or a digit adjacent to a
|
|
46
|
+
* letter.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isEligiblePrimaryTerm(term: string): boolean;
|
|
49
|
+
/** Ranker D's PRIMARY-arm eligible terms: raw split, filtered to symbol-shaped. */
|
|
50
|
+
export declare function deriveEligiblePrimaryTerms(query: string): string[];
|
|
51
|
+
export interface DeclexRow {
|
|
52
|
+
readonly chunk_id: string;
|
|
53
|
+
readonly symbol_name: string;
|
|
54
|
+
readonly chunk_type: string;
|
|
55
|
+
readonly match_type: 'full' | 'segment';
|
|
56
|
+
}
|
|
57
|
+
export interface DeclexDiagnostics {
|
|
58
|
+
/** D produced >= 1 candidate. */
|
|
59
|
+
readonly fired: boolean;
|
|
60
|
+
/** The winning (first-ordered) candidate's match type, or null if D did not fire. */
|
|
61
|
+
readonly top_match_channel: 'full' | 'segment' | null;
|
|
62
|
+
/** Pre-cap candidate pool size. */
|
|
63
|
+
readonly candidate_count: number;
|
|
64
|
+
readonly primary_eligible_terms: readonly string[];
|
|
65
|
+
}
|
|
66
|
+
export interface DeclexSearchOptions {
|
|
67
|
+
/** The FINAL SQL limit to apply (the caller's already-multiplied candidate
|
|
68
|
+
* pool — same convention as ranker I; multiply by
|
|
69
|
+
* {@link RANKER_D_POOL_MULTIPLIER} before calling). */
|
|
70
|
+
readonly limit: number;
|
|
71
|
+
/**
|
|
72
|
+
* Restrict candidates to files matching the caller's `file_pattern` /
|
|
73
|
+
* `language`. Omitted means unrestricted, which is what the Q1/DECLEX
|
|
74
|
+
* measurement arms and their frozen reconstructions
|
|
75
|
+
* (`eval/declex-rank-check.mjs`) ran with — they pass `{ limit }` only, so
|
|
76
|
+
* their behaviour is unchanged by this option existing.
|
|
77
|
+
*/
|
|
78
|
+
readonly scope?: SearchScope | undefined;
|
|
79
|
+
}
|
|
80
|
+
export interface DeclexSearchResult {
|
|
81
|
+
readonly rows: DeclexRow[];
|
|
82
|
+
readonly diagnostics: DeclexDiagnostics;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Ranker D: declaration-exact match against `chunks.symbol_name` (full-name
|
|
86
|
+
* or final-dot-segment), case-insensitive, deterministically ordered.
|
|
87
|
+
*
|
|
88
|
+
* Ordering (registration): full-name matches before segment-only matches;
|
|
89
|
+
* then fewer total same-matched-name candidates first; then ascending
|
|
90
|
+
* chunk_id. JUDGMENT CALL (flagged per this codebase's convention, e.g.
|
|
91
|
+
* `eval/idfuse-score.mjs`'s a-fortiori routing note): "same-name" is read as
|
|
92
|
+
* "same MATCHED name" — full-name candidates group by their own
|
|
93
|
+
* `symbol_name`; segment candidates group by the shared final dot-segment
|
|
94
|
+
* (the quantity the design review's F-4 finding is actually about — a
|
|
95
|
+
* `toJSON`-class query facing ~140 candidates that all share the SEGMENT
|
|
96
|
+
* "toJSON", not 140 candidates sharing one `symbol_name`, since each belongs
|
|
97
|
+
* to a different class). This groups the exact multiplicity class the
|
|
98
|
+
* registration's own fixture (Gate B, high-multiplicity segment) is built to
|
|
99
|
+
* exercise.
|
|
100
|
+
*
|
|
101
|
+
* `options.scope` restricts the candidate pool to the caller's `file_pattern` /
|
|
102
|
+
* `language` before any of the above is computed, so `diagnostics.candidate_count`
|
|
103
|
+
* and the ordering both describe the scoped pool — a scoped search behaves as
|
|
104
|
+
* though the index contained only the files in scope.
|
|
105
|
+
*
|
|
106
|
+
* @param query - the RAW query string (term derivation happens here).
|
|
107
|
+
*/
|
|
108
|
+
export declare function searchRankerD(db: Db, query: string, options: DeclexSearchOptions): Promise<DeclexSearchResult>;
|
|
109
|
+
//# sourceMappingURL=declex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declex.d.ts","sourceRoot":"","sources":["../../src/search/declex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAA0C,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtF;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAM1C;;gFAEgF;AAChF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE1D;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAO3D;AAED,mFAAmF;AACnF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAElE;AAiHD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,qFAAqF;IACrF,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACtD,mCAAmC;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,sBAAsB,EAAE,SAAS,MAAM,EAAE,CAAC;CACpD;AAED,MAAM,WAAW,mBAAmB;IAClC;;2DAEuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,EAAE,EACN,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA8E7B"}
|