mcp-maestro-mobile-ai 1.3.0 → 1.4.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 +244 -143
- package/ROADMAP.md +21 -8
- package/package.json +6 -3
- package/src/mcp-server/index.js +1059 -816
- package/src/mcp-server/schemas/toolSchemas.js +636 -0
- package/src/mcp-server/utils/maestro.js +265 -29
- package/src/mcp-server/utils/security.js +1200 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod Schemas for MCP Tool Input Validation
|
|
3
|
+
*
|
|
4
|
+
* This module provides strict input validation for all MCP tools
|
|
5
|
+
* using Zod schemas. These schemas are used to validate inputs
|
|
6
|
+
* before tool execution for security and data integrity.
|
|
7
|
+
*
|
|
8
|
+
* @module toolSchemas
|
|
9
|
+
* @version 1.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
// ============================================
|
|
15
|
+
// COMMON VALIDATION PATTERNS
|
|
16
|
+
// ============================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Pattern for valid file paths (no path traversal)
|
|
20
|
+
*/
|
|
21
|
+
const safeFilePathPattern = /^[a-zA-Z0-9_\-./\\]+$/;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Pattern for valid app IDs (e.g., com.example.app)
|
|
25
|
+
*/
|
|
26
|
+
const appIdPattern = /^[a-zA-Z][a-zA-Z0-9_]*(\.[a-zA-Z][a-zA-Z0-9_]*)+$/;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Pattern for valid device IDs (emulator-5554, RF8M12345XY, 192.168.1.1:5555)
|
|
30
|
+
*/
|
|
31
|
+
const deviceIdPattern = /^[a-zA-Z0-9][a-zA-Z0-9_\-.:]*$/;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Pattern for valid test/flow names
|
|
35
|
+
*/
|
|
36
|
+
const namePattern = /^[a-zA-Z0-9][a-zA-Z0-9_\-\s.]*$/;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pattern for valid screen names
|
|
40
|
+
*/
|
|
41
|
+
const screenNamePattern = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
42
|
+
|
|
43
|
+
// ============================================
|
|
44
|
+
// CUSTOM REFINEMENTS
|
|
45
|
+
// ============================================
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Refinement to check for path traversal attempts
|
|
49
|
+
*/
|
|
50
|
+
const noPathTraversal = (val) => !val.includes("..");
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Refinement to check for shell injection characters
|
|
54
|
+
*/
|
|
55
|
+
const noShellInjection = (val) => !/[;&|`$]/.test(val);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Refinement to check for command substitution
|
|
59
|
+
*/
|
|
60
|
+
const noCommandSubstitution = (val) =>
|
|
61
|
+
!/\$\([^)]*\)/.test(val) && !/`[^`]*`/.test(val);
|
|
62
|
+
|
|
63
|
+
// ============================================
|
|
64
|
+
// REUSABLE SCHEMA COMPONENTS
|
|
65
|
+
// ============================================
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Safe file path schema
|
|
69
|
+
*/
|
|
70
|
+
export const safeFilePath = z
|
|
71
|
+
.string()
|
|
72
|
+
.min(1, "File path is required")
|
|
73
|
+
.max(500, "File path too long")
|
|
74
|
+
.refine(noPathTraversal, "Path traversal not allowed (..)")
|
|
75
|
+
.refine(noShellInjection, "Invalid characters in path");
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* App ID schema
|
|
79
|
+
*/
|
|
80
|
+
export const appIdSchema = z
|
|
81
|
+
.string()
|
|
82
|
+
.min(3, "App ID too short")
|
|
83
|
+
.max(150, "App ID too long")
|
|
84
|
+
.regex(appIdPattern, "Invalid app ID format (expected: com.example.app)");
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Optional App ID schema
|
|
88
|
+
*/
|
|
89
|
+
export const optionalAppIdSchema = z
|
|
90
|
+
.string()
|
|
91
|
+
.max(150, "App ID too long")
|
|
92
|
+
.regex(appIdPattern, "Invalid app ID format")
|
|
93
|
+
.optional();
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Device ID schema
|
|
97
|
+
*/
|
|
98
|
+
export const deviceIdSchema = z
|
|
99
|
+
.string()
|
|
100
|
+
.min(1, "Device ID is required")
|
|
101
|
+
.max(100, "Device ID too long")
|
|
102
|
+
.regex(deviceIdPattern, "Invalid device ID format");
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Test name schema
|
|
106
|
+
*/
|
|
107
|
+
export const testNameSchema = z
|
|
108
|
+
.string()
|
|
109
|
+
.min(1, "Test name is required")
|
|
110
|
+
.max(200, "Test name too long")
|
|
111
|
+
.refine(noShellInjection, "Invalid characters in test name")
|
|
112
|
+
.refine(noPathTraversal, "Invalid test name");
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* YAML content schema
|
|
116
|
+
*/
|
|
117
|
+
export const yamlContentSchema = z
|
|
118
|
+
.string()
|
|
119
|
+
.min(10, "YAML content too short")
|
|
120
|
+
.max(50000, "YAML content too long")
|
|
121
|
+
.refine(noCommandSubstitution, "Command substitution not allowed in YAML");
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Retries schema
|
|
125
|
+
*/
|
|
126
|
+
export const retriesSchema = z
|
|
127
|
+
.number()
|
|
128
|
+
.int("Retries must be an integer")
|
|
129
|
+
.min(0, "Retries cannot be negative")
|
|
130
|
+
.max(10, "Maximum 10 retries allowed")
|
|
131
|
+
.optional();
|
|
132
|
+
|
|
133
|
+
// ============================================
|
|
134
|
+
// PROMPT TOOLS SCHEMAS
|
|
135
|
+
// ============================================
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Schema for read_prompt_file tool
|
|
139
|
+
*/
|
|
140
|
+
export const readPromptFileSchema = z.object({
|
|
141
|
+
file: safeFilePath,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Schema for list_prompt_files tool
|
|
146
|
+
*/
|
|
147
|
+
export const listPromptFilesSchema = z.object({
|
|
148
|
+
directory: z
|
|
149
|
+
.string()
|
|
150
|
+
.max(200, "Directory path too long")
|
|
151
|
+
.refine(noPathTraversal, "Path traversal not allowed")
|
|
152
|
+
.optional(),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// ============================================
|
|
156
|
+
// DEVICE MANAGEMENT SCHEMAS
|
|
157
|
+
// ============================================
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Schema for list_devices tool (no params)
|
|
161
|
+
*/
|
|
162
|
+
export const listDevicesSchema = z.object({});
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Schema for select_device tool
|
|
166
|
+
*/
|
|
167
|
+
export const selectDeviceSchema = z.object({
|
|
168
|
+
deviceId: deviceIdSchema,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Schema for clear_device tool (no params)
|
|
173
|
+
*/
|
|
174
|
+
export const clearDeviceSchema = z.object({});
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Schema for check_device tool (no params)
|
|
178
|
+
*/
|
|
179
|
+
export const checkDeviceSchema = z.object({});
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Schema for check_app tool
|
|
183
|
+
*/
|
|
184
|
+
export const checkAppSchema = z.object({
|
|
185
|
+
appId: optionalAppIdSchema,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// ============================================
|
|
189
|
+
// CONFIGURATION SCHEMAS
|
|
190
|
+
// ============================================
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Schema for get_app_config tool (no params)
|
|
194
|
+
*/
|
|
195
|
+
export const getAppConfigSchema = z.object({});
|
|
196
|
+
|
|
197
|
+
// ============================================
|
|
198
|
+
// VALIDATION TOOL SCHEMAS
|
|
199
|
+
// ============================================
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Schema for validate_maestro_yaml tool
|
|
203
|
+
*/
|
|
204
|
+
export const validateMaestroYamlSchema = z.object({
|
|
205
|
+
yaml: yamlContentSchema,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// ============================================
|
|
209
|
+
// TEST EXECUTION SCHEMAS
|
|
210
|
+
// ============================================
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Single test item schema (for arrays)
|
|
214
|
+
*/
|
|
215
|
+
export const testItemSchema = z.object({
|
|
216
|
+
yaml: yamlContentSchema,
|
|
217
|
+
name: testNameSchema,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Schema for run_test tool
|
|
222
|
+
*/
|
|
223
|
+
export const runTestSchema = z.object({
|
|
224
|
+
yaml: yamlContentSchema,
|
|
225
|
+
name: testNameSchema,
|
|
226
|
+
retries: retriesSchema,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Schema for run_test_suite tool
|
|
231
|
+
*/
|
|
232
|
+
export const runTestSuiteSchema = z.object({
|
|
233
|
+
tests: z
|
|
234
|
+
.array(testItemSchema)
|
|
235
|
+
.min(1, "At least one test is required")
|
|
236
|
+
.max(100, "Maximum 100 tests allowed"),
|
|
237
|
+
retries: retriesSchema,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Schema for run_tests_with_report tool
|
|
242
|
+
*/
|
|
243
|
+
export const runTestsWithReportSchema = z.object({
|
|
244
|
+
tests: z
|
|
245
|
+
.array(testItemSchema)
|
|
246
|
+
.min(1, "At least one test is required")
|
|
247
|
+
.max(100, "Maximum 100 tests allowed"),
|
|
248
|
+
promptFile: z.string().max(200).optional(),
|
|
249
|
+
appId: optionalAppIdSchema,
|
|
250
|
+
retries: retriesSchema,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// ============================================
|
|
254
|
+
// RESULTS & REPORTING SCHEMAS
|
|
255
|
+
// ============================================
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Test result item schema
|
|
259
|
+
*/
|
|
260
|
+
export const testResultItemSchema = z.object({
|
|
261
|
+
name: z.string().min(1).max(200),
|
|
262
|
+
success: z.boolean(),
|
|
263
|
+
duration: z.number().optional(),
|
|
264
|
+
error: z.string().max(5000).optional(),
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Schema for generate_report tool
|
|
269
|
+
*/
|
|
270
|
+
export const generateReportSchema = z.object({
|
|
271
|
+
results: z
|
|
272
|
+
.array(testResultItemSchema)
|
|
273
|
+
.min(1, "At least one result is required")
|
|
274
|
+
.max(500, "Maximum 500 results allowed"),
|
|
275
|
+
promptFile: z.string().max(200).optional(),
|
|
276
|
+
appId: optionalAppIdSchema,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Schema for list_reports tool (no params)
|
|
281
|
+
*/
|
|
282
|
+
export const listReportsSchema = z.object({});
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Schema for get_test_results tool
|
|
286
|
+
*/
|
|
287
|
+
export const getTestResultsSchema = z.object({
|
|
288
|
+
runId: z
|
|
289
|
+
.string()
|
|
290
|
+
.max(100, "Run ID too long")
|
|
291
|
+
.refine(noShellInjection, "Invalid run ID")
|
|
292
|
+
.optional(),
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Schema for take_screenshot tool
|
|
297
|
+
*/
|
|
298
|
+
export const takeScreenshotSchema = z.object({
|
|
299
|
+
name: z
|
|
300
|
+
.string()
|
|
301
|
+
.min(1, "Screenshot name is required")
|
|
302
|
+
.max(100, "Screenshot name too long")
|
|
303
|
+
.refine(noShellInjection, "Invalid characters in name")
|
|
304
|
+
.refine(noPathTraversal, "Invalid screenshot name"),
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Schema for cleanup_results tool
|
|
309
|
+
*/
|
|
310
|
+
export const cleanupResultsSchema = z.object({
|
|
311
|
+
keepLast: z
|
|
312
|
+
.number()
|
|
313
|
+
.int()
|
|
314
|
+
.min(1, "Must keep at least 1 result")
|
|
315
|
+
.max(1000, "Maximum 1000 results")
|
|
316
|
+
.optional(),
|
|
317
|
+
deleteScreenshots: z.boolean().optional(),
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// ============================================
|
|
321
|
+
// APP CONTEXT/TRAINING SCHEMAS
|
|
322
|
+
// ============================================
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Schema for register_elements tool
|
|
326
|
+
*/
|
|
327
|
+
export const registerElementsSchema = z.object({
|
|
328
|
+
appId: appIdSchema,
|
|
329
|
+
elements: z.record(
|
|
330
|
+
z.string(),
|
|
331
|
+
z.object({
|
|
332
|
+
testId: z.string().max(200).optional(),
|
|
333
|
+
accessibilityLabel: z.string().max(200).optional(),
|
|
334
|
+
text: z.string().max(500).optional(),
|
|
335
|
+
type: z.string().max(50).optional(),
|
|
336
|
+
description: z.string().max(500).optional(),
|
|
337
|
+
})
|
|
338
|
+
),
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Schema for register_screen tool
|
|
343
|
+
*/
|
|
344
|
+
export const registerScreenSchema = z.object({
|
|
345
|
+
appId: appIdSchema,
|
|
346
|
+
screenName: z
|
|
347
|
+
.string()
|
|
348
|
+
.min(1, "Screen name is required")
|
|
349
|
+
.max(100, "Screen name too long")
|
|
350
|
+
.regex(screenNamePattern, "Invalid screen name format"),
|
|
351
|
+
screenData: z.object({
|
|
352
|
+
description: z.string().max(500).optional(),
|
|
353
|
+
elements: z.array(z.string().max(100)).max(100).optional(),
|
|
354
|
+
actions: z.array(z.string().max(100)).max(50).optional(),
|
|
355
|
+
}),
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Schema for save_successful_flow tool
|
|
360
|
+
*/
|
|
361
|
+
export const saveSuccessfulFlowSchema = z.object({
|
|
362
|
+
appId: appIdSchema,
|
|
363
|
+
flowName: z
|
|
364
|
+
.string()
|
|
365
|
+
.min(1, "Flow name is required")
|
|
366
|
+
.max(100, "Flow name too long")
|
|
367
|
+
.refine(noShellInjection, "Invalid characters in flow name"),
|
|
368
|
+
yamlContent: yamlContentSchema,
|
|
369
|
+
description: z.string().max(500).optional(),
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Schema for get_saved_flows tool
|
|
374
|
+
*/
|
|
375
|
+
export const getSavedFlowsSchema = z.object({
|
|
376
|
+
appId: appIdSchema,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Schema for delete_flow tool
|
|
381
|
+
*/
|
|
382
|
+
export const deleteFlowSchema = z.object({
|
|
383
|
+
appId: appIdSchema,
|
|
384
|
+
flowName: z
|
|
385
|
+
.string()
|
|
386
|
+
.min(1, "Flow name is required")
|
|
387
|
+
.max(100, "Flow name too long"),
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Schema for get_ai_context tool
|
|
392
|
+
*/
|
|
393
|
+
export const getAiContextSchema = z.object({
|
|
394
|
+
appId: appIdSchema,
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Schema for get_full_context tool
|
|
399
|
+
*/
|
|
400
|
+
export const getFullContextSchema = z.object({
|
|
401
|
+
appId: appIdSchema,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Schema for clear_app_context tool
|
|
406
|
+
*/
|
|
407
|
+
export const clearAppContextSchema = z.object({
|
|
408
|
+
appId: appIdSchema,
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Schema for list_app_contexts tool (no params)
|
|
413
|
+
*/
|
|
414
|
+
export const listAppContextsSchema = z.object({});
|
|
415
|
+
|
|
416
|
+
// ============================================
|
|
417
|
+
// YAML GENERATION TOOL SCHEMAS
|
|
418
|
+
// ============================================
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Schema for get_yaml_instructions tool
|
|
422
|
+
*/
|
|
423
|
+
export const getYamlInstructionsSchema = z.object({
|
|
424
|
+
appId: optionalAppIdSchema,
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Schema for validate_yaml_structure tool
|
|
429
|
+
*/
|
|
430
|
+
export const validateYamlStructureSchema = z.object({
|
|
431
|
+
yamlContent: yamlContentSchema,
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Valid pattern names
|
|
436
|
+
*/
|
|
437
|
+
const validPatternNames = [
|
|
438
|
+
"login",
|
|
439
|
+
"form",
|
|
440
|
+
"search",
|
|
441
|
+
"navigation",
|
|
442
|
+
"list",
|
|
443
|
+
"settings",
|
|
444
|
+
"logout",
|
|
445
|
+
];
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Schema for get_test_pattern tool
|
|
449
|
+
*/
|
|
450
|
+
export const getTestPatternSchema = z.object({
|
|
451
|
+
patternName: z.enum(validPatternNames, {
|
|
452
|
+
errorMap: () => ({
|
|
453
|
+
message: `Pattern must be one of: ${validPatternNames.join(", ")}`,
|
|
454
|
+
}),
|
|
455
|
+
}),
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Schema for get_screen_analysis_help tool (no params)
|
|
460
|
+
*/
|
|
461
|
+
export const getScreenAnalysisHelpSchema = z.object({});
|
|
462
|
+
|
|
463
|
+
// ============================================
|
|
464
|
+
// SCHEMA REGISTRY
|
|
465
|
+
// ============================================
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Map of tool names to their Zod schemas
|
|
469
|
+
*/
|
|
470
|
+
export const toolSchemas = {
|
|
471
|
+
// Prompt tools
|
|
472
|
+
read_prompt_file: readPromptFileSchema,
|
|
473
|
+
list_prompt_files: listPromptFilesSchema,
|
|
474
|
+
|
|
475
|
+
// Device management
|
|
476
|
+
list_devices: listDevicesSchema,
|
|
477
|
+
select_device: selectDeviceSchema,
|
|
478
|
+
clear_device: clearDeviceSchema,
|
|
479
|
+
check_device: checkDeviceSchema,
|
|
480
|
+
check_app: checkAppSchema,
|
|
481
|
+
|
|
482
|
+
// Configuration
|
|
483
|
+
get_app_config: getAppConfigSchema,
|
|
484
|
+
|
|
485
|
+
// Validation
|
|
486
|
+
validate_maestro_yaml: validateMaestroYamlSchema,
|
|
487
|
+
|
|
488
|
+
// Test execution
|
|
489
|
+
run_test: runTestSchema,
|
|
490
|
+
run_test_suite: runTestSuiteSchema,
|
|
491
|
+
run_tests_with_report: runTestsWithReportSchema,
|
|
492
|
+
|
|
493
|
+
// Results & reporting
|
|
494
|
+
generate_report: generateReportSchema,
|
|
495
|
+
list_reports: listReportsSchema,
|
|
496
|
+
get_test_results: getTestResultsSchema,
|
|
497
|
+
take_screenshot: takeScreenshotSchema,
|
|
498
|
+
cleanup_results: cleanupResultsSchema,
|
|
499
|
+
|
|
500
|
+
// App context/training
|
|
501
|
+
register_elements: registerElementsSchema,
|
|
502
|
+
register_screen: registerScreenSchema,
|
|
503
|
+
save_successful_flow: saveSuccessfulFlowSchema,
|
|
504
|
+
get_saved_flows: getSavedFlowsSchema,
|
|
505
|
+
delete_flow: deleteFlowSchema,
|
|
506
|
+
get_ai_context: getAiContextSchema,
|
|
507
|
+
get_full_context: getFullContextSchema,
|
|
508
|
+
clear_app_context: clearAppContextSchema,
|
|
509
|
+
list_app_contexts: listAppContextsSchema,
|
|
510
|
+
|
|
511
|
+
// YAML generation
|
|
512
|
+
get_yaml_instructions: getYamlInstructionsSchema,
|
|
513
|
+
validate_yaml_structure: validateYamlStructureSchema,
|
|
514
|
+
get_test_pattern: getTestPatternSchema,
|
|
515
|
+
get_screen_analysis_help: getScreenAnalysisHelpSchema,
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
// ============================================
|
|
519
|
+
// VALIDATION UTILITIES
|
|
520
|
+
// ============================================
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Validate tool input against its schema
|
|
524
|
+
*
|
|
525
|
+
* @param {string} toolName - Name of the tool
|
|
526
|
+
* @param {object} input - Input to validate
|
|
527
|
+
* @returns {object} Validation result with success, data, and errors
|
|
528
|
+
*/
|
|
529
|
+
export function validateToolInput(toolName, input) {
|
|
530
|
+
const schema = toolSchemas[toolName];
|
|
531
|
+
|
|
532
|
+
if (!schema) {
|
|
533
|
+
return {
|
|
534
|
+
success: true,
|
|
535
|
+
data: input,
|
|
536
|
+
warning: `No schema defined for tool: ${toolName}`,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const result = schema.safeParse(input || {});
|
|
541
|
+
|
|
542
|
+
if (result.success) {
|
|
543
|
+
return {
|
|
544
|
+
success: true,
|
|
545
|
+
data: result.data,
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Format errors for better readability
|
|
550
|
+
const formattedErrors = result.error.issues.map((issue) => ({
|
|
551
|
+
field: issue.path.join(".") || "root",
|
|
552
|
+
message: issue.message,
|
|
553
|
+
code: issue.code,
|
|
554
|
+
}));
|
|
555
|
+
|
|
556
|
+
return {
|
|
557
|
+
success: false,
|
|
558
|
+
errors: formattedErrors,
|
|
559
|
+
message: `Validation failed: ${formattedErrors
|
|
560
|
+
.map((e) => e.message)
|
|
561
|
+
.join(", ")}`,
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Get schema for a specific tool
|
|
567
|
+
*
|
|
568
|
+
* @param {string} toolName - Name of the tool
|
|
569
|
+
* @returns {z.ZodSchema|null} Zod schema or null if not found
|
|
570
|
+
*/
|
|
571
|
+
export function getSchemaForTool(toolName) {
|
|
572
|
+
return toolSchemas[toolName] || null;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* List all tools with schemas
|
|
577
|
+
*
|
|
578
|
+
* @returns {string[]} Array of tool names
|
|
579
|
+
*/
|
|
580
|
+
export function listToolsWithSchemas() {
|
|
581
|
+
return Object.keys(toolSchemas);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// ============================================
|
|
585
|
+
// EXPORTS
|
|
586
|
+
// ============================================
|
|
587
|
+
|
|
588
|
+
export default {
|
|
589
|
+
// Schema registry
|
|
590
|
+
toolSchemas,
|
|
591
|
+
|
|
592
|
+
// Utilities
|
|
593
|
+
validateToolInput,
|
|
594
|
+
getSchemaForTool,
|
|
595
|
+
listToolsWithSchemas,
|
|
596
|
+
|
|
597
|
+
// Common schemas
|
|
598
|
+
safeFilePath,
|
|
599
|
+
appIdSchema,
|
|
600
|
+
deviceIdSchema,
|
|
601
|
+
testNameSchema,
|
|
602
|
+
yamlContentSchema,
|
|
603
|
+
retriesSchema,
|
|
604
|
+
|
|
605
|
+
// Individual tool schemas (for direct imports)
|
|
606
|
+
readPromptFileSchema,
|
|
607
|
+
listPromptFilesSchema,
|
|
608
|
+
listDevicesSchema,
|
|
609
|
+
selectDeviceSchema,
|
|
610
|
+
clearDeviceSchema,
|
|
611
|
+
checkDeviceSchema,
|
|
612
|
+
checkAppSchema,
|
|
613
|
+
getAppConfigSchema,
|
|
614
|
+
validateMaestroYamlSchema,
|
|
615
|
+
runTestSchema,
|
|
616
|
+
runTestSuiteSchema,
|
|
617
|
+
runTestsWithReportSchema,
|
|
618
|
+
generateReportSchema,
|
|
619
|
+
listReportsSchema,
|
|
620
|
+
getTestResultsSchema,
|
|
621
|
+
takeScreenshotSchema,
|
|
622
|
+
cleanupResultsSchema,
|
|
623
|
+
registerElementsSchema,
|
|
624
|
+
registerScreenSchema,
|
|
625
|
+
saveSuccessfulFlowSchema,
|
|
626
|
+
getSavedFlowsSchema,
|
|
627
|
+
deleteFlowSchema,
|
|
628
|
+
getAiContextSchema,
|
|
629
|
+
getFullContextSchema,
|
|
630
|
+
clearAppContextSchema,
|
|
631
|
+
listAppContextsSchema,
|
|
632
|
+
getYamlInstructionsSchema,
|
|
633
|
+
validateYamlStructureSchema,
|
|
634
|
+
getTestPatternSchema,
|
|
635
|
+
getScreenAnalysisHelpSchema,
|
|
636
|
+
};
|