@aiscene/android 1.3.4

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.
@@ -0,0 +1,225 @@
1
+ import { AbstractInterface } from '@midscene/core/device';
2
+ import type { ActionParam } from '@midscene/core';
3
+ import type { ActionReturn } from '@midscene/core';
4
+ import { ADB } from 'appium-adb';
5
+ import { Agent } from '@midscene/core/agent';
6
+ import { AgentOpt } from '@midscene/core/agent';
7
+ import { AndroidDeviceInputOpt } from '@midscene/core/device';
8
+ import { AndroidDeviceOpt } from '@midscene/core/device';
9
+ import { Device } from 'appium-adb';
10
+ import { DeviceAction } from '@midscene/core';
11
+ import { ElementCacheFeature } from '@midscene/core';
12
+ import type { ElementInfo } from '@midscene/shared/extractor';
13
+ import { IModelConfig } from '@midscene/shared/env';
14
+ import { InterfaceType } from '@midscene/core';
15
+ import { overrideAIConfig } from '@midscene/shared/env';
16
+ import { Point } from '@midscene/core';
17
+ import { Rect } from '@midscene/core';
18
+ import { Size } from '@midscene/core';
19
+
20
+ declare type ActionArgs<T extends DeviceAction> = [ActionParam<T>] extends [undefined] ? [] : [ActionParam<T>];
21
+
22
+ export declare function agentFromAdbDevice(deviceId?: string, opts?: AndroidAgentOpt & AndroidDeviceOpt): Promise<AndroidAgent>;
23
+
24
+ export declare class AndroidAgent extends Agent<AndroidDevice> {
25
+ /**
26
+ * Trigger the system back operation on Android devices
27
+ */
28
+ back: WrappedAction<DeviceActionAndroidBackButton>;
29
+ /**
30
+ * Trigger the system home operation on Android devices
31
+ */
32
+ home: WrappedAction<DeviceActionAndroidHomeButton>;
33
+ /**
34
+ * Trigger the system recent apps operation on Android devices
35
+ */
36
+ recentApps: WrappedAction<DeviceActionAndroidRecentAppsButton>;
37
+ /**
38
+ * User-provided app name to package name mapping
39
+ */
40
+ private appNameMapping;
41
+ constructor(device: AndroidDevice, opts?: AndroidAgentOpt);
42
+ /**
43
+ * Launch an Android app or URL
44
+ * @param uri - App package name, URL, or app name to launch
45
+ */
46
+ launch(uri: string): Promise<void>;
47
+ /**
48
+ * Execute ADB shell command on Android device
49
+ * @param command - ADB shell command to execute
50
+ */
51
+ runAdbShell(command: string): Promise<string>;
52
+ private createActionWrapper;
53
+ }
54
+
55
+ export declare type AndroidAgentOpt = AgentOpt & {
56
+ /**
57
+ * Custom mapping of app names to package names
58
+ * User-provided mappings will take precedence over default mappings
59
+ */
60
+ appNameMapping?: Record<string, string>;
61
+ };
62
+
63
+ export declare class AndroidDevice implements AbstractInterface {
64
+ private deviceId;
65
+ private yadbPushed;
66
+ private devicePixelRatio;
67
+ private devicePixelRatioInitialized;
68
+ private scalingRatio;
69
+ private adb;
70
+ private connectingAdb;
71
+ private destroyed;
72
+ private description;
73
+ private customActions?;
74
+ private cachedScreenSize;
75
+ private cachedOrientation;
76
+ private cachedPhysicalDisplayId;
77
+ private scrcpyAdapter;
78
+ private appNameMapping;
79
+ interfaceType: InterfaceType;
80
+ uri: string | undefined;
81
+ options?: AndroidDeviceOpt;
82
+ actionSpace(): DeviceAction<any>[];
83
+ constructor(deviceId: string, options?: AndroidDeviceOpt);
84
+ describe(): string;
85
+ connect(): Promise<ADB>;
86
+ getAdb(): Promise<ADB>;
87
+ private createAdbProxy;
88
+ /**
89
+ * Get or create the scrcpy adapter (lazy initialization)
90
+ */
91
+ private getScrcpyAdapter;
92
+ /**
93
+ * Get device physical info needed by scrcpy adapter
94
+ */
95
+ private getDevicePhysicalInfo;
96
+ /**
97
+ * Set the app name to package name mapping
98
+ */
99
+ setAppNameMapping(mapping: Record<string, string>): void;
100
+ /**
101
+ * Resolve app name to package name using the mapping
102
+ * Comparison is case-insensitive and ignores spaces, dashes, and underscores.
103
+ * Keys in appNameMapping are pre-normalized, so we only need to normalize the input.
104
+ * @param appName The app name to resolve
105
+ */
106
+ private resolvePackageName;
107
+ launch(uri: string): Promise<AndroidDevice>;
108
+ execYadb(keyboardContent: string): Promise<void>;
109
+ getElementsInfo(): Promise<ElementInfo[]>;
110
+ getElementsNodeTree(): Promise<any>;
111
+ getScreenSize(): Promise<{
112
+ override: string;
113
+ physical: string;
114
+ orientation: number;
115
+ isCurrentOrientation?: boolean;
116
+ }>;
117
+ private initializeDevicePixelRatio;
118
+ getDisplayDensity(): Promise<number>;
119
+ getDisplayOrientation(): Promise<number>;
120
+ size(): Promise<Size>;
121
+ /**
122
+ * Generate cache feature for an element at given center point
123
+ * Cache is based on test case ID + device ID, so screen size is guaranteed to be consistent
124
+ * for same test case on same device. We store exact coordinates for maximum accuracy.
125
+ */
126
+ cacheFeatureForPoint(center: [number, number], options?: {
127
+ targetDescription?: string;
128
+ modelConfig?: IModelConfig;
129
+ }): Promise<ElementCacheFeature>;
130
+ /**
131
+ * Find element rect from cache feature
132
+ * Since cache is keyed by test case ID + device ID, screen size will be identical
133
+ * We return the exact cached coordinates for maximum accuracy.
134
+ */
135
+ rectMatchesCacheFeature(feature: ElementCacheFeature): Promise<Rect>;
136
+ private adjustCoordinates;
137
+ /**
138
+ * Calculate the end point for scroll operations based on start point, scroll delta, and screen boundaries.
139
+ * This method ensures that scroll operations stay within screen bounds and maintain a minimum scroll distance
140
+ * for effective scrolling gestures on Android devices.
141
+ *
142
+ * @param start - The starting point of the scroll gesture
143
+ * @param deltaX - The horizontal scroll distance (positive = scroll right, negative = scroll left)
144
+ * @param deltaY - The vertical scroll distance (positive = scroll down, negative = scroll up)
145
+ * @param maxWidth - The maximum width boundary (screen width)
146
+ * @param maxHeight - The maximum height boundary (screen height)
147
+ * @returns The calculated end point for the scroll gesture
148
+ */
149
+ private calculateScrollEndPoint;
150
+ screenshotBase64(): Promise<string>;
151
+ clearInput(element?: ElementInfo): Promise<void>;
152
+ forceScreenshot(path: string): Promise<void>;
153
+ url(): Promise<string>;
154
+ scrollUntilTop(startPoint?: Point): Promise<void>;
155
+ scrollUntilBottom(startPoint?: Point): Promise<void>;
156
+ scrollUntilLeft(startPoint?: Point): Promise<void>;
157
+ scrollUntilRight(startPoint?: Point): Promise<void>;
158
+ scrollUp(distance?: number, startPoint?: Point): Promise<void>;
159
+ scrollDown(distance?: number, startPoint?: Point): Promise<void>;
160
+ scrollLeft(distance?: number, startPoint?: Point): Promise<void>;
161
+ scrollRight(distance?: number, startPoint?: Point): Promise<void>;
162
+ ensureYadb(): Promise<void>;
163
+ /**
164
+ * Check if text contains characters that may cause issues with ADB inputText
165
+ * This includes:
166
+ * - Non-ASCII characters (Unicode characters like ö, é, ñ, Chinese, Japanese, etc.)
167
+ * - Format specifiers that may be interpreted by shell (%, $)
168
+ * - Special shell characters that need escaping
169
+ */
170
+ private shouldUseYadbForText;
171
+ keyboardType(text: string, options?: AndroidDeviceInputOpt): Promise<void>;
172
+ private normalizeKeyName;
173
+ keyboardPress(key: string): Promise<void>;
174
+ mouseClick(x: number, y: number): Promise<void>;
175
+ mouseDoubleClick(x: number, y: number): Promise<void>;
176
+ mouseMove(): Promise<void>;
177
+ mouseDrag(from: {
178
+ x: number;
179
+ y: number;
180
+ }, to: {
181
+ x: number;
182
+ y: number;
183
+ }, duration?: number): Promise<void>;
184
+ scroll(deltaX: number, deltaY: number, duration?: number): Promise<void>;
185
+ destroy(): Promise<void>;
186
+ /**
187
+ * Get the current time from the Android device.
188
+ * Returns the device's current timestamp in milliseconds.
189
+ * This is useful when the system time and device time are not synchronized.
190
+ */
191
+ getTimestamp(): Promise<number>;
192
+ back(): Promise<void>;
193
+ home(): Promise<void>;
194
+ recentApps(): Promise<void>;
195
+ longPress(x: number, y: number, duration?: number): Promise<void>;
196
+ pullDown(startPoint?: Point, distance?: number, duration?: number): Promise<void>;
197
+ pullDrag(from: {
198
+ x: number;
199
+ y: number;
200
+ }, to: {
201
+ x: number;
202
+ y: number;
203
+ }, duration: number): Promise<void>;
204
+ pullUp(startPoint?: Point, distance?: number, duration?: number): Promise<void>;
205
+ private getDisplayArg;
206
+ getPhysicalDisplayId(): Promise<string | null>;
207
+ hideKeyboard(options?: AndroidDeviceInputOpt, timeoutMs?: number): Promise<boolean>;
208
+ }
209
+
210
+ declare type DeviceActionAndroidBackButton = DeviceAction<undefined, void>;
211
+
212
+ declare type DeviceActionAndroidHomeButton = DeviceAction<undefined, void>;
213
+
214
+ declare type DeviceActionAndroidRecentAppsButton = DeviceAction<undefined, void>;
215
+
216
+ export declare function getConnectedDevices(): Promise<Device[]>;
217
+
218
+ export { overrideAIConfig }
219
+
220
+ /**
221
+ * Helper type to convert DeviceAction to wrapped method signature
222
+ */
223
+ declare type WrappedAction<T extends DeviceAction> = (...args: ActionArgs<T>) => Promise<ActionReturn<T>>;
224
+
225
+ export { }
@@ -0,0 +1,263 @@
1
+ import { AbstractInterface } from '@midscene/core/device';
2
+ import type { ActionParam } from '@midscene/core';
3
+ import type { ActionReturn } from '@midscene/core';
4
+ import { ADB } from 'appium-adb';
5
+ import { Agent } from '@midscene/core/agent';
6
+ import { AgentOpt } from '@midscene/core/agent';
7
+ import { AndroidDeviceInputOpt } from '@midscene/core/device';
8
+ import { AndroidDeviceOpt } from '@midscene/core/device';
9
+ import { BaseMCPServer } from '@midscene/shared/mcp';
10
+ import { BaseMidsceneTools } from '@midscene/shared/mcp';
11
+ import { DeviceAction } from '@midscene/core';
12
+ import { ElementCacheFeature } from '@midscene/core';
13
+ import type { ElementInfo } from '@midscene/shared/extractor';
14
+ import { IModelConfig } from '@midscene/shared/env';
15
+ import { InterfaceType } from '@midscene/core';
16
+ import { LaunchMCPServerOptions } from '@midscene/shared/mcp';
17
+ import { LaunchMCPServerResult } from '@midscene/shared/mcp';
18
+ import { Point } from '@midscene/core';
19
+ import { Rect } from '@midscene/core';
20
+ import { Size } from '@midscene/core';
21
+ import { Tool } from '@midscene/shared/mcp';
22
+ import { ToolDefinition } from '@midscene/shared/mcp';
23
+
24
+ declare type ActionArgs<T extends DeviceAction> = [ActionParam<T>] extends [undefined] ? [] : [ActionParam<T>];
25
+
26
+ declare class AndroidAgent extends Agent<AndroidDevice> {
27
+ /**
28
+ * Trigger the system back operation on Android devices
29
+ */
30
+ back: WrappedAction<DeviceActionAndroidBackButton>;
31
+ /**
32
+ * Trigger the system home operation on Android devices
33
+ */
34
+ home: WrappedAction<DeviceActionAndroidHomeButton>;
35
+ /**
36
+ * Trigger the system recent apps operation on Android devices
37
+ */
38
+ recentApps: WrappedAction<DeviceActionAndroidRecentAppsButton>;
39
+ /**
40
+ * User-provided app name to package name mapping
41
+ */
42
+ private appNameMapping;
43
+ constructor(device: AndroidDevice, opts?: AndroidAgentOpt);
44
+ /**
45
+ * Launch an Android app or URL
46
+ * @param uri - App package name, URL, or app name to launch
47
+ */
48
+ launch(uri: string): Promise<void>;
49
+ /**
50
+ * Execute ADB shell command on Android device
51
+ * @param command - ADB shell command to execute
52
+ */
53
+ runAdbShell(command: string): Promise<string>;
54
+ private createActionWrapper;
55
+ }
56
+
57
+ declare type AndroidAgentOpt = AgentOpt & {
58
+ /**
59
+ * Custom mapping of app names to package names
60
+ * User-provided mappings will take precedence over default mappings
61
+ */
62
+ appNameMapping?: Record<string, string>;
63
+ };
64
+
65
+ declare class AndroidDevice implements AbstractInterface {
66
+ private deviceId;
67
+ private yadbPushed;
68
+ private devicePixelRatio;
69
+ private devicePixelRatioInitialized;
70
+ private scalingRatio;
71
+ private adb;
72
+ private connectingAdb;
73
+ private destroyed;
74
+ private description;
75
+ private customActions?;
76
+ private cachedScreenSize;
77
+ private cachedOrientation;
78
+ private cachedPhysicalDisplayId;
79
+ private scrcpyAdapter;
80
+ private appNameMapping;
81
+ interfaceType: InterfaceType;
82
+ uri: string | undefined;
83
+ options?: AndroidDeviceOpt;
84
+ actionSpace(): DeviceAction<any>[];
85
+ constructor(deviceId: string, options?: AndroidDeviceOpt);
86
+ describe(): string;
87
+ connect(): Promise<ADB>;
88
+ getAdb(): Promise<ADB>;
89
+ private createAdbProxy;
90
+ /**
91
+ * Get or create the scrcpy adapter (lazy initialization)
92
+ */
93
+ private getScrcpyAdapter;
94
+ /**
95
+ * Get device physical info needed by scrcpy adapter
96
+ */
97
+ private getDevicePhysicalInfo;
98
+ /**
99
+ * Set the app name to package name mapping
100
+ */
101
+ setAppNameMapping(mapping: Record<string, string>): void;
102
+ /**
103
+ * Resolve app name to package name using the mapping
104
+ * Comparison is case-insensitive and ignores spaces, dashes, and underscores.
105
+ * Keys in appNameMapping are pre-normalized, so we only need to normalize the input.
106
+ * @param appName The app name to resolve
107
+ */
108
+ private resolvePackageName;
109
+ launch(uri: string): Promise<AndroidDevice>;
110
+ execYadb(keyboardContent: string): Promise<void>;
111
+ getElementsInfo(): Promise<ElementInfo[]>;
112
+ getElementsNodeTree(): Promise<any>;
113
+ getScreenSize(): Promise<{
114
+ override: string;
115
+ physical: string;
116
+ orientation: number;
117
+ isCurrentOrientation?: boolean;
118
+ }>;
119
+ private initializeDevicePixelRatio;
120
+ getDisplayDensity(): Promise<number>;
121
+ getDisplayOrientation(): Promise<number>;
122
+ size(): Promise<Size>;
123
+ /**
124
+ * Generate cache feature for an element at given center point
125
+ * Cache is based on test case ID + device ID, so screen size is guaranteed to be consistent
126
+ * for same test case on same device. We store exact coordinates for maximum accuracy.
127
+ */
128
+ cacheFeatureForPoint(center: [number, number], options?: {
129
+ targetDescription?: string;
130
+ modelConfig?: IModelConfig;
131
+ }): Promise<ElementCacheFeature>;
132
+ /**
133
+ * Find element rect from cache feature
134
+ * Since cache is keyed by test case ID + device ID, screen size will be identical
135
+ * We return the exact cached coordinates for maximum accuracy.
136
+ */
137
+ rectMatchesCacheFeature(feature: ElementCacheFeature): Promise<Rect>;
138
+ private adjustCoordinates;
139
+ /**
140
+ * Calculate the end point for scroll operations based on start point, scroll delta, and screen boundaries.
141
+ * This method ensures that scroll operations stay within screen bounds and maintain a minimum scroll distance
142
+ * for effective scrolling gestures on Android devices.
143
+ *
144
+ * @param start - The starting point of the scroll gesture
145
+ * @param deltaX - The horizontal scroll distance (positive = scroll right, negative = scroll left)
146
+ * @param deltaY - The vertical scroll distance (positive = scroll down, negative = scroll up)
147
+ * @param maxWidth - The maximum width boundary (screen width)
148
+ * @param maxHeight - The maximum height boundary (screen height)
149
+ * @returns The calculated end point for the scroll gesture
150
+ */
151
+ private calculateScrollEndPoint;
152
+ screenshotBase64(): Promise<string>;
153
+ clearInput(element?: ElementInfo): Promise<void>;
154
+ forceScreenshot(path: string): Promise<void>;
155
+ url(): Promise<string>;
156
+ scrollUntilTop(startPoint?: Point): Promise<void>;
157
+ scrollUntilBottom(startPoint?: Point): Promise<void>;
158
+ scrollUntilLeft(startPoint?: Point): Promise<void>;
159
+ scrollUntilRight(startPoint?: Point): Promise<void>;
160
+ scrollUp(distance?: number, startPoint?: Point): Promise<void>;
161
+ scrollDown(distance?: number, startPoint?: Point): Promise<void>;
162
+ scrollLeft(distance?: number, startPoint?: Point): Promise<void>;
163
+ scrollRight(distance?: number, startPoint?: Point): Promise<void>;
164
+ ensureYadb(): Promise<void>;
165
+ /**
166
+ * Check if text contains characters that may cause issues with ADB inputText
167
+ * This includes:
168
+ * - Non-ASCII characters (Unicode characters like ö, é, ñ, Chinese, Japanese, etc.)
169
+ * - Format specifiers that may be interpreted by shell (%, $)
170
+ * - Special shell characters that need escaping
171
+ */
172
+ private shouldUseYadbForText;
173
+ keyboardType(text: string, options?: AndroidDeviceInputOpt): Promise<void>;
174
+ private normalizeKeyName;
175
+ keyboardPress(key: string): Promise<void>;
176
+ mouseClick(x: number, y: number): Promise<void>;
177
+ mouseDoubleClick(x: number, y: number): Promise<void>;
178
+ mouseMove(): Promise<void>;
179
+ mouseDrag(from: {
180
+ x: number;
181
+ y: number;
182
+ }, to: {
183
+ x: number;
184
+ y: number;
185
+ }, duration?: number): Promise<void>;
186
+ scroll(deltaX: number, deltaY: number, duration?: number): Promise<void>;
187
+ destroy(): Promise<void>;
188
+ /**
189
+ * Get the current time from the Android device.
190
+ * Returns the device's current timestamp in milliseconds.
191
+ * This is useful when the system time and device time are not synchronized.
192
+ */
193
+ getTimestamp(): Promise<number>;
194
+ back(): Promise<void>;
195
+ home(): Promise<void>;
196
+ recentApps(): Promise<void>;
197
+ longPress(x: number, y: number, duration?: number): Promise<void>;
198
+ pullDown(startPoint?: Point, distance?: number, duration?: number): Promise<void>;
199
+ pullDrag(from: {
200
+ x: number;
201
+ y: number;
202
+ }, to: {
203
+ x: number;
204
+ y: number;
205
+ }, duration: number): Promise<void>;
206
+ pullUp(startPoint?: Point, distance?: number, duration?: number): Promise<void>;
207
+ private getDisplayArg;
208
+ getPhysicalDisplayId(): Promise<string | null>;
209
+ hideKeyboard(options?: AndroidDeviceInputOpt, timeoutMs?: number): Promise<boolean>;
210
+ }
211
+
212
+ /**
213
+ * Android MCP Server
214
+ * Provides MCP tools for Android automation through ADB
215
+ */
216
+ export declare class AndroidMCPServer extends BaseMCPServer {
217
+ constructor(toolsManager?: AndroidMidsceneTools);
218
+ protected createToolsManager(): AndroidMidsceneTools;
219
+ }
220
+
221
+ /**
222
+ * Android-specific tools manager
223
+ * Extends BaseMidsceneTools to provide Android ADB device connection tools
224
+ */
225
+ declare class AndroidMidsceneTools extends BaseMidsceneTools<AndroidAgent> {
226
+ protected createTemporaryDevice(): AndroidDevice;
227
+ protected ensureAgent(deviceId?: string): Promise<AndroidAgent>;
228
+ /**
229
+ * Provide Android-specific platform tools
230
+ */
231
+ protected preparePlatformTools(): ToolDefinition[];
232
+ }
233
+
234
+ declare type DeviceActionAndroidBackButton = DeviceAction<undefined, void>;
235
+
236
+ declare type DeviceActionAndroidHomeButton = DeviceAction<undefined, void>;
237
+
238
+ declare type DeviceActionAndroidRecentAppsButton = DeviceAction<undefined, void>;
239
+
240
+ /**
241
+ * Create MCP kit for a specific Android Agent
242
+ */
243
+ export declare function mcpKitForAgent(agent: Agent | AndroidAgent): Promise<{
244
+ description: string;
245
+ tools: Tool[];
246
+ }>;
247
+
248
+ /**
249
+ * Create an MCP server launcher for a specific Android Agent
250
+ */
251
+ export declare function mcpServerForAgent(agent: Agent | AndroidAgent): {
252
+ launch(options?: {
253
+ verbose?: boolean;
254
+ }): Promise<LaunchMCPServerResult>;
255
+ launchHttp(options: LaunchMCPServerOptions): Promise<LaunchMCPServerResult>;
256
+ };
257
+
258
+ /**
259
+ * Helper type to convert DeviceAction to wrapped method signature
260
+ */
261
+ declare type WrappedAction<T extends DeviceAction> = (...args: ActionArgs<T>) => Promise<ActionReturn<T>>;
262
+
263
+ export { }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@aiscene/android",
3
+ "version": "1.3.4",
4
+ "description": "Android automation library for Midscene",
5
+ "keywords": [
6
+ "Android UI automation",
7
+ "Android AI testing",
8
+ "Android automation library",
9
+ "Android automation tool",
10
+ "Android use"
11
+ ],
12
+ "main": "./dist/lib/index.js",
13
+ "module": "./dist/es/index.mjs",
14
+ "types": "./dist/types/index.d.ts",
15
+ "files": ["bin", "dist", "README.md"],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/types/index.d.ts",
19
+ "import": "./dist/es/index.mjs",
20
+ "require": "./dist/lib/index.js"
21
+ },
22
+ "./mcp-server": {
23
+ "types": "./dist/types/mcp-server.d.ts",
24
+ "import": "./dist/es/mcp-server.mjs",
25
+ "require": "./dist/lib/mcp-server.js"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "scripts": {
30
+ "dev": "npm run build:watch",
31
+ "prebuild": "node scripts/download-scrcpy-server.mjs && node scripts/download-yadb.mjs",
32
+ "build": "rslib build",
33
+ "build:watch": "rslib build --watch --no-clean",
34
+ "prepack": "node scripts/download-scrcpy-server.mjs && node scripts/download-yadb.mjs",
35
+ "playground": "DEBUG=midscene:* tsx demo/playground.ts",
36
+ "test": "vitest --run",
37
+ "test:u": "vitest --run -u",
38
+ "test:ai": "AI_TEST_TYPE=android npm run test",
39
+ "test:ai:cache": "MIDSCENE_CACHE=true AI_TEST_TYPE=android npm run test"
40
+ },
41
+ "dependencies": {
42
+ "@midscene/core": "^1.3.4",
43
+ "@midscene/shared": "^1.3.4",
44
+ "@yume-chan/adb": "^1.1.0",
45
+ "@yume-chan/adb-scrcpy": "^1.1.0",
46
+ "@yume-chan/adb-server-node-tcp": "^1.1.0",
47
+ "@yume-chan/scrcpy": "^1.1.0",
48
+ "@yume-chan/stream-extra": "^1.0.0",
49
+ "appium-adb": "12.12.1",
50
+ "sharp": "^0.34.3"
51
+ },
52
+ "optionalDependencies": {
53
+ "@ffmpeg-installer/ffmpeg": "^1.1.0"
54
+ },
55
+ "devDependencies": {
56
+ "@midscene/playground": "workspace:*",
57
+ "@rslib/core": "^0.18.3",
58
+ "@types/node": "^18.0.0",
59
+ "dotenv": "^16.4.5",
60
+ "gh-release-fetch": "^4.0.3",
61
+ "typescript": "^5.8.3",
62
+ "tsx": "^4.19.2",
63
+ "vitest": "3.0.5",
64
+ "zod": "3.24.3"
65
+ },
66
+ "license": "MIT",
67
+ "publishConfig": {
68
+ "access": "public",
69
+ "registry": "https://registry.npmjs.org"
70
+ }
71
+ }