projscan 0.11.0 → 0.14.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 (278) hide show
  1. package/README.md +57 -33
  2. package/dist/analyzers/crossPackageImportCheck.d.ts +13 -0
  3. package/dist/analyzers/crossPackageImportCheck.js +136 -0
  4. package/dist/analyzers/crossPackageImportCheck.js.map +1 -0
  5. package/dist/analyzers/cycleCheck.d.ts +12 -0
  6. package/dist/analyzers/cycleCheck.js +65 -0
  7. package/dist/analyzers/cycleCheck.js.map +1 -0
  8. package/dist/analyzers/unusedDependencyCheck.js +69 -17
  9. package/dist/analyzers/unusedDependencyCheck.js.map +1 -1
  10. package/dist/cli/_shared.d.ts +16 -0
  11. package/dist/cli/_shared.js +210 -0
  12. package/dist/cli/_shared.js.map +1 -0
  13. package/dist/cli/commands/analyze.d.ts +1 -0
  14. package/dist/cli/commands/analyze.js +87 -0
  15. package/dist/cli/commands/analyze.js.map +1 -0
  16. package/dist/cli/commands/audit.d.ts +1 -0
  17. package/dist/cli/commands/audit.js +53 -0
  18. package/dist/cli/commands/audit.js.map +1 -0
  19. package/dist/cli/commands/badge.d.ts +1 -0
  20. package/dist/cli/commands/badge.js +45 -0
  21. package/dist/cli/commands/badge.js.map +1 -0
  22. package/dist/cli/commands/ci.d.ts +1 -0
  23. package/dist/cli/commands/ci.js +57 -0
  24. package/dist/cli/commands/ci.js.map +1 -0
  25. package/dist/cli/commands/coupling.d.ts +1 -0
  26. package/dist/cli/commands/coupling.js +83 -0
  27. package/dist/cli/commands/coupling.js.map +1 -0
  28. package/dist/cli/commands/coverage.d.ts +1 -0
  29. package/dist/cli/commands/coverage.js +63 -0
  30. package/dist/cli/commands/coverage.js.map +1 -0
  31. package/dist/cli/commands/dependencies.d.ts +1 -0
  32. package/dist/cli/commands/dependencies.js +46 -0
  33. package/dist/cli/commands/dependencies.js.map +1 -0
  34. package/dist/cli/commands/diagram.d.ts +1 -0
  35. package/dist/cli/commands/diagram.js +45 -0
  36. package/dist/cli/commands/diagram.js.map +1 -0
  37. package/dist/cli/commands/diff.d.ts +1 -0
  38. package/dist/cli/commands/diff.js +70 -0
  39. package/dist/cli/commands/diff.js.map +1 -0
  40. package/dist/cli/commands/doctor.d.ts +1 -0
  41. package/dist/cli/commands/doctor.js +62 -0
  42. package/dist/cli/commands/doctor.js.map +1 -0
  43. package/dist/cli/commands/explain.d.ts +1 -0
  44. package/dist/cli/commands/explain.js +42 -0
  45. package/dist/cli/commands/explain.js.map +1 -0
  46. package/dist/cli/commands/explainIssue.d.ts +1 -0
  47. package/dist/cli/commands/explainIssue.js +49 -0
  48. package/dist/cli/commands/explainIssue.js.map +1 -0
  49. package/dist/cli/commands/file.d.ts +1 -0
  50. package/dist/cli/commands/file.js +45 -0
  51. package/dist/cli/commands/file.js.map +1 -0
  52. package/dist/cli/commands/fix.d.ts +1 -0
  53. package/dist/cli/commands/fix.js +70 -0
  54. package/dist/cli/commands/fix.js.map +1 -0
  55. package/dist/cli/commands/fixSuggest.d.ts +1 -0
  56. package/dist/cli/commands/fixSuggest.js +71 -0
  57. package/dist/cli/commands/fixSuggest.js.map +1 -0
  58. package/dist/cli/commands/help.d.ts +1 -0
  59. package/dist/cli/commands/help.js +11 -0
  60. package/dist/cli/commands/help.js.map +1 -0
  61. package/dist/cli/commands/hotspots.d.ts +1 -0
  62. package/dist/cli/commands/hotspots.js +74 -0
  63. package/dist/cli/commands/hotspots.js.map +1 -0
  64. package/dist/cli/commands/mcp.d.ts +1 -0
  65. package/dist/cli/commands/mcp.js +21 -0
  66. package/dist/cli/commands/mcp.js.map +1 -0
  67. package/dist/cli/commands/outdated.d.ts +1 -0
  68. package/dist/cli/commands/outdated.js +51 -0
  69. package/dist/cli/commands/outdated.js.map +1 -0
  70. package/dist/cli/commands/prDiff.d.ts +1 -0
  71. package/dist/cli/commands/prDiff.js +59 -0
  72. package/dist/cli/commands/prDiff.js.map +1 -0
  73. package/dist/cli/commands/review.d.ts +1 -0
  74. package/dist/cli/commands/review.js +66 -0
  75. package/dist/cli/commands/review.js.map +1 -0
  76. package/dist/cli/commands/search.d.ts +1 -0
  77. package/dist/cli/commands/search.js +233 -0
  78. package/dist/cli/commands/search.js.map +1 -0
  79. package/dist/cli/commands/structure.d.ts +1 -0
  80. package/dist/cli/commands/structure.js +58 -0
  81. package/dist/cli/commands/structure.js.map +1 -0
  82. package/dist/cli/commands/upgrade.d.ts +1 -0
  83. package/dist/cli/commands/upgrade.js +44 -0
  84. package/dist/cli/commands/upgrade.js.map +1 -0
  85. package/dist/cli/commands/workspaces.d.ts +1 -0
  86. package/dist/cli/commands/workspaces.js +35 -0
  87. package/dist/cli/commands/workspaces.js.map +1 -0
  88. package/dist/cli/index.js +51 -1416
  89. package/dist/cli/index.js.map +1 -1
  90. package/dist/core/ast.d.ts +20 -0
  91. package/dist/core/ast.js +190 -0
  92. package/dist/core/ast.js.map +1 -1
  93. package/dist/core/auditRunner.d.ts +8 -0
  94. package/dist/core/auditRunner.js +50 -1
  95. package/dist/core/auditRunner.js.map +1 -1
  96. package/dist/core/codeGraph.d.ts +7 -1
  97. package/dist/core/codeGraph.js +2 -0
  98. package/dist/core/codeGraph.js.map +1 -1
  99. package/dist/core/couplingAnalyzer.d.ts +1 -1
  100. package/dist/core/couplingAnalyzer.js +3 -3
  101. package/dist/core/dependencyAnalyzer.d.ts +15 -1
  102. package/dist/core/dependencyAnalyzer.js +115 -18
  103. package/dist/core/dependencyAnalyzer.js.map +1 -1
  104. package/dist/core/explainIssue.d.ts +9 -0
  105. package/dist/core/explainIssue.js +106 -0
  106. package/dist/core/explainIssue.js.map +1 -0
  107. package/dist/core/fileInspector.js +12 -0
  108. package/dist/core/fileInspector.js.map +1 -1
  109. package/dist/core/fixSuggest.d.ts +41 -0
  110. package/dist/core/fixSuggest.js +327 -0
  111. package/dist/core/fixSuggest.js.map +1 -0
  112. package/dist/core/hotspotAnalyzer.js +2 -2
  113. package/dist/core/indexCache.js +5 -1
  114. package/dist/core/indexCache.js.map +1 -1
  115. package/dist/core/issueEngine.js +18 -0
  116. package/dist/core/issueEngine.js.map +1 -1
  117. package/dist/core/languages/LanguageAdapter.d.ts +1 -1
  118. package/dist/core/languages/goAdapter.js +12 -5
  119. package/dist/core/languages/goAdapter.js.map +1 -1
  120. package/dist/core/languages/goCallSites.d.ts +20 -0
  121. package/dist/core/languages/goCallSites.js +42 -0
  122. package/dist/core/languages/goCallSites.js.map +1 -0
  123. package/dist/core/languages/goCyclomatic.d.ts +1 -1
  124. package/dist/core/languages/goCyclomatic.js +2 -2
  125. package/dist/core/languages/goExports.d.ts +1 -1
  126. package/dist/core/languages/goExports.js +1 -1
  127. package/dist/core/languages/goFunctions.d.ts +24 -0
  128. package/dist/core/languages/goFunctions.js +99 -0
  129. package/dist/core/languages/goFunctions.js.map +1 -0
  130. package/dist/core/languages/goManifests.d.ts +1 -1
  131. package/dist/core/languages/goManifests.js +2 -2
  132. package/dist/core/languages/javaAdapter.d.ts +2 -0
  133. package/dist/core/languages/javaAdapter.js +153 -0
  134. package/dist/core/languages/javaAdapter.js.map +1 -0
  135. package/dist/core/languages/javaCallSites.d.ts +16 -0
  136. package/dist/core/languages/javaCallSites.js +45 -0
  137. package/dist/core/languages/javaCallSites.js.map +1 -0
  138. package/dist/core/languages/javaCyclomatic.d.ts +21 -0
  139. package/dist/core/languages/javaCyclomatic.js +49 -0
  140. package/dist/core/languages/javaCyclomatic.js.map +1 -0
  141. package/dist/core/languages/javaExports.d.ts +25 -0
  142. package/dist/core/languages/javaExports.js +80 -0
  143. package/dist/core/languages/javaExports.js.map +1 -0
  144. package/dist/core/languages/javaFunctions.d.ts +22 -0
  145. package/dist/core/languages/javaFunctions.js +87 -0
  146. package/dist/core/languages/javaFunctions.js.map +1 -0
  147. package/dist/core/languages/javaImports.d.ts +25 -0
  148. package/dist/core/languages/javaImports.js +49 -0
  149. package/dist/core/languages/javaImports.js.map +1 -0
  150. package/dist/core/languages/javaManifests.d.ts +25 -0
  151. package/dist/core/languages/javaManifests.js +86 -0
  152. package/dist/core/languages/javaManifests.js.map +1 -0
  153. package/dist/core/languages/pythonAdapter.js +8 -1
  154. package/dist/core/languages/pythonAdapter.js.map +1 -1
  155. package/dist/core/languages/pythonCallSites.d.ts +19 -0
  156. package/dist/core/languages/pythonCallSites.js +40 -0
  157. package/dist/core/languages/pythonCallSites.js.map +1 -0
  158. package/dist/core/languages/pythonFunctions.d.ts +23 -0
  159. package/dist/core/languages/pythonFunctions.js +87 -0
  160. package/dist/core/languages/pythonFunctions.js.map +1 -0
  161. package/dist/core/languages/registry.js +3 -1
  162. package/dist/core/languages/registry.js.map +1 -1
  163. package/dist/core/languages/rubyAdapter.d.ts +2 -0
  164. package/dist/core/languages/rubyAdapter.js +136 -0
  165. package/dist/core/languages/rubyAdapter.js.map +1 -0
  166. package/dist/core/languages/rubyCallSites.d.ts +16 -0
  167. package/dist/core/languages/rubyCallSites.js +34 -0
  168. package/dist/core/languages/rubyCallSites.js.map +1 -0
  169. package/dist/core/languages/rubyCyclomatic.d.ts +19 -0
  170. package/dist/core/languages/rubyCyclomatic.js +47 -0
  171. package/dist/core/languages/rubyCyclomatic.js.map +1 -0
  172. package/dist/core/languages/rubyExports.d.ts +24 -0
  173. package/dist/core/languages/rubyExports.js +53 -0
  174. package/dist/core/languages/rubyExports.js.map +1 -0
  175. package/dist/core/languages/rubyFunctions.d.ts +22 -0
  176. package/dist/core/languages/rubyFunctions.js +91 -0
  177. package/dist/core/languages/rubyFunctions.js.map +1 -0
  178. package/dist/core/languages/rubyImports.d.ts +12 -0
  179. package/dist/core/languages/rubyImports.js +75 -0
  180. package/dist/core/languages/rubyImports.js.map +1 -0
  181. package/dist/core/languages/rubyManifests.d.ts +20 -0
  182. package/dist/core/languages/rubyManifests.js +55 -0
  183. package/dist/core/languages/rubyManifests.js.map +1 -0
  184. package/dist/core/languages/treeSitterLoader.js +3 -1
  185. package/dist/core/languages/treeSitterLoader.js.map +1 -1
  186. package/dist/core/monorepo.js +5 -5
  187. package/dist/core/outdatedDetector.d.ts +13 -2
  188. package/dist/core/outdatedDetector.js +86 -16
  189. package/dist/core/outdatedDetector.js.map +1 -1
  190. package/dist/core/prDiff.d.ts +1 -1
  191. package/dist/core/prDiff.js +2 -2
  192. package/dist/core/review.d.ts +21 -0
  193. package/dist/core/review.js +457 -0
  194. package/dist/core/review.js.map +1 -0
  195. package/dist/grammars/tree-sitter-java.wasm +0 -0
  196. package/dist/grammars/tree-sitter-ruby.wasm +0 -0
  197. package/dist/index.d.ts +5 -1
  198. package/dist/index.js +3 -0
  199. package/dist/index.js.map +1 -1
  200. package/dist/mcp/server.js +0 -22
  201. package/dist/mcp/server.js.map +1 -1
  202. package/dist/mcp/tools/_shared.d.ts +24 -0
  203. package/dist/mcp/tools/_shared.js +82 -0
  204. package/dist/mcp/tools/_shared.js.map +1 -0
  205. package/dist/mcp/tools/analyze.d.ts +2 -0
  206. package/dist/mcp/tools/analyze.js +55 -0
  207. package/dist/mcp/tools/analyze.js.map +1 -0
  208. package/dist/mcp/tools/audit.d.ts +2 -0
  209. package/dist/mcp/tools/audit.js +37 -0
  210. package/dist/mcp/tools/audit.js.map +1 -0
  211. package/dist/mcp/tools/coupling.d.ts +2 -0
  212. package/dist/mcp/tools/coupling.js +67 -0
  213. package/dist/mcp/tools/coupling.js.map +1 -0
  214. package/dist/mcp/tools/coverage.d.ts +2 -0
  215. package/dist/mcp/tools/coverage.js +53 -0
  216. package/dist/mcp/tools/coverage.js.map +1 -0
  217. package/dist/mcp/tools/dependencies.d.ts +2 -0
  218. package/dist/mcp/tools/dependencies.js +22 -0
  219. package/dist/mcp/tools/dependencies.js.map +1 -0
  220. package/dist/mcp/tools/doctor.d.ts +2 -0
  221. package/dist/mcp/tools/doctor.js +30 -0
  222. package/dist/mcp/tools/doctor.js.map +1 -0
  223. package/dist/mcp/tools/explain.d.ts +2 -0
  224. package/dist/mcp/tools/explain.js +30 -0
  225. package/dist/mcp/tools/explain.js.map +1 -0
  226. package/dist/mcp/tools/explainIssue.d.ts +2 -0
  227. package/dist/mcp/tools/explainIssue.js +30 -0
  228. package/dist/mcp/tools/explainIssue.js.map +1 -0
  229. package/dist/mcp/tools/file.d.ts +2 -0
  230. package/dist/mcp/tools/file.js +22 -0
  231. package/dist/mcp/tools/file.js.map +1 -0
  232. package/dist/mcp/tools/fixSuggest.d.ts +2 -0
  233. package/dist/mcp/tools/fixSuggest.js +57 -0
  234. package/dist/mcp/tools/fixSuggest.js.map +1 -0
  235. package/dist/mcp/tools/graph.d.ts +2 -0
  236. package/dist/mcp/tools/graph.js +69 -0
  237. package/dist/mcp/tools/graph.js.map +1 -0
  238. package/dist/mcp/tools/hotspots.d.ts +2 -0
  239. package/dist/mcp/tools/hotspots.js +103 -0
  240. package/dist/mcp/tools/hotspots.js.map +1 -0
  241. package/dist/mcp/tools/outdated.d.ts +2 -0
  242. package/dist/mcp/tools/outdated.js +36 -0
  243. package/dist/mcp/tools/outdated.js.map +1 -0
  244. package/dist/mcp/tools/prDiff.d.ts +2 -0
  245. package/dist/mcp/tools/prDiff.js +38 -0
  246. package/dist/mcp/tools/prDiff.js.map +1 -0
  247. package/dist/mcp/tools/review.d.ts +2 -0
  248. package/dist/mcp/tools/review.js +54 -0
  249. package/dist/mcp/tools/review.js.map +1 -0
  250. package/dist/mcp/tools/search.d.ts +2 -0
  251. package/dist/mcp/tools/search.js +167 -0
  252. package/dist/mcp/tools/search.js.map +1 -0
  253. package/dist/mcp/tools/structure.d.ts +2 -0
  254. package/dist/mcp/tools/structure.js +34 -0
  255. package/dist/mcp/tools/structure.js.map +1 -0
  256. package/dist/mcp/tools/upgrade.d.ts +2 -0
  257. package/dist/mcp/tools/upgrade.js +38 -0
  258. package/dist/mcp/tools/upgrade.js.map +1 -0
  259. package/dist/mcp/tools/workspaces.d.ts +2 -0
  260. package/dist/mcp/tools/workspaces.js +13 -0
  261. package/dist/mcp/tools/workspaces.js.map +1 -0
  262. package/dist/mcp/tools.d.ts +12 -6
  263. package/dist/mcp/tools.js +46 -854
  264. package/dist/mcp/tools.js.map +1 -1
  265. package/dist/reporters/consoleReporter.d.ts +9 -1
  266. package/dist/reporters/consoleReporter.js +177 -0
  267. package/dist/reporters/consoleReporter.js.map +1 -1
  268. package/dist/reporters/jsonReporter.d.ts +9 -1
  269. package/dist/reporters/jsonReporter.js +9 -0
  270. package/dist/reporters/jsonReporter.js.map +1 -1
  271. package/dist/reporters/markdownReporter.d.ts +9 -1
  272. package/dist/reporters/markdownReporter.js +141 -0
  273. package/dist/reporters/markdownReporter.js.map +1 -1
  274. package/dist/tool-manifest.json +446 -0
  275. package/dist/types.d.ts +235 -5
  276. package/dist/utils/config.js +26 -9
  277. package/dist/utils/config.js.map +1 -1
  278. package/package.json +8 -3
@@ -0,0 +1,2 @@
1
+ import type { McpTool } from './_shared.js';
2
+ export declare const graphTool: McpTool;
@@ -0,0 +1,69 @@
1
+ import { scanRepository } from '../../core/repositoryScanner.js';
2
+ import { buildCodeGraph, filesImportingFile, filesImportingPackage, filesDefiningSymbol, exportsOf, importsOf, } from '../../core/codeGraph.js';
3
+ import { loadCachedGraph, saveCachedGraph } from '../../core/indexCache.js';
4
+ export const graphTool = {
5
+ name: 'projscan_graph',
6
+ description: 'Query the AST-based code graph directly. Returns imports, exports, importers, or symbol definitions for a file or symbol. Agents should prefer this over analyze/doctor/explain for targeted structural questions - it is much cheaper and more accurate.',
7
+ inputSchema: {
8
+ type: 'object',
9
+ properties: {
10
+ file: {
11
+ type: 'string',
12
+ description: 'File path (relative to project root) to query.',
13
+ },
14
+ symbol: {
15
+ type: 'string',
16
+ description: 'Symbol name to query (e.g. a function or class). Use instead of `file` to find where a symbol is defined.',
17
+ },
18
+ direction: {
19
+ type: 'string',
20
+ description: 'What to return: "imports" (what the file imports), "exports" (what the file exports), "importers" (who imports the file), "symbol_defs" (files defining the symbol), "package_importers" (files importing a package by name).',
21
+ enum: ['imports', 'exports', 'importers', 'symbol_defs', 'package_importers'],
22
+ },
23
+ limit: { type: 'number', description: 'Max entries returned (default 50).' },
24
+ max_tokens: { type: 'number', description: 'Cap the response to roughly this many tokens.' },
25
+ },
26
+ required: ['direction'],
27
+ },
28
+ handler: async (args, rootPath) => {
29
+ const scan = await scanRepository(rootPath);
30
+ const cached = await loadCachedGraph(rootPath);
31
+ const graph = await buildCodeGraph(rootPath, scan.files, cached);
32
+ await saveCachedGraph(rootPath, graph);
33
+ const direction = String(args.direction);
34
+ const file = typeof args.file === 'string' ? args.file : undefined;
35
+ const symbol = typeof args.symbol === 'string' ? args.symbol : undefined;
36
+ const limit = Math.max(1, Math.min(500, typeof args.limit === 'number' ? args.limit : 50));
37
+ switch (direction) {
38
+ case 'imports': {
39
+ if (!file)
40
+ throw new Error('file argument is required for direction=imports');
41
+ return { file, imports: importsOf(graph, file).slice(0, limit) };
42
+ }
43
+ case 'exports': {
44
+ if (!file)
45
+ throw new Error('file argument is required for direction=exports');
46
+ return { file, exports: exportsOf(graph, file).slice(0, limit) };
47
+ }
48
+ case 'importers': {
49
+ if (!file)
50
+ throw new Error('file argument is required for direction=importers');
51
+ return { file, importers: filesImportingFile(graph, file).slice(0, limit) };
52
+ }
53
+ case 'symbol_defs': {
54
+ if (!symbol)
55
+ throw new Error('symbol argument is required for direction=symbol_defs');
56
+ return { symbol, definedIn: filesDefiningSymbol(graph, symbol).slice(0, limit) };
57
+ }
58
+ case 'package_importers': {
59
+ const pkg = symbol ?? file;
60
+ if (!pkg)
61
+ throw new Error('symbol (or file) argument is required for direction=package_importers');
62
+ return { package: pkg, importers: filesImportingPackage(graph, pkg).slice(0, limit) };
63
+ }
64
+ default:
65
+ throw new Error(`unknown direction: ${direction}`);
66
+ }
67
+ },
68
+ };
69
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/mcp/tools/graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpTool } from './_shared.js';
2
+ export declare const hotspotsTool: McpTool;
@@ -0,0 +1,103 @@
1
+ import { scanRepository } from '../../core/repositoryScanner.js';
2
+ import { collectIssues } from '../../core/issueEngine.js';
3
+ import { analyzeHotspots } from '../../core/hotspotAnalyzer.js';
4
+ import { buildCodeGraph } from '../../core/codeGraph.js';
5
+ import { loadCachedGraph, saveCachedGraph } from '../../core/indexCache.js';
6
+ import { detectWorkspaces, filterFilesByPackage } from '../../core/monorepo.js';
7
+ import { paginate, listChecksum, readPageParams } from '../pagination.js';
8
+ import { emitProgress } from '../progress.js';
9
+ export const hotspotsTool = {
10
+ name: 'projscan_hotspots',
11
+ description: 'Rank files by risk using git churn × AST cyclomatic complexity × open issues. Returns the most dangerous files to touch. Each hotspot includes `cyclomaticComplexity` (null for non-AST languages, where line count is used as fallback). Supports cursor-based pagination: pass the `nextCursor` from a previous response back as `cursor` to fetch the next page. Pass `view: "functions"` to flatten results into the top-N riskiest individual functions across all hotspots, ranked by per-function CC.',
12
+ inputSchema: {
13
+ type: 'object',
14
+ properties: {
15
+ limit: {
16
+ type: 'number',
17
+ description: 'Cap on total hotspots ranked (default 100). For paging the returned set, use `page_size` + `cursor` instead.',
18
+ },
19
+ since: {
20
+ type: 'string',
21
+ description: 'Git history window. Examples: "12 months ago", "2024-01-01". Default: "12 months ago".',
22
+ },
23
+ cursor: { type: 'string', description: 'Opaque cursor from a previous response. Omit for the first page.' },
24
+ page_size: { type: 'number', description: 'Items per page (default 50, max 500).' },
25
+ max_tokens: { type: 'number', description: 'Cap response to roughly this many tokens.' },
26
+ package: {
27
+ type: 'string',
28
+ description: 'Optional. Workspace package name (from projscan_workspaces) to scope hotspots to one package only.',
29
+ },
30
+ view: {
31
+ type: 'string',
32
+ enum: ['files', 'functions'],
33
+ description: 'Output shape. "files" (default) returns ranked hotspot files. "functions" returns the top-N individual functions across all hotspots, sorted by per-function CC desc.',
34
+ },
35
+ },
36
+ },
37
+ handler: async (args, rootPath) => {
38
+ emitProgress(0, 5, 'scanning repository');
39
+ const scan = await scanRepository(rootPath);
40
+ emitProgress(1, 5, 'collecting issues');
41
+ const issues = await collectIssues(rootPath, scan.files);
42
+ const limit = typeof args.limit === 'number' ? args.limit : 100;
43
+ const since = typeof args.since === 'string' ? args.since : undefined;
44
+ emitProgress(2, 5, 'building code graph');
45
+ const cached = await loadCachedGraph(rootPath);
46
+ const graph = await buildCodeGraph(rootPath, scan.files, cached);
47
+ await saveCachedGraph(rootPath, graph);
48
+ emitProgress(3, 5, 'analyzing git churn + risk');
49
+ const report = await analyzeHotspots(rootPath, scan.files, issues, { limit, since, graph });
50
+ if (typeof args.package === 'string' && args.package.length > 0) {
51
+ const ws = await detectWorkspaces(rootPath);
52
+ const allowed = new Set(filterFilesByPackage(ws, args.package, report.hotspots.map((h) => h.relativePath)));
53
+ report.hotspots = report.hotspots.filter((h) => allowed.has(h.relativePath));
54
+ }
55
+ // 0.13.0: function-level view. Flattens per-file `functions` lists into a
56
+ // single ranked list. Skips files with no per-function CC (e.g. ones the
57
+ // adapter parsed but found no function definitions, or non-AST languages).
58
+ if (args.view === 'functions') {
59
+ const ranked = [];
60
+ for (const h of report.hotspots) {
61
+ const gf = graph.files.get(h.relativePath);
62
+ if (!gf || !gf.functions || gf.functions.length === 0)
63
+ continue;
64
+ for (const fn of gf.functions) {
65
+ ranked.push({
66
+ file: h.relativePath,
67
+ name: fn.name,
68
+ line: fn.line,
69
+ endLine: fn.endLine,
70
+ cyclomaticComplexity: fn.cyclomaticComplexity,
71
+ fileRiskScore: h.riskScore,
72
+ });
73
+ }
74
+ }
75
+ ranked.sort((a, b) => b.cyclomaticComplexity - a.cyclomaticComplexity);
76
+ const page = paginate(ranked, readPageParams(args), listChecksum(ranked));
77
+ emitProgress(5, 5, 'done');
78
+ return {
79
+ available: report.available,
80
+ reason: report.reason,
81
+ window: report.window,
82
+ view: 'functions',
83
+ functions: page.items,
84
+ totalFunctionsRanked: ranked.length,
85
+ nextCursor: page.nextCursor,
86
+ total: page.total,
87
+ };
88
+ }
89
+ emitProgress(4, 5, 'paginating');
90
+ const page = paginate(report.hotspots, readPageParams(args), listChecksum(report.hotspots));
91
+ emitProgress(5, 5, 'done');
92
+ return {
93
+ available: report.available,
94
+ reason: report.reason,
95
+ window: report.window,
96
+ hotspots: page.items,
97
+ totalFilesRanked: report.totalFilesRanked,
98
+ nextCursor: page.nextCursor,
99
+ total: page.total,
100
+ };
101
+ },
102
+ };
103
+ //# sourceMappingURL=hotspots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotspots.js","sourceRoot":"","sources":["../../../src/mcp/tools/hotspots.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { type McpTool } from './_shared.js';
2
+ export declare const outdatedTool: McpTool;
@@ -0,0 +1,36 @@
1
+ import { detectOutdated } from '../../core/outdatedDetector.js';
2
+ import { detectWorkspaces } from '../../core/monorepo.js';
3
+ import { paginate, listChecksum, readPageParams } from '../pagination.js';
4
+ import { PACKAGE_ARG_SCHEMA } from './_shared.js';
5
+ export const outdatedTool = {
6
+ name: 'projscan_outdated',
7
+ description: 'Compare declared vs installed versions of every package. Reports drift (patch/minor/major). Workspace-aware in monorepos: each package.json is scanned, and each entry is tagged with the workspace it came from. Pass `package` to scope to a single workspace. Offline - does not hit the npm registry. Supports cursor pagination.',
8
+ inputSchema: {
9
+ type: 'object',
10
+ properties: {
11
+ package: PACKAGE_ARG_SCHEMA,
12
+ cursor: { type: 'string', description: 'Opaque cursor from a previous response.' },
13
+ page_size: { type: 'number', description: 'Items per page (default 50).' },
14
+ max_tokens: { type: 'number', description: 'Cap response size.' },
15
+ },
16
+ },
17
+ handler: async (args, rootPath) => {
18
+ const workspaces = await detectWorkspaces(rootPath);
19
+ const report = await detectOutdated(rootPath, {
20
+ workspaces,
21
+ ...(typeof args.package === 'string' ? { workspaceFilter: args.package } : {}),
22
+ });
23
+ if (!report.available)
24
+ return report;
25
+ const page = paginate(report.packages, readPageParams(args), listChecksum(report.packages));
26
+ return {
27
+ available: true,
28
+ totalPackages: report.totalPackages,
29
+ packages: page.items,
30
+ byWorkspace: report.byWorkspace,
31
+ total: page.total,
32
+ nextCursor: page.nextCursor,
33
+ };
34
+ },
35
+ };
36
+ //# sourceMappingURL=outdated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outdated.js","sourceRoot":"","sources":["../../../src/mcp/tools/outdated.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAgB,MAAM,cAAc,CAAC;AAEhE,MAAM,CAAC,MAAM,YAAY,GAAY;IACnC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EACT,uUAAuU;IACzU,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,OAAO,EAAE,kBAAkB;YAC3B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yCAAyC,EAAE;YAClF,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8BAA8B,EAAE;YAC1E,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE;SAClE;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE;YAC5C,UAAU;YACV,GAAG,CAAC,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/E,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,SAAS;YAAE,OAAO,MAAM,CAAC;QACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5F,OAAO;YACL,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,QAAQ,EAAE,IAAI,CAAC,KAAK;YACpB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { type McpTool } from './_shared.js';
2
+ export declare const prDiffTool: McpTool;
@@ -0,0 +1,38 @@
1
+ import { computePrDiff } from '../../core/prDiff.js';
2
+ import { emitProgress } from '../progress.js';
3
+ import { PACKAGE_ARG_SCHEMA, resolvePackageFilter } from './_shared.js';
4
+ export const prDiffTool = {
5
+ name: 'projscan_pr_diff',
6
+ description: 'Structural (AST) diff between two refs - what changed in exports, imports, call sites, cyclomatic complexity, and fan-in. Not a text diff: this surfaces the symbols and edges that an agent reviewing a PR actually cares about. Defaults: base=origin/main (falls back to main/master/HEAD~1), head=HEAD. Spins up a throwaway git worktree at the base ref to get a clean second graph.',
7
+ inputSchema: {
8
+ type: 'object',
9
+ properties: {
10
+ base: {
11
+ type: 'string',
12
+ description: 'Base ref (branch, tag, sha). Default: origin/main, falling back to main/master/HEAD~1.',
13
+ },
14
+ head: { type: 'string', description: 'Head ref. Default: HEAD.' },
15
+ max_tokens: { type: 'number', description: 'Cap the response to roughly this many tokens.' },
16
+ package: PACKAGE_ARG_SCHEMA,
17
+ },
18
+ },
19
+ handler: async (args, rootPath) => {
20
+ emitProgress(0, 3, 'resolving refs');
21
+ const base = typeof args.base === 'string' ? args.base : undefined;
22
+ const head = typeof args.head === 'string' ? args.head : undefined;
23
+ emitProgress(1, 3, 'building base + head graphs');
24
+ const report = await computePrDiff(rootPath, { base, head });
25
+ emitProgress(2, 3, 'diffing');
26
+ const passes = await resolvePackageFilter(rootPath, args);
27
+ if (passes) {
28
+ report.filesAdded = report.filesAdded.filter(passes);
29
+ report.filesRemoved = report.filesRemoved.filter(passes);
30
+ report.filesModified = report.filesModified.filter((f) => passes(f.relativePath));
31
+ report.totalFilesChanged =
32
+ report.filesAdded.length + report.filesRemoved.length + report.filesModified.length;
33
+ }
34
+ emitProgress(3, 3, 'done');
35
+ return report;
36
+ },
37
+ };
38
+ //# sourceMappingURL=prDiff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prDiff.js","sourceRoot":"","sources":["../../../src/mcp/tools/prDiff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAgB,MAAM,cAAc,CAAC;AAEtF,MAAM,CAAC,MAAM,UAAU,GAAY;IACjC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,4XAA4X;IAC9X,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,wFAAwF;aACtG;YACD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0BAA0B,EAAE;YACjE,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+CAA+C,EAAE;YAC5F,OAAO,EAAE,kBAAkB;SAC5B;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,6BAA6B,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC1D,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACrD,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACzD,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;YAClF,MAAM,CAAC,iBAAiB;gBACtB,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;QACxF,CAAC;QACD,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpTool } from './_shared.js';
2
+ export declare const reviewTool: McpTool;
@@ -0,0 +1,54 @@
1
+ import { computeReview } from '../../core/review.js';
2
+ import { detectWorkspaces, filterFilesByPackage } from '../../core/monorepo.js';
3
+ import { emitProgress } from '../progress.js';
4
+ export const reviewTool = {
5
+ name: 'projscan_review',
6
+ description: 'One-call PR review. Combines projscan_pr_diff + per-changed-file risk score + new/expanded import cycles + risky function additions + dependency changes, plus a verdict ("ok" | "review" | "block") with a one-line summary. Use when an agent is asked "is this PR safe to merge?" Defaults: base=origin/main (falls back to main/master/HEAD~1), head=HEAD.',
7
+ inputSchema: {
8
+ type: 'object',
9
+ properties: {
10
+ base: {
11
+ type: 'string',
12
+ description: 'Base ref (branch, tag, sha). Default: origin/main, falling back to main/master/HEAD~1.',
13
+ },
14
+ head: { type: 'string', description: 'Head ref. Default: HEAD.' },
15
+ max_tokens: { type: 'number', description: 'Cap the response to roughly this many tokens.' },
16
+ package: {
17
+ type: 'string',
18
+ description: 'Optional. Workspace package name to scope all sections of the review to a single package.',
19
+ },
20
+ },
21
+ },
22
+ handler: async (args, rootPath) => {
23
+ emitProgress(0, 4, 'resolving refs');
24
+ const base = typeof args.base === 'string' ? args.base : undefined;
25
+ const head = typeof args.head === 'string' ? args.head : undefined;
26
+ emitProgress(1, 4, 'building base + head graphs');
27
+ const report = await computeReview(rootPath, { base, head });
28
+ if (typeof args.package === 'string' && args.package.length > 0 && report.available) {
29
+ emitProgress(2, 4, 'scoping to workspace');
30
+ const ws = await detectWorkspaces(rootPath);
31
+ const target = args.package;
32
+ const allChangedPaths = [
33
+ ...report.prDiff.filesAdded,
34
+ ...report.prDiff.filesRemoved,
35
+ ...report.prDiff.filesModified.map((f) => f.relativePath),
36
+ ];
37
+ const allowed = new Set(filterFilesByPackage(ws, target, allChangedPaths));
38
+ report.prDiff.filesAdded = report.prDiff.filesAdded.filter((f) => allowed.has(f));
39
+ report.prDiff.filesRemoved = report.prDiff.filesRemoved.filter((f) => allowed.has(f));
40
+ report.prDiff.filesModified = report.prDiff.filesModified.filter((f) => allowed.has(f.relativePath));
41
+ report.prDiff.totalFilesChanged =
42
+ report.prDiff.filesAdded.length +
43
+ report.prDiff.filesRemoved.length +
44
+ report.prDiff.filesModified.length;
45
+ report.changedFiles = report.changedFiles.filter((f) => allowed.has(f.relativePath));
46
+ report.newCycles = report.newCycles.filter((c) => c.files.some((f) => allowed.has(f)));
47
+ report.riskyFunctions = report.riskyFunctions.filter((f) => allowed.has(f.file));
48
+ report.dependencyChanges = report.dependencyChanges.filter((d) => d.workspace === target);
49
+ }
50
+ emitProgress(4, 4, 'done');
51
+ return report;
52
+ },
53
+ };
54
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/mcp/tools/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { type McpTool } from './_shared.js';
2
+ export declare const searchTool: McpTool;
@@ -0,0 +1,167 @@
1
+ import { scanRepository } from '../../core/repositoryScanner.js';
2
+ import { buildCodeGraph } from '../../core/codeGraph.js';
3
+ import { loadCachedGraph, saveCachedGraph } from '../../core/indexCache.js';
4
+ import { buildSearchIndex, search as searchIndex, attachExcerpts, expandQuery, } from '../../core/searchIndex.js';
5
+ import { buildSemanticIndex, semanticSearch, reciprocalRankFusion, } from '../../core/semanticSearch.js';
6
+ import { isSemanticAvailable } from '../../core/embeddings.js';
7
+ import { paginate, listChecksum, readPageParams } from '../pagination.js';
8
+ import { PACKAGE_ARG_SCHEMA, resolvePackageFilter } from './_shared.js';
9
+ export const searchTool = {
10
+ name: 'projscan_search',
11
+ description: 'Ranked search across the project. Lexical (BM25) by default; optional semantic (vector) and hybrid (RRF fusion) modes available when the @xenova/transformers peer dependency is installed. Scope controls what to search: "auto"/"content" (ranked content matches with excerpts), "symbols" (exported names), "files" (path substring).',
12
+ inputSchema: {
13
+ type: 'object',
14
+ properties: {
15
+ query: {
16
+ type: 'string',
17
+ description: 'Search string. Multi-word queries are treated as OR across BM25 terms; semantic mode embeds the full query.',
18
+ },
19
+ scope: {
20
+ type: 'string',
21
+ description: 'What to search over: "auto" (= content), "symbols", "files", "content".',
22
+ enum: ['auto', 'symbols', 'files', 'content'],
23
+ },
24
+ mode: {
25
+ type: 'string',
26
+ description: '"lexical" (default, BM25) | "semantic" (embeddings, requires peer dep) | "hybrid" (BM25 + semantic via reciprocal rank fusion). Ignored for "symbols" and "files" scopes.',
27
+ enum: ['lexical', 'semantic', 'hybrid'],
28
+ },
29
+ limit: { type: 'number', description: 'Max matches returned (default 30).' },
30
+ max_tokens: { type: 'number', description: 'Cap the response to roughly this many tokens.' },
31
+ package: PACKAGE_ARG_SCHEMA,
32
+ },
33
+ required: ['query'],
34
+ },
35
+ handler: async (args, rootPath) => {
36
+ const query = String(args.query ?? '').trim();
37
+ if (!query)
38
+ throw new Error('query argument is required and must be non-empty');
39
+ const scope = String(args.scope ?? 'auto');
40
+ const limit = Math.max(1, Math.min(500, typeof args.limit === 'number' ? args.limit : 30));
41
+ const scan = await scanRepository(rootPath);
42
+ const cached = await loadCachedGraph(rootPath);
43
+ const graph = await buildCodeGraph(rootPath, scan.files, cached);
44
+ await saveCachedGraph(rootPath, graph);
45
+ const passes = await resolvePackageFilter(rootPath, args);
46
+ if (scope === 'files') {
47
+ const q = query.toLowerCase();
48
+ const all = scan.files
49
+ .filter((f) => f.relativePath.toLowerCase().includes(q))
50
+ .filter((f) => !passes || passes(f.relativePath))
51
+ .map((f) => ({ file: f.relativePath, sizeBytes: f.sizeBytes }));
52
+ const page = paginate(all, readPageParams(args), listChecksum(all));
53
+ return { scope, query, matches: page.items, total: page.total, nextCursor: page.nextCursor };
54
+ }
55
+ if (scope === 'symbols') {
56
+ const q = query.toLowerCase();
57
+ const rawMatches = [];
58
+ for (const [file, entry] of graph.files) {
59
+ if (passes && !passes(file))
60
+ continue;
61
+ for (const exp of entry.exports) {
62
+ const name = exp.name.toLowerCase();
63
+ if (!name.includes(q))
64
+ continue;
65
+ const rank = name === q ? 0 : name.startsWith(q) ? 1 : 2;
66
+ rawMatches.push({ symbol: exp.name, kind: exp.kind, file, line: exp.line, rank });
67
+ }
68
+ }
69
+ rawMatches.sort((a, b) => a.rank - b.rank);
70
+ const cleaned = rawMatches.map((m) => ({
71
+ symbol: m.symbol,
72
+ kind: m.kind,
73
+ file: m.file,
74
+ line: m.line,
75
+ }));
76
+ const page = paginate(cleaned, readPageParams(args), listChecksum(cleaned));
77
+ return { scope, query, matches: page.items, total: page.total, nextCursor: page.nextCursor };
78
+ }
79
+ const mode = String(args.mode ?? 'lexical');
80
+ const index = await buildSearchIndex(rootPath, scan.files, graph);
81
+ const lexicalHitsAll = searchIndex(index, query, { limit });
82
+ const lexicalHits = passes ? lexicalHitsAll.filter((h) => passes(h.file)) : lexicalHitsAll;
83
+ const tokens = expandQuery(query);
84
+ if (mode === 'lexical') {
85
+ const withExcerpts = await attachExcerpts(rootPath, lexicalHits, tokens);
86
+ const page = paginate(withExcerpts, readPageParams(args), listChecksum(withExcerpts));
87
+ return {
88
+ scope: scope === 'auto' ? 'content' : scope,
89
+ mode: 'lexical',
90
+ query,
91
+ queryTokens: tokens,
92
+ matches: page.items,
93
+ total: page.total,
94
+ nextCursor: page.nextCursor,
95
+ };
96
+ }
97
+ const hasSemantic = await isSemanticAvailable();
98
+ if (!hasSemantic) {
99
+ return {
100
+ scope: scope === 'auto' ? 'content' : scope,
101
+ mode,
102
+ query,
103
+ error: 'Semantic search requires the optional peer dependency @xenova/transformers. Install it with: npm install @xenova/transformers',
104
+ available: false,
105
+ matches: [],
106
+ total: 0,
107
+ };
108
+ }
109
+ const semIndex = await buildSemanticIndex(rootPath, scan.files);
110
+ if (!semIndex) {
111
+ return {
112
+ scope: scope === 'auto' ? 'content' : scope,
113
+ mode,
114
+ query,
115
+ error: 'Semantic index build failed (peer loaded but model not usable).',
116
+ available: false,
117
+ matches: [],
118
+ total: 0,
119
+ };
120
+ }
121
+ const semHitsAll = await semanticSearch(semIndex, query, { limit });
122
+ const semHits = passes ? semHitsAll.filter((h) => passes(h.file)) : semHitsAll;
123
+ if (mode === 'semantic') {
124
+ const enriched = await attachExcerpts(rootPath, semHits.map((h) => ({
125
+ file: h.file,
126
+ score: h.score,
127
+ matched: [],
128
+ symbolMatch: false,
129
+ pathMatch: false,
130
+ excerpt: '',
131
+ line: 0,
132
+ })), tokens);
133
+ const page = paginate(enriched, readPageParams(args), listChecksum(enriched));
134
+ return {
135
+ scope: scope === 'auto' ? 'content' : scope,
136
+ mode: 'semantic',
137
+ query,
138
+ model: semIndex.model,
139
+ matches: page.items,
140
+ total: page.total,
141
+ nextCursor: page.nextCursor,
142
+ };
143
+ }
144
+ const fused = reciprocalRankFusion([lexicalHits, semHits]).slice(0, limit);
145
+ const enriched = await attachExcerpts(rootPath, fused.map((f) => ({
146
+ file: f.file,
147
+ score: f.score,
148
+ matched: [],
149
+ symbolMatch: false,
150
+ pathMatch: false,
151
+ excerpt: '',
152
+ line: 0,
153
+ })), tokens);
154
+ const page = paginate(enriched, readPageParams(args), listChecksum(enriched));
155
+ return {
156
+ scope: scope === 'auto' ? 'content' : scope,
157
+ mode: 'hybrid',
158
+ query,
159
+ queryTokens: tokens,
160
+ model: semIndex.model,
161
+ matches: page.items,
162
+ total: page.total,
163
+ nextCursor: page.nextCursor,
164
+ };
165
+ },
166
+ };
167
+ //# 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,2 @@
1
+ import { type McpTool } from './_shared.js';
2
+ export declare const structureTool: McpTool;
@@ -0,0 +1,34 @@
1
+ import { scanRepository } from '../../core/repositoryScanner.js';
2
+ import { detectWorkspaces } from '../../core/monorepo.js';
3
+ import { PACKAGE_ARG_SCHEMA, sliceTree } from './_shared.js';
4
+ export const structureTool = {
5
+ name: 'projscan_structure',
6
+ description: 'Return the project directory tree with file counts.',
7
+ inputSchema: {
8
+ type: 'object',
9
+ properties: {
10
+ package: PACKAGE_ARG_SCHEMA,
11
+ },
12
+ },
13
+ handler: async (args, rootPath) => {
14
+ const scan = await scanRepository(rootPath);
15
+ const pkgName = typeof args.package === 'string' && args.package.length > 0 ? args.package : null;
16
+ if (!pkgName) {
17
+ return { structure: scan.directoryTree, totalFiles: scan.totalFiles };
18
+ }
19
+ const ws = await detectWorkspaces(rootPath);
20
+ const pkg = ws.packages.find((p) => p.name === pkgName);
21
+ if (!pkg || pkg.isRoot || !pkg.relativePath) {
22
+ return { structure: scan.directoryTree, totalFiles: scan.totalFiles };
23
+ }
24
+ const sliced = sliceTree(scan.directoryTree, pkg.relativePath);
25
+ if (!sliced) {
26
+ return {
27
+ structure: { name: pkg.name, path: pkg.relativePath, children: [], fileCount: 0, totalFileCount: 0 },
28
+ totalFiles: 0,
29
+ };
30
+ }
31
+ return { structure: sliced, totalFiles: sliced.totalFileCount };
32
+ },
33
+ };
34
+ //# sourceMappingURL=structure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure.js","sourceRoot":"","sources":["../../../src/mcp/tools/structure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAgB,MAAM,cAAc,CAAC;AAE3E,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,IAAI,EAAE,oBAAoB;IAC1B,WAAW,EAAE,qDAAqD;IAClE,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,OAAO,EAAE,kBAAkB;SAC5B;KACF;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QAClG,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;QACxE,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YAC5C,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;QACxE,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;QAC/D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;gBACL,SAAS,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE;gBACpG,UAAU,EAAE,CAAC;aACd,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC;IAClE,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { type McpTool } from './_shared.js';
2
+ export declare const upgradeTool: McpTool;