@side-quest/kit 0.0.0 → 0.2.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/CHANGELOG.md +36 -0
- package/README.md +54 -352
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +156 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -2509
- package/dist/index.js.map +1 -0
- package/dist/lib/ast/index.d.ts +11 -0
- package/dist/lib/ast/index.d.ts.map +1 -0
- package/dist/lib/ast/index.js +15 -0
- package/dist/lib/ast/index.js.map +1 -0
- package/dist/lib/ast/languages.d.ts +55 -0
- package/dist/lib/ast/languages.d.ts.map +1 -0
- package/dist/lib/ast/languages.js +146 -0
- package/dist/lib/ast/languages.js.map +1 -0
- package/dist/lib/ast/pattern.d.ts +84 -0
- package/dist/lib/ast/pattern.d.ts.map +1 -0
- package/dist/lib/ast/pattern.js +268 -0
- package/dist/lib/ast/pattern.js.map +1 -0
- package/dist/lib/ast/searcher.d.ts +89 -0
- package/dist/lib/ast/searcher.d.ts.map +1 -0
- package/dist/lib/ast/searcher.js +316 -0
- package/dist/lib/ast/searcher.js.map +1 -0
- package/dist/lib/ast/types.d.ts +93 -0
- package/dist/lib/ast/types.d.ts.map +1 -0
- package/dist/lib/ast/types.js +23 -0
- package/dist/lib/ast/types.js.map +1 -0
- package/dist/lib/commands/callers.d.ts +20 -0
- package/dist/lib/commands/callers.d.ts.map +1 -0
- package/dist/lib/commands/callers.js +162 -0
- package/dist/lib/commands/callers.js.map +1 -0
- package/dist/lib/commands/find.d.ts +15 -0
- package/dist/lib/commands/find.d.ts.map +1 -0
- package/dist/lib/commands/find.js +113 -0
- package/dist/lib/commands/find.js.map +1 -0
- package/dist/lib/commands/overview.d.ts +6 -0
- package/dist/lib/commands/overview.d.ts.map +1 -0
- package/dist/lib/commands/overview.js +52 -0
- package/dist/lib/commands/overview.js.map +1 -0
- package/dist/lib/commands/prime.d.ts +16 -0
- package/dist/lib/commands/prime.d.ts.map +1 -0
- package/dist/lib/commands/prime.js +168 -0
- package/dist/lib/commands/prime.js.map +1 -0
- package/dist/lib/commands/search.d.ts +20 -0
- package/dist/lib/commands/search.d.ts.map +1 -0
- package/dist/lib/commands/search.js +111 -0
- package/dist/lib/commands/search.js.map +1 -0
- package/dist/lib/errors.d.ts +80 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +189 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/formatters/output.d.ts +5 -0
- package/dist/lib/formatters/output.d.ts.map +1 -0
- package/dist/lib/formatters/output.js +5 -0
- package/dist/lib/formatters/output.js.map +1 -0
- package/dist/lib/formatters.d.ts +29 -0
- package/dist/lib/formatters.d.ts.map +1 -0
- package/dist/lib/formatters.js +141 -0
- package/dist/lib/formatters.js.map +1 -0
- package/dist/lib/index-tools.d.ts +108 -0
- package/dist/lib/index-tools.d.ts.map +1 -0
- package/dist/lib/index-tools.js +311 -0
- package/dist/lib/index-tools.js.map +1 -0
- package/dist/lib/index.d.ts +21 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +42 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/kit-wrapper.d.ts +70 -0
- package/dist/lib/kit-wrapper.d.ts.map +1 -0
- package/dist/lib/kit-wrapper.js +462 -0
- package/dist/lib/kit-wrapper.js.map +1 -0
- package/dist/lib/logger.d.ts +28 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +39 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/types.d.ts +179 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +48 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utils/args.d.ts +40 -0
- package/dist/lib/utils/args.d.ts.map +1 -0
- package/dist/lib/utils/args.js +58 -0
- package/dist/lib/utils/args.js.map +1 -0
- package/dist/lib/utils/git.d.ts +23 -0
- package/dist/lib/utils/git.d.ts.map +1 -0
- package/dist/lib/utils/git.js +50 -0
- package/dist/lib/utils/git.js.map +1 -0
- package/dist/lib/utils/index-parser.d.ts +155 -0
- package/dist/lib/utils/index-parser.d.ts.map +1 -0
- package/dist/lib/utils/index-parser.js +252 -0
- package/dist/lib/utils/index-parser.js.map +1 -0
- package/dist/lib/validators.d.ts +138 -0
- package/dist/lib/validators.d.ts.map +1 -0
- package/dist/lib/validators.js +302 -0
- package/dist/lib/validators.js.map +1 -0
- package/dist/mcp/index.d.ts +19 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +769 -0
- package/dist/mcp/index.js.map +1 -0
- package/package.json +5 -2
- package/src/cli.ts +170 -0
- package/src/lib/ast/index.ts +32 -0
- package/src/lib/ast/languages.ts +172 -0
- package/src/lib/ast/pattern.ts +299 -0
- package/src/lib/ast/searcher.ts +381 -0
- package/src/lib/ast/types.ts +99 -0
- package/src/lib/commands/callers.ts +226 -0
- package/src/lib/commands/find.ts +159 -0
- package/src/lib/commands/overview.ts +73 -0
- package/src/lib/commands/prime.ts +271 -0
- package/src/lib/commands/search.ts +146 -0
- package/src/lib/errors.ts +221 -0
- package/src/lib/formatters/output.ts +9 -0
- package/src/lib/formatters.ts +189 -0
- package/src/lib/index-tools.ts +471 -0
- package/src/lib/index.ts +122 -0
- package/src/lib/kit-wrapper.ts +675 -0
- package/src/lib/logger.ts +57 -0
- package/src/lib/types.ts +228 -0
- package/src/lib/utils/args.ts +72 -0
- package/src/lib/utils/git.ts +65 -0
- package/src/lib/utils/index-parser.ts +350 -0
- package/src/lib/validators.ts +437 -0
- package/src/mcp/index.ts +144 -79
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Kit MCP Server (Slim)
|
|
4
|
+
*
|
|
5
|
+
* 7 focused tools for token-efficient codebase navigation using Kit CLI.
|
|
6
|
+
*
|
|
7
|
+
* Tools:
|
|
8
|
+
* 1. kit_prime - Generate/refresh PROJECT_INDEX.json
|
|
9
|
+
* 2. kit_find - Symbol lookup + file overview (merged)
|
|
10
|
+
* 3. kit_references - Callers + usages (merged)
|
|
11
|
+
* 4. kit_semantic - Vector search with grep fallback
|
|
12
|
+
* 5. kit_ast_search - Tree-sitter structural search
|
|
13
|
+
* 6. kit_context - Extract enclosing definition around file:line
|
|
14
|
+
* 7. kit_chunk - Split file into LLM-friendly chunks
|
|
15
|
+
*
|
|
16
|
+
* Observability: JSONL file logging to ~/.claude/logs/kit.jsonl
|
|
17
|
+
*/
|
|
18
|
+
import { createCorrelationId, log, startServer, tool, z, } from '@side-quest/core/mcp';
|
|
19
|
+
import { wrapToolHandler } from '@side-quest/core/mcp-response';
|
|
20
|
+
import { buildEnhancedPath, spawnSyncCollect } from '@side-quest/core/spawn';
|
|
21
|
+
import { executeAstSearch, executeIndexFind, executeIndexOverview, executeIndexPrime, executeKitGrep, executeKitSemantic, executeKitUsages, formatIndexFindResults, formatIndexOverviewResults, formatIndexPrimeResults, formatSemanticResults, ResponseFormat, SearchMode, validateAstSearchInputs, validatePath, validateSemanticInputs, validateUsagesInputs, } from '../lib/index.js';
|
|
22
|
+
import { findGitRootSync } from '../lib/utils/git.js';
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Logger Adapter
|
|
25
|
+
// ============================================================================
|
|
26
|
+
/**
|
|
27
|
+
* Adapter to bridge @side-quest/core/mcp log API to wrapToolHandler Logger interface.
|
|
28
|
+
*
|
|
29
|
+
* wrapToolHandler expects: logger.info(message, properties)
|
|
30
|
+
* @side-quest/core/mcp provides: log.info(properties, subsystem)
|
|
31
|
+
*/
|
|
32
|
+
function createLoggerAdapter(subsystem) {
|
|
33
|
+
return {
|
|
34
|
+
info: (message, properties) => {
|
|
35
|
+
log.info({ message, ...properties }, subsystem);
|
|
36
|
+
},
|
|
37
|
+
error: (message, properties) => {
|
|
38
|
+
log.error({ message, ...properties }, subsystem);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// 1. kit_prime - Generate/refresh PROJECT_INDEX.json
|
|
44
|
+
// ============================================================================
|
|
45
|
+
tool('kit_prime', {
|
|
46
|
+
description: `Generate or refresh PROJECT_INDEX.json for the codebase.
|
|
47
|
+
|
|
48
|
+
Creates a pre-built index enabling token-efficient queries:
|
|
49
|
+
- Indexes all symbols (functions, classes, types, etc.)
|
|
50
|
+
- Enables fast symbol lookup without scanning files
|
|
51
|
+
- Auto-detects git repository root
|
|
52
|
+
|
|
53
|
+
The index is valid for 24 hours. Use force=true to regenerate.
|
|
54
|
+
|
|
55
|
+
Requires Kit CLI: uv tool install cased-kit`,
|
|
56
|
+
inputSchema: {
|
|
57
|
+
path: z
|
|
58
|
+
.string()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('Directory to index (default: git root, then CWD)'),
|
|
61
|
+
force: z
|
|
62
|
+
.boolean()
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('Force regenerate even if index is less than 24 hours old'),
|
|
65
|
+
response_format: z
|
|
66
|
+
.enum(['markdown', 'json'])
|
|
67
|
+
.optional()
|
|
68
|
+
.default('json')
|
|
69
|
+
.describe("Output format: 'markdown' or 'json' (default)"),
|
|
70
|
+
},
|
|
71
|
+
annotations: {
|
|
72
|
+
readOnlyHint: false,
|
|
73
|
+
destructiveHint: false,
|
|
74
|
+
idempotentHint: true,
|
|
75
|
+
openWorldHint: false,
|
|
76
|
+
},
|
|
77
|
+
}, wrapToolHandler(async (args, format) => {
|
|
78
|
+
const { path, force } = args;
|
|
79
|
+
const result = await executeIndexPrime(force, path);
|
|
80
|
+
if ('isError' in result && result.isError) {
|
|
81
|
+
throw new Error(result.error);
|
|
82
|
+
}
|
|
83
|
+
const responseFormat = format === ResponseFormat.JSON
|
|
84
|
+
? ResponseFormat.JSON
|
|
85
|
+
: ResponseFormat.MARKDOWN;
|
|
86
|
+
return formatIndexPrimeResults(result, responseFormat);
|
|
87
|
+
}, {
|
|
88
|
+
toolName: 'kit_prime',
|
|
89
|
+
logger: createLoggerAdapter('symbols'),
|
|
90
|
+
createCid: createCorrelationId,
|
|
91
|
+
}));
|
|
92
|
+
// ============================================================================
|
|
93
|
+
// 2. kit_find - Symbol lookup + file overview (merged)
|
|
94
|
+
// ============================================================================
|
|
95
|
+
tool('kit_find', {
|
|
96
|
+
description: `Find symbol definitions or list all symbols in a file from PROJECT_INDEX.json.
|
|
97
|
+
|
|
98
|
+
Two modes:
|
|
99
|
+
- Symbol lookup: Pass symbol_name to find where a function/class/type is defined
|
|
100
|
+
- File overview: Pass file_path to see all symbols in a file without reading source
|
|
101
|
+
|
|
102
|
+
~50x token savings compared to reading full files.
|
|
103
|
+
|
|
104
|
+
NOTE: Requires PROJECT_INDEX.json. Run kit_prime first if not present.`,
|
|
105
|
+
inputSchema: {
|
|
106
|
+
symbol_name: z
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe('Symbol name to search for. Example: "executeKitGrep". Provide this OR file_path.'),
|
|
110
|
+
file_path: z
|
|
111
|
+
.string()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe('File path to get all symbols for (relative to repo root). Example: "src/kit-wrapper.ts". Provide this OR symbol_name.'),
|
|
114
|
+
index_path: z
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe('Path to PROJECT_INDEX.json or directory containing it (default: walks up to find it)'),
|
|
118
|
+
response_format: z
|
|
119
|
+
.enum(['markdown', 'json'])
|
|
120
|
+
.optional()
|
|
121
|
+
.default('json')
|
|
122
|
+
.describe("Output format: 'markdown' or 'json' (default)"),
|
|
123
|
+
},
|
|
124
|
+
annotations: {
|
|
125
|
+
readOnlyHint: true,
|
|
126
|
+
destructiveHint: false,
|
|
127
|
+
idempotentHint: true,
|
|
128
|
+
openWorldHint: false,
|
|
129
|
+
},
|
|
130
|
+
}, wrapToolHandler(async (args, format) => {
|
|
131
|
+
const { symbol_name, file_path, index_path } = args;
|
|
132
|
+
if (!symbol_name && !file_path) {
|
|
133
|
+
throw new Error('Either symbol_name or file_path is required. Pass symbol_name to find a definition, or file_path to list all symbols in a file.');
|
|
134
|
+
}
|
|
135
|
+
const responseFormat = format === ResponseFormat.JSON
|
|
136
|
+
? ResponseFormat.JSON
|
|
137
|
+
: ResponseFormat.MARKDOWN;
|
|
138
|
+
// File overview mode
|
|
139
|
+
if (file_path) {
|
|
140
|
+
const result = await executeIndexOverview(file_path, index_path);
|
|
141
|
+
if ('isError' in result && result.isError) {
|
|
142
|
+
throw new Error(result.error);
|
|
143
|
+
}
|
|
144
|
+
return formatIndexOverviewResults(result, responseFormat);
|
|
145
|
+
}
|
|
146
|
+
// Symbol lookup mode
|
|
147
|
+
const result = await executeIndexFind(symbol_name, index_path);
|
|
148
|
+
if ('isError' in result && result.isError) {
|
|
149
|
+
throw new Error(result.error);
|
|
150
|
+
}
|
|
151
|
+
return formatIndexFindResults(result, responseFormat);
|
|
152
|
+
}, {
|
|
153
|
+
toolName: 'kit_find',
|
|
154
|
+
logger: createLoggerAdapter('symbols'),
|
|
155
|
+
createCid: createCorrelationId,
|
|
156
|
+
}));
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// 3. kit_references - Callers + usages (merged)
|
|
159
|
+
// ============================================================================
|
|
160
|
+
tool('kit_references', {
|
|
161
|
+
description: `Find all references to a symbol -- call sites, usages, and definitions.
|
|
162
|
+
|
|
163
|
+
Three modes:
|
|
164
|
+
- all (default): Find all references (definitions + call sites + type usages)
|
|
165
|
+
- callers_only: Only call sites (filters out definitions)
|
|
166
|
+
- definitions_only: Only definition locations
|
|
167
|
+
|
|
168
|
+
Uses PROJECT_INDEX.json + grep for callers, Kit CLI for usages.
|
|
169
|
+
|
|
170
|
+
Requires Kit CLI: uv tool install cased-kit`,
|
|
171
|
+
inputSchema: {
|
|
172
|
+
symbol: z
|
|
173
|
+
.string()
|
|
174
|
+
.describe('Symbol name to find references for. Example: "executeFind"'),
|
|
175
|
+
mode: z
|
|
176
|
+
.enum(['all', 'callers_only', 'definitions_only'])
|
|
177
|
+
.optional()
|
|
178
|
+
.describe("Reference mode: 'all' (default), 'callers_only', or 'definitions_only'"),
|
|
179
|
+
symbol_type: z
|
|
180
|
+
.string()
|
|
181
|
+
.optional()
|
|
182
|
+
.describe('Filter by symbol type (for usages mode): "function", "class", "type", etc.'),
|
|
183
|
+
path: z
|
|
184
|
+
.string()
|
|
185
|
+
.optional()
|
|
186
|
+
.describe('Repository path to search (default: current directory)'),
|
|
187
|
+
response_format: z
|
|
188
|
+
.enum(['markdown', 'json'])
|
|
189
|
+
.optional()
|
|
190
|
+
.default('json')
|
|
191
|
+
.describe("Output format: 'markdown' or 'json' (default)"),
|
|
192
|
+
},
|
|
193
|
+
annotations: {
|
|
194
|
+
readOnlyHint: true,
|
|
195
|
+
destructiveHint: false,
|
|
196
|
+
idempotentHint: true,
|
|
197
|
+
openWorldHint: false,
|
|
198
|
+
},
|
|
199
|
+
}, wrapToolHandler(async (args, format) => {
|
|
200
|
+
const { symbol, mode = 'all', symbol_type, path, } = args;
|
|
201
|
+
if (mode === 'callers_only') {
|
|
202
|
+
// Validate symbol for callers mode (allowlist valid identifiers)
|
|
203
|
+
const trimmed = symbol.trim();
|
|
204
|
+
if (!trimmed) {
|
|
205
|
+
throw new Error('symbol is required and cannot be empty');
|
|
206
|
+
}
|
|
207
|
+
if (!/^[a-zA-Z_$][a-zA-Z0-9_$.<>#]*$/.test(trimmed)) {
|
|
208
|
+
throw new Error('symbol must be a valid identifier (letters, numbers, _, $, ., <, >, #)');
|
|
209
|
+
}
|
|
210
|
+
// Call library function directly instead of spawning CLI
|
|
211
|
+
// Uses kit grep to find all occurrences, then filters to call sites only
|
|
212
|
+
const grepResult = executeKitGrep({
|
|
213
|
+
pattern: trimmed,
|
|
214
|
+
path,
|
|
215
|
+
caseSensitive: true,
|
|
216
|
+
maxResults: 500,
|
|
217
|
+
});
|
|
218
|
+
// Handle error result
|
|
219
|
+
if ('error' in grepResult) {
|
|
220
|
+
throw new Error(`${grepResult.error}${grepResult.hint ? `\nHint: ${grepResult.hint}` : ''}`);
|
|
221
|
+
}
|
|
222
|
+
// Filter out definition patterns to show only call sites
|
|
223
|
+
// Heuristics: exclude lines that look like function declarations or assignments
|
|
224
|
+
const definitionPatterns = [
|
|
225
|
+
/^function\s+/, // function declarations
|
|
226
|
+
/^export\s+(async\s+)?function\s+/, // exported functions
|
|
227
|
+
/^(const|let|var)\s+\w+\s*=\s*function/, // function expressions
|
|
228
|
+
/^(const|let|var)\s+\w+\s*=\s*\(/, // arrow functions
|
|
229
|
+
/^(const|let|var)\s+\w+\s*=\s*async\s*\(/, // async arrow functions
|
|
230
|
+
/^async\s+function\s+/, // async function declarations
|
|
231
|
+
];
|
|
232
|
+
const callSites = grepResult.matches.filter((match) => {
|
|
233
|
+
const content = match.content.trim();
|
|
234
|
+
return !definitionPatterns.some((pattern) => pattern.test(content));
|
|
235
|
+
});
|
|
236
|
+
// Build callers result in same format as CLI command
|
|
237
|
+
const callersResult = {
|
|
238
|
+
functionName: trimmed,
|
|
239
|
+
callSites: callSites.map((m) => ({
|
|
240
|
+
file: m.file,
|
|
241
|
+
line: m.line || 0,
|
|
242
|
+
context: m.content,
|
|
243
|
+
})),
|
|
244
|
+
count: callSites.length,
|
|
245
|
+
};
|
|
246
|
+
// Format output
|
|
247
|
+
if (format === ResponseFormat.JSON) {
|
|
248
|
+
return JSON.stringify(callersResult, null, 2);
|
|
249
|
+
}
|
|
250
|
+
// Markdown format
|
|
251
|
+
let markdown = `## Call Sites\n\n`;
|
|
252
|
+
markdown += `**Function:** \`${trimmed}\`\n`;
|
|
253
|
+
markdown += `**Call sites found:** ${callersResult.count}\n\n`;
|
|
254
|
+
if (callersResult.count === 0) {
|
|
255
|
+
markdown += '_No call sites found_\n';
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// Group by file
|
|
259
|
+
const byFile = new Map();
|
|
260
|
+
for (const site of callSites) {
|
|
261
|
+
if (!byFile.has(site.file)) {
|
|
262
|
+
byFile.set(site.file, []);
|
|
263
|
+
}
|
|
264
|
+
byFile.get(site.file)?.push(site);
|
|
265
|
+
}
|
|
266
|
+
for (const [file, sites] of byFile.entries()) {
|
|
267
|
+
markdown += `### ${file}\n\n`;
|
|
268
|
+
for (const site of sites) {
|
|
269
|
+
markdown += `- Line ${site.line || '?'}: \`${site.content.trim()}\`\n`;
|
|
270
|
+
}
|
|
271
|
+
markdown += '\n';
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return markdown;
|
|
275
|
+
}
|
|
276
|
+
// Validate inputs for usages modes
|
|
277
|
+
const validation = validateUsagesInputs({
|
|
278
|
+
symbolName: symbol,
|
|
279
|
+
symbolType: symbol_type,
|
|
280
|
+
path,
|
|
281
|
+
});
|
|
282
|
+
if (!validation.valid) {
|
|
283
|
+
throw new Error(validation.errors.join('; '));
|
|
284
|
+
}
|
|
285
|
+
// For "all" and "definitions_only", use Kit usages
|
|
286
|
+
const result = executeKitUsages({
|
|
287
|
+
symbolName: validation.validated.symbolName,
|
|
288
|
+
symbolType: validation.validated.symbolType,
|
|
289
|
+
path: validation.validated.path,
|
|
290
|
+
});
|
|
291
|
+
if ('error' in result) {
|
|
292
|
+
throw new Error(`${result.error}${result.hint ? `\nHint: ${result.hint}` : ''}`);
|
|
293
|
+
}
|
|
294
|
+
// Filter to definitions only if requested
|
|
295
|
+
if (mode === 'definitions_only') {
|
|
296
|
+
result.usages = result.usages.filter((u) => u.type === 'definition' || u.type === 'export');
|
|
297
|
+
result.count = result.usages.length;
|
|
298
|
+
}
|
|
299
|
+
if (format === ResponseFormat.JSON) {
|
|
300
|
+
return JSON.stringify(result, null, 2);
|
|
301
|
+
}
|
|
302
|
+
// Format as markdown
|
|
303
|
+
let markdown = `## Symbol References\n\n`;
|
|
304
|
+
markdown += `**Symbol:** \`${result.symbolName}\`\n`;
|
|
305
|
+
markdown += `**Mode:** ${mode}\n`;
|
|
306
|
+
markdown += `**References found:** ${result.count}\n\n`;
|
|
307
|
+
if (result.usages.length === 0) {
|
|
308
|
+
markdown += '_No references found_\n';
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
for (const usage of result.usages) {
|
|
312
|
+
markdown += `### ${usage.file}${usage.line ? `:${usage.line}` : ''}\n`;
|
|
313
|
+
markdown += `**Type:** \`${usage.type}\` | **Name:** \`${usage.name}\`\n`;
|
|
314
|
+
if (usage.context) {
|
|
315
|
+
markdown += `\`\`\`\n${usage.context}\n\`\`\`\n`;
|
|
316
|
+
}
|
|
317
|
+
markdown += '\n';
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return markdown;
|
|
321
|
+
}, {
|
|
322
|
+
toolName: 'kit_references',
|
|
323
|
+
logger: createLoggerAdapter('references'),
|
|
324
|
+
createCid: createCorrelationId,
|
|
325
|
+
}));
|
|
326
|
+
// ============================================================================
|
|
327
|
+
// 4. kit_semantic - Vector search with grep fallback
|
|
328
|
+
// ============================================================================
|
|
329
|
+
tool('kit_semantic', {
|
|
330
|
+
description: `Semantic search using natural language queries and vector embeddings.
|
|
331
|
+
|
|
332
|
+
Find code by meaning rather than exact text matches. Great for:
|
|
333
|
+
- "How does authentication work?"
|
|
334
|
+
- "Error handling patterns"
|
|
335
|
+
- "Database connection logic"
|
|
336
|
+
|
|
337
|
+
NOTE: Requires ML dependencies. If unavailable, falls back to text search.
|
|
338
|
+
To enable: uv tool install 'cased-kit[ml]'`,
|
|
339
|
+
inputSchema: {
|
|
340
|
+
query: z
|
|
341
|
+
.string()
|
|
342
|
+
.describe('Natural language query. Example: "authentication flow logic"'),
|
|
343
|
+
path: z
|
|
344
|
+
.string()
|
|
345
|
+
.optional()
|
|
346
|
+
.describe('Repository path to search (default: current directory)'),
|
|
347
|
+
top_k: z
|
|
348
|
+
.number()
|
|
349
|
+
.optional()
|
|
350
|
+
.describe('Number of results to return (default: 5, max: 50)'),
|
|
351
|
+
chunk_by: z
|
|
352
|
+
.enum(['symbols', 'lines'])
|
|
353
|
+
.optional()
|
|
354
|
+
.describe("Chunking strategy: 'symbols' (default) or 'lines'"),
|
|
355
|
+
build_index: z
|
|
356
|
+
.boolean()
|
|
357
|
+
.optional()
|
|
358
|
+
.describe('Force rebuild of vector index (default: false)'),
|
|
359
|
+
response_format: z
|
|
360
|
+
.enum(['markdown', 'json'])
|
|
361
|
+
.optional()
|
|
362
|
+
.default('json')
|
|
363
|
+
.describe("Output format: 'markdown' or 'json' (default)"),
|
|
364
|
+
},
|
|
365
|
+
annotations: {
|
|
366
|
+
readOnlyHint: true,
|
|
367
|
+
destructiveHint: false,
|
|
368
|
+
idempotentHint: true,
|
|
369
|
+
openWorldHint: false,
|
|
370
|
+
},
|
|
371
|
+
}, wrapToolHandler(async (args, format) => {
|
|
372
|
+
const { query, path, top_k, chunk_by, build_index } = args;
|
|
373
|
+
// Validate semantic search inputs
|
|
374
|
+
const validation = validateSemanticInputs({ query, path, topK: top_k });
|
|
375
|
+
if (!validation.valid) {
|
|
376
|
+
throw new Error(validation.errors.join('; '));
|
|
377
|
+
}
|
|
378
|
+
// Call library function directly instead of spawning CLI
|
|
379
|
+
const result = executeKitSemantic({
|
|
380
|
+
query: validation.validated.query,
|
|
381
|
+
path: validation.validated.path,
|
|
382
|
+
topK: validation.validated.topK,
|
|
383
|
+
chunkBy: chunk_by,
|
|
384
|
+
buildIndex: build_index,
|
|
385
|
+
});
|
|
386
|
+
// Handle error result
|
|
387
|
+
if ('error' in result) {
|
|
388
|
+
throw new Error(`${result.error}${result.hint ? `\nHint: ${result.hint}` : ''}`);
|
|
389
|
+
}
|
|
390
|
+
// Format result using existing formatter
|
|
391
|
+
const responseFormat = format === ResponseFormat.JSON
|
|
392
|
+
? ResponseFormat.JSON
|
|
393
|
+
: ResponseFormat.MARKDOWN;
|
|
394
|
+
return formatSemanticResults(result, responseFormat);
|
|
395
|
+
}, {
|
|
396
|
+
toolName: 'kit_semantic',
|
|
397
|
+
logger: createLoggerAdapter('semantic'),
|
|
398
|
+
createCid: createCorrelationId,
|
|
399
|
+
}));
|
|
400
|
+
// ============================================================================
|
|
401
|
+
// 5. kit_ast_search - Tree-sitter structural search
|
|
402
|
+
// ============================================================================
|
|
403
|
+
tool('kit_ast_search', {
|
|
404
|
+
description: `AST pattern search using tree-sitter for structural code matching.
|
|
405
|
+
|
|
406
|
+
Find code by structure rather than text. More precise than grep for:
|
|
407
|
+
- "async function" - Find all async functions
|
|
408
|
+
- "try catch" - Find try-catch blocks
|
|
409
|
+
- "React hooks" - Find useState/useEffect calls
|
|
410
|
+
- "class extends" - Find class inheritance
|
|
411
|
+
|
|
412
|
+
Supports TypeScript, JavaScript, and Python.
|
|
413
|
+
|
|
414
|
+
Two modes:
|
|
415
|
+
- simple (default): Natural language patterns like "async function"
|
|
416
|
+
- pattern: JSON criteria like {"type": "function_declaration", "async": true}`,
|
|
417
|
+
inputSchema: {
|
|
418
|
+
pattern: z
|
|
419
|
+
.string()
|
|
420
|
+
.describe('Search pattern. Simple mode: "async function", "try catch". Pattern mode: {"type": "function_declaration"}'),
|
|
421
|
+
mode: z
|
|
422
|
+
.enum(['simple', 'pattern'])
|
|
423
|
+
.optional()
|
|
424
|
+
.describe("Search mode: 'simple' (default) for natural language, 'pattern' for JSON criteria"),
|
|
425
|
+
file_pattern: z
|
|
426
|
+
.string()
|
|
427
|
+
.optional()
|
|
428
|
+
.describe('File glob pattern to search (default: all supported files). Example: "*.ts"'),
|
|
429
|
+
path: z
|
|
430
|
+
.string()
|
|
431
|
+
.optional()
|
|
432
|
+
.describe('Repository path to search (default: current directory)'),
|
|
433
|
+
max_results: z
|
|
434
|
+
.number()
|
|
435
|
+
.optional()
|
|
436
|
+
.describe('Maximum results to return (default: 100)'),
|
|
437
|
+
response_format: z
|
|
438
|
+
.enum(['markdown', 'json'])
|
|
439
|
+
.optional()
|
|
440
|
+
.default('json')
|
|
441
|
+
.describe("Output format: 'markdown' or 'json' (default)"),
|
|
442
|
+
},
|
|
443
|
+
annotations: {
|
|
444
|
+
readOnlyHint: true,
|
|
445
|
+
destructiveHint: false,
|
|
446
|
+
idempotentHint: true,
|
|
447
|
+
openWorldHint: false,
|
|
448
|
+
},
|
|
449
|
+
}, wrapToolHandler(async (args, format) => {
|
|
450
|
+
const { pattern, mode, file_pattern, path, max_results } = args;
|
|
451
|
+
// Validate AST search inputs
|
|
452
|
+
const validation = validateAstSearchInputs({
|
|
453
|
+
pattern,
|
|
454
|
+
mode,
|
|
455
|
+
filePattern: file_pattern,
|
|
456
|
+
path,
|
|
457
|
+
maxResults: max_results,
|
|
458
|
+
});
|
|
459
|
+
if (!validation.valid) {
|
|
460
|
+
throw new Error(validation.errors.join('; '));
|
|
461
|
+
}
|
|
462
|
+
const result = await executeAstSearch({
|
|
463
|
+
pattern: validation.validated.pattern,
|
|
464
|
+
mode: validation.validated.mode === 'pattern'
|
|
465
|
+
? SearchMode.PATTERN
|
|
466
|
+
: SearchMode.SIMPLE,
|
|
467
|
+
filePattern: validation.validated.filePattern,
|
|
468
|
+
path: validation.validated.path,
|
|
469
|
+
maxResults: validation.validated.maxResults,
|
|
470
|
+
});
|
|
471
|
+
if ('error' in result) {
|
|
472
|
+
throw new Error(`${result.error}${result.hint ? `\nHint: ${result.hint}` : ''}`);
|
|
473
|
+
}
|
|
474
|
+
if (format === ResponseFormat.JSON) {
|
|
475
|
+
return JSON.stringify(result, null, 2);
|
|
476
|
+
}
|
|
477
|
+
let markdown = `## AST Search Results\n\n`;
|
|
478
|
+
markdown += `**Pattern:** \`${result.pattern}\`\n`;
|
|
479
|
+
markdown += `**Mode:** ${result.mode}\n`;
|
|
480
|
+
markdown += `**Matches:** ${result.count}\n\n`;
|
|
481
|
+
if (result.matches.length === 0) {
|
|
482
|
+
markdown += '_No matches found_\n';
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
for (const match of result.matches) {
|
|
486
|
+
markdown += `### ${match.file}:${match.line}\n`;
|
|
487
|
+
markdown += `**Node type:** \`${match.nodeType}\`\n`;
|
|
488
|
+
if (match.context.parentFunction) {
|
|
489
|
+
markdown += `**In function:** \`${match.context.parentFunction}\`\n`;
|
|
490
|
+
}
|
|
491
|
+
if (match.context.parentClass) {
|
|
492
|
+
markdown += `**In class:** \`${match.context.parentClass}\`\n`;
|
|
493
|
+
}
|
|
494
|
+
markdown += `\`\`\`\n${match.text.slice(0, 300)}${match.text.length > 300 ? '...' : ''}\n\`\`\`\n\n`;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return markdown;
|
|
498
|
+
}, {
|
|
499
|
+
toolName: 'kit_ast_search',
|
|
500
|
+
logger: createLoggerAdapter('ast'),
|
|
501
|
+
createCid: createCorrelationId,
|
|
502
|
+
}));
|
|
503
|
+
// ============================================================================
|
|
504
|
+
// 6. kit_context - Extract enclosing definition around file:line
|
|
505
|
+
// ============================================================================
|
|
506
|
+
tool('kit_context', {
|
|
507
|
+
description: `Extract the full enclosing definition around a specific line in a file.
|
|
508
|
+
|
|
509
|
+
Uses Kit CLI to find the complete function/class/method that contains a given line.
|
|
510
|
+
Great for:
|
|
511
|
+
- Getting full context around a line reference
|
|
512
|
+
- Extracting complete function bodies without reading entire files
|
|
513
|
+
- Understanding code surrounding a specific location
|
|
514
|
+
|
|
515
|
+
Requires Kit CLI v3.0+: uv tool install cased-kit`,
|
|
516
|
+
inputSchema: {
|
|
517
|
+
file_path: z
|
|
518
|
+
.string()
|
|
519
|
+
.describe('Relative path to the file within the repository. Example: "src/kit-wrapper.ts"'),
|
|
520
|
+
line: z.number().describe('Line number to extract context around'),
|
|
521
|
+
path: z
|
|
522
|
+
.string()
|
|
523
|
+
.optional()
|
|
524
|
+
.describe('Repository path (default: git root or current directory)'),
|
|
525
|
+
response_format: z
|
|
526
|
+
.enum(['markdown', 'json'])
|
|
527
|
+
.optional()
|
|
528
|
+
.default('json')
|
|
529
|
+
.describe("Output format: 'markdown' or 'json' (default)"),
|
|
530
|
+
},
|
|
531
|
+
annotations: {
|
|
532
|
+
readOnlyHint: true,
|
|
533
|
+
destructiveHint: false,
|
|
534
|
+
idempotentHint: true,
|
|
535
|
+
openWorldHint: false,
|
|
536
|
+
},
|
|
537
|
+
}, wrapToolHandler(async (args, format) => {
|
|
538
|
+
const { file_path, line, path } = args;
|
|
539
|
+
// Validate file_path - no traversal, non-empty, no null bytes, relative only
|
|
540
|
+
const fileTrimmed = file_path.trim();
|
|
541
|
+
if (!fileTrimmed) {
|
|
542
|
+
throw new Error('file_path is required');
|
|
543
|
+
}
|
|
544
|
+
// Reject null bytes
|
|
545
|
+
if (fileTrimmed.includes('\x00')) {
|
|
546
|
+
throw new Error('file_path contains invalid characters');
|
|
547
|
+
}
|
|
548
|
+
// Reject absolute paths
|
|
549
|
+
if (fileTrimmed.startsWith('/') || fileTrimmed.startsWith('\\')) {
|
|
550
|
+
throw new Error('file_path must be a relative path');
|
|
551
|
+
}
|
|
552
|
+
// Normalize and check for directory traversal
|
|
553
|
+
const normalized = fileTrimmed.replace(/\\/g, '/');
|
|
554
|
+
if (normalized.includes('..')) {
|
|
555
|
+
throw new Error('file_path must not contain directory traversal');
|
|
556
|
+
}
|
|
557
|
+
if (line < 1) {
|
|
558
|
+
throw new Error('line must be a positive integer');
|
|
559
|
+
}
|
|
560
|
+
// Validate path param if provided
|
|
561
|
+
if (path) {
|
|
562
|
+
const pathResult = validatePath(path);
|
|
563
|
+
if (!pathResult.valid) {
|
|
564
|
+
throw new Error(pathResult.error);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const repoPath = path || findGitRootSync() || process.cwd();
|
|
568
|
+
const result = spawnSyncCollect(['kit', 'context', repoPath, '--', file_path, String(line)], {
|
|
569
|
+
env: { PATH: buildEnhancedPath() },
|
|
570
|
+
});
|
|
571
|
+
if (result.exitCode !== 0) {
|
|
572
|
+
throw new Error(result.stderr || `Failed to extract context for ${file_path}:${line}`);
|
|
573
|
+
}
|
|
574
|
+
const output = result.stdout.trim();
|
|
575
|
+
if (format === ResponseFormat.JSON) {
|
|
576
|
+
// Kit context outputs JSON by default
|
|
577
|
+
try {
|
|
578
|
+
const parsed = JSON.parse(output);
|
|
579
|
+
return JSON.stringify(parsed, null, 2);
|
|
580
|
+
}
|
|
581
|
+
catch {
|
|
582
|
+
return JSON.stringify({ context: output, file: file_path, line });
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
// Markdown format
|
|
586
|
+
let markdown = `## Context for ${file_path}:${line}\n\n`;
|
|
587
|
+
try {
|
|
588
|
+
const parsed = JSON.parse(output);
|
|
589
|
+
if (parsed.context || parsed.code) {
|
|
590
|
+
const code = parsed.context || parsed.code || output;
|
|
591
|
+
const ext = file_path.split('.').pop() || '';
|
|
592
|
+
const lang = { ts: 'typescript', js: 'javascript', py: 'python' }[ext] || '';
|
|
593
|
+
markdown += `\`\`\`${lang}\n${code}\n\`\`\`\n`;
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
markdown += `\`\`\`\n${output}\n\`\`\`\n`;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
catch {
|
|
600
|
+
markdown += `\`\`\`\n${output}\n\`\`\`\n`;
|
|
601
|
+
}
|
|
602
|
+
return markdown;
|
|
603
|
+
}, {
|
|
604
|
+
toolName: 'kit_context',
|
|
605
|
+
logger: createLoggerAdapter('context'),
|
|
606
|
+
createCid: createCorrelationId,
|
|
607
|
+
}));
|
|
608
|
+
// ============================================================================
|
|
609
|
+
// 7. kit_chunk - Split file into LLM-friendly chunks
|
|
610
|
+
// ============================================================================
|
|
611
|
+
tool('kit_chunk', {
|
|
612
|
+
description: `Split a file into LLM-friendly chunks for efficient processing.
|
|
613
|
+
|
|
614
|
+
Two strategies:
|
|
615
|
+
- symbols (default): Chunk at function/class boundaries (semantic)
|
|
616
|
+
- lines: Chunk by line count (configurable max_lines)
|
|
617
|
+
|
|
618
|
+
Great for:
|
|
619
|
+
- Processing large files piece by piece
|
|
620
|
+
- Token-efficient file analysis
|
|
621
|
+
- Focused code review on specific sections
|
|
622
|
+
|
|
623
|
+
Requires Kit CLI v3.0+: uv tool install cased-kit`,
|
|
624
|
+
inputSchema: {
|
|
625
|
+
file_path: z
|
|
626
|
+
.string()
|
|
627
|
+
.describe('Relative path to the file within the repository. Example: "src/kit-wrapper.ts"'),
|
|
628
|
+
strategy: z
|
|
629
|
+
.enum(['symbols', 'lines'])
|
|
630
|
+
.optional()
|
|
631
|
+
.describe("Chunking strategy: 'symbols' (default, at function boundaries) or 'lines' (by line count)"),
|
|
632
|
+
max_lines: z
|
|
633
|
+
.number()
|
|
634
|
+
.optional()
|
|
635
|
+
.describe("Maximum lines per chunk (only for 'lines' strategy, default: 50)"),
|
|
636
|
+
path: z
|
|
637
|
+
.string()
|
|
638
|
+
.optional()
|
|
639
|
+
.describe('Repository path (default: git root or current directory)'),
|
|
640
|
+
response_format: z
|
|
641
|
+
.enum(['markdown', 'json'])
|
|
642
|
+
.optional()
|
|
643
|
+
.default('json')
|
|
644
|
+
.describe("Output format: 'markdown' or 'json' (default)"),
|
|
645
|
+
},
|
|
646
|
+
annotations: {
|
|
647
|
+
readOnlyHint: true,
|
|
648
|
+
destructiveHint: false,
|
|
649
|
+
idempotentHint: true,
|
|
650
|
+
openWorldHint: false,
|
|
651
|
+
},
|
|
652
|
+
}, wrapToolHandler(async (args, format) => {
|
|
653
|
+
const { file_path, strategy = 'symbols', max_lines, path, } = args;
|
|
654
|
+
// Validate file_path - no traversal, non-empty, no null bytes, relative only
|
|
655
|
+
const fileTrimmed = file_path.trim();
|
|
656
|
+
if (!fileTrimmed) {
|
|
657
|
+
throw new Error('file_path is required');
|
|
658
|
+
}
|
|
659
|
+
// Reject null bytes
|
|
660
|
+
if (fileTrimmed.includes('\x00')) {
|
|
661
|
+
throw new Error('file_path contains invalid characters');
|
|
662
|
+
}
|
|
663
|
+
// Reject absolute paths
|
|
664
|
+
if (fileTrimmed.startsWith('/') || fileTrimmed.startsWith('\\')) {
|
|
665
|
+
throw new Error('file_path must be a relative path');
|
|
666
|
+
}
|
|
667
|
+
// Normalize and check for directory traversal
|
|
668
|
+
const normalized = fileTrimmed.replace(/\\/g, '/');
|
|
669
|
+
if (normalized.includes('..')) {
|
|
670
|
+
throw new Error('file_path must not contain directory traversal');
|
|
671
|
+
}
|
|
672
|
+
// Validate max_lines bounds (1-500)
|
|
673
|
+
if (max_lines !== undefined && (max_lines < 1 || max_lines > 500)) {
|
|
674
|
+
throw new Error('max_lines must be between 1 and 500');
|
|
675
|
+
}
|
|
676
|
+
// Validate path param if provided
|
|
677
|
+
if (path) {
|
|
678
|
+
const pathResult = validatePath(path);
|
|
679
|
+
if (!pathResult.valid) {
|
|
680
|
+
throw new Error(pathResult.error);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
const repoPath = path || findGitRootSync() || process.cwd();
|
|
684
|
+
let cmd;
|
|
685
|
+
if (strategy === 'symbols') {
|
|
686
|
+
cmd = ['kit', 'chunk-symbols', repoPath, '--', file_path];
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
cmd = ['kit', 'chunk-lines', repoPath];
|
|
690
|
+
if (max_lines) {
|
|
691
|
+
cmd.push('-n', String(max_lines));
|
|
692
|
+
}
|
|
693
|
+
cmd.push('--', file_path);
|
|
694
|
+
}
|
|
695
|
+
const result = spawnSyncCollect(cmd, {
|
|
696
|
+
env: { PATH: buildEnhancedPath() },
|
|
697
|
+
});
|
|
698
|
+
if (result.exitCode !== 0) {
|
|
699
|
+
throw new Error(result.stderr || `Failed to chunk ${file_path}`);
|
|
700
|
+
}
|
|
701
|
+
const output = result.stdout.trim();
|
|
702
|
+
if (format === ResponseFormat.JSON) {
|
|
703
|
+
try {
|
|
704
|
+
const parsed = JSON.parse(output);
|
|
705
|
+
return JSON.stringify(parsed, null, 2);
|
|
706
|
+
}
|
|
707
|
+
catch {
|
|
708
|
+
return JSON.stringify({
|
|
709
|
+
file: file_path,
|
|
710
|
+
strategy,
|
|
711
|
+
chunks: [output],
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
// Markdown format
|
|
716
|
+
let markdown = `## File Chunks: ${file_path}\n\n`;
|
|
717
|
+
markdown += `**Strategy:** ${strategy}\n`;
|
|
718
|
+
try {
|
|
719
|
+
const parsed = JSON.parse(output);
|
|
720
|
+
const chunks = Array.isArray(parsed)
|
|
721
|
+
? parsed
|
|
722
|
+
: parsed.chunks || [parsed];
|
|
723
|
+
markdown += `**Chunks:** ${chunks.length}\n\n`;
|
|
724
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
725
|
+
const chunk = chunks[i];
|
|
726
|
+
markdown += `### Chunk ${i + 1}`;
|
|
727
|
+
if (chunk.name || chunk.symbol) {
|
|
728
|
+
markdown += ` - ${chunk.name || chunk.symbol}`;
|
|
729
|
+
}
|
|
730
|
+
markdown += '\n';
|
|
731
|
+
if (chunk.start_line || chunk.startLine) {
|
|
732
|
+
markdown += `Lines ${chunk.start_line || chunk.startLine}-${chunk.end_line || chunk.endLine}\n`;
|
|
733
|
+
}
|
|
734
|
+
const code = chunk.content || chunk.code || chunk.text || JSON.stringify(chunk);
|
|
735
|
+
const ext = file_path.split('.').pop() || '';
|
|
736
|
+
const lang = { ts: 'typescript', js: 'javascript', py: 'python' }[ext] || '';
|
|
737
|
+
markdown += `\`\`\`${lang}\n${code}\n\`\`\`\n\n`;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
catch {
|
|
741
|
+
markdown += `\`\`\`\n${output}\n\`\`\`\n`;
|
|
742
|
+
}
|
|
743
|
+
return markdown;
|
|
744
|
+
}, {
|
|
745
|
+
toolName: 'kit_chunk',
|
|
746
|
+
logger: createLoggerAdapter('chunk'),
|
|
747
|
+
createCid: createCorrelationId,
|
|
748
|
+
}));
|
|
749
|
+
// ============================================================================
|
|
750
|
+
// Start Server
|
|
751
|
+
// ============================================================================
|
|
752
|
+
if (import.meta.main) {
|
|
753
|
+
startServer('kit', {
|
|
754
|
+
version: '1.0.0',
|
|
755
|
+
fileLogging: {
|
|
756
|
+
enabled: true,
|
|
757
|
+
subsystems: [
|
|
758
|
+
'symbols',
|
|
759
|
+
'references',
|
|
760
|
+
'semantic',
|
|
761
|
+
'ast',
|
|
762
|
+
'context',
|
|
763
|
+
'chunk',
|
|
764
|
+
],
|
|
765
|
+
level: 'debug',
|
|
766
|
+
},
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
//# sourceMappingURL=index.js.map
|