@hypothesi/tauri-mcp-server 0.12.0 → 0.13.1-tauri.2.12.0.1
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/dist/driver/app-discovery.d.ts +4 -2
- package/dist/driver/app-discovery.js +23 -3
- package/dist/driver/plugin-client.d.ts +23 -1
- package/dist/driver/plugin-client.js +127 -2
- package/dist/driver/plugin-commands.d.ts +8 -4
- package/dist/driver/plugin-commands.js +71 -16
- package/dist/driver/scripts/find-element.js +129 -16
- package/dist/driver/scripts/focus.js +31 -4
- package/dist/driver/scripts/html2canvas-loader.js +20 -2
- package/dist/driver/scripts/index.d.ts +2 -4
- package/dist/driver/scripts/index.js +40 -11
- package/dist/driver/scripts/interact.js +66 -5
- package/dist/driver/scripts/resolve-ref.js +101 -50
- package/dist/driver/session-manager.d.ts +1 -0
- package/dist/driver/session-manager.js +53 -6
- package/dist/driver/webview-executor.d.ts +20 -8
- package/dist/driver/webview-executor.js +159 -58
- package/dist/driver/webview-interactions.d.ts +56 -41
- package/dist/driver/webview-interactions.js +62 -40
- package/dist/monitor/logs.d.ts +14 -2
- package/dist/monitor/logs.js +37 -5
- package/dist/tools-registry.js +35 -33
- package/dist/version.d.ts +5 -0
- package/dist/version.js +16 -0
- package/package.json +3 -2
- package/dist/driver/scripts/get-styles.js +0 -47
- package/dist/driver/scripts/keyboard.js +0 -76
|
@@ -18,9 +18,10 @@ export declare const InteractSchema: z.ZodObject<{
|
|
|
18
18
|
windowId: z.ZodOptional<z.ZodString>;
|
|
19
19
|
appIdentifier: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
20
20
|
} & {
|
|
21
|
-
action: z.ZodEnum<["click", "double-click", "long-press", "scroll", "swipe", "focus"]>;
|
|
21
|
+
action: z.ZodEnum<["click", "double-click", "long-press", "scroll", "swipe", "focus", "hover", "right-click"]>;
|
|
22
22
|
selector: z.ZodOptional<z.ZodString>;
|
|
23
23
|
strategy: z.ZodDefault<z.ZodEnum<["css", "xpath", "text"]>>;
|
|
24
|
+
nth: z.ZodOptional<z.ZodNumber>;
|
|
24
25
|
x: z.ZodOptional<z.ZodNumber>;
|
|
25
26
|
y: z.ZodOptional<z.ZodNumber>;
|
|
26
27
|
duration: z.ZodOptional<z.ZodNumber>;
|
|
@@ -31,11 +32,12 @@ export declare const InteractSchema: z.ZodObject<{
|
|
|
31
32
|
toX: z.ZodOptional<z.ZodNumber>;
|
|
32
33
|
toY: z.ZodOptional<z.ZodNumber>;
|
|
33
34
|
}, "strip", z.ZodTypeAny, {
|
|
34
|
-
action: "swipe" | "focus" | "click" | "double-click" | "long-press" | "scroll";
|
|
35
|
+
action: "swipe" | "focus" | "click" | "double-click" | "long-press" | "scroll" | "hover" | "right-click";
|
|
35
36
|
strategy: "css" | "text" | "xpath";
|
|
36
37
|
windowId?: string | undefined;
|
|
37
38
|
appIdentifier?: string | number | undefined;
|
|
38
39
|
selector?: string | undefined;
|
|
40
|
+
nth?: number | undefined;
|
|
39
41
|
x?: number | undefined;
|
|
40
42
|
y?: number | undefined;
|
|
41
43
|
duration?: number | undefined;
|
|
@@ -46,11 +48,12 @@ export declare const InteractSchema: z.ZodObject<{
|
|
|
46
48
|
toX?: number | undefined;
|
|
47
49
|
toY?: number | undefined;
|
|
48
50
|
}, {
|
|
49
|
-
action: "swipe" | "focus" | "click" | "double-click" | "long-press" | "scroll";
|
|
51
|
+
action: "swipe" | "focus" | "click" | "double-click" | "long-press" | "scroll" | "hover" | "right-click";
|
|
50
52
|
windowId?: string | undefined;
|
|
51
53
|
appIdentifier?: string | number | undefined;
|
|
52
54
|
selector?: string | undefined;
|
|
53
55
|
strategy?: "css" | "text" | "xpath" | undefined;
|
|
56
|
+
nth?: number | undefined;
|
|
54
57
|
x?: number | undefined;
|
|
55
58
|
y?: number | undefined;
|
|
56
59
|
duration?: number | undefined;
|
|
@@ -69,19 +72,22 @@ export declare const ScreenshotSchema: z.ZodObject<{
|
|
|
69
72
|
quality: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
70
73
|
filePath: z.ZodOptional<z.ZodString>;
|
|
71
74
|
maxWidth: z.ZodOptional<z.ZodNumber>;
|
|
75
|
+
allowScreenCapture: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
72
76
|
}, "strip", z.ZodTypeAny, {
|
|
73
77
|
format: "png" | "jpeg";
|
|
74
78
|
quality: number;
|
|
79
|
+
allowScreenCapture: boolean;
|
|
75
80
|
windowId?: string | undefined;
|
|
76
81
|
appIdentifier?: string | number | undefined;
|
|
77
82
|
maxWidth?: number | undefined;
|
|
78
83
|
filePath?: string | undefined;
|
|
79
84
|
}, {
|
|
80
|
-
format?: "png" | "jpeg" | undefined;
|
|
81
|
-
quality?: number | undefined;
|
|
82
85
|
windowId?: string | undefined;
|
|
83
86
|
appIdentifier?: string | number | undefined;
|
|
87
|
+
format?: "png" | "jpeg" | undefined;
|
|
88
|
+
quality?: number | undefined;
|
|
84
89
|
maxWidth?: number | undefined;
|
|
90
|
+
allowScreenCapture?: boolean | undefined;
|
|
85
91
|
filePath?: string | undefined;
|
|
86
92
|
}>;
|
|
87
93
|
export declare const KeyboardSchema: z.ZodObject<{
|
|
@@ -91,25 +97,28 @@ export declare const KeyboardSchema: z.ZodObject<{
|
|
|
91
97
|
action: z.ZodEnum<["type", "press", "down", "up"]>;
|
|
92
98
|
selector: z.ZodOptional<z.ZodString>;
|
|
93
99
|
strategy: z.ZodDefault<z.ZodEnum<["css", "xpath", "text"]>>;
|
|
100
|
+
nth: z.ZodOptional<z.ZodNumber>;
|
|
94
101
|
text: z.ZodOptional<z.ZodString>;
|
|
95
102
|
key: z.ZodOptional<z.ZodString>;
|
|
96
103
|
modifiers: z.ZodOptional<z.ZodArray<z.ZodEnum<["Control", "Alt", "Shift", "Meta"]>, "many">>;
|
|
97
104
|
}, "strip", z.ZodTypeAny, {
|
|
98
105
|
action: "type" | "press" | "down" | "up";
|
|
99
106
|
strategy: "css" | "text" | "xpath";
|
|
100
|
-
text?: string | undefined;
|
|
101
107
|
windowId?: string | undefined;
|
|
102
108
|
appIdentifier?: string | number | undefined;
|
|
109
|
+
text?: string | undefined;
|
|
103
110
|
selector?: string | undefined;
|
|
111
|
+
nth?: number | undefined;
|
|
104
112
|
key?: string | undefined;
|
|
105
113
|
modifiers?: ("Control" | "Alt" | "Shift" | "Meta")[] | undefined;
|
|
106
114
|
}, {
|
|
107
115
|
action: "type" | "press" | "down" | "up";
|
|
108
|
-
text?: string | undefined;
|
|
109
116
|
windowId?: string | undefined;
|
|
110
117
|
appIdentifier?: string | number | undefined;
|
|
118
|
+
text?: string | undefined;
|
|
111
119
|
selector?: string | undefined;
|
|
112
120
|
strategy?: "css" | "text" | "xpath" | undefined;
|
|
121
|
+
nth?: number | undefined;
|
|
113
122
|
key?: string | undefined;
|
|
114
123
|
modifiers?: ("Control" | "Alt" | "Shift" | "Meta")[] | undefined;
|
|
115
124
|
}>;
|
|
@@ -136,42 +145,22 @@ export declare const WaitForSchema: z.ZodObject<{
|
|
|
136
145
|
appIdentifier?: string | number | undefined;
|
|
137
146
|
strategy?: "css" | "text" | "xpath" | undefined;
|
|
138
147
|
}>;
|
|
139
|
-
export declare const GetStylesSchema: z.ZodObject<{
|
|
140
|
-
windowId: z.ZodOptional<z.ZodString>;
|
|
141
|
-
appIdentifier: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
142
|
-
} & {
|
|
143
|
-
selector: z.ZodString;
|
|
144
|
-
strategy: z.ZodDefault<z.ZodEnum<["css", "xpath", "text"]>>;
|
|
145
|
-
properties: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
146
|
-
multiple: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
147
|
-
}, "strip", z.ZodTypeAny, {
|
|
148
|
-
selector: string;
|
|
149
|
-
strategy: "css" | "text" | "xpath";
|
|
150
|
-
multiple: boolean;
|
|
151
|
-
windowId?: string | undefined;
|
|
152
|
-
appIdentifier?: string | number | undefined;
|
|
153
|
-
properties?: string[] | undefined;
|
|
154
|
-
}, {
|
|
155
|
-
selector: string;
|
|
156
|
-
windowId?: string | undefined;
|
|
157
|
-
appIdentifier?: string | number | undefined;
|
|
158
|
-
strategy?: "css" | "text" | "xpath" | undefined;
|
|
159
|
-
properties?: string[] | undefined;
|
|
160
|
-
multiple?: boolean | undefined;
|
|
161
|
-
}>;
|
|
162
148
|
export declare const ExecuteJavaScriptSchema: z.ZodObject<{
|
|
163
149
|
windowId: z.ZodOptional<z.ZodString>;
|
|
164
150
|
appIdentifier: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
165
151
|
} & {
|
|
166
152
|
script: z.ZodString;
|
|
167
153
|
args: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
|
|
154
|
+
timeout: z.ZodOptional<z.ZodNumber>;
|
|
168
155
|
}, "strip", z.ZodTypeAny, {
|
|
169
156
|
script: string;
|
|
157
|
+
timeout?: number | undefined;
|
|
170
158
|
windowId?: string | undefined;
|
|
171
159
|
appIdentifier?: string | number | undefined;
|
|
172
160
|
args?: unknown[] | undefined;
|
|
173
161
|
}, {
|
|
174
162
|
script: string;
|
|
163
|
+
timeout?: number | undefined;
|
|
175
164
|
windowId?: string | undefined;
|
|
176
165
|
appIdentifier?: string | number | undefined;
|
|
177
166
|
args?: unknown[] | undefined;
|
|
@@ -181,14 +170,20 @@ export declare const FocusElementSchema: z.ZodObject<{
|
|
|
181
170
|
appIdentifier: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
182
171
|
} & {
|
|
183
172
|
selector: z.ZodString;
|
|
173
|
+
strategy: z.ZodDefault<z.ZodEnum<["css", "xpath", "text"]>>;
|
|
174
|
+
nth: z.ZodOptional<z.ZodNumber>;
|
|
184
175
|
}, "strip", z.ZodTypeAny, {
|
|
185
176
|
selector: string;
|
|
177
|
+
strategy: "css" | "text" | "xpath";
|
|
186
178
|
windowId?: string | undefined;
|
|
187
179
|
appIdentifier?: string | number | undefined;
|
|
180
|
+
nth?: number | undefined;
|
|
188
181
|
}, {
|
|
189
182
|
selector: string;
|
|
190
183
|
windowId?: string | undefined;
|
|
191
184
|
appIdentifier?: string | number | undefined;
|
|
185
|
+
strategy?: "css" | "text" | "xpath" | undefined;
|
|
186
|
+
nth?: number | undefined;
|
|
192
187
|
}>;
|
|
193
188
|
export declare const FindElementSchema: z.ZodObject<{
|
|
194
189
|
windowId: z.ZodOptional<z.ZodString>;
|
|
@@ -196,16 +191,31 @@ export declare const FindElementSchema: z.ZodObject<{
|
|
|
196
191
|
} & {
|
|
197
192
|
selector: z.ZodString;
|
|
198
193
|
strategy: z.ZodDefault<z.ZodEnum<["css", "xpath", "text"]>>;
|
|
194
|
+
nth: z.ZodOptional<z.ZodNumber>;
|
|
195
|
+
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
196
|
+
properties: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
197
|
+
visibleOnly: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
198
|
+
includeHtml: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
199
199
|
}, "strip", z.ZodTypeAny, {
|
|
200
200
|
selector: string;
|
|
201
201
|
strategy: "css" | "text" | "xpath";
|
|
202
|
+
limit: number;
|
|
203
|
+
visibleOnly: boolean;
|
|
204
|
+
includeHtml: boolean;
|
|
202
205
|
windowId?: string | undefined;
|
|
203
206
|
appIdentifier?: string | number | undefined;
|
|
207
|
+
nth?: number | undefined;
|
|
208
|
+
properties?: string[] | undefined;
|
|
204
209
|
}, {
|
|
205
210
|
selector: string;
|
|
206
211
|
windowId?: string | undefined;
|
|
207
212
|
appIdentifier?: string | number | undefined;
|
|
208
213
|
strategy?: "css" | "text" | "xpath" | undefined;
|
|
214
|
+
nth?: number | undefined;
|
|
215
|
+
limit?: number | undefined;
|
|
216
|
+
properties?: string[] | undefined;
|
|
217
|
+
visibleOnly?: boolean | undefined;
|
|
218
|
+
includeHtml?: boolean | undefined;
|
|
209
219
|
}>;
|
|
210
220
|
export declare const GetConsoleLogsSchema: z.ZodObject<{
|
|
211
221
|
windowId: z.ZodOptional<z.ZodString>;
|
|
@@ -215,14 +225,14 @@ export declare const GetConsoleLogsSchema: z.ZodObject<{
|
|
|
215
225
|
since: z.ZodOptional<z.ZodString>;
|
|
216
226
|
}, "strip", z.ZodTypeAny, {
|
|
217
227
|
filter?: string | undefined;
|
|
228
|
+
since?: string | undefined;
|
|
218
229
|
windowId?: string | undefined;
|
|
219
230
|
appIdentifier?: string | number | undefined;
|
|
220
|
-
since?: string | undefined;
|
|
221
231
|
}, {
|
|
222
232
|
filter?: string | undefined;
|
|
233
|
+
since?: string | undefined;
|
|
223
234
|
windowId?: string | undefined;
|
|
224
235
|
appIdentifier?: string | number | undefined;
|
|
225
|
-
since?: string | undefined;
|
|
226
236
|
}>;
|
|
227
237
|
export declare const DomSnapshotSchema: z.ZodObject<{
|
|
228
238
|
windowId: z.ZodOptional<z.ZodString>;
|
|
@@ -248,6 +258,7 @@ export declare function interact(options: {
|
|
|
248
258
|
action: string;
|
|
249
259
|
selector?: string;
|
|
250
260
|
strategy?: string;
|
|
261
|
+
nth?: number;
|
|
251
262
|
x?: number;
|
|
252
263
|
y?: number;
|
|
253
264
|
duration?: number;
|
|
@@ -267,6 +278,7 @@ export interface ScreenshotOptions {
|
|
|
267
278
|
filePath?: string;
|
|
268
279
|
appIdentifier?: string | number;
|
|
269
280
|
maxWidth?: number;
|
|
281
|
+
allowScreenCapture?: boolean;
|
|
270
282
|
}
|
|
271
283
|
export interface ScreenshotFileResult {
|
|
272
284
|
filePath: string;
|
|
@@ -277,6 +289,7 @@ export interface KeyboardOptions {
|
|
|
277
289
|
action: string;
|
|
278
290
|
selectorOrKey?: string;
|
|
279
291
|
strategy?: string;
|
|
292
|
+
nth?: number;
|
|
280
293
|
textOrModifiers?: string | string[];
|
|
281
294
|
modifiers?: string[];
|
|
282
295
|
windowId?: string;
|
|
@@ -292,18 +305,10 @@ export interface WaitForOptions {
|
|
|
292
305
|
appIdentifier?: string | number;
|
|
293
306
|
}
|
|
294
307
|
export declare function waitFor(options: WaitForOptions): Promise<string>;
|
|
295
|
-
export interface GetStylesOptions {
|
|
296
|
-
selector: string;
|
|
297
|
-
strategy?: string;
|
|
298
|
-
properties?: string[];
|
|
299
|
-
multiple?: boolean;
|
|
300
|
-
windowId?: string;
|
|
301
|
-
appIdentifier?: string | number;
|
|
302
|
-
}
|
|
303
|
-
export declare function getStyles(options: GetStylesOptions): Promise<string>;
|
|
304
308
|
export interface ExecuteJavaScriptOptions {
|
|
305
309
|
script: string;
|
|
306
310
|
args?: unknown[];
|
|
311
|
+
timeout?: number;
|
|
307
312
|
windowId?: string;
|
|
308
313
|
appIdentifier?: string | number;
|
|
309
314
|
}
|
|
@@ -311,6 +316,7 @@ export declare function executeJavaScript(options: ExecuteJavaScriptOptions): Pr
|
|
|
311
316
|
export interface FocusElementOptions {
|
|
312
317
|
selector: string;
|
|
313
318
|
strategy?: string;
|
|
319
|
+
nth?: number;
|
|
314
320
|
windowId?: string;
|
|
315
321
|
appIdentifier?: string | number;
|
|
316
322
|
}
|
|
@@ -318,6 +324,11 @@ export declare function focusElement(options: FocusElementOptions): Promise<stri
|
|
|
318
324
|
export interface FindElementOptions {
|
|
319
325
|
selector: string;
|
|
320
326
|
strategy: string;
|
|
327
|
+
nth?: number;
|
|
328
|
+
limit?: number;
|
|
329
|
+
properties?: string[];
|
|
330
|
+
visibleOnly?: boolean;
|
|
331
|
+
includeHtml?: boolean;
|
|
321
332
|
windowId?: string;
|
|
322
333
|
appIdentifier?: string | number;
|
|
323
334
|
}
|
|
@@ -326,6 +337,10 @@ export interface FindElementOptions {
|
|
|
326
337
|
*/
|
|
327
338
|
export declare function findElement(options: FindElementOptions): Promise<string>;
|
|
328
339
|
export interface GetConsoleLogsOptions {
|
|
340
|
+
lines?: number;
|
|
341
|
+
level?: 'log' | 'debug' | 'info' | 'warn' | 'error';
|
|
342
|
+
maxChars?: number;
|
|
343
|
+
maxCharsPerEntry?: number;
|
|
329
344
|
filter?: string;
|
|
330
345
|
since?: string;
|
|
331
346
|
windowId?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { writeFile } from 'node:fs/promises';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import { executeInWebview, executeInWebviewWithContext, captureScreenshot, getConsoleLogs as getConsoleLogsFromCapture, } from './webview-executor.js';
|
|
4
|
+
import { executeInWebview, executeInWebviewWithContext, executeAsyncInWebview, captureScreenshot, getConsoleLogs as getConsoleLogsFromCapture, } from './webview-executor.js';
|
|
5
5
|
import { SCRIPTS, buildScript, buildTypeScript, buildKeyEventScript } from './scripts/index.js';
|
|
6
6
|
// ============================================================================
|
|
7
7
|
// Base Schema for Window Targeting
|
|
@@ -24,14 +24,21 @@ export const WindowTargetSchema = z.object({
|
|
|
24
24
|
const selectorStrategyField = z.enum(['css', 'xpath', 'text']).default('css').describe('Selector strategy: "css" (default) for CSS selectors, "xpath" for XPath expressions, ' +
|
|
25
25
|
'"text" to find elements by text content, with fallback to placeholder, aria-label, ' +
|
|
26
26
|
'and title attributes. Ref IDs (e.g., "ref=e3") work with any strategy.');
|
|
27
|
+
/**
|
|
28
|
+
* Optional nth parameter for disambiguating multiple matches.
|
|
29
|
+
* Required when a text selector matches more than one visible element.
|
|
30
|
+
*/
|
|
31
|
+
const nthField = z.number().int().min(0).optional().describe('Zero-based index to pick one of several matching elements. ' +
|
|
32
|
+
'Omit when the selector is unique. Required when a text selector matches more than one visible element.');
|
|
27
33
|
// ============================================================================
|
|
28
34
|
// Schemas
|
|
29
35
|
// ============================================================================
|
|
30
36
|
export const InteractSchema = WindowTargetSchema.extend({
|
|
31
|
-
action: z.enum(['click', 'double-click', 'long-press', 'scroll', 'swipe', 'focus'])
|
|
37
|
+
action: z.enum(['click', 'double-click', 'long-press', 'scroll', 'swipe', 'focus', 'hover', 'right-click'])
|
|
32
38
|
.describe('Type of interaction to perform'),
|
|
33
39
|
selector: z.string().optional().describe('Element selector: CSS selector (default), XPath expression, text content, or ref ID (e.g., "ref=e3")'),
|
|
34
40
|
strategy: selectorStrategyField,
|
|
41
|
+
nth: nthField,
|
|
35
42
|
x: z.number().optional().describe('X coordinate for direct coordinate interaction'),
|
|
36
43
|
y: z.number().optional().describe('Y coordinate for direct coordinate interaction'),
|
|
37
44
|
duration: z.number().optional()
|
|
@@ -49,6 +56,7 @@ export const ScreenshotSchema = WindowTargetSchema.extend({
|
|
|
49
56
|
filePath: z.string().optional().describe('File path to save the screenshot to instead of returning as base64'),
|
|
50
57
|
maxWidth: z.number().int().positive().optional().describe('Maximum width in pixels. Images wider than this will be scaled down proportionally. ' +
|
|
51
58
|
'Can also be set via TAURI_MCP_SCREENSHOT_MAX_WIDTH environment variable.'),
|
|
59
|
+
allowScreenCapture: z.boolean().optional().default(false).describe('Allow an interactive OS screen-sharing permission prompt if native and html2canvas capture fail'),
|
|
52
60
|
});
|
|
53
61
|
export const KeyboardSchema = WindowTargetSchema.extend({
|
|
54
62
|
action: z.enum(['type', 'press', 'down', 'up'])
|
|
@@ -56,6 +64,7 @@ export const KeyboardSchema = WindowTargetSchema.extend({
|
|
|
56
64
|
selector: z.string().optional().describe('Element selector for element to type into (required for "type" action): ' +
|
|
57
65
|
'CSS selector (default), XPath, text content, or ref ID'),
|
|
58
66
|
strategy: selectorStrategyField,
|
|
67
|
+
nth: nthField,
|
|
59
68
|
text: z.string().optional().describe('Text to type (required for "type" action)'),
|
|
60
69
|
key: z.string().optional().describe('Key to press (required for "press/down/up" actions, e.g., "Enter", "a", "Escape")'),
|
|
61
70
|
modifiers: z.array(z.enum(['Control', 'Alt', 'Shift', 'Meta'])).optional().describe('Modifier keys to hold'),
|
|
@@ -66,26 +75,30 @@ export const WaitForSchema = WindowTargetSchema.extend({
|
|
|
66
75
|
strategy: selectorStrategyField.describe('Selector strategy (applies when type is "selector"): "css" (default), "xpath", or "text".'),
|
|
67
76
|
timeout: z.number().optional().default(5000).describe('Timeout in milliseconds (default: 5000ms)'),
|
|
68
77
|
});
|
|
69
|
-
export const GetStylesSchema = WindowTargetSchema.extend({
|
|
70
|
-
selector: z.string().describe('Element selector: CSS selector (default), XPath expression, text content, or ref ID'),
|
|
71
|
-
strategy: selectorStrategyField,
|
|
72
|
-
properties: z.array(z.string()).optional().describe('Specific CSS properties to retrieve. If omitted, returns all computed styles'),
|
|
73
|
-
multiple: z.boolean().optional().default(false)
|
|
74
|
-
.describe('Whether to get styles for all matching elements (true) or just the first (false)'),
|
|
75
|
-
});
|
|
76
78
|
export const ExecuteJavaScriptSchema = WindowTargetSchema.extend({
|
|
77
79
|
script: z.string().describe('JavaScript code to execute in the webview context. ' +
|
|
78
80
|
'If returning a value, it must be JSON-serializable. ' +
|
|
79
81
|
'For functions that return values, use IIFE syntax: "(() => { return value; })()" not "() => { return value; }"'),
|
|
80
82
|
args: z.array(z.unknown()).optional().describe('Arguments to pass to the script'),
|
|
83
|
+
timeout: z.number().int().positive().optional().describe('Execution timeout in milliseconds'),
|
|
81
84
|
});
|
|
82
85
|
export const FocusElementSchema = WindowTargetSchema.extend({
|
|
83
86
|
selector: z.string().describe('CSS selector for element to focus'),
|
|
87
|
+
strategy: selectorStrategyField,
|
|
88
|
+
nth: nthField,
|
|
84
89
|
});
|
|
85
90
|
export const FindElementSchema = WindowTargetSchema.extend({
|
|
86
91
|
selector: z.string().describe('The selector to find: CSS selector (default), XPath expression, text content, or ref ID (e.g., "ref=e3"). ' +
|
|
87
92
|
'Interpretation depends on strategy.'),
|
|
88
93
|
strategy: selectorStrategyField,
|
|
94
|
+
nth: nthField,
|
|
95
|
+
limit: z.number().int().min(1).max(50).optional().default(5)
|
|
96
|
+
.describe('Maximum number of matches to return. Total match count is always reported.'),
|
|
97
|
+
properties: z.array(z.string()).optional().describe('Computed CSS properties to include for each match, e.g. ["display","opacity","font-size"].'),
|
|
98
|
+
visibleOnly: z.boolean().optional().default(true)
|
|
99
|
+
.describe('Return only rendered elements. Set false to include display:none and off-screen nodes.'),
|
|
100
|
+
includeHtml: z.boolean().optional().default(false)
|
|
101
|
+
.describe('Include outerHTML for each match, truncated to 2000 characters.'),
|
|
89
102
|
});
|
|
90
103
|
export const GetConsoleLogsSchema = WindowTargetSchema.extend({
|
|
91
104
|
filter: z.string().optional().describe('Regex or keyword to filter logs'),
|
|
@@ -100,7 +113,7 @@ export const DomSnapshotSchema = WindowTargetSchema.extend({
|
|
|
100
113
|
// Implementation Functions
|
|
101
114
|
// ============================================================================
|
|
102
115
|
export async function interact(options) {
|
|
103
|
-
const { action, selector, strategy, x, y, duration, scrollX, scrollY, fromX, fromY, toX, toY, windowId, appIdentifier } = options;
|
|
116
|
+
const { action, selector, strategy, nth, x, y, duration, scrollX, scrollY, fromX, fromY, toX, toY, windowId, appIdentifier } = options;
|
|
104
117
|
// Handle swipe action separately since it has different logic
|
|
105
118
|
if (action === 'swipe') {
|
|
106
119
|
return performSwipe({ fromX, fromY, toX, toY, duration, windowId, appIdentifier });
|
|
@@ -110,12 +123,13 @@ export async function interact(options) {
|
|
|
110
123
|
if (!selector) {
|
|
111
124
|
throw new Error('Focus action requires a selector');
|
|
112
125
|
}
|
|
113
|
-
return focusElement({ selector, strategy, windowId, appIdentifier });
|
|
126
|
+
return focusElement({ selector, strategy, nth, windowId, appIdentifier });
|
|
114
127
|
}
|
|
115
128
|
const script = buildScript(SCRIPTS.interact, {
|
|
116
129
|
action,
|
|
117
130
|
selector: selector ?? null,
|
|
118
131
|
strategy: strategy ?? 'css',
|
|
132
|
+
nth: nth ?? null,
|
|
119
133
|
x: x ?? null,
|
|
120
134
|
y: y ?? null,
|
|
121
135
|
duration: duration ?? 500,
|
|
@@ -145,9 +159,11 @@ async function performSwipe(options) {
|
|
|
145
159
|
}
|
|
146
160
|
}
|
|
147
161
|
export async function screenshot(options = {}) {
|
|
148
|
-
const { quality, format = 'jpeg', windowId, filePath, appIdentifier, maxWidth } = options;
|
|
162
|
+
const { quality, format = 'jpeg', windowId, filePath, appIdentifier, maxWidth, allowScreenCapture } = options;
|
|
149
163
|
// Use the native screenshot function from webview-executor
|
|
150
|
-
const result = await captureScreenshot({
|
|
164
|
+
const result = await captureScreenshot({
|
|
165
|
+
format, quality, windowId, appIdentifier, maxWidth, allowScreenCapture,
|
|
166
|
+
});
|
|
151
167
|
// If filePath is provided, write to file instead of returning base64
|
|
152
168
|
if (filePath) {
|
|
153
169
|
// Find the image content in the result
|
|
@@ -162,15 +178,15 @@ export async function screenshot(options = {}) {
|
|
|
162
178
|
return result;
|
|
163
179
|
}
|
|
164
180
|
export async function keyboard(options) {
|
|
165
|
-
const { action, selectorOrKey, strategy, textOrModifiers, modifiers, windowId, appIdentifier } = options;
|
|
181
|
+
const { action, selectorOrKey, strategy, nth, textOrModifiers, modifiers, windowId, appIdentifier } = options;
|
|
166
182
|
// Handle the different parameter combinations based on action
|
|
167
183
|
if (action === 'type') {
|
|
168
184
|
const selector = selectorOrKey;
|
|
169
185
|
const text = textOrModifiers;
|
|
170
|
-
if (!selector ||
|
|
186
|
+
if (!selector || text === undefined) {
|
|
171
187
|
throw new Error('Type action requires both selector and text parameters');
|
|
172
188
|
}
|
|
173
|
-
const script = buildTypeScript(selector, text, strategy);
|
|
189
|
+
const script = buildTypeScript(selector, text, strategy, nth);
|
|
174
190
|
try {
|
|
175
191
|
return await executeInWebview(script, windowId, appIdentifier);
|
|
176
192
|
}
|
|
@@ -205,24 +221,8 @@ export async function waitFor(options) {
|
|
|
205
221
|
throw new Error(`Wait failed: ${message}`);
|
|
206
222
|
}
|
|
207
223
|
}
|
|
208
|
-
export async function getStyles(options) {
|
|
209
|
-
const { selector, strategy, properties, multiple = false, windowId, appIdentifier } = options;
|
|
210
|
-
const script = buildScript(SCRIPTS.getStyles, {
|
|
211
|
-
selector,
|
|
212
|
-
strategy: strategy ?? 'css',
|
|
213
|
-
properties: properties || [],
|
|
214
|
-
multiple,
|
|
215
|
-
});
|
|
216
|
-
try {
|
|
217
|
-
return await executeInWebview(script, windowId, appIdentifier);
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
221
|
-
throw new Error(`Get styles failed: ${message}`);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
224
|
export async function executeJavaScript(options) {
|
|
225
|
-
const { script, args, windowId, appIdentifier } = options;
|
|
225
|
+
const { script, args, timeout, windowId, appIdentifier } = options;
|
|
226
226
|
// If args are provided, we need to inject them into the script context
|
|
227
227
|
const wrappedScript = args && args.length > 0
|
|
228
228
|
? `
|
|
@@ -233,7 +233,13 @@ export async function executeJavaScript(options) {
|
|
|
233
233
|
`
|
|
234
234
|
: script;
|
|
235
235
|
try {
|
|
236
|
-
const
|
|
236
|
+
const execution = timeout === undefined
|
|
237
|
+
? await executeInWebviewWithContext(wrappedScript, windowId, appIdentifier)
|
|
238
|
+
: {
|
|
239
|
+
result: await executeAsyncInWebview(buildTimedScript(wrappedScript), windowId, timeout, appIdentifier),
|
|
240
|
+
windowLabel: windowId ?? 'main',
|
|
241
|
+
};
|
|
242
|
+
const { result, windowLabel, warning } = execution;
|
|
237
243
|
// Build response with window context
|
|
238
244
|
let response = result;
|
|
239
245
|
if (warning) {
|
|
@@ -248,9 +254,16 @@ export async function executeJavaScript(options) {
|
|
|
248
254
|
throw new Error(`JavaScript execution failed: ${message}`);
|
|
249
255
|
}
|
|
250
256
|
}
|
|
257
|
+
function buildTimedScript(script) {
|
|
258
|
+
const trimmed = script.trim();
|
|
259
|
+
if (/\breturn\b/.test(trimmed) && !trimmed.startsWith('(')) {
|
|
260
|
+
return `return (async () => { ${trimmed} })();`;
|
|
261
|
+
}
|
|
262
|
+
return `return (${trimmed});`;
|
|
263
|
+
}
|
|
251
264
|
export async function focusElement(options) {
|
|
252
|
-
const { selector, strategy, windowId, appIdentifier } = options;
|
|
253
|
-
const script = buildScript(SCRIPTS.focus, { selector, strategy: strategy ?? 'css' });
|
|
265
|
+
const { selector, strategy, nth, windowId, appIdentifier } = options;
|
|
266
|
+
const script = buildScript(SCRIPTS.focus, { selector, strategy: strategy ?? 'css', nth: nth ?? null });
|
|
254
267
|
try {
|
|
255
268
|
return await executeInWebview(script, windowId, appIdentifier);
|
|
256
269
|
}
|
|
@@ -263,8 +276,17 @@ export async function focusElement(options) {
|
|
|
263
276
|
* Find an element using various selector strategies.
|
|
264
277
|
*/
|
|
265
278
|
export async function findElement(options) {
|
|
266
|
-
const { selector, strategy, windowId, appIdentifier } = options;
|
|
267
|
-
|
|
279
|
+
const { selector, strategy, nth, limit, properties, visibleOnly, includeHtml, windowId, appIdentifier } = options;
|
|
280
|
+
await ensureAriaApiLoaded(windowId, appIdentifier);
|
|
281
|
+
const script = buildScript(SCRIPTS.findElement, {
|
|
282
|
+
selector,
|
|
283
|
+
strategy,
|
|
284
|
+
nth: nth ?? null,
|
|
285
|
+
limit: limit ?? 5,
|
|
286
|
+
properties: properties || [],
|
|
287
|
+
visibleOnly: visibleOnly ?? true,
|
|
288
|
+
includeHtml: includeHtml ?? false,
|
|
289
|
+
});
|
|
268
290
|
try {
|
|
269
291
|
return await executeInWebview(script, windowId, appIdentifier);
|
|
270
292
|
}
|
|
@@ -277,9 +299,9 @@ export async function findElement(options) {
|
|
|
277
299
|
* Get console logs from the webview.
|
|
278
300
|
*/
|
|
279
301
|
export async function getConsoleLogs(options = {}) {
|
|
280
|
-
const { filter, since, windowId, appIdentifier } = options;
|
|
302
|
+
const { lines = 50, level, maxChars = 20000, maxCharsPerEntry = 2000, filter, since, windowId, appIdentifier } = options;
|
|
281
303
|
try {
|
|
282
|
-
return await getConsoleLogsFromCapture(filter, since, windowId, appIdentifier);
|
|
304
|
+
return await getConsoleLogsFromCapture({ filter, since, lines, windowId, appIdentifier, level, maxChars, maxCharsPerEntry });
|
|
283
305
|
}
|
|
284
306
|
catch (error) {
|
|
285
307
|
const message = error instanceof Error ? error.message : String(error);
|
package/dist/monitor/logs.d.ts
CHANGED
|
@@ -2,28 +2,40 @@ import { z } from 'zod';
|
|
|
2
2
|
export declare const ReadLogsSchema: z.ZodObject<{
|
|
3
3
|
source: z.ZodEnum<["console", "android", "ios", "system"]>;
|
|
4
4
|
lines: z.ZodDefault<z.ZodNumber>;
|
|
5
|
+
level: z.ZodOptional<z.ZodEnum<["log", "debug", "info", "warn", "error"]>>;
|
|
6
|
+
maxChars: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
7
|
+
maxCharsPerEntry: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
5
8
|
filter: z.ZodOptional<z.ZodString>;
|
|
6
9
|
since: z.ZodOptional<z.ZodString>;
|
|
7
10
|
windowId: z.ZodOptional<z.ZodString>;
|
|
8
11
|
appIdentifier: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
9
12
|
}, "strip", z.ZodTypeAny, {
|
|
10
13
|
lines: number;
|
|
14
|
+
maxChars: number;
|
|
15
|
+
maxCharsPerEntry: number;
|
|
11
16
|
source: "android" | "ios" | "console" | "system";
|
|
12
17
|
filter?: string | undefined;
|
|
18
|
+
since?: string | undefined;
|
|
13
19
|
windowId?: string | undefined;
|
|
14
20
|
appIdentifier?: string | number | undefined;
|
|
15
|
-
|
|
21
|
+
level?: "error" | "log" | "debug" | "info" | "warn" | undefined;
|
|
16
22
|
}, {
|
|
17
23
|
source: "android" | "ios" | "console" | "system";
|
|
18
24
|
filter?: string | undefined;
|
|
19
25
|
lines?: number | undefined;
|
|
26
|
+
since?: string | undefined;
|
|
20
27
|
windowId?: string | undefined;
|
|
21
28
|
appIdentifier?: string | number | undefined;
|
|
22
|
-
|
|
29
|
+
level?: "error" | "log" | "debug" | "info" | "warn" | undefined;
|
|
30
|
+
maxChars?: number | undefined;
|
|
31
|
+
maxCharsPerEntry?: number | undefined;
|
|
23
32
|
}>;
|
|
24
33
|
export interface ReadLogsOptions {
|
|
25
34
|
source: 'console' | 'android' | 'ios' | 'system';
|
|
26
35
|
lines?: number;
|
|
36
|
+
level?: 'log' | 'debug' | 'info' | 'warn' | 'error';
|
|
37
|
+
maxChars?: number;
|
|
38
|
+
maxCharsPerEntry?: number;
|
|
27
39
|
filter?: string;
|
|
28
40
|
since?: string;
|
|
29
41
|
windowId?: string;
|
package/dist/monitor/logs.js
CHANGED
|
@@ -47,19 +47,25 @@ function findAdbPath() {
|
|
|
47
47
|
export const ReadLogsSchema = z.object({
|
|
48
48
|
source: z.enum(['console', 'android', 'ios', 'system'])
|
|
49
49
|
.describe('Log source: "console" for webview JS logs, "android" for logcat, "ios" for simulator, "system" for desktop'),
|
|
50
|
-
lines: z.number().default(50),
|
|
50
|
+
lines: z.number().int().positive().default(50),
|
|
51
|
+
level: z.enum(['log', 'debug', 'info', 'warn', 'error']).optional()
|
|
52
|
+
.describe('Only return entries at this console level.'),
|
|
53
|
+
maxChars: z.number().int().min(500).max(100000).optional().default(20000)
|
|
54
|
+
.describe('Maximum characters in the response. Entries are truncated and the oldest are dropped to fit.'),
|
|
55
|
+
maxCharsPerEntry: z.number().int().min(100).max(20000).optional().default(2000)
|
|
56
|
+
.describe('Maximum characters kept from each log entry.'),
|
|
51
57
|
filter: z.string().optional().describe('Regex or keyword to filter logs'),
|
|
52
58
|
since: z.string().optional().describe('ISO timestamp to filter logs since (e.g. 2023-10-27T10:00:00Z)'),
|
|
53
59
|
windowId: z.string().optional().describe('Window label for console logs (defaults to "main")'),
|
|
54
60
|
appIdentifier: z.union([z.string(), z.number()]).optional().describe('App port or bundle ID for console logs. Defaults to the only connected app or the default app if multiple are connected.'),
|
|
55
61
|
});
|
|
56
62
|
export async function readLogs(options) {
|
|
57
|
-
const { source, lines = 50, filter, since, windowId, appIdentifier } = options;
|
|
63
|
+
const { source, lines = 50, level, maxChars = 20000, maxCharsPerEntry = 2000, filter, since, windowId, appIdentifier } = options;
|
|
58
64
|
try {
|
|
59
65
|
let output = '';
|
|
60
66
|
// Handle console logs (webview JS logs)
|
|
61
67
|
if (source === 'console') {
|
|
62
|
-
return await getConsoleLogs({ filter, since, windowId, appIdentifier });
|
|
68
|
+
return await getConsoleLogs({ lines, level, maxChars, maxCharsPerEntry, filter, since, windowId, appIdentifier });
|
|
63
69
|
}
|
|
64
70
|
if (source === 'android') {
|
|
65
71
|
const adbPath = findAdbPath();
|
|
@@ -134,16 +140,42 @@ export async function readLogs(options) {
|
|
|
134
140
|
return `Error reading system logs: ${e}`;
|
|
135
141
|
}
|
|
136
142
|
}
|
|
143
|
+
// Apply level filter
|
|
144
|
+
if (level) {
|
|
145
|
+
const levelPrefix = `[ ${level.toUpperCase()} ]`;
|
|
146
|
+
output = output.split('\n').filter((line) => { return line.includes(levelPrefix); }).join('\n');
|
|
147
|
+
}
|
|
148
|
+
// Apply regex filter
|
|
137
149
|
if (filter) {
|
|
138
150
|
try {
|
|
139
151
|
const regex = new RegExp(filter, 'i');
|
|
140
|
-
|
|
152
|
+
output = output.split('\n').filter((line) => { return regex.test(line); }).join('\n');
|
|
141
153
|
}
|
|
142
154
|
catch (e) {
|
|
143
155
|
return `Invalid filter regex: ${e}`;
|
|
144
156
|
}
|
|
145
157
|
}
|
|
146
|
-
|
|
158
|
+
// Apply character budget
|
|
159
|
+
const outputLines = output.split('\n');
|
|
160
|
+
let budget = maxChars, dropped = 0;
|
|
161
|
+
const finalLines = [];
|
|
162
|
+
for (let i = outputLines.length - 1; i >= 0; i--) {
|
|
163
|
+
let line = outputLines[i];
|
|
164
|
+
if (line.length > maxCharsPerEntry) {
|
|
165
|
+
line = line.slice(0, maxCharsPerEntry) + '…[' + (line.length - maxCharsPerEntry) + ' more chars]';
|
|
166
|
+
}
|
|
167
|
+
if (line.length > budget) {
|
|
168
|
+
dropped = i + 1;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
budget -= line.length + 1; // +1 for newline
|
|
172
|
+
finalLines.unshift(line);
|
|
173
|
+
}
|
|
174
|
+
if (dropped > 0) {
|
|
175
|
+
finalLines.unshift('[ ' + dropped + ' older entries dropped to fit maxChars=' + maxChars +
|
|
176
|
+
'. Narrow with level, filter, or since. ]');
|
|
177
|
+
}
|
|
178
|
+
return finalLines.join('\n');
|
|
147
179
|
}
|
|
148
180
|
catch (error) {
|
|
149
181
|
return `Error reading logs: ${error}`;
|