@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,437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kit Plugin Validators
|
|
3
|
+
*
|
|
4
|
+
* Input validation and security utilities for safe Kit CLI operations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { normalizePath, pathExistsSync, statSync } from '@side-quest/core/fs'
|
|
8
|
+
import {
|
|
9
|
+
validateGlob,
|
|
10
|
+
validateInteger,
|
|
11
|
+
validateRegex,
|
|
12
|
+
} from '@side-quest/core/validation'
|
|
13
|
+
import { getDefaultKitPath } from './types.js'
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Path Validation
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Result of path validation.
|
|
21
|
+
*/
|
|
22
|
+
export interface PathValidationResult {
|
|
23
|
+
/** Whether the path is valid */
|
|
24
|
+
valid: boolean
|
|
25
|
+
/** Normalized absolute path (only if valid) */
|
|
26
|
+
path?: string
|
|
27
|
+
/** Error message (only if invalid) */
|
|
28
|
+
error?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Validate a path for Kit operations.
|
|
33
|
+
*
|
|
34
|
+
* Checks:
|
|
35
|
+
* - Path exists
|
|
36
|
+
* - Path is a directory (for search operations)
|
|
37
|
+
* - No path traversal attacks (.. sequences escaping base)
|
|
38
|
+
*
|
|
39
|
+
* @param inputPath - Path to validate
|
|
40
|
+
* @param options - Validation options
|
|
41
|
+
* @returns Validation result with normalized path or error
|
|
42
|
+
*/
|
|
43
|
+
export function validatePath(
|
|
44
|
+
inputPath: string,
|
|
45
|
+
options: {
|
|
46
|
+
/** Base directory to restrict access within (optional) */
|
|
47
|
+
basePath?: string
|
|
48
|
+
/** Whether the path must be a directory (default: true) */
|
|
49
|
+
mustBeDirectory?: boolean
|
|
50
|
+
/** Whether the path must exist (default: true) */
|
|
51
|
+
mustExist?: boolean
|
|
52
|
+
} = {},
|
|
53
|
+
): PathValidationResult {
|
|
54
|
+
const { basePath, mustBeDirectory = true, mustExist = true } = options
|
|
55
|
+
|
|
56
|
+
// Empty path check
|
|
57
|
+
if (!inputPath || inputPath.trim() === '') {
|
|
58
|
+
return { valid: false, error: 'Path cannot be empty' }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Normalize the path
|
|
62
|
+
const normalizedPath = normalizePath(inputPath, basePath)
|
|
63
|
+
|
|
64
|
+
// Path traversal check - if basePath is specified, ensure we stay within it
|
|
65
|
+
if (basePath) {
|
|
66
|
+
const normalizedBase = normalizePath(basePath)
|
|
67
|
+
if (!normalizedPath.startsWith(normalizedBase)) {
|
|
68
|
+
return {
|
|
69
|
+
valid: false,
|
|
70
|
+
error: 'Path traversal detected: path escapes base directory',
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Existence check
|
|
76
|
+
if (mustExist && !pathExistsSync(normalizedPath)) {
|
|
77
|
+
return { valid: false, error: `Path does not exist: ${normalizedPath}` }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Directory check
|
|
81
|
+
if (mustExist && mustBeDirectory) {
|
|
82
|
+
try {
|
|
83
|
+
const stats = statSync(normalizedPath)
|
|
84
|
+
if (!stats.isDirectory()) {
|
|
85
|
+
return {
|
|
86
|
+
valid: false,
|
|
87
|
+
error: `Path is not a directory: ${normalizedPath}`,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
return { valid: false, error: `Cannot access path: ${normalizedPath}` }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return { valid: true, path: normalizedPath }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// Integer Validation
|
|
100
|
+
// ============================================================================
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Validate a number is a positive integer within bounds.
|
|
104
|
+
* @deprecated Use validateInteger from @sidequest/core/validation instead
|
|
105
|
+
* @param value - Value to validate
|
|
106
|
+
* @param options - Validation options
|
|
107
|
+
* @returns Validation result
|
|
108
|
+
*/
|
|
109
|
+
export function validatePositiveInt(
|
|
110
|
+
value: unknown,
|
|
111
|
+
options: {
|
|
112
|
+
/** Field name for error messages */
|
|
113
|
+
name: string
|
|
114
|
+
/** Minimum allowed value (default: 1) */
|
|
115
|
+
min?: number
|
|
116
|
+
/** Maximum allowed value (default: 10000) */
|
|
117
|
+
max?: number
|
|
118
|
+
/** Default value if undefined */
|
|
119
|
+
defaultValue?: number
|
|
120
|
+
},
|
|
121
|
+
): { valid: boolean; value?: number; error?: string } {
|
|
122
|
+
// Delegate to core validateInteger with backward-compatible defaults
|
|
123
|
+
return validateInteger(value, {
|
|
124
|
+
name: options.name,
|
|
125
|
+
min: options.min ?? 1,
|
|
126
|
+
max: options.max ?? 10000,
|
|
127
|
+
defaultValue: options.defaultValue,
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// Composite Validators
|
|
133
|
+
// ============================================================================
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Validate all inputs for a grep search operation.
|
|
137
|
+
* @param inputs - Grep inputs to validate
|
|
138
|
+
* @returns Combined validation result
|
|
139
|
+
*/
|
|
140
|
+
export function validateGrepInputs(inputs: {
|
|
141
|
+
pattern: string
|
|
142
|
+
path?: string
|
|
143
|
+
include?: string
|
|
144
|
+
exclude?: string
|
|
145
|
+
maxResults?: number
|
|
146
|
+
}): {
|
|
147
|
+
valid: boolean
|
|
148
|
+
errors: string[]
|
|
149
|
+
validated?: {
|
|
150
|
+
pattern: string
|
|
151
|
+
path: string
|
|
152
|
+
include?: string
|
|
153
|
+
exclude?: string
|
|
154
|
+
maxResults: number
|
|
155
|
+
}
|
|
156
|
+
} {
|
|
157
|
+
const errors: string[] = []
|
|
158
|
+
|
|
159
|
+
// Validate pattern - core returns ValidationResult<RegExp>
|
|
160
|
+
const patternResult = validateRegex(inputs.pattern)
|
|
161
|
+
if (!patternResult.valid) {
|
|
162
|
+
errors.push(patternResult.error!)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Validate path
|
|
166
|
+
const pathResult = validatePath(inputs.path || getDefaultKitPath())
|
|
167
|
+
if (!pathResult.valid) {
|
|
168
|
+
errors.push(pathResult.error!)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Validate include glob (optional)
|
|
172
|
+
let validatedInclude: string | undefined
|
|
173
|
+
if (inputs.include) {
|
|
174
|
+
const includeResult = validateGlob(inputs.include)
|
|
175
|
+
if (!includeResult.valid) {
|
|
176
|
+
errors.push(`Include pattern: ${includeResult.error}`)
|
|
177
|
+
} else {
|
|
178
|
+
validatedInclude = includeResult.value
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Validate exclude glob (optional)
|
|
183
|
+
let validatedExclude: string | undefined
|
|
184
|
+
if (inputs.exclude) {
|
|
185
|
+
const excludeResult = validateGlob(inputs.exclude)
|
|
186
|
+
if (!excludeResult.valid) {
|
|
187
|
+
errors.push(`Exclude pattern: ${excludeResult.error}`)
|
|
188
|
+
} else {
|
|
189
|
+
validatedExclude = excludeResult.value
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Validate maxResults
|
|
194
|
+
const maxResultsResult = validatePositiveInt(inputs.maxResults, {
|
|
195
|
+
name: 'maxResults',
|
|
196
|
+
min: 1,
|
|
197
|
+
max: 1000,
|
|
198
|
+
defaultValue: 100,
|
|
199
|
+
})
|
|
200
|
+
if (!maxResultsResult.valid) {
|
|
201
|
+
errors.push(maxResultsResult.error!)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (errors.length > 0) {
|
|
205
|
+
return { valid: false, errors }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
valid: true,
|
|
210
|
+
errors: [],
|
|
211
|
+
validated: {
|
|
212
|
+
pattern: patternResult.value!.source, // Extract source from compiled RegExp
|
|
213
|
+
path: pathResult.path!,
|
|
214
|
+
include: validatedInclude,
|
|
215
|
+
exclude: validatedExclude,
|
|
216
|
+
maxResults: maxResultsResult.value!,
|
|
217
|
+
},
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Validate all inputs for a semantic search operation.
|
|
223
|
+
* @param inputs - Semantic search inputs to validate
|
|
224
|
+
* @returns Combined validation result
|
|
225
|
+
*/
|
|
226
|
+
export function validateSemanticInputs(inputs: {
|
|
227
|
+
query: string
|
|
228
|
+
path?: string
|
|
229
|
+
topK?: number
|
|
230
|
+
}): {
|
|
231
|
+
valid: boolean
|
|
232
|
+
errors: string[]
|
|
233
|
+
validated?: {
|
|
234
|
+
query: string
|
|
235
|
+
path: string
|
|
236
|
+
topK: number
|
|
237
|
+
}
|
|
238
|
+
} {
|
|
239
|
+
const errors: string[] = []
|
|
240
|
+
|
|
241
|
+
// Validate query (not a regex, just non-empty)
|
|
242
|
+
if (!inputs.query || inputs.query.trim() === '') {
|
|
243
|
+
errors.push('Query cannot be empty')
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Validate path
|
|
247
|
+
const pathResult = validatePath(inputs.path || getDefaultKitPath())
|
|
248
|
+
if (!pathResult.valid) {
|
|
249
|
+
errors.push(pathResult.error!)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Validate topK
|
|
253
|
+
const topKResult = validatePositiveInt(inputs.topK, {
|
|
254
|
+
name: 'topK',
|
|
255
|
+
min: 1,
|
|
256
|
+
max: 50,
|
|
257
|
+
defaultValue: 5,
|
|
258
|
+
})
|
|
259
|
+
if (!topKResult.valid) {
|
|
260
|
+
errors.push(topKResult.error!)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (errors.length > 0) {
|
|
264
|
+
return { valid: false, errors }
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
valid: true,
|
|
269
|
+
errors: [],
|
|
270
|
+
validated: {
|
|
271
|
+
query: inputs.query.trim(),
|
|
272
|
+
path: pathResult.path!,
|
|
273
|
+
topK: topKResult.value!,
|
|
274
|
+
},
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Validate all inputs for a symbol usages operation.
|
|
280
|
+
* @param inputs - Usages inputs to validate
|
|
281
|
+
* @returns Combined validation result
|
|
282
|
+
*/
|
|
283
|
+
export function validateUsagesInputs(inputs: {
|
|
284
|
+
path?: string
|
|
285
|
+
symbolName: string
|
|
286
|
+
symbolType?: string
|
|
287
|
+
}): {
|
|
288
|
+
valid: boolean
|
|
289
|
+
errors: string[]
|
|
290
|
+
validated?: {
|
|
291
|
+
path: string
|
|
292
|
+
symbolName: string
|
|
293
|
+
symbolType?: string
|
|
294
|
+
}
|
|
295
|
+
} {
|
|
296
|
+
const errors: string[] = []
|
|
297
|
+
|
|
298
|
+
// Validate path
|
|
299
|
+
const pathResult = validatePath(inputs.path || getDefaultKitPath())
|
|
300
|
+
if (!pathResult.valid) {
|
|
301
|
+
errors.push(pathResult.error!)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Validate symbol name
|
|
305
|
+
if (!inputs.symbolName || inputs.symbolName.trim() === '') {
|
|
306
|
+
errors.push('Symbol name is required')
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Validate symbol type (optional)
|
|
310
|
+
let validatedSymbolType: string | undefined
|
|
311
|
+
if (inputs.symbolType) {
|
|
312
|
+
const sanitized = inputs.symbolType.trim().toLowerCase()
|
|
313
|
+
const validTypes = [
|
|
314
|
+
'function',
|
|
315
|
+
'class',
|
|
316
|
+
'variable',
|
|
317
|
+
'type',
|
|
318
|
+
'interface',
|
|
319
|
+
'method',
|
|
320
|
+
'property',
|
|
321
|
+
'constant',
|
|
322
|
+
]
|
|
323
|
+
if (sanitized && !validTypes.includes(sanitized)) {
|
|
324
|
+
errors.push(
|
|
325
|
+
`Invalid symbol type: ${inputs.symbolType}. Valid types: ${validTypes.join(', ')}`,
|
|
326
|
+
)
|
|
327
|
+
} else {
|
|
328
|
+
validatedSymbolType = sanitized || undefined
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (errors.length > 0) {
|
|
333
|
+
return { valid: false, errors }
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
valid: true,
|
|
338
|
+
errors: [],
|
|
339
|
+
validated: {
|
|
340
|
+
path: pathResult.path!,
|
|
341
|
+
symbolName: inputs.symbolName.trim(),
|
|
342
|
+
symbolType: validatedSymbolType,
|
|
343
|
+
},
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Validate all inputs for an AST search operation.
|
|
349
|
+
* @param inputs - AST search inputs to validate
|
|
350
|
+
* @returns Combined validation result
|
|
351
|
+
*/
|
|
352
|
+
export function validateAstSearchInputs(inputs: {
|
|
353
|
+
pattern: string
|
|
354
|
+
mode?: string
|
|
355
|
+
filePattern?: string
|
|
356
|
+
path?: string
|
|
357
|
+
maxResults?: number
|
|
358
|
+
}): {
|
|
359
|
+
valid: boolean
|
|
360
|
+
errors: string[]
|
|
361
|
+
validated?: {
|
|
362
|
+
pattern: string
|
|
363
|
+
mode: 'simple' | 'pattern'
|
|
364
|
+
filePattern?: string
|
|
365
|
+
path: string
|
|
366
|
+
maxResults: number
|
|
367
|
+
}
|
|
368
|
+
} {
|
|
369
|
+
const errors: string[] = []
|
|
370
|
+
|
|
371
|
+
// Validate pattern
|
|
372
|
+
if (!inputs.pattern || inputs.pattern.trim() === '') {
|
|
373
|
+
errors.push('Pattern cannot be empty')
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Validate mode
|
|
377
|
+
const validModes = ['simple', 'pattern']
|
|
378
|
+
const mode = (inputs.mode || 'simple').toLowerCase()
|
|
379
|
+
if (!validModes.includes(mode)) {
|
|
380
|
+
errors.push(
|
|
381
|
+
`Invalid mode: ${inputs.mode}. Valid modes: ${validModes.join(', ')}`,
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Validate pattern mode JSON if mode is 'pattern'
|
|
386
|
+
if (mode === 'pattern' && inputs.pattern) {
|
|
387
|
+
try {
|
|
388
|
+
JSON.parse(inputs.pattern)
|
|
389
|
+
} catch {
|
|
390
|
+
// Allow non-JSON patterns - they'll be treated as textMatch
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Validate file pattern (optional glob)
|
|
395
|
+
let validatedFilePattern: string | undefined
|
|
396
|
+
if (inputs.filePattern) {
|
|
397
|
+
const patternResult = validateGlob(inputs.filePattern)
|
|
398
|
+
if (!patternResult.valid) {
|
|
399
|
+
errors.push(`File pattern: ${patternResult.error}`)
|
|
400
|
+
} else {
|
|
401
|
+
validatedFilePattern = patternResult.value
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Validate path
|
|
406
|
+
const pathResult = validatePath(inputs.path || getDefaultKitPath())
|
|
407
|
+
if (!pathResult.valid) {
|
|
408
|
+
errors.push(pathResult.error!)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Validate maxResults
|
|
412
|
+
const maxResultsResult = validatePositiveInt(inputs.maxResults, {
|
|
413
|
+
name: 'maxResults',
|
|
414
|
+
min: 1,
|
|
415
|
+
max: 500,
|
|
416
|
+
defaultValue: 100,
|
|
417
|
+
})
|
|
418
|
+
if (!maxResultsResult.valid) {
|
|
419
|
+
errors.push(maxResultsResult.error!)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (errors.length > 0) {
|
|
423
|
+
return { valid: false, errors }
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
valid: true,
|
|
428
|
+
errors: [],
|
|
429
|
+
validated: {
|
|
430
|
+
pattern: inputs.pattern.trim(),
|
|
431
|
+
mode: mode as 'simple' | 'pattern',
|
|
432
|
+
filePattern: validatedFilePattern,
|
|
433
|
+
path: pathResult.path!,
|
|
434
|
+
maxResults: maxResultsResult.value!,
|
|
435
|
+
},
|
|
436
|
+
}
|
|
437
|
+
}
|