@midscene/android 1.5.2 → 1.5.3-beta-20260305031559.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/dist/es/cli.mjs +30 -11
- package/dist/es/index.mjs +30 -11
- package/dist/es/mcp-server.mjs +30 -11
- package/dist/lib/cli.js +30 -11
- package/dist/lib/index.js +30 -11
- package/dist/lib/mcp-server.js +30 -11
- package/dist/types/index.d.ts +2 -0
- package/dist/types/mcp-server.d.ts +2 -0
- package/package.json +4 -4
package/dist/es/cli.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import { BaseMidsceneTools } from "@midscene/shared/mcp";
|
|
|
8
8
|
import { Agent } from "@midscene/core/agent";
|
|
9
9
|
import { mergeAndNormalizeAppNameMapping, normalizeForComparison, repeat } from "@midscene/shared/utils";
|
|
10
10
|
import node_assert from "node:assert";
|
|
11
|
+
import { execFile } from "node:child_process";
|
|
11
12
|
import { defineAction, defineActionClearInput, defineActionCursorMove, defineActionDoubleClick, defineActionDragAndDrop, defineActionKeyboardPress, defineActionScroll, defineActionSwipe, defineActionTap, normalizeMobileSwipeParam } from "@midscene/core/device";
|
|
12
13
|
import { getTmpFile, sleep } from "@midscene/core/utils";
|
|
13
14
|
import { MIDSCENE_ADB_PATH, MIDSCENE_ADB_REMOTE_HOST, MIDSCENE_ADB_REMOTE_PORT, MIDSCENE_ANDROID_IME_STRATEGY, globalConfigManager } from "@midscene/shared/env";
|
|
@@ -1171,14 +1172,23 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1171
1172
|
const androidScreenshotPath = `/data/local/tmp/ms_${screenshotId}.png`;
|
|
1172
1173
|
const useShellScreencap = 'number' == typeof this.options?.displayId;
|
|
1173
1174
|
try {
|
|
1174
|
-
if (useShellScreencap
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1175
|
+
if (!useShellScreencap && this.takeScreenshotFailCount < AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) {
|
|
1176
|
+
debugDevice('Taking screenshot via adb.takeScreenshot');
|
|
1177
|
+
screenshotBuffer = await adb.takeScreenshot(null);
|
|
1178
|
+
debugDevice('adb.takeScreenshot completed');
|
|
1179
|
+
if (!screenshotBuffer) {
|
|
1180
|
+
this.takeScreenshotFailCount++;
|
|
1181
|
+
throw new Error('Failed to capture screenshot: screenshotBuffer is null');
|
|
1182
|
+
}
|
|
1183
|
+
if (!isValidImageBuffer(screenshotBuffer)) {
|
|
1184
|
+
debugDevice('Invalid image buffer detected: not a valid image format');
|
|
1185
|
+
this.takeScreenshotFailCount++;
|
|
1186
|
+
throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
|
|
1187
|
+
}
|
|
1188
|
+
this.takeScreenshotFailCount = 0;
|
|
1189
|
+
} else {
|
|
1190
|
+
if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
|
|
1191
|
+
throw new Error('Using shell screencap directly');
|
|
1182
1192
|
}
|
|
1183
1193
|
const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
|
|
1184
1194
|
if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
|
|
@@ -1210,9 +1220,16 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1210
1220
|
if (!isValidImageBuffer(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
|
|
1211
1221
|
debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
|
|
1212
1222
|
} finally{
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1223
|
+
const adbPath = adb.executable?.path || 'adb';
|
|
1224
|
+
const child = execFile(adbPath, [
|
|
1225
|
+
'-s',
|
|
1226
|
+
this.deviceId,
|
|
1227
|
+
'shell',
|
|
1228
|
+
`rm ${androidScreenshotPath}`
|
|
1229
|
+
], {
|
|
1230
|
+
timeout: 3000
|
|
1231
|
+
}, ()=>{});
|
|
1232
|
+
child.unref();
|
|
1216
1233
|
}
|
|
1217
1234
|
}
|
|
1218
1235
|
if (!screenshotBuffer) throw new Error('Failed to capture screenshot: all methods failed');
|
|
@@ -1656,6 +1673,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1656
1673
|
device_define_property(this, "scrcpyAdapter", null);
|
|
1657
1674
|
device_define_property(this, "appNameMapping", {});
|
|
1658
1675
|
device_define_property(this, "cachedAdjustScale", null);
|
|
1676
|
+
device_define_property(this, "takeScreenshotFailCount", 0);
|
|
1659
1677
|
device_define_property(this, "interfaceType", 'android');
|
|
1660
1678
|
device_define_property(this, "uri", void 0);
|
|
1661
1679
|
device_define_property(this, "options", void 0);
|
|
@@ -1665,6 +1683,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1665
1683
|
this.customActions = options?.customActions;
|
|
1666
1684
|
}
|
|
1667
1685
|
}
|
|
1686
|
+
device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
|
|
1668
1687
|
const runAdbShellParamSchema = z.object({
|
|
1669
1688
|
command: z.string().describe('ADB shell command to execute')
|
|
1670
1689
|
});
|
package/dist/es/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import * as __rspack_external_node_fs_5ea92f0c from "node:fs";
|
|
|
3
3
|
import * as __rspack_external_node_module_ab9f2194 from "node:module";
|
|
4
4
|
import * as __rspack_external_node_path_c5b9b54f from "node:path";
|
|
5
5
|
import node_assert from "node:assert";
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
6
7
|
import { getMidsceneLocationSchema, z } from "@midscene/core";
|
|
7
8
|
import { defineAction, defineActionClearInput, defineActionCursorMove, defineActionDoubleClick, defineActionDragAndDrop, defineActionKeyboardPress, defineActionScroll, defineActionSwipe, defineActionTap, normalizeMobileSwipeParam } from "@midscene/core/device";
|
|
8
9
|
import { getTmpFile, sleep } from "@midscene/core/utils";
|
|
@@ -1073,14 +1074,23 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1073
1074
|
const androidScreenshotPath = `/data/local/tmp/ms_${screenshotId}.png`;
|
|
1074
1075
|
const useShellScreencap = 'number' == typeof this.options?.displayId;
|
|
1075
1076
|
try {
|
|
1076
|
-
if (useShellScreencap
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1077
|
+
if (!useShellScreencap && this.takeScreenshotFailCount < AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) {
|
|
1078
|
+
debugDevice('Taking screenshot via adb.takeScreenshot');
|
|
1079
|
+
screenshotBuffer = await adb.takeScreenshot(null);
|
|
1080
|
+
debugDevice('adb.takeScreenshot completed');
|
|
1081
|
+
if (!screenshotBuffer) {
|
|
1082
|
+
this.takeScreenshotFailCount++;
|
|
1083
|
+
throw new Error('Failed to capture screenshot: screenshotBuffer is null');
|
|
1084
|
+
}
|
|
1085
|
+
if (!isValidImageBuffer(screenshotBuffer)) {
|
|
1086
|
+
debugDevice('Invalid image buffer detected: not a valid image format');
|
|
1087
|
+
this.takeScreenshotFailCount++;
|
|
1088
|
+
throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
|
|
1089
|
+
}
|
|
1090
|
+
this.takeScreenshotFailCount = 0;
|
|
1091
|
+
} else {
|
|
1092
|
+
if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
|
|
1093
|
+
throw new Error('Using shell screencap directly');
|
|
1084
1094
|
}
|
|
1085
1095
|
const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
|
|
1086
1096
|
if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
|
|
@@ -1112,9 +1122,16 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1112
1122
|
if (!isValidImageBuffer(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
|
|
1113
1123
|
debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
|
|
1114
1124
|
} finally{
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1125
|
+
const adbPath = adb.executable?.path || 'adb';
|
|
1126
|
+
const child = execFile(adbPath, [
|
|
1127
|
+
'-s',
|
|
1128
|
+
this.deviceId,
|
|
1129
|
+
'shell',
|
|
1130
|
+
`rm ${androidScreenshotPath}`
|
|
1131
|
+
], {
|
|
1132
|
+
timeout: 3000
|
|
1133
|
+
}, ()=>{});
|
|
1134
|
+
child.unref();
|
|
1118
1135
|
}
|
|
1119
1136
|
}
|
|
1120
1137
|
if (!screenshotBuffer) throw new Error('Failed to capture screenshot: all methods failed');
|
|
@@ -1558,6 +1575,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1558
1575
|
device_define_property(this, "scrcpyAdapter", null);
|
|
1559
1576
|
device_define_property(this, "appNameMapping", {});
|
|
1560
1577
|
device_define_property(this, "cachedAdjustScale", null);
|
|
1578
|
+
device_define_property(this, "takeScreenshotFailCount", 0);
|
|
1561
1579
|
device_define_property(this, "interfaceType", 'android');
|
|
1562
1580
|
device_define_property(this, "uri", void 0);
|
|
1563
1581
|
device_define_property(this, "options", void 0);
|
|
@@ -1567,6 +1585,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1567
1585
|
this.customActions = options?.customActions;
|
|
1568
1586
|
}
|
|
1569
1587
|
}
|
|
1588
|
+
device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
|
|
1570
1589
|
const runAdbShellParamSchema = z.object({
|
|
1571
1590
|
command: z.string().describe('ADB shell command to execute')
|
|
1572
1591
|
});
|
package/dist/es/mcp-server.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { BaseMCPServer, BaseMidsceneTools, createMCPServerLauncher } from "@mids
|
|
|
6
6
|
import { Agent } from "@midscene/core/agent";
|
|
7
7
|
import { mergeAndNormalizeAppNameMapping, normalizeForComparison, repeat } from "@midscene/shared/utils";
|
|
8
8
|
import node_assert from "node:assert";
|
|
9
|
+
import { execFile } from "node:child_process";
|
|
9
10
|
import { getMidsceneLocationSchema, z } from "@midscene/core";
|
|
10
11
|
import { defineAction, defineActionClearInput, defineActionCursorMove, defineActionDoubleClick, defineActionDragAndDrop, defineActionKeyboardPress, defineActionScroll, defineActionSwipe, defineActionTap, normalizeMobileSwipeParam } from "@midscene/core/device";
|
|
11
12
|
import { getTmpFile, sleep } from "@midscene/core/utils";
|
|
@@ -1170,14 +1171,23 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1170
1171
|
const androidScreenshotPath = `/data/local/tmp/ms_${screenshotId}.png`;
|
|
1171
1172
|
const useShellScreencap = 'number' == typeof this.options?.displayId;
|
|
1172
1173
|
try {
|
|
1173
|
-
if (useShellScreencap
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1174
|
+
if (!useShellScreencap && this.takeScreenshotFailCount < AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) {
|
|
1175
|
+
debugDevice('Taking screenshot via adb.takeScreenshot');
|
|
1176
|
+
screenshotBuffer = await adb.takeScreenshot(null);
|
|
1177
|
+
debugDevice('adb.takeScreenshot completed');
|
|
1178
|
+
if (!screenshotBuffer) {
|
|
1179
|
+
this.takeScreenshotFailCount++;
|
|
1180
|
+
throw new Error('Failed to capture screenshot: screenshotBuffer is null');
|
|
1181
|
+
}
|
|
1182
|
+
if (!isValidImageBuffer(screenshotBuffer)) {
|
|
1183
|
+
debugDevice('Invalid image buffer detected: not a valid image format');
|
|
1184
|
+
this.takeScreenshotFailCount++;
|
|
1185
|
+
throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
|
|
1186
|
+
}
|
|
1187
|
+
this.takeScreenshotFailCount = 0;
|
|
1188
|
+
} else {
|
|
1189
|
+
if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
|
|
1190
|
+
throw new Error('Using shell screencap directly');
|
|
1181
1191
|
}
|
|
1182
1192
|
const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
|
|
1183
1193
|
if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
|
|
@@ -1209,9 +1219,16 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1209
1219
|
if (!isValidImageBuffer(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
|
|
1210
1220
|
debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
|
|
1211
1221
|
} finally{
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1222
|
+
const adbPath = adb.executable?.path || 'adb';
|
|
1223
|
+
const child = execFile(adbPath, [
|
|
1224
|
+
'-s',
|
|
1225
|
+
this.deviceId,
|
|
1226
|
+
'shell',
|
|
1227
|
+
`rm ${androidScreenshotPath}`
|
|
1228
|
+
], {
|
|
1229
|
+
timeout: 3000
|
|
1230
|
+
}, ()=>{});
|
|
1231
|
+
child.unref();
|
|
1215
1232
|
}
|
|
1216
1233
|
}
|
|
1217
1234
|
if (!screenshotBuffer) throw new Error('Failed to capture screenshot: all methods failed');
|
|
@@ -1655,6 +1672,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1655
1672
|
device_define_property(this, "scrcpyAdapter", null);
|
|
1656
1673
|
device_define_property(this, "appNameMapping", {});
|
|
1657
1674
|
device_define_property(this, "cachedAdjustScale", null);
|
|
1675
|
+
device_define_property(this, "takeScreenshotFailCount", 0);
|
|
1658
1676
|
device_define_property(this, "interfaceType", 'android');
|
|
1659
1677
|
device_define_property(this, "uri", void 0);
|
|
1660
1678
|
device_define_property(this, "options", void 0);
|
|
@@ -1664,6 +1682,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1664
1682
|
this.customActions = options?.customActions;
|
|
1665
1683
|
}
|
|
1666
1684
|
}
|
|
1685
|
+
device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
|
|
1667
1686
|
const runAdbShellParamSchema = z.object({
|
|
1668
1687
|
command: z.string().describe('ADB shell command to execute')
|
|
1669
1688
|
});
|
package/dist/lib/cli.js
CHANGED
|
@@ -525,6 +525,7 @@ var __webpack_exports__ = {};
|
|
|
525
525
|
};
|
|
526
526
|
const external_node_assert_namespaceObject = require("node:assert");
|
|
527
527
|
var external_node_assert_default = /*#__PURE__*/ __webpack_require__.n(external_node_assert_namespaceObject);
|
|
528
|
+
const external_node_child_process_namespaceObject = require("node:child_process");
|
|
528
529
|
var external_node_fs_ = __webpack_require__("node:fs");
|
|
529
530
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_);
|
|
530
531
|
var external_node_module_ = __webpack_require__("node:module");
|
|
@@ -1186,14 +1187,23 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1186
1187
|
const androidScreenshotPath = `/data/local/tmp/ms_${screenshotId}.png`;
|
|
1187
1188
|
const useShellScreencap = 'number' == typeof this.options?.displayId;
|
|
1188
1189
|
try {
|
|
1189
|
-
if (useShellScreencap
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1190
|
+
if (!useShellScreencap && this.takeScreenshotFailCount < AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) {
|
|
1191
|
+
debugDevice('Taking screenshot via adb.takeScreenshot');
|
|
1192
|
+
screenshotBuffer = await adb.takeScreenshot(null);
|
|
1193
|
+
debugDevice('adb.takeScreenshot completed');
|
|
1194
|
+
if (!screenshotBuffer) {
|
|
1195
|
+
this.takeScreenshotFailCount++;
|
|
1196
|
+
throw new Error('Failed to capture screenshot: screenshotBuffer is null');
|
|
1197
|
+
}
|
|
1198
|
+
if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) {
|
|
1199
|
+
debugDevice('Invalid image buffer detected: not a valid image format');
|
|
1200
|
+
this.takeScreenshotFailCount++;
|
|
1201
|
+
throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
|
|
1202
|
+
}
|
|
1203
|
+
this.takeScreenshotFailCount = 0;
|
|
1204
|
+
} else {
|
|
1205
|
+
if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
|
|
1206
|
+
throw new Error('Using shell screencap directly');
|
|
1197
1207
|
}
|
|
1198
1208
|
const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
|
|
1199
1209
|
if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
|
|
@@ -1225,9 +1235,16 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1225
1235
|
if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
|
|
1226
1236
|
debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
|
|
1227
1237
|
} finally{
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1238
|
+
const adbPath = adb.executable?.path || 'adb';
|
|
1239
|
+
const child = (0, external_node_child_process_namespaceObject.execFile)(adbPath, [
|
|
1240
|
+
'-s',
|
|
1241
|
+
this.deviceId,
|
|
1242
|
+
'shell',
|
|
1243
|
+
`rm ${androidScreenshotPath}`
|
|
1244
|
+
], {
|
|
1245
|
+
timeout: 3000
|
|
1246
|
+
}, ()=>{});
|
|
1247
|
+
child.unref();
|
|
1231
1248
|
}
|
|
1232
1249
|
}
|
|
1233
1250
|
if (!screenshotBuffer) throw new Error('Failed to capture screenshot: all methods failed');
|
|
@@ -1671,6 +1688,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1671
1688
|
device_define_property(this, "scrcpyAdapter", null);
|
|
1672
1689
|
device_define_property(this, "appNameMapping", {});
|
|
1673
1690
|
device_define_property(this, "cachedAdjustScale", null);
|
|
1691
|
+
device_define_property(this, "takeScreenshotFailCount", 0);
|
|
1674
1692
|
device_define_property(this, "interfaceType", 'android');
|
|
1675
1693
|
device_define_property(this, "uri", void 0);
|
|
1676
1694
|
device_define_property(this, "options", void 0);
|
|
@@ -1680,6 +1698,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1680
1698
|
this.customActions = options?.customActions;
|
|
1681
1699
|
}
|
|
1682
1700
|
}
|
|
1701
|
+
device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
|
|
1683
1702
|
const runAdbShellParamSchema = core_namespaceObject.z.object({
|
|
1684
1703
|
command: core_namespaceObject.z.string().describe('ADB shell command to execute')
|
|
1685
1704
|
});
|
package/dist/lib/index.js
CHANGED
|
@@ -442,6 +442,7 @@ var __webpack_exports__ = {};
|
|
|
442
442
|
});
|
|
443
443
|
const external_node_assert_namespaceObject = require("node:assert");
|
|
444
444
|
var external_node_assert_default = /*#__PURE__*/ __webpack_require__.n(external_node_assert_namespaceObject);
|
|
445
|
+
const external_node_child_process_namespaceObject = require("node:child_process");
|
|
445
446
|
var external_node_fs_ = __webpack_require__("node:fs");
|
|
446
447
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_);
|
|
447
448
|
var external_node_module_ = __webpack_require__("node:module");
|
|
@@ -1106,14 +1107,23 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1106
1107
|
const androidScreenshotPath = `/data/local/tmp/ms_${screenshotId}.png`;
|
|
1107
1108
|
const useShellScreencap = 'number' == typeof this.options?.displayId;
|
|
1108
1109
|
try {
|
|
1109
|
-
if (useShellScreencap
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1110
|
+
if (!useShellScreencap && this.takeScreenshotFailCount < AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) {
|
|
1111
|
+
debugDevice('Taking screenshot via adb.takeScreenshot');
|
|
1112
|
+
screenshotBuffer = await adb.takeScreenshot(null);
|
|
1113
|
+
debugDevice('adb.takeScreenshot completed');
|
|
1114
|
+
if (!screenshotBuffer) {
|
|
1115
|
+
this.takeScreenshotFailCount++;
|
|
1116
|
+
throw new Error('Failed to capture screenshot: screenshotBuffer is null');
|
|
1117
|
+
}
|
|
1118
|
+
if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) {
|
|
1119
|
+
debugDevice('Invalid image buffer detected: not a valid image format');
|
|
1120
|
+
this.takeScreenshotFailCount++;
|
|
1121
|
+
throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
|
|
1122
|
+
}
|
|
1123
|
+
this.takeScreenshotFailCount = 0;
|
|
1124
|
+
} else {
|
|
1125
|
+
if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
|
|
1126
|
+
throw new Error('Using shell screencap directly');
|
|
1117
1127
|
}
|
|
1118
1128
|
const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
|
|
1119
1129
|
if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
|
|
@@ -1145,9 +1155,16 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1145
1155
|
if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
|
|
1146
1156
|
debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
|
|
1147
1157
|
} finally{
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1158
|
+
const adbPath = adb.executable?.path || 'adb';
|
|
1159
|
+
const child = (0, external_node_child_process_namespaceObject.execFile)(adbPath, [
|
|
1160
|
+
'-s',
|
|
1161
|
+
this.deviceId,
|
|
1162
|
+
'shell',
|
|
1163
|
+
`rm ${androidScreenshotPath}`
|
|
1164
|
+
], {
|
|
1165
|
+
timeout: 3000
|
|
1166
|
+
}, ()=>{});
|
|
1167
|
+
child.unref();
|
|
1151
1168
|
}
|
|
1152
1169
|
}
|
|
1153
1170
|
if (!screenshotBuffer) throw new Error('Failed to capture screenshot: all methods failed');
|
|
@@ -1591,6 +1608,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1591
1608
|
device_define_property(this, "scrcpyAdapter", null);
|
|
1592
1609
|
device_define_property(this, "appNameMapping", {});
|
|
1593
1610
|
device_define_property(this, "cachedAdjustScale", null);
|
|
1611
|
+
device_define_property(this, "takeScreenshotFailCount", 0);
|
|
1594
1612
|
device_define_property(this, "interfaceType", 'android');
|
|
1595
1613
|
device_define_property(this, "uri", void 0);
|
|
1596
1614
|
device_define_property(this, "options", void 0);
|
|
@@ -1600,6 +1618,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1600
1618
|
this.customActions = options?.customActions;
|
|
1601
1619
|
}
|
|
1602
1620
|
}
|
|
1621
|
+
device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
|
|
1603
1622
|
const runAdbShellParamSchema = core_namespaceObject.z.object({
|
|
1604
1623
|
command: core_namespaceObject.z.string().describe('ADB shell command to execute')
|
|
1605
1624
|
});
|
package/dist/lib/mcp-server.js
CHANGED
|
@@ -539,6 +539,7 @@ var __webpack_exports__ = {};
|
|
|
539
539
|
};
|
|
540
540
|
const external_node_assert_namespaceObject = require("node:assert");
|
|
541
541
|
var external_node_assert_default = /*#__PURE__*/ __webpack_require__.n(external_node_assert_namespaceObject);
|
|
542
|
+
const external_node_child_process_namespaceObject = require("node:child_process");
|
|
542
543
|
var external_node_fs_ = __webpack_require__("node:fs");
|
|
543
544
|
var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_);
|
|
544
545
|
var external_node_module_ = __webpack_require__("node:module");
|
|
@@ -1201,14 +1202,23 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1201
1202
|
const androidScreenshotPath = `/data/local/tmp/ms_${screenshotId}.png`;
|
|
1202
1203
|
const useShellScreencap = 'number' == typeof this.options?.displayId;
|
|
1203
1204
|
try {
|
|
1204
|
-
if (useShellScreencap
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1205
|
+
if (!useShellScreencap && this.takeScreenshotFailCount < AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) {
|
|
1206
|
+
debugDevice('Taking screenshot via adb.takeScreenshot');
|
|
1207
|
+
screenshotBuffer = await adb.takeScreenshot(null);
|
|
1208
|
+
debugDevice('adb.takeScreenshot completed');
|
|
1209
|
+
if (!screenshotBuffer) {
|
|
1210
|
+
this.takeScreenshotFailCount++;
|
|
1211
|
+
throw new Error('Failed to capture screenshot: screenshotBuffer is null');
|
|
1212
|
+
}
|
|
1213
|
+
if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) {
|
|
1214
|
+
debugDevice('Invalid image buffer detected: not a valid image format');
|
|
1215
|
+
this.takeScreenshotFailCount++;
|
|
1216
|
+
throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
|
|
1217
|
+
}
|
|
1218
|
+
this.takeScreenshotFailCount = 0;
|
|
1219
|
+
} else {
|
|
1220
|
+
if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
|
|
1221
|
+
throw new Error('Using shell screencap directly');
|
|
1212
1222
|
}
|
|
1213
1223
|
const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
|
|
1214
1224
|
if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
|
|
@@ -1240,9 +1250,16 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1240
1250
|
if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
|
|
1241
1251
|
debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
|
|
1242
1252
|
} finally{
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1253
|
+
const adbPath = adb.executable?.path || 'adb';
|
|
1254
|
+
const child = (0, external_node_child_process_namespaceObject.execFile)(adbPath, [
|
|
1255
|
+
'-s',
|
|
1256
|
+
this.deviceId,
|
|
1257
|
+
'shell',
|
|
1258
|
+
`rm ${androidScreenshotPath}`
|
|
1259
|
+
], {
|
|
1260
|
+
timeout: 3000
|
|
1261
|
+
}, ()=>{});
|
|
1262
|
+
child.unref();
|
|
1246
1263
|
}
|
|
1247
1264
|
}
|
|
1248
1265
|
if (!screenshotBuffer) throw new Error('Failed to capture screenshot: all methods failed');
|
|
@@ -1686,6 +1703,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1686
1703
|
device_define_property(this, "scrcpyAdapter", null);
|
|
1687
1704
|
device_define_property(this, "appNameMapping", {});
|
|
1688
1705
|
device_define_property(this, "cachedAdjustScale", null);
|
|
1706
|
+
device_define_property(this, "takeScreenshotFailCount", 0);
|
|
1689
1707
|
device_define_property(this, "interfaceType", 'android');
|
|
1690
1708
|
device_define_property(this, "uri", void 0);
|
|
1691
1709
|
device_define_property(this, "options", void 0);
|
|
@@ -1695,6 +1713,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1695
1713
|
this.customActions = options?.customActions;
|
|
1696
1714
|
}
|
|
1697
1715
|
}
|
|
1716
|
+
device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
|
|
1698
1717
|
const runAdbShellParamSchema = core_namespaceObject.z.object({
|
|
1699
1718
|
command: core_namespaceObject.z.string().describe('ADB shell command to execute')
|
|
1700
1719
|
});
|
package/dist/types/index.d.ts
CHANGED
|
@@ -74,6 +74,8 @@ export declare class AndroidDevice implements AbstractInterface {
|
|
|
74
74
|
private scrcpyAdapter;
|
|
75
75
|
private appNameMapping;
|
|
76
76
|
private cachedAdjustScale;
|
|
77
|
+
private takeScreenshotFailCount;
|
|
78
|
+
private static readonly TAKE_SCREENSHOT_FAIL_THRESHOLD;
|
|
77
79
|
interfaceType: InterfaceType;
|
|
78
80
|
uri: string | undefined;
|
|
79
81
|
options?: AndroidDeviceOpt;
|
|
@@ -75,6 +75,8 @@ declare class AndroidDevice implements AbstractInterface {
|
|
|
75
75
|
private scrcpyAdapter;
|
|
76
76
|
private appNameMapping;
|
|
77
77
|
private cachedAdjustScale;
|
|
78
|
+
private takeScreenshotFailCount;
|
|
79
|
+
private static readonly TAKE_SCREENSHOT_FAIL_THRESHOLD;
|
|
78
80
|
interfaceType: InterfaceType;
|
|
79
81
|
uri: string | undefined;
|
|
80
82
|
options?: AndroidDeviceOpt;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/android",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.3-beta-20260305031559.0",
|
|
4
4
|
"description": "Android automation library for Midscene",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Android UI automation",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"@yume-chan/stream-extra": "^1.0.0",
|
|
42
42
|
"appium-adb": "12.12.1",
|
|
43
43
|
"sharp": "^0.34.3",
|
|
44
|
-
"@midscene/core": "1.5.
|
|
45
|
-
"@midscene/shared": "1.5.
|
|
44
|
+
"@midscene/core": "1.5.3-beta-20260305031559.0",
|
|
45
|
+
"@midscene/shared": "1.5.3-beta-20260305031559.0"
|
|
46
46
|
},
|
|
47
47
|
"optionalDependencies": {
|
|
48
48
|
"@ffmpeg-installer/ffmpeg": "^1.1.0"
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"tsx": "^4.19.2",
|
|
57
57
|
"vitest": "3.0.5",
|
|
58
58
|
"zod": "3.24.3",
|
|
59
|
-
"@midscene/playground": "1.5.
|
|
59
|
+
"@midscene/playground": "1.5.3-beta-20260305031559.0"
|
|
60
60
|
},
|
|
61
61
|
"license": "MIT",
|
|
62
62
|
"scripts": {
|