@optave/codegraph 2.6.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -52
- package/package.json +5 -5
- package/src/ast.js +392 -0
- package/src/batch.js +93 -3
- package/src/builder.js +314 -95
- package/src/cfg.js +1451 -0
- package/src/change-journal.js +130 -0
- package/src/cli.js +411 -139
- package/src/complexity.js +8 -8
- package/src/dataflow.js +1187 -0
- package/src/db.js +96 -0
- package/src/embedder.js +16 -16
- package/src/export.js +305 -0
- package/src/extractors/csharp.js +64 -1
- package/src/extractors/go.js +66 -1
- package/src/extractors/hcl.js +22 -0
- package/src/extractors/java.js +61 -1
- package/src/extractors/javascript.js +142 -0
- package/src/extractors/php.js +79 -0
- package/src/extractors/python.js +134 -0
- package/src/extractors/ruby.js +89 -0
- package/src/extractors/rust.js +71 -1
- package/src/index.js +51 -3
- package/src/mcp.js +403 -222
- package/src/paginate.js +3 -3
- package/src/parser.js +8 -0
- package/src/queries.js +362 -36
- package/src/structure.js +4 -1
- package/src/viewer.js +948 -0
- package/src/watcher.js +36 -1
package/src/mcp.js
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { createRequire } from 'node:module';
|
|
9
|
+
import { AST_NODE_KINDS } from './ast.js';
|
|
9
10
|
import { findCycles } from './cycles.js';
|
|
10
11
|
import { findDbPath } from './db.js';
|
|
11
12
|
import { MCP_DEFAULTS, MCP_MAX_LIMIT } from './paginate.js';
|
|
12
|
-
import {
|
|
13
|
+
import { diffImpactMermaid, EVERY_EDGE_KIND, EVERY_SYMBOL_KIND, VALID_ROLES } from './queries.js';
|
|
13
14
|
|
|
14
15
|
const REPO_PROP = {
|
|
15
16
|
repo: {
|
|
@@ -25,23 +26,71 @@ const PAGINATION_PROPS = {
|
|
|
25
26
|
|
|
26
27
|
const BASE_TOOLS = [
|
|
27
28
|
{
|
|
28
|
-
name: '
|
|
29
|
-
description:
|
|
29
|
+
name: 'query',
|
|
30
|
+
description:
|
|
31
|
+
'Query the call graph: find callers/callees with transitive chain, or find shortest path between two symbols',
|
|
30
32
|
inputSchema: {
|
|
31
33
|
type: 'object',
|
|
32
34
|
properties: {
|
|
33
|
-
name: { type: 'string', description: 'Function name
|
|
35
|
+
name: { type: 'string', description: 'Function/method/class name (partial match)' },
|
|
36
|
+
mode: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
enum: ['deps', 'path'],
|
|
39
|
+
description: 'deps (default): dependency chain. path: shortest path to target',
|
|
40
|
+
},
|
|
34
41
|
depth: {
|
|
35
42
|
type: 'number',
|
|
36
|
-
description: '
|
|
37
|
-
|
|
43
|
+
description: 'Transitive depth (deps default: 3, path default: 10)',
|
|
44
|
+
},
|
|
45
|
+
file: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'Scope search to functions in this file (partial match)',
|
|
48
|
+
},
|
|
49
|
+
kind: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
enum: EVERY_SYMBOL_KIND,
|
|
52
|
+
description: 'Filter by symbol kind',
|
|
53
|
+
},
|
|
54
|
+
to: { type: 'string', description: 'Target symbol for path mode (required in path mode)' },
|
|
55
|
+
edge_kinds: {
|
|
56
|
+
type: 'array',
|
|
57
|
+
items: { type: 'string', enum: EVERY_EDGE_KIND },
|
|
58
|
+
description: 'Edge kinds to follow in path mode (default: ["calls"])',
|
|
38
59
|
},
|
|
60
|
+
reverse: {
|
|
61
|
+
type: 'boolean',
|
|
62
|
+
description: 'Follow edges backward in path mode',
|
|
63
|
+
default: false,
|
|
64
|
+
},
|
|
65
|
+
from_file: { type: 'string', description: 'Disambiguate source by file in path mode' },
|
|
66
|
+
to_file: { type: 'string', description: 'Disambiguate target by file in path mode' },
|
|
39
67
|
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
40
68
|
...PAGINATION_PROPS,
|
|
41
69
|
},
|
|
42
70
|
required: ['name'],
|
|
43
71
|
},
|
|
44
72
|
},
|
|
73
|
+
{
|
|
74
|
+
name: 'path',
|
|
75
|
+
description: 'Find shortest path between two symbols in the dependency graph',
|
|
76
|
+
inputSchema: {
|
|
77
|
+
type: 'object',
|
|
78
|
+
properties: {
|
|
79
|
+
from: { type: 'string', description: 'Source symbol name' },
|
|
80
|
+
to: { type: 'string', description: 'Target symbol name' },
|
|
81
|
+
depth: { type: 'number', description: 'Max traversal depth (default: 10)' },
|
|
82
|
+
edge_kinds: {
|
|
83
|
+
type: 'array',
|
|
84
|
+
items: { type: 'string', enum: EVERY_EDGE_KIND },
|
|
85
|
+
description: 'Edge kinds to follow (default: ["calls"])',
|
|
86
|
+
},
|
|
87
|
+
from_file: { type: 'string', description: 'Disambiguate source by file' },
|
|
88
|
+
to_file: { type: 'string', description: 'Disambiguate target by file' },
|
|
89
|
+
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
90
|
+
},
|
|
91
|
+
required: ['from', 'to'],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
45
94
|
{
|
|
46
95
|
name: 'file_deps',
|
|
47
96
|
description: 'Show what a file imports and what imports it',
|
|
@@ -55,6 +104,20 @@ const BASE_TOOLS = [
|
|
|
55
104
|
required: ['file'],
|
|
56
105
|
},
|
|
57
106
|
},
|
|
107
|
+
{
|
|
108
|
+
name: 'file_exports',
|
|
109
|
+
description:
|
|
110
|
+
'Show exported symbols of a file with per-symbol consumers — who calls each export and from where',
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: 'object',
|
|
113
|
+
properties: {
|
|
114
|
+
file: { type: 'string', description: 'File path (partial match supported)' },
|
|
115
|
+
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
116
|
+
...PAGINATION_PROPS,
|
|
117
|
+
},
|
|
118
|
+
required: ['file'],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
58
121
|
{
|
|
59
122
|
name: 'impact_analysis',
|
|
60
123
|
description: 'Show files affected by changes to a given file (transitive)',
|
|
@@ -87,29 +150,6 @@ const BASE_TOOLS = [
|
|
|
87
150
|
},
|
|
88
151
|
},
|
|
89
152
|
},
|
|
90
|
-
{
|
|
91
|
-
name: 'fn_deps',
|
|
92
|
-
description: 'Show function-level dependency chain: what a function calls and what calls it',
|
|
93
|
-
inputSchema: {
|
|
94
|
-
type: 'object',
|
|
95
|
-
properties: {
|
|
96
|
-
name: { type: 'string', description: 'Function/method/class name (partial match)' },
|
|
97
|
-
depth: { type: 'number', description: 'Transitive caller depth', default: 3 },
|
|
98
|
-
file: {
|
|
99
|
-
type: 'string',
|
|
100
|
-
description: 'Scope search to functions in this file (partial match)',
|
|
101
|
-
},
|
|
102
|
-
kind: {
|
|
103
|
-
type: 'string',
|
|
104
|
-
enum: ALL_SYMBOL_KINDS,
|
|
105
|
-
description: 'Filter to a specific symbol kind',
|
|
106
|
-
},
|
|
107
|
-
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
108
|
-
...PAGINATION_PROPS,
|
|
109
|
-
},
|
|
110
|
-
required: ['name'],
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
153
|
{
|
|
114
154
|
name: 'fn_impact',
|
|
115
155
|
description:
|
|
@@ -125,7 +165,7 @@ const BASE_TOOLS = [
|
|
|
125
165
|
},
|
|
126
166
|
kind: {
|
|
127
167
|
type: 'string',
|
|
128
|
-
enum:
|
|
168
|
+
enum: EVERY_SYMBOL_KIND,
|
|
129
169
|
description: 'Filter to a specific symbol kind',
|
|
130
170
|
},
|
|
131
171
|
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
@@ -134,33 +174,6 @@ const BASE_TOOLS = [
|
|
|
134
174
|
required: ['name'],
|
|
135
175
|
},
|
|
136
176
|
},
|
|
137
|
-
{
|
|
138
|
-
name: 'symbol_path',
|
|
139
|
-
description: 'Find the shortest path between two symbols in the call graph (A calls...calls B)',
|
|
140
|
-
inputSchema: {
|
|
141
|
-
type: 'object',
|
|
142
|
-
properties: {
|
|
143
|
-
from: { type: 'string', description: 'Source symbol name (partial match)' },
|
|
144
|
-
to: { type: 'string', description: 'Target symbol name (partial match)' },
|
|
145
|
-
max_depth: { type: 'number', description: 'Maximum BFS depth', default: 10 },
|
|
146
|
-
edge_kinds: {
|
|
147
|
-
type: 'array',
|
|
148
|
-
items: { type: 'string' },
|
|
149
|
-
description: 'Edge kinds to follow (default: ["calls"])',
|
|
150
|
-
},
|
|
151
|
-
reverse: { type: 'boolean', description: 'Follow edges backward', default: false },
|
|
152
|
-
from_file: { type: 'string', description: 'Disambiguate source by file (partial match)' },
|
|
153
|
-
to_file: { type: 'string', description: 'Disambiguate target by file (partial match)' },
|
|
154
|
-
kind: {
|
|
155
|
-
type: 'string',
|
|
156
|
-
enum: ALL_SYMBOL_KINDS,
|
|
157
|
-
description: 'Filter both symbols by kind',
|
|
158
|
-
},
|
|
159
|
-
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
160
|
-
},
|
|
161
|
-
required: ['from', 'to'],
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
177
|
{
|
|
165
178
|
name: 'context',
|
|
166
179
|
description:
|
|
@@ -180,7 +193,7 @@ const BASE_TOOLS = [
|
|
|
180
193
|
},
|
|
181
194
|
kind: {
|
|
182
195
|
type: 'string',
|
|
183
|
-
enum:
|
|
196
|
+
enum: EVERY_SYMBOL_KIND,
|
|
184
197
|
description: 'Filter to a specific symbol kind',
|
|
185
198
|
},
|
|
186
199
|
no_source: {
|
|
@@ -200,17 +213,19 @@ const BASE_TOOLS = [
|
|
|
200
213
|
},
|
|
201
214
|
},
|
|
202
215
|
{
|
|
203
|
-
name: '
|
|
216
|
+
name: 'symbol_children',
|
|
204
217
|
description:
|
|
205
|
-
'
|
|
218
|
+
'List sub-declaration children of a symbol: parameters, properties, constants. Answers "what fields does this class have?" without reading source.',
|
|
206
219
|
inputSchema: {
|
|
207
220
|
type: 'object',
|
|
208
221
|
properties: {
|
|
209
|
-
|
|
222
|
+
name: { type: 'string', description: 'Function/method/class name (partial match)' },
|
|
223
|
+
file: { type: 'string', description: 'Scope to file (partial match)' },
|
|
224
|
+
kind: { type: 'string', enum: EVERY_SYMBOL_KIND, description: 'Filter by symbol kind' },
|
|
210
225
|
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
211
226
|
...PAGINATION_PROPS,
|
|
212
227
|
},
|
|
213
|
-
required: ['
|
|
228
|
+
required: ['name'],
|
|
214
229
|
},
|
|
215
230
|
},
|
|
216
231
|
{
|
|
@@ -274,13 +289,14 @@ const BASE_TOOLS = [
|
|
|
274
289
|
},
|
|
275
290
|
{
|
|
276
291
|
name: 'export_graph',
|
|
277
|
-
description:
|
|
292
|
+
description:
|
|
293
|
+
'Export the dependency graph in DOT, Mermaid, JSON, GraphML, GraphSON, or Neo4j CSV format',
|
|
278
294
|
inputSchema: {
|
|
279
295
|
type: 'object',
|
|
280
296
|
properties: {
|
|
281
297
|
format: {
|
|
282
298
|
type: 'string',
|
|
283
|
-
enum: ['dot', 'mermaid', 'json'],
|
|
299
|
+
enum: ['dot', 'mermaid', 'json', 'graphml', 'graphson', 'neo4j'],
|
|
284
300
|
description: 'Export format',
|
|
285
301
|
},
|
|
286
302
|
file_level: {
|
|
@@ -348,29 +364,6 @@ const BASE_TOOLS = [
|
|
|
348
364
|
},
|
|
349
365
|
},
|
|
350
366
|
},
|
|
351
|
-
{
|
|
352
|
-
name: 'hotspots',
|
|
353
|
-
description:
|
|
354
|
-
'Find structural hotspots: files or directories with extreme fan-in, fan-out, or symbol density',
|
|
355
|
-
inputSchema: {
|
|
356
|
-
type: 'object',
|
|
357
|
-
properties: {
|
|
358
|
-
metric: {
|
|
359
|
-
type: 'string',
|
|
360
|
-
enum: ['fan-in', 'fan-out', 'density', 'coupling'],
|
|
361
|
-
description: 'Metric to rank by',
|
|
362
|
-
},
|
|
363
|
-
level: {
|
|
364
|
-
type: 'string',
|
|
365
|
-
enum: ['file', 'directory'],
|
|
366
|
-
description: 'Rank files or directories',
|
|
367
|
-
},
|
|
368
|
-
limit: { type: 'number', description: 'Number of results to return', default: 10 },
|
|
369
|
-
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
370
|
-
offset: { type: 'number', description: 'Skip this many results (pagination, default: 0)' },
|
|
371
|
-
},
|
|
372
|
-
},
|
|
373
|
-
},
|
|
374
367
|
{
|
|
375
368
|
name: 'co_changes',
|
|
376
369
|
description:
|
|
@@ -396,14 +389,19 @@ const BASE_TOOLS = [
|
|
|
396
389
|
{
|
|
397
390
|
name: 'execution_flow',
|
|
398
391
|
description:
|
|
399
|
-
'Trace execution flow forward from an entry point
|
|
392
|
+
'Trace execution flow forward from an entry point through callees to leaves, or list all entry points with list=true',
|
|
400
393
|
inputSchema: {
|
|
401
394
|
type: 'object',
|
|
402
395
|
properties: {
|
|
403
396
|
name: {
|
|
404
397
|
type: 'string',
|
|
405
398
|
description:
|
|
406
|
-
'Entry point or function name (
|
|
399
|
+
'Entry point or function name (required unless list=true). Supports prefix-stripped matching.',
|
|
400
|
+
},
|
|
401
|
+
list: {
|
|
402
|
+
type: 'boolean',
|
|
403
|
+
description: 'List all entry points grouped by type',
|
|
404
|
+
default: false,
|
|
407
405
|
},
|
|
408
406
|
depth: { type: 'number', description: 'Max forward traversal depth', default: 10 },
|
|
409
407
|
file: {
|
|
@@ -412,25 +410,12 @@ const BASE_TOOLS = [
|
|
|
412
410
|
},
|
|
413
411
|
kind: {
|
|
414
412
|
type: 'string',
|
|
415
|
-
enum:
|
|
413
|
+
enum: EVERY_SYMBOL_KIND,
|
|
416
414
|
description: 'Filter to a specific symbol kind',
|
|
417
415
|
},
|
|
418
416
|
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
419
417
|
...PAGINATION_PROPS,
|
|
420
418
|
},
|
|
421
|
-
required: ['name'],
|
|
422
|
-
},
|
|
423
|
-
},
|
|
424
|
-
{
|
|
425
|
-
name: 'list_entry_points',
|
|
426
|
-
description:
|
|
427
|
-
'List all framework entry points (routes, commands, events) in the codebase, grouped by type',
|
|
428
|
-
inputSchema: {
|
|
429
|
-
type: 'object',
|
|
430
|
-
properties: {
|
|
431
|
-
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
432
|
-
...PAGINATION_PROPS,
|
|
433
|
-
},
|
|
434
419
|
},
|
|
435
420
|
},
|
|
436
421
|
{
|
|
@@ -468,23 +453,6 @@ const BASE_TOOLS = [
|
|
|
468
453
|
},
|
|
469
454
|
},
|
|
470
455
|
},
|
|
471
|
-
{
|
|
472
|
-
name: 'manifesto',
|
|
473
|
-
description:
|
|
474
|
-
'Evaluate manifesto rules and return pass/fail verdicts for code health. Checks function complexity, file metrics, and cycle rules against configured thresholds.',
|
|
475
|
-
inputSchema: {
|
|
476
|
-
type: 'object',
|
|
477
|
-
properties: {
|
|
478
|
-
file: { type: 'string', description: 'Scope to file (partial match)' },
|
|
479
|
-
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
480
|
-
kind: {
|
|
481
|
-
type: 'string',
|
|
482
|
-
description: 'Filter by symbol kind (function, method, class, etc.)',
|
|
483
|
-
},
|
|
484
|
-
...PAGINATION_PROPS,
|
|
485
|
-
},
|
|
486
|
-
},
|
|
487
|
-
},
|
|
488
456
|
{
|
|
489
457
|
name: 'communities',
|
|
490
458
|
description:
|
|
@@ -542,6 +510,11 @@ const BASE_TOOLS = [
|
|
|
542
510
|
type: 'object',
|
|
543
511
|
properties: {
|
|
544
512
|
target: { type: 'string', description: 'File path or function name' },
|
|
513
|
+
quick: {
|
|
514
|
+
type: 'boolean',
|
|
515
|
+
description: 'Structural summary only (skip impact + health)',
|
|
516
|
+
default: false,
|
|
517
|
+
},
|
|
545
518
|
depth: { type: 'number', description: 'Impact analysis depth (default: 3)', default: 3 },
|
|
546
519
|
file: { type: 'string', description: 'Scope to file (partial match)' },
|
|
547
520
|
kind: {
|
|
@@ -549,6 +522,7 @@ const BASE_TOOLS = [
|
|
|
549
522
|
description: 'Filter by symbol kind (function, method, class, etc.)',
|
|
550
523
|
},
|
|
551
524
|
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
525
|
+
...PAGINATION_PROPS,
|
|
552
526
|
},
|
|
553
527
|
required: ['target'],
|
|
554
528
|
},
|
|
@@ -568,10 +542,10 @@ const BASE_TOOLS = [
|
|
|
568
542
|
'explain',
|
|
569
543
|
'where',
|
|
570
544
|
'query',
|
|
571
|
-
'fn',
|
|
572
545
|
'impact',
|
|
573
546
|
'deps',
|
|
574
547
|
'flow',
|
|
548
|
+
'dataflow',
|
|
575
549
|
'complexity',
|
|
576
550
|
],
|
|
577
551
|
description: 'The query command to run for each target',
|
|
@@ -591,7 +565,7 @@ const BASE_TOOLS = [
|
|
|
591
565
|
},
|
|
592
566
|
kind: {
|
|
593
567
|
type: 'string',
|
|
594
|
-
enum:
|
|
568
|
+
enum: EVERY_SYMBOL_KIND,
|
|
595
569
|
description: 'Filter symbol kind',
|
|
596
570
|
},
|
|
597
571
|
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
@@ -606,6 +580,12 @@ const BASE_TOOLS = [
|
|
|
606
580
|
inputSchema: {
|
|
607
581
|
type: 'object',
|
|
608
582
|
properties: {
|
|
583
|
+
level: {
|
|
584
|
+
type: 'string',
|
|
585
|
+
enum: ['function', 'file', 'directory'],
|
|
586
|
+
description:
|
|
587
|
+
'Granularity: function (default) | file | directory. File/directory shows hotspots',
|
|
588
|
+
},
|
|
609
589
|
sort: {
|
|
610
590
|
type: 'string',
|
|
611
591
|
enum: ['risk', 'complexity', 'churn', 'fan-in', 'mi'],
|
|
@@ -656,15 +636,60 @@ const BASE_TOOLS = [
|
|
|
656
636
|
required: ['base', 'target'],
|
|
657
637
|
},
|
|
658
638
|
},
|
|
639
|
+
{
|
|
640
|
+
name: 'cfg',
|
|
641
|
+
description: 'Show intraprocedural control flow graph for a function. Requires build --cfg.',
|
|
642
|
+
inputSchema: {
|
|
643
|
+
type: 'object',
|
|
644
|
+
properties: {
|
|
645
|
+
name: { type: 'string', description: 'Function/method name (partial match)' },
|
|
646
|
+
format: {
|
|
647
|
+
type: 'string',
|
|
648
|
+
enum: ['json', 'dot', 'mermaid'],
|
|
649
|
+
description: 'Output format (default: json)',
|
|
650
|
+
},
|
|
651
|
+
file: { type: 'string', description: 'Scope to file (partial match)' },
|
|
652
|
+
kind: { type: 'string', enum: EVERY_SYMBOL_KIND, description: 'Filter by symbol kind' },
|
|
653
|
+
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
654
|
+
...PAGINATION_PROPS,
|
|
655
|
+
},
|
|
656
|
+
required: ['name'],
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
name: 'dataflow',
|
|
661
|
+
description: 'Show data flow edges or data-dependent blast radius. Requires build --dataflow.',
|
|
662
|
+
inputSchema: {
|
|
663
|
+
type: 'object',
|
|
664
|
+
properties: {
|
|
665
|
+
name: { type: 'string', description: 'Function/method name (partial match)' },
|
|
666
|
+
mode: {
|
|
667
|
+
type: 'string',
|
|
668
|
+
enum: ['edges', 'impact'],
|
|
669
|
+
description: 'edges (default) or impact',
|
|
670
|
+
},
|
|
671
|
+
depth: { type: 'number', description: 'Max depth for impact mode', default: 5 },
|
|
672
|
+
file: { type: 'string', description: 'Scope to file (partial match)' },
|
|
673
|
+
kind: { type: 'string', enum: EVERY_SYMBOL_KIND, description: 'Filter by symbol kind' },
|
|
674
|
+
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
675
|
+
...PAGINATION_PROPS,
|
|
676
|
+
},
|
|
677
|
+
required: ['name'],
|
|
678
|
+
},
|
|
679
|
+
},
|
|
659
680
|
{
|
|
660
681
|
name: 'check',
|
|
661
682
|
description:
|
|
662
|
-
'
|
|
683
|
+
'CI gate: run manifesto rules (no args), diff predicates (with ref/staged), or both (with rules flag). Returns pass/fail verdicts.',
|
|
663
684
|
inputSchema: {
|
|
664
685
|
type: 'object',
|
|
665
686
|
properties: {
|
|
666
687
|
ref: { type: 'string', description: 'Git ref to diff against (default: HEAD)' },
|
|
667
688
|
staged: { type: 'boolean', description: 'Analyze staged changes instead of unstaged' },
|
|
689
|
+
rules: {
|
|
690
|
+
type: 'boolean',
|
|
691
|
+
description: 'Also run manifesto rules alongside diff predicates',
|
|
692
|
+
},
|
|
668
693
|
cycles: { type: 'boolean', description: 'Enable cycles predicate (default: true)' },
|
|
669
694
|
blast_radius: {
|
|
670
695
|
type: 'number',
|
|
@@ -673,7 +698,35 @@ const BASE_TOOLS = [
|
|
|
673
698
|
signatures: { type: 'boolean', description: 'Enable signatures predicate (default: true)' },
|
|
674
699
|
boundaries: { type: 'boolean', description: 'Enable boundaries predicate (default: true)' },
|
|
675
700
|
depth: { type: 'number', description: 'Max BFS depth for blast radius (default: 3)' },
|
|
701
|
+
file: { type: 'string', description: 'Scope to file (partial match, manifesto mode)' },
|
|
702
|
+
kind: {
|
|
703
|
+
type: 'string',
|
|
704
|
+
description: 'Filter by symbol kind (manifesto mode)',
|
|
705
|
+
},
|
|
706
|
+
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
707
|
+
...PAGINATION_PROPS,
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
name: 'ast_query',
|
|
713
|
+
description:
|
|
714
|
+
'Search stored AST nodes (calls, literals, new, throw, await) by pattern. Requires a prior build.',
|
|
715
|
+
inputSchema: {
|
|
716
|
+
type: 'object',
|
|
717
|
+
properties: {
|
|
718
|
+
pattern: {
|
|
719
|
+
type: 'string',
|
|
720
|
+
description: 'GLOB pattern for node name (auto-wrapped in *..* for substring match)',
|
|
721
|
+
},
|
|
722
|
+
kind: {
|
|
723
|
+
type: 'string',
|
|
724
|
+
enum: AST_NODE_KINDS,
|
|
725
|
+
description: 'Filter by AST node kind',
|
|
726
|
+
},
|
|
727
|
+
file: { type: 'string', description: 'Scope to file (partial match)' },
|
|
676
728
|
no_tests: { type: 'boolean', description: 'Exclude test files', default: false },
|
|
729
|
+
...PAGINATION_PROPS,
|
|
677
730
|
},
|
|
678
731
|
},
|
|
679
732
|
},
|
|
@@ -743,14 +796,15 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
743
796
|
|
|
744
797
|
// Lazy import query functions to avoid circular deps at module load
|
|
745
798
|
const {
|
|
746
|
-
queryNameData,
|
|
747
799
|
impactAnalysisData,
|
|
748
800
|
moduleMapData,
|
|
749
801
|
fileDepsData,
|
|
802
|
+
exportsData,
|
|
750
803
|
fnDepsData,
|
|
751
804
|
fnImpactData,
|
|
752
805
|
pathData,
|
|
753
806
|
contextData,
|
|
807
|
+
childrenData,
|
|
754
808
|
explainData,
|
|
755
809
|
whereData,
|
|
756
810
|
diffImpactData,
|
|
@@ -801,11 +855,41 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
801
855
|
|
|
802
856
|
let result;
|
|
803
857
|
switch (name) {
|
|
804
|
-
case '
|
|
805
|
-
|
|
858
|
+
case 'query': {
|
|
859
|
+
const qMode = args.mode || 'deps';
|
|
860
|
+
if (qMode === 'path') {
|
|
861
|
+
if (!args.to) {
|
|
862
|
+
result = { error: 'path mode requires a "to" argument' };
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
result = pathData(args.name, args.to, dbPath, {
|
|
866
|
+
maxDepth: args.depth ?? 10,
|
|
867
|
+
edgeKinds: args.edge_kinds,
|
|
868
|
+
reverse: args.reverse,
|
|
869
|
+
fromFile: args.from_file,
|
|
870
|
+
toFile: args.to_file,
|
|
871
|
+
kind: args.kind,
|
|
872
|
+
noTests: args.no_tests,
|
|
873
|
+
});
|
|
874
|
+
} else {
|
|
875
|
+
result = fnDepsData(args.name, dbPath, {
|
|
876
|
+
depth: args.depth,
|
|
877
|
+
file: args.file,
|
|
878
|
+
kind: args.kind,
|
|
879
|
+
noTests: args.no_tests,
|
|
880
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.query, MCP_MAX_LIMIT),
|
|
881
|
+
offset: args.offset ?? 0,
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
break;
|
|
885
|
+
}
|
|
886
|
+
case 'path':
|
|
887
|
+
result = pathData(args.from, args.to, dbPath, {
|
|
888
|
+
maxDepth: args.depth ?? 10,
|
|
889
|
+
edgeKinds: args.edge_kinds,
|
|
890
|
+
fromFile: args.from_file,
|
|
891
|
+
toFile: args.to_file,
|
|
806
892
|
noTests: args.no_tests,
|
|
807
|
-
limit: Math.min(args.limit ?? MCP_DEFAULTS.query_function, MCP_MAX_LIMIT),
|
|
808
|
-
offset: args.offset ?? 0,
|
|
809
893
|
});
|
|
810
894
|
break;
|
|
811
895
|
case 'file_deps':
|
|
@@ -815,6 +899,13 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
815
899
|
offset: args.offset ?? 0,
|
|
816
900
|
});
|
|
817
901
|
break;
|
|
902
|
+
case 'file_exports':
|
|
903
|
+
result = exportsData(args.file, dbPath, {
|
|
904
|
+
noTests: args.no_tests,
|
|
905
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.file_exports, MCP_MAX_LIMIT),
|
|
906
|
+
offset: args.offset ?? 0,
|
|
907
|
+
});
|
|
908
|
+
break;
|
|
818
909
|
case 'impact_analysis':
|
|
819
910
|
result = impactAnalysisData(args.file, dbPath, {
|
|
820
911
|
noTests: args.no_tests,
|
|
@@ -832,16 +923,6 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
832
923
|
case 'module_map':
|
|
833
924
|
result = moduleMapData(dbPath, args.limit || 20, { noTests: args.no_tests });
|
|
834
925
|
break;
|
|
835
|
-
case 'fn_deps':
|
|
836
|
-
result = fnDepsData(args.name, dbPath, {
|
|
837
|
-
depth: args.depth,
|
|
838
|
-
file: args.file,
|
|
839
|
-
kind: args.kind,
|
|
840
|
-
noTests: args.no_tests,
|
|
841
|
-
limit: Math.min(args.limit ?? MCP_DEFAULTS.fn_deps, MCP_MAX_LIMIT),
|
|
842
|
-
offset: args.offset ?? 0,
|
|
843
|
-
});
|
|
844
|
-
break;
|
|
845
926
|
case 'fn_impact':
|
|
846
927
|
result = fnImpactData(args.name, dbPath, {
|
|
847
928
|
depth: args.depth,
|
|
@@ -852,17 +933,6 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
852
933
|
offset: args.offset ?? 0,
|
|
853
934
|
});
|
|
854
935
|
break;
|
|
855
|
-
case 'symbol_path':
|
|
856
|
-
result = pathData(args.from, args.to, dbPath, {
|
|
857
|
-
maxDepth: args.max_depth,
|
|
858
|
-
edgeKinds: args.edge_kinds,
|
|
859
|
-
reverse: args.reverse,
|
|
860
|
-
fromFile: args.from_file,
|
|
861
|
-
toFile: args.to_file,
|
|
862
|
-
kind: args.kind,
|
|
863
|
-
noTests: args.no_tests,
|
|
864
|
-
});
|
|
865
|
-
break;
|
|
866
936
|
case 'context':
|
|
867
937
|
result = contextData(args.name, dbPath, {
|
|
868
938
|
depth: args.depth,
|
|
@@ -875,10 +945,12 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
875
945
|
offset: args.offset ?? 0,
|
|
876
946
|
});
|
|
877
947
|
break;
|
|
878
|
-
case '
|
|
879
|
-
result =
|
|
948
|
+
case 'symbol_children':
|
|
949
|
+
result = childrenData(args.name, dbPath, {
|
|
950
|
+
file: args.file,
|
|
951
|
+
kind: args.kind,
|
|
880
952
|
noTests: args.no_tests,
|
|
881
|
-
limit: Math.min(args.limit ?? MCP_DEFAULTS.
|
|
953
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.context, MCP_MAX_LIMIT),
|
|
882
954
|
offset: args.offset ?? 0,
|
|
883
955
|
});
|
|
884
956
|
break;
|
|
@@ -967,7 +1039,14 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
967
1039
|
break;
|
|
968
1040
|
}
|
|
969
1041
|
case 'export_graph': {
|
|
970
|
-
const {
|
|
1042
|
+
const {
|
|
1043
|
+
exportDOT,
|
|
1044
|
+
exportGraphML,
|
|
1045
|
+
exportGraphSON,
|
|
1046
|
+
exportJSON,
|
|
1047
|
+
exportMermaid,
|
|
1048
|
+
exportNeo4jCSV,
|
|
1049
|
+
} = await import('./export.js');
|
|
971
1050
|
const db = new Database(findDbPath(dbPath), { readonly: true });
|
|
972
1051
|
const fileLevel = args.file_level !== false;
|
|
973
1052
|
const exportLimit = args.limit
|
|
@@ -986,13 +1065,26 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
986
1065
|
offset: args.offset ?? 0,
|
|
987
1066
|
});
|
|
988
1067
|
break;
|
|
1068
|
+
case 'graphml':
|
|
1069
|
+
result = exportGraphML(db, { fileLevel, limit: exportLimit });
|
|
1070
|
+
break;
|
|
1071
|
+
case 'graphson':
|
|
1072
|
+
result = exportGraphSON(db, {
|
|
1073
|
+
fileLevel,
|
|
1074
|
+
limit: exportLimit,
|
|
1075
|
+
offset: args.offset ?? 0,
|
|
1076
|
+
});
|
|
1077
|
+
break;
|
|
1078
|
+
case 'neo4j':
|
|
1079
|
+
result = exportNeo4jCSV(db, { fileLevel, limit: exportLimit });
|
|
1080
|
+
break;
|
|
989
1081
|
default:
|
|
990
1082
|
db.close();
|
|
991
1083
|
return {
|
|
992
1084
|
content: [
|
|
993
1085
|
{
|
|
994
1086
|
type: 'text',
|
|
995
|
-
text: `Unknown format: ${args.format}. Use dot, mermaid, or
|
|
1087
|
+
text: `Unknown format: ${args.format}. Use dot, mermaid, json, graphml, graphson, or neo4j.`,
|
|
996
1088
|
},
|
|
997
1089
|
],
|
|
998
1090
|
isError: true,
|
|
@@ -1031,17 +1123,6 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
1031
1123
|
});
|
|
1032
1124
|
break;
|
|
1033
1125
|
}
|
|
1034
|
-
case 'hotspots': {
|
|
1035
|
-
const { hotspotsData } = await import('./structure.js');
|
|
1036
|
-
result = hotspotsData(dbPath, {
|
|
1037
|
-
metric: args.metric,
|
|
1038
|
-
level: args.level,
|
|
1039
|
-
limit: Math.min(args.limit ?? MCP_DEFAULTS.hotspots, MCP_MAX_LIMIT),
|
|
1040
|
-
offset: args.offset ?? 0,
|
|
1041
|
-
noTests: args.no_tests,
|
|
1042
|
-
});
|
|
1043
|
-
break;
|
|
1044
|
-
}
|
|
1045
1126
|
case 'co_changes': {
|
|
1046
1127
|
const { coChangeData, coChangeTopData } = await import('./cochange.js');
|
|
1047
1128
|
result = args.file
|
|
@@ -1060,24 +1141,28 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
1060
1141
|
break;
|
|
1061
1142
|
}
|
|
1062
1143
|
case 'execution_flow': {
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1144
|
+
if (args.list) {
|
|
1145
|
+
const { listEntryPointsData } = await import('./flow.js');
|
|
1146
|
+
result = listEntryPointsData(dbPath, {
|
|
1147
|
+
noTests: args.no_tests,
|
|
1148
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.execution_flow, MCP_MAX_LIMIT),
|
|
1149
|
+
offset: args.offset ?? 0,
|
|
1150
|
+
});
|
|
1151
|
+
} else {
|
|
1152
|
+
if (!args.name) {
|
|
1153
|
+
result = { error: 'Provide a name or set list=true' };
|
|
1154
|
+
break;
|
|
1155
|
+
}
|
|
1156
|
+
const { flowData } = await import('./flow.js');
|
|
1157
|
+
result = flowData(args.name, dbPath, {
|
|
1158
|
+
depth: args.depth,
|
|
1159
|
+
file: args.file,
|
|
1160
|
+
kind: args.kind,
|
|
1161
|
+
noTests: args.no_tests,
|
|
1162
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.execution_flow, MCP_MAX_LIMIT),
|
|
1163
|
+
offset: args.offset ?? 0,
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1081
1166
|
break;
|
|
1082
1167
|
}
|
|
1083
1168
|
case 'complexity': {
|
|
@@ -1095,17 +1180,6 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
1095
1180
|
});
|
|
1096
1181
|
break;
|
|
1097
1182
|
}
|
|
1098
|
-
case 'manifesto': {
|
|
1099
|
-
const { manifestoData } = await import('./manifesto.js');
|
|
1100
|
-
result = manifestoData(dbPath, {
|
|
1101
|
-
file: args.file,
|
|
1102
|
-
noTests: args.no_tests,
|
|
1103
|
-
kind: args.kind,
|
|
1104
|
-
limit: Math.min(args.limit ?? MCP_DEFAULTS.manifesto, MCP_MAX_LIMIT),
|
|
1105
|
-
offset: args.offset ?? 0,
|
|
1106
|
-
});
|
|
1107
|
-
break;
|
|
1108
|
-
}
|
|
1109
1183
|
case 'communities': {
|
|
1110
1184
|
const { communitiesData } = await import('./communities.js');
|
|
1111
1185
|
result = communitiesData(dbPath, {
|
|
@@ -1130,13 +1204,21 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
1130
1204
|
break;
|
|
1131
1205
|
}
|
|
1132
1206
|
case 'audit': {
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1207
|
+
if (args.quick) {
|
|
1208
|
+
result = explainData(args.target, dbPath, {
|
|
1209
|
+
noTests: args.no_tests,
|
|
1210
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.explain, MCP_MAX_LIMIT),
|
|
1211
|
+
offset: args.offset ?? 0,
|
|
1212
|
+
});
|
|
1213
|
+
} else {
|
|
1214
|
+
const { auditData } = await import('./audit.js');
|
|
1215
|
+
result = auditData(args.target, dbPath, {
|
|
1216
|
+
depth: args.depth,
|
|
1217
|
+
file: args.file,
|
|
1218
|
+
kind: args.kind,
|
|
1219
|
+
noTests: args.no_tests,
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1140
1222
|
break;
|
|
1141
1223
|
}
|
|
1142
1224
|
case 'batch_query': {
|
|
@@ -1150,18 +1232,36 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
1150
1232
|
break;
|
|
1151
1233
|
}
|
|
1152
1234
|
case 'triage': {
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1235
|
+
if (args.level === 'file' || args.level === 'directory') {
|
|
1236
|
+
const { hotspotsData } = await import('./structure.js');
|
|
1237
|
+
const TRIAGE_TO_HOTSPOT = {
|
|
1238
|
+
risk: 'fan-in',
|
|
1239
|
+
complexity: 'density',
|
|
1240
|
+
churn: 'coupling',
|
|
1241
|
+
mi: 'fan-in',
|
|
1242
|
+
};
|
|
1243
|
+
const metric = TRIAGE_TO_HOTSPOT[args.sort] ?? args.sort;
|
|
1244
|
+
result = hotspotsData(dbPath, {
|
|
1245
|
+
metric,
|
|
1246
|
+
level: args.level,
|
|
1247
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.hotspots, MCP_MAX_LIMIT),
|
|
1248
|
+
offset: args.offset ?? 0,
|
|
1249
|
+
noTests: args.no_tests,
|
|
1250
|
+
});
|
|
1251
|
+
} else {
|
|
1252
|
+
const { triageData } = await import('./triage.js');
|
|
1253
|
+
result = triageData(dbPath, {
|
|
1254
|
+
sort: args.sort,
|
|
1255
|
+
minScore: args.min_score,
|
|
1256
|
+
role: args.role,
|
|
1257
|
+
file: args.file,
|
|
1258
|
+
kind: args.kind,
|
|
1259
|
+
noTests: args.no_tests,
|
|
1260
|
+
weights: args.weights,
|
|
1261
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.triage, MCP_MAX_LIMIT),
|
|
1262
|
+
offset: args.offset ?? 0,
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1165
1265
|
break;
|
|
1166
1266
|
}
|
|
1167
1267
|
case 'branch_compare': {
|
|
@@ -1173,17 +1273,98 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
1173
1273
|
result = args.format === 'mermaid' ? branchCompareMermaid(bcData) : bcData;
|
|
1174
1274
|
break;
|
|
1175
1275
|
}
|
|
1276
|
+
case 'cfg': {
|
|
1277
|
+
const { cfgData, cfgToDOT, cfgToMermaid } = await import('./cfg.js');
|
|
1278
|
+
const cfgResult = cfgData(args.name, dbPath, {
|
|
1279
|
+
file: args.file,
|
|
1280
|
+
kind: args.kind,
|
|
1281
|
+
noTests: args.no_tests,
|
|
1282
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.query, MCP_MAX_LIMIT),
|
|
1283
|
+
offset: args.offset ?? 0,
|
|
1284
|
+
});
|
|
1285
|
+
if (args.format === 'dot') {
|
|
1286
|
+
result = { text: cfgToDOT(cfgResult) };
|
|
1287
|
+
} else if (args.format === 'mermaid') {
|
|
1288
|
+
result = { text: cfgToMermaid(cfgResult) };
|
|
1289
|
+
} else {
|
|
1290
|
+
result = cfgResult;
|
|
1291
|
+
}
|
|
1292
|
+
break;
|
|
1293
|
+
}
|
|
1294
|
+
case 'dataflow': {
|
|
1295
|
+
const dfMode = args.mode || 'edges';
|
|
1296
|
+
if (dfMode === 'impact') {
|
|
1297
|
+
const { dataflowImpactData } = await import('./dataflow.js');
|
|
1298
|
+
result = dataflowImpactData(args.name, dbPath, {
|
|
1299
|
+
depth: args.depth,
|
|
1300
|
+
file: args.file,
|
|
1301
|
+
kind: args.kind,
|
|
1302
|
+
noTests: args.no_tests,
|
|
1303
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.fn_impact, MCP_MAX_LIMIT),
|
|
1304
|
+
offset: args.offset ?? 0,
|
|
1305
|
+
});
|
|
1306
|
+
} else {
|
|
1307
|
+
const { dataflowData } = await import('./dataflow.js');
|
|
1308
|
+
result = dataflowData(args.name, dbPath, {
|
|
1309
|
+
file: args.file,
|
|
1310
|
+
kind: args.kind,
|
|
1311
|
+
noTests: args.no_tests,
|
|
1312
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.query, MCP_MAX_LIMIT),
|
|
1313
|
+
offset: args.offset ?? 0,
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
break;
|
|
1317
|
+
}
|
|
1176
1318
|
case 'check': {
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
staged
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1319
|
+
const isDiffMode = args.ref || args.staged;
|
|
1320
|
+
|
|
1321
|
+
if (!isDiffMode && !args.rules) {
|
|
1322
|
+
// No ref, no staged → run manifesto rules on whole codebase
|
|
1323
|
+
const { manifestoData } = await import('./manifesto.js');
|
|
1324
|
+
result = manifestoData(dbPath, {
|
|
1325
|
+
file: args.file,
|
|
1326
|
+
noTests: args.no_tests,
|
|
1327
|
+
kind: args.kind,
|
|
1328
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.manifesto, MCP_MAX_LIMIT),
|
|
1329
|
+
offset: args.offset ?? 0,
|
|
1330
|
+
});
|
|
1331
|
+
} else {
|
|
1332
|
+
const { checkData } = await import('./check.js');
|
|
1333
|
+
const checkResult = checkData(dbPath, {
|
|
1334
|
+
ref: args.ref,
|
|
1335
|
+
staged: args.staged,
|
|
1336
|
+
cycles: args.cycles,
|
|
1337
|
+
blastRadius: args.blast_radius,
|
|
1338
|
+
signatures: args.signatures,
|
|
1339
|
+
boundaries: args.boundaries,
|
|
1340
|
+
depth: args.depth,
|
|
1341
|
+
noTests: args.no_tests,
|
|
1342
|
+
});
|
|
1343
|
+
|
|
1344
|
+
if (args.rules) {
|
|
1345
|
+
const { manifestoData } = await import('./manifesto.js');
|
|
1346
|
+
const manifestoResult = manifestoData(dbPath, {
|
|
1347
|
+
file: args.file,
|
|
1348
|
+
noTests: args.no_tests,
|
|
1349
|
+
kind: args.kind,
|
|
1350
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.manifesto, MCP_MAX_LIMIT),
|
|
1351
|
+
offset: args.offset ?? 0,
|
|
1352
|
+
});
|
|
1353
|
+
result = { check: checkResult, manifesto: manifestoResult };
|
|
1354
|
+
} else {
|
|
1355
|
+
result = checkResult;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
break;
|
|
1359
|
+
}
|
|
1360
|
+
case 'ast_query': {
|
|
1361
|
+
const { astQueryData } = await import('./ast.js');
|
|
1362
|
+
result = astQueryData(args.pattern, dbPath, {
|
|
1363
|
+
kind: args.kind,
|
|
1364
|
+
file: args.file,
|
|
1186
1365
|
noTests: args.no_tests,
|
|
1366
|
+
limit: Math.min(args.limit ?? MCP_DEFAULTS.ast_query, MCP_MAX_LIMIT),
|
|
1367
|
+
offset: args.offset ?? 0,
|
|
1187
1368
|
});
|
|
1188
1369
|
break;
|
|
1189
1370
|
}
|