@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.
Files changed (257) hide show
  1. package/LICENSE +21 -0
  2. package/MAST_SPEC.md +2926 -0
  3. package/README.md +842 -0
  4. package/assets/skill.md +45 -0
  5. package/dist/ast/extract.d.ts +65 -0
  6. package/dist/ast/extract.d.ts.map +1 -0
  7. package/dist/ast/extract.js +147 -0
  8. package/dist/ast/extract.js.map +1 -0
  9. package/dist/ast/extractor.d.ts +85 -0
  10. package/dist/ast/extractor.d.ts.map +1 -0
  11. package/dist/ast/extractor.js +2 -0
  12. package/dist/ast/extractor.js.map +1 -0
  13. package/dist/ast/extractors/markdown.d.ts +40 -0
  14. package/dist/ast/extractors/markdown.d.ts.map +1 -0
  15. package/dist/ast/extractors/markdown.js +175 -0
  16. package/dist/ast/extractors/markdown.js.map +1 -0
  17. package/dist/ast/extractors/typescript.d.ts +179 -0
  18. package/dist/ast/extractors/typescript.d.ts.map +1 -0
  19. package/dist/ast/extractors/typescript.js +1439 -0
  20. package/dist/ast/extractors/typescript.js.map +1 -0
  21. package/dist/ast/parser.d.ts +5 -0
  22. package/dist/ast/parser.d.ts.map +1 -0
  23. package/dist/ast/parser.js +21 -0
  24. package/dist/ast/parser.js.map +1 -0
  25. package/dist/ast/types.d.ts +586 -0
  26. package/dist/ast/types.d.ts.map +1 -0
  27. package/dist/ast/types.js +3 -0
  28. package/dist/ast/types.js.map +1 -0
  29. package/dist/cli/docs-cmd.d.ts +22 -0
  30. package/dist/cli/docs-cmd.d.ts.map +1 -0
  31. package/dist/cli/docs-cmd.js +100 -0
  32. package/dist/cli/docs-cmd.js.map +1 -0
  33. package/dist/cli/index-cmd.d.ts +72 -0
  34. package/dist/cli/index-cmd.d.ts.map +1 -0
  35. package/dist/cli/index-cmd.js +263 -0
  36. package/dist/cli/index-cmd.js.map +1 -0
  37. package/dist/cli/index.d.ts +3 -0
  38. package/dist/cli/index.d.ts.map +1 -0
  39. package/dist/cli/index.js +4 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cli/init.d.ts +14 -0
  42. package/dist/cli/init.d.ts.map +1 -0
  43. package/dist/cli/init.js +64 -0
  44. package/dist/cli/init.js.map +1 -0
  45. package/dist/cli/install-hooks.d.ts +3 -0
  46. package/dist/cli/install-hooks.d.ts.map +1 -0
  47. package/dist/cli/install-hooks.js +34 -0
  48. package/dist/cli/install-hooks.js.map +1 -0
  49. package/dist/cli/metrics-cmd.d.ts +3 -0
  50. package/dist/cli/metrics-cmd.d.ts.map +1 -0
  51. package/dist/cli/metrics-cmd.js +164 -0
  52. package/dist/cli/metrics-cmd.js.map +1 -0
  53. package/dist/cli/program.d.ts +14 -0
  54. package/dist/cli/program.d.ts.map +1 -0
  55. package/dist/cli/program.js +44 -0
  56. package/dist/cli/program.js.map +1 -0
  57. package/dist/cli/query.d.ts +46 -0
  58. package/dist/cli/query.d.ts.map +1 -0
  59. package/dist/cli/query.js +153 -0
  60. package/dist/cli/query.js.map +1 -0
  61. package/dist/cli/search-cmd.d.ts +33 -0
  62. package/dist/cli/search-cmd.d.ts.map +1 -0
  63. package/dist/cli/search-cmd.js +114 -0
  64. package/dist/cli/search-cmd.js.map +1 -0
  65. package/dist/cli/serve.d.ts +3 -0
  66. package/dist/cli/serve.d.ts.map +1 -0
  67. package/dist/cli/serve.js +19 -0
  68. package/dist/cli/serve.js.map +1 -0
  69. package/dist/cli/skill-install.d.ts +39 -0
  70. package/dist/cli/skill-install.d.ts.map +1 -0
  71. package/dist/cli/skill-install.js +57 -0
  72. package/dist/cli/skill-install.js.map +1 -0
  73. package/dist/cli/status.d.ts +35 -0
  74. package/dist/cli/status.d.ts.map +1 -0
  75. package/dist/cli/status.js +117 -0
  76. package/dist/cli/status.js.map +1 -0
  77. package/dist/cli/upgrade-cmd.d.ts +48 -0
  78. package/dist/cli/upgrade-cmd.d.ts.map +1 -0
  79. package/dist/cli/upgrade-cmd.js +129 -0
  80. package/dist/cli/upgrade-cmd.js.map +1 -0
  81. package/dist/cli/version.d.ts +3 -0
  82. package/dist/cli/version.d.ts.map +1 -0
  83. package/dist/cli/version.js +19 -0
  84. package/dist/cli/version.js.map +1 -0
  85. package/dist/env.d.ts +17 -0
  86. package/dist/env.d.ts.map +1 -0
  87. package/dist/env.js +17 -0
  88. package/dist/env.js.map +1 -0
  89. package/dist/graph/checker-resolver.d.ts +156 -0
  90. package/dist/graph/checker-resolver.d.ts.map +1 -0
  91. package/dist/graph/checker-resolver.js +458 -0
  92. package/dist/graph/checker-resolver.js.map +1 -0
  93. package/dist/graph/db.d.ts +318 -0
  94. package/dist/graph/db.d.ts.map +1 -0
  95. package/dist/graph/db.js +266 -0
  96. package/dist/graph/db.js.map +1 -0
  97. package/dist/graph/index.d.ts +4 -0
  98. package/dist/graph/index.d.ts.map +1 -0
  99. package/dist/graph/index.js +5 -0
  100. package/dist/graph/index.js.map +1 -0
  101. package/dist/graph/local-type-env.d.ts +45 -0
  102. package/dist/graph/local-type-env.d.ts.map +1 -0
  103. package/dist/graph/local-type-env.js +59 -0
  104. package/dist/graph/local-type-env.js.map +1 -0
  105. package/dist/graph/path-range.d.ts +40 -0
  106. package/dist/graph/path-range.d.ts.map +1 -0
  107. package/dist/graph/path-range.js +42 -0
  108. package/dist/graph/path-range.js.map +1 -0
  109. package/dist/graph/populate.d.ts +263 -0
  110. package/dist/graph/populate.d.ts.map +1 -0
  111. package/dist/graph/populate.js +984 -0
  112. package/dist/graph/populate.js.map +1 -0
  113. package/dist/graph/queries.d.ts +114 -0
  114. package/dist/graph/queries.d.ts.map +1 -0
  115. package/dist/graph/queries.js +415 -0
  116. package/dist/graph/queries.js.map +1 -0
  117. package/dist/graph/sqliteBatch.d.ts +48 -0
  118. package/dist/graph/sqliteBatch.d.ts.map +1 -0
  119. package/dist/graph/sqliteBatch.js +93 -0
  120. package/dist/graph/sqliteBatch.js.map +1 -0
  121. package/dist/indexer/freshness.d.ts +48 -0
  122. package/dist/indexer/freshness.d.ts.map +1 -0
  123. package/dist/indexer/freshness.js +72 -0
  124. package/dist/indexer/freshness.js.map +1 -0
  125. package/dist/indexer/import-resolver.d.ts +50 -0
  126. package/dist/indexer/import-resolver.d.ts.map +1 -0
  127. package/dist/indexer/import-resolver.js +318 -0
  128. package/dist/indexer/import-resolver.js.map +1 -0
  129. package/dist/indexer/index.d.ts +249 -0
  130. package/dist/indexer/index.d.ts.map +1 -0
  131. package/dist/indexer/index.js +560 -0
  132. package/dist/indexer/index.js.map +1 -0
  133. package/dist/indexer/walker.d.ts +60 -0
  134. package/dist/indexer/walker.d.ts.map +1 -0
  135. package/dist/indexer/walker.js +128 -0
  136. package/dist/indexer/walker.js.map +1 -0
  137. package/dist/indexer/watcher.d.ts +80 -0
  138. package/dist/indexer/watcher.d.ts.map +1 -0
  139. package/dist/indexer/watcher.js +151 -0
  140. package/dist/indexer/watcher.js.map +1 -0
  141. package/dist/mcp/context.d.ts +23 -0
  142. package/dist/mcp/context.d.ts.map +1 -0
  143. package/dist/mcp/context.js +2 -0
  144. package/dist/mcp/context.js.map +1 -0
  145. package/dist/mcp/register-tools.d.ts +21 -0
  146. package/dist/mcp/register-tools.d.ts.map +1 -0
  147. package/dist/mcp/register-tools.js +42 -0
  148. package/dist/mcp/register-tools.js.map +1 -0
  149. package/dist/mcp/server.d.ts +58 -0
  150. package/dist/mcp/server.d.ts.map +1 -0
  151. package/dist/mcp/server.js +177 -0
  152. package/dist/mcp/server.js.map +1 -0
  153. package/dist/mcp/staleness.d.ts +72 -0
  154. package/dist/mcp/staleness.d.ts.map +1 -0
  155. package/dist/mcp/staleness.js +213 -0
  156. package/dist/mcp/staleness.js.map +1 -0
  157. package/dist/mcp/startup.d.ts +40 -0
  158. package/dist/mcp/startup.d.ts.map +1 -0
  159. package/dist/mcp/startup.js +114 -0
  160. package/dist/mcp/startup.js.map +1 -0
  161. package/dist/mcp/tools/_helpers.d.ts +26 -0
  162. package/dist/mcp/tools/_helpers.d.ts.map +1 -0
  163. package/dist/mcp/tools/_helpers.js +54 -0
  164. package/dist/mcp/tools/_helpers.js.map +1 -0
  165. package/dist/mcp/tools/callers.d.ts +4 -0
  166. package/dist/mcp/tools/callers.d.ts.map +1 -0
  167. package/dist/mcp/tools/callers.js +112 -0
  168. package/dist/mcp/tools/callers.js.map +1 -0
  169. package/dist/mcp/tools/dependencies.d.ts +4 -0
  170. package/dist/mcp/tools/dependencies.d.ts.map +1 -0
  171. package/dist/mcp/tools/dependencies.js +36 -0
  172. package/dist/mcp/tools/dependencies.js.map +1 -0
  173. package/dist/mcp/tools/efficiency.d.ts +4 -0
  174. package/dist/mcp/tools/efficiency.d.ts.map +1 -0
  175. package/dist/mcp/tools/efficiency.js +39 -0
  176. package/dist/mcp/tools/efficiency.js.map +1 -0
  177. package/dist/mcp/tools/exports.d.ts +4 -0
  178. package/dist/mcp/tools/exports.d.ts.map +1 -0
  179. package/dist/mcp/tools/exports.js +56 -0
  180. package/dist/mcp/tools/exports.js.map +1 -0
  181. package/dist/mcp/tools/implementors.d.ts +4 -0
  182. package/dist/mcp/tools/implementors.d.ts.map +1 -0
  183. package/dist/mcp/tools/implementors.js +47 -0
  184. package/dist/mcp/tools/implementors.js.map +1 -0
  185. package/dist/mcp/tools/project-skeleton.d.ts +4 -0
  186. package/dist/mcp/tools/project-skeleton.d.ts.map +1 -0
  187. package/dist/mcp/tools/project-skeleton.js +61 -0
  188. package/dist/mcp/tools/project-skeleton.js.map +1 -0
  189. package/dist/mcp/tools/reindex.d.ts +14 -0
  190. package/dist/mcp/tools/reindex.d.ts.map +1 -0
  191. package/dist/mcp/tools/reindex.js +32 -0
  192. package/dist/mcp/tools/reindex.js.map +1 -0
  193. package/dist/mcp/tools/rename-impact.d.ts +4 -0
  194. package/dist/mcp/tools/rename-impact.d.ts.map +1 -0
  195. package/dist/mcp/tools/rename-impact.js +124 -0
  196. package/dist/mcp/tools/rename-impact.js.map +1 -0
  197. package/dist/mcp/tools/search.d.ts +4 -0
  198. package/dist/mcp/tools/search.d.ts.map +1 -0
  199. package/dist/mcp/tools/search.js +69 -0
  200. package/dist/mcp/tools/search.js.map +1 -0
  201. package/dist/mcp/tools/signature.d.ts +4 -0
  202. package/dist/mcp/tools/signature.d.ts.map +1 -0
  203. package/dist/mcp/tools/signature.js +127 -0
  204. package/dist/mcp/tools/signature.js.map +1 -0
  205. package/dist/mcp/tools/status.d.ts +4 -0
  206. package/dist/mcp/tools/status.d.ts.map +1 -0
  207. package/dist/mcp/tools/status.js +30 -0
  208. package/dist/mcp/tools/status.js.map +1 -0
  209. package/dist/search/declex.d.ts +109 -0
  210. package/dist/search/declex.d.ts.map +1 -0
  211. package/dist/search/declex.js +242 -0
  212. package/dist/search/declex.js.map +1 -0
  213. package/dist/search/fts.d.ts +77 -0
  214. package/dist/search/fts.d.ts.map +1 -0
  215. package/dist/search/fts.js +223 -0
  216. package/dist/search/fts.js.map +1 -0
  217. package/dist/search/fused.d.ts +110 -0
  218. package/dist/search/fused.d.ts.map +1 -0
  219. package/dist/search/fused.js +323 -0
  220. package/dist/search/fused.js.map +1 -0
  221. package/dist/search/potential-matches.d.ts +88 -0
  222. package/dist/search/potential-matches.d.ts.map +1 -0
  223. package/dist/search/potential-matches.js +83 -0
  224. package/dist/search/potential-matches.js.map +1 -0
  225. package/dist/search/scope.d.ts +66 -0
  226. package/dist/search/scope.d.ts.map +1 -0
  227. package/dist/search/scope.js +71 -0
  228. package/dist/search/scope.js.map +1 -0
  229. package/dist/store/config.d.ts +57 -0
  230. package/dist/store/config.d.ts.map +1 -0
  231. package/dist/store/config.js +208 -0
  232. package/dist/store/config.js.map +1 -0
  233. package/dist/store/lock.d.ts +101 -0
  234. package/dist/store/lock.d.ts.map +1 -0
  235. package/dist/store/lock.js +182 -0
  236. package/dist/store/lock.js.map +1 -0
  237. package/dist/store/lockMetrics.d.ts +52 -0
  238. package/dist/store/lockMetrics.d.ts.map +1 -0
  239. package/dist/store/lockMetrics.js +29 -0
  240. package/dist/store/lockMetrics.js.map +1 -0
  241. package/dist/store/sqliteChunkStore.d.ts +44 -0
  242. package/dist/store/sqliteChunkStore.d.ts.map +1 -0
  243. package/dist/store/sqliteChunkStore.js +135 -0
  244. package/dist/store/sqliteChunkStore.js.map +1 -0
  245. package/dist/telemetry/lockMetricsSummary.d.ts +42 -0
  246. package/dist/telemetry/lockMetricsSummary.d.ts.map +1 -0
  247. package/dist/telemetry/lockMetricsSummary.js +139 -0
  248. package/dist/telemetry/lockMetricsSummary.js.map +1 -0
  249. package/dist/telemetry/metrics.d.ts +140 -0
  250. package/dist/telemetry/metrics.d.ts.map +1 -0
  251. package/dist/telemetry/metrics.js +312 -0
  252. package/dist/telemetry/metrics.js.map +1 -0
  253. package/dist/telemetry/tokenizer.d.ts +125 -0
  254. package/dist/telemetry/tokenizer.d.ts.map +1 -0
  255. package/dist/telemetry/tokenizer.js +174 -0
  256. package/dist/telemetry/tokenizer.js.map +1 -0
  257. 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,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { AppContext } from '../context.js';
3
+ export declare function registerRenameImpactTool(server: McpServer, ctx: AppContext): void;
4
+ //# sourceMappingURL=rename-impact.d.ts.map
@@ -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":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACrG,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEtF;;;;GAIG;AACH,SAAS,cAAc,CAAC,QAAgB,EAAE,SAAiB,EAAE,OAAe;IAC1E,OAAO;QACL,GAAG,QAAQ,kCAAkC;QAC7C,GAAG,SAAS,uCAAuC;QACnD,GAAG,OAAO,6BAA6B;KACxC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,GAAe;IACzE,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,kXAAkX,EAClX;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kEAAkE,CAAC;QAC/F,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;KACtH,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC;QAExC,sEAAsE;QACtE,uEAAuE;QACvE,gDAAgD;QAChD,oEAAoE;QACpE,8DAA8D;QAC9D,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC7D,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC;QACpB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,IAAI,SAAS,CAAC,CAAC;QAEpF,MAAM,iBAAiB,GAAsB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/D,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW,KAAK,CAAC;SACjC,CAAC,CAAC,CAAC;QAEJ,+DAA+D;QAC/D,sEAAsE;QACtE,6DAA6D;QAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE1B,IAAI,gBAAgB,GAAqB,EAAE,CAAC;QAC5C,IAAI,iBAAiB,GAA8B,EAAE,CAAC;QACtD,IAAI,cAAc,GAAuB,EAAE,CAAC;QAC5C,IAAI,4BAA4B,GAAG,CAAC,CAAC;QACrC,IAAI,qCAAqC,GAAG,CAAC,CAAC;QAC9C,IAAI,kBAAsC,CAAC;QAE3C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,uEAAuE;YACvE,6EAA6E;YAC7E,MAAM,YAAY,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YAC1E,gBAAgB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC1C,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,aAAa,EAAE,CAAC,CAAC,aAAa;gBAC9B,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,UAAU,EAAE,CAAC,CAAC,UAA8B;aAC7C,CAAC,CAAC,CAAC;YAEJ,MAAM,eAAe,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;YACxH,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC;YAC5C,4BAA4B,GAAG,eAAe,CAAC,4BAA4B,CAAC;YAC5E,qCAAqC,GAAG,eAAe,CAAC,qCAAqC,CAAC;YAC9F,kBAAkB,GAAG,eAAe,CAAC,mBAAmB,CAAC;YAEzD,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC5F,cAAc,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtC,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,GAAG,EAAE,CAAC,CAAC,GAAG;aACX,CAAC,CAAC,CAAC;QACN,CAAC;QAED,MAAM,eAAe,GAAG;YACtB,GAAG,IAAI,GAAG,CAAC;gBACT,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5C,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC3C,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5C,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;aAC1C,CAAC;SACH,CAAC;QACF,MAAM,IAAI,GAAG,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;QACxF,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACjD,MAAM,mBAAmB,GAAG,qBAAqB,CAAC,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACrG,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAEtC,0EAA0E;QAC1E,MAAM,eAAe,GACnB,iBAAiB,CAAC,MAAM,KAAK,CAAC;YAC9B,gBAAgB,CAAC,MAAM,KAAK,CAAC;YAC7B,iBAAiB,CAAC,MAAM,KAAK,CAAC;YAC9B,cAAc,CAAC,MAAM,KAAK,CAAC;YAC3B,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC,CAAC,EAAE,WAAW,EAAE,IAAa,EAAE;YAChC,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,QAAQ,GAAyB;YACrC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,GAAG,IAAI;YACP,mEAAmE;YACnE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,+BAA+B,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,GAAG,eAAe;YAClB,OAAO,EAAE;gBACP,iBAAiB,EAAE,iBAAiB,CAAC,MAAM;gBAC3C,cAAc,EAAE,gBAAgB,CAAC,MAAM;gBACvC,eAAe,EAAE,iBAAiB,CAAC,MAAM;gBACzC,YAAY,EAAE,cAAc,CAAC,MAAM;gBACnC,SAAS,EACP,MAAM,KAAK,SAAS;oBAClB,CAAC,CAAC,WAAW,IAAI,CAAC,MAAM,+CAA+C;oBACvE,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC;gBAC9F,gCAAgC,EAAE,4BAA4B;gBAC9D,wCAAwC,EAAE,qCAAqC;gBAC/E,8EAA8E;gBAC9E,GAAG,CAAC,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACzF;YACD,MAAM,EAAE,cAAc,CAAC,oBAAoB,EAAE,MAAM,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,CAAC;SACvG,CAAC;QACF,KAAK,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE;YAC1B,QAAQ,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,EAAE,mBAAmB;YAC3E,UAAU,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI;SACnD,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACnB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IAClF,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { AppContext } from '../context.js';
3
+ export declare function registerSearchTool(server: McpServer, ctx: AppContext): void;
4
+ //# sourceMappingURL=search.d.ts.map
@@ -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,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { AppContext } from '../context.js';
3
+ export declare function registerSignatureTool(server: McpServer, ctx: AppContext): void;
4
+ //# sourceMappingURL=signature.d.ts.map
@@ -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,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { AppContext } from '../context.js';
3
+ export declare function registerStatusTool(server: McpServer, ctx: AppContext): void;
4
+ //# sourceMappingURL=status.d.ts.map
@@ -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"}