@midscene/android 1.7.10-beta-20260507123827.0 → 1.7.10

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 CHANGED
@@ -12,7 +12,7 @@ import { execFile } from "node:child_process";
12
12
  import { defineAction, defineActionClearInput, defineActionCursorMove, defineActionDoubleClick, defineActionDragAndDrop, defineActionKeyboardPress, defineActionLongPress, defineActionPinch, defineActionScroll, defineActionSwipe, defineActionTap, normalizeMobileSwipeParam, normalizePinchParam } from "@midscene/core/device";
13
13
  import { getTmpFile, sleep } from "@midscene/core/utils";
14
14
  import { MIDSCENE_ADB_PATH, MIDSCENE_ADB_REMOTE_HOST, MIDSCENE_ADB_REMOTE_PORT, MIDSCENE_ANDROID_IME_STRATEGY, globalConfigManager } from "@midscene/shared/env";
15
- import { createImgBase64ByFormat, isValidImageBuffer } from "@midscene/shared/img";
15
+ import { createImgBase64ByFormat, validateScreenshotBuffer } from "@midscene/shared/img";
16
16
  import { ADB as external_appium_adb_ADB } from "appium-adb";
17
17
  var __webpack_modules__ = {
18
18
  "./src/scrcpy-manager.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
@@ -1252,25 +1252,21 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1252
1252
  debugDevice('Taking screenshot via adb.takeScreenshot');
1253
1253
  screenshotBuffer = await adb.takeScreenshot(null);
1254
1254
  debugDevice('adb.takeScreenshot completed');
1255
- if (!screenshotBuffer) {
1256
- this.takeScreenshotFailCount++;
1257
- throw new Error('Failed to capture screenshot: screenshotBuffer is null');
1258
- }
1259
- if (!isValidImageBuffer(screenshotBuffer)) {
1260
- debugDevice('Invalid image buffer detected: not a valid image format');
1255
+ try {
1256
+ validateScreenshotBuffer(screenshotBuffer, {
1257
+ label: 'Screenshot',
1258
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1259
+ });
1260
+ } catch (validationError) {
1261
+ debugDevice('Invalid screenshot buffer detected: %s', validationError instanceof Error ? validationError.message : String(validationError));
1261
1262
  this.takeScreenshotFailCount++;
1262
- throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
1263
+ throw validationError;
1263
1264
  }
1264
1265
  this.takeScreenshotFailCount = 0;
1265
1266
  } else {
1266
1267
  if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
1267
1268
  throw new Error('Using shell screencap directly');
1268
1269
  }
1269
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1270
- if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
1271
- debugDevice(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1272
- throw new Error(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1273
- }
1274
1270
  } catch (error) {
1275
1271
  debugDevice(`Taking screenshot via adb.takeScreenshot failed or was skipped: ${error}`);
1276
1272
  const screenshotPath = getTmpFile('png');
@@ -1291,9 +1287,10 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1291
1287
  await adb.pull(androidScreenshotPath, screenshotPath);
1292
1288
  debugDevice(`adb.pull completed, local path: ${screenshotPath}`);
1293
1289
  screenshotBuffer = await external_node_fs_["default"].promises.readFile(screenshotPath);
1294
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1295
- if (!screenshotBuffer || validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) throw new Error(`Fallback screenshot validation failed: buffer size ${screenshotBuffer?.length || 0} bytes (minimum: ${validScreenshotBufferSize})`);
1296
- if (!isValidImageBuffer(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
1290
+ validateScreenshotBuffer(screenshotBuffer, {
1291
+ label: 'Fallback screenshot',
1292
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1293
+ });
1297
1294
  debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
1298
1295
  } finally{
1299
1296
  const adbPath = adb.executable?.path ?? 'adb';
@@ -1779,6 +1776,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1779
1776
  }
1780
1777
  }
1781
1778
  device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
1779
+ device_define_property(AndroidDevice, "DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE", 1024);
1782
1780
  const runAdbShellParamSchema = z.object({
1783
1781
  command: z.string().describe('ADB shell command to execute')
1784
1782
  });
@@ -2018,7 +2016,7 @@ class AndroidMidsceneTools extends BaseMidsceneTools {
2018
2016
  const tools = new AndroidMidsceneTools();
2019
2017
  runToolsCLI(tools, 'midscene-android', {
2020
2018
  stripPrefix: 'android_',
2021
- version: "1.7.10-beta-20260507123827.0",
2019
+ version: "1.7.10",
2022
2020
  extraCommands: createReportCliCommands()
2023
2021
  }).catch((e)=>{
2024
2022
  process.exit(reportCLIError(e));
package/dist/es/index.mjs CHANGED
@@ -8,7 +8,7 @@ import { getMidsceneLocationSchema, z } from "@midscene/core";
8
8
  import { defineAction, defineActionClearInput, defineActionCursorMove, defineActionDoubleClick, defineActionDragAndDrop, defineActionKeyboardPress, defineActionLongPress, defineActionPinch, defineActionScroll, defineActionSwipe, defineActionTap, normalizeMobileSwipeParam, normalizePinchParam } from "@midscene/core/device";
9
9
  import { getTmpFile, sleep } from "@midscene/core/utils";
10
10
  import { MIDSCENE_ADB_PATH, MIDSCENE_ADB_REMOTE_HOST, MIDSCENE_ADB_REMOTE_PORT, MIDSCENE_ANDROID_IME_STRATEGY, globalConfigManager, overrideAIConfig } from "@midscene/shared/env";
11
- import { createImgBase64ByFormat, isValidImageBuffer } from "@midscene/shared/img";
11
+ import { createImgBase64ByFormat, validateScreenshotBuffer } from "@midscene/shared/img";
12
12
  import { mergeAndNormalizeAppNameMapping, normalizeForComparison, repeat } from "@midscene/shared/utils";
13
13
  import { ADB } from "appium-adb";
14
14
  import { Agent } from "@midscene/core/agent";
@@ -1155,25 +1155,21 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1155
1155
  debugDevice('Taking screenshot via adb.takeScreenshot');
1156
1156
  screenshotBuffer = await adb.takeScreenshot(null);
1157
1157
  debugDevice('adb.takeScreenshot completed');
1158
- if (!screenshotBuffer) {
1159
- this.takeScreenshotFailCount++;
1160
- throw new Error('Failed to capture screenshot: screenshotBuffer is null');
1161
- }
1162
- if (!isValidImageBuffer(screenshotBuffer)) {
1163
- debugDevice('Invalid image buffer detected: not a valid image format');
1158
+ try {
1159
+ validateScreenshotBuffer(screenshotBuffer, {
1160
+ label: 'Screenshot',
1161
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1162
+ });
1163
+ } catch (validationError) {
1164
+ debugDevice('Invalid screenshot buffer detected: %s', validationError instanceof Error ? validationError.message : String(validationError));
1164
1165
  this.takeScreenshotFailCount++;
1165
- throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
1166
+ throw validationError;
1166
1167
  }
1167
1168
  this.takeScreenshotFailCount = 0;
1168
1169
  } else {
1169
1170
  if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
1170
1171
  throw new Error('Using shell screencap directly');
1171
1172
  }
1172
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1173
- if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
1174
- debugDevice(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1175
- throw new Error(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1176
- }
1177
1173
  } catch (error) {
1178
1174
  debugDevice(`Taking screenshot via adb.takeScreenshot failed or was skipped: ${error}`);
1179
1175
  const screenshotPath = getTmpFile('png');
@@ -1194,9 +1190,10 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1194
1190
  await adb.pull(androidScreenshotPath, screenshotPath);
1195
1191
  debugDevice(`adb.pull completed, local path: ${screenshotPath}`);
1196
1192
  screenshotBuffer = await external_node_fs_["default"].promises.readFile(screenshotPath);
1197
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1198
- if (!screenshotBuffer || validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) throw new Error(`Fallback screenshot validation failed: buffer size ${screenshotBuffer?.length || 0} bytes (minimum: ${validScreenshotBufferSize})`);
1199
- if (!isValidImageBuffer(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
1193
+ validateScreenshotBuffer(screenshotBuffer, {
1194
+ label: 'Fallback screenshot',
1195
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1196
+ });
1200
1197
  debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
1201
1198
  } finally{
1202
1199
  const adbPath = adb.executable?.path ?? 'adb';
@@ -1682,6 +1679,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1682
1679
  }
1683
1680
  }
1684
1681
  device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
1682
+ device_define_property(AndroidDevice, "DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE", 1024);
1685
1683
  const runAdbShellParamSchema = z.object({
1686
1684
  command: z.string().describe('ADB shell command to execute')
1687
1685
  });
@@ -11,7 +11,7 @@ import { getMidsceneLocationSchema, z } from "@midscene/core";
11
11
  import { defineAction, defineActionClearInput, defineActionCursorMove, defineActionDoubleClick, defineActionDragAndDrop, defineActionKeyboardPress, defineActionLongPress, defineActionPinch, defineActionScroll, defineActionSwipe, defineActionTap, normalizeMobileSwipeParam, normalizePinchParam } from "@midscene/core/device";
12
12
  import { getTmpFile, sleep } from "@midscene/core/utils";
13
13
  import { MIDSCENE_ADB_PATH, MIDSCENE_ADB_REMOTE_HOST, MIDSCENE_ADB_REMOTE_PORT, MIDSCENE_ANDROID_IME_STRATEGY, globalConfigManager } from "@midscene/shared/env";
14
- import { createImgBase64ByFormat, isValidImageBuffer } from "@midscene/shared/img";
14
+ import { createImgBase64ByFormat, validateScreenshotBuffer } from "@midscene/shared/img";
15
15
  import { ADB as external_appium_adb_ADB } from "appium-adb";
16
16
  import { BaseMidsceneTools } from "@midscene/shared/mcp/base-tools";
17
17
  var __webpack_modules__ = {
@@ -1252,25 +1252,21 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1252
1252
  debugDevice('Taking screenshot via adb.takeScreenshot');
1253
1253
  screenshotBuffer = await adb.takeScreenshot(null);
1254
1254
  debugDevice('adb.takeScreenshot completed');
1255
- if (!screenshotBuffer) {
1256
- this.takeScreenshotFailCount++;
1257
- throw new Error('Failed to capture screenshot: screenshotBuffer is null');
1258
- }
1259
- if (!isValidImageBuffer(screenshotBuffer)) {
1260
- debugDevice('Invalid image buffer detected: not a valid image format');
1255
+ try {
1256
+ validateScreenshotBuffer(screenshotBuffer, {
1257
+ label: 'Screenshot',
1258
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1259
+ });
1260
+ } catch (validationError) {
1261
+ debugDevice('Invalid screenshot buffer detected: %s', validationError instanceof Error ? validationError.message : String(validationError));
1261
1262
  this.takeScreenshotFailCount++;
1262
- throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
1263
+ throw validationError;
1263
1264
  }
1264
1265
  this.takeScreenshotFailCount = 0;
1265
1266
  } else {
1266
1267
  if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
1267
1268
  throw new Error('Using shell screencap directly');
1268
1269
  }
1269
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1270
- if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
1271
- debugDevice(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1272
- throw new Error(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1273
- }
1274
1270
  } catch (error) {
1275
1271
  debugDevice(`Taking screenshot via adb.takeScreenshot failed or was skipped: ${error}`);
1276
1272
  const screenshotPath = getTmpFile('png');
@@ -1291,9 +1287,10 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1291
1287
  await adb.pull(androidScreenshotPath, screenshotPath);
1292
1288
  debugDevice(`adb.pull completed, local path: ${screenshotPath}`);
1293
1289
  screenshotBuffer = await external_node_fs_["default"].promises.readFile(screenshotPath);
1294
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1295
- if (!screenshotBuffer || validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) throw new Error(`Fallback screenshot validation failed: buffer size ${screenshotBuffer?.length || 0} bytes (minimum: ${validScreenshotBufferSize})`);
1296
- if (!isValidImageBuffer(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
1290
+ validateScreenshotBuffer(screenshotBuffer, {
1291
+ label: 'Fallback screenshot',
1292
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1293
+ });
1297
1294
  debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
1298
1295
  } finally{
1299
1296
  const adbPath = adb.executable?.path ?? 'adb';
@@ -1779,6 +1776,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1779
1776
  }
1780
1777
  }
1781
1778
  device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
1779
+ device_define_property(AndroidDevice, "DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE", 1024);
1782
1780
  const runAdbShellParamSchema = z.object({
1783
1781
  command: z.string().describe('ADB shell command to execute')
1784
1782
  });
@@ -2022,7 +2020,7 @@ class AndroidMCPServer extends BaseMCPServer {
2022
2020
  constructor(toolsManager){
2023
2021
  super({
2024
2022
  name: '@midscene/android-mcp',
2025
- version: "1.7.10-beta-20260507123827.0",
2023
+ version: "1.7.10",
2026
2024
  description: 'Control the Android device using natural language commands'
2027
2025
  }, toolsManager);
2028
2026
  }
package/dist/lib/cli.js CHANGED
@@ -1267,25 +1267,21 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1267
1267
  debugDevice('Taking screenshot via adb.takeScreenshot');
1268
1268
  screenshotBuffer = await adb.takeScreenshot(null);
1269
1269
  debugDevice('adb.takeScreenshot completed');
1270
- if (!screenshotBuffer) {
1271
- this.takeScreenshotFailCount++;
1272
- throw new Error('Failed to capture screenshot: screenshotBuffer is null');
1273
- }
1274
- if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) {
1275
- debugDevice('Invalid image buffer detected: not a valid image format');
1270
+ try {
1271
+ (0, img_namespaceObject.validateScreenshotBuffer)(screenshotBuffer, {
1272
+ label: 'Screenshot',
1273
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1274
+ });
1275
+ } catch (validationError) {
1276
+ debugDevice('Invalid screenshot buffer detected: %s', validationError instanceof Error ? validationError.message : String(validationError));
1276
1277
  this.takeScreenshotFailCount++;
1277
- throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
1278
+ throw validationError;
1278
1279
  }
1279
1280
  this.takeScreenshotFailCount = 0;
1280
1281
  } else {
1281
1282
  if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
1282
1283
  throw new Error('Using shell screencap directly');
1283
1284
  }
1284
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1285
- if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
1286
- debugDevice(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1287
- throw new Error(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1288
- }
1289
1285
  } catch (error) {
1290
1286
  debugDevice(`Taking screenshot via adb.takeScreenshot failed or was skipped: ${error}`);
1291
1287
  const screenshotPath = (0, core_utils_namespaceObject.getTmpFile)('png');
@@ -1306,9 +1302,10 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1306
1302
  await adb.pull(androidScreenshotPath, screenshotPath);
1307
1303
  debugDevice(`adb.pull completed, local path: ${screenshotPath}`);
1308
1304
  screenshotBuffer = await external_node_fs_default().promises.readFile(screenshotPath);
1309
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1310
- if (!screenshotBuffer || validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) throw new Error(`Fallback screenshot validation failed: buffer size ${screenshotBuffer?.length || 0} bytes (minimum: ${validScreenshotBufferSize})`);
1311
- if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
1305
+ (0, img_namespaceObject.validateScreenshotBuffer)(screenshotBuffer, {
1306
+ label: 'Fallback screenshot',
1307
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1308
+ });
1312
1309
  debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
1313
1310
  } finally{
1314
1311
  const adbPath = adb.executable?.path ?? 'adb';
@@ -1794,6 +1791,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1794
1791
  }
1795
1792
  }
1796
1793
  device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
1794
+ device_define_property(AndroidDevice, "DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE", 1024);
1797
1795
  const runAdbShellParamSchema = core_namespaceObject.z.object({
1798
1796
  command: core_namespaceObject.z.string().describe('ADB shell command to execute')
1799
1797
  });
@@ -2033,7 +2031,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
2033
2031
  const tools = new AndroidMidsceneTools();
2034
2032
  (0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-android', {
2035
2033
  stripPrefix: 'android_',
2036
- version: "1.7.10-beta-20260507123827.0",
2034
+ version: "1.7.10",
2037
2035
  extraCommands: (0, core_namespaceObject.createReportCliCommands)()
2038
2036
  }).catch((e)=>{
2039
2037
  process.exit((0, cli_namespaceObject.reportCLIError)(e));
package/dist/lib/index.js CHANGED
@@ -1189,25 +1189,21 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1189
1189
  debugDevice('Taking screenshot via adb.takeScreenshot');
1190
1190
  screenshotBuffer = await adb.takeScreenshot(null);
1191
1191
  debugDevice('adb.takeScreenshot completed');
1192
- if (!screenshotBuffer) {
1193
- this.takeScreenshotFailCount++;
1194
- throw new Error('Failed to capture screenshot: screenshotBuffer is null');
1195
- }
1196
- if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) {
1197
- debugDevice('Invalid image buffer detected: not a valid image format');
1192
+ try {
1193
+ (0, img_namespaceObject.validateScreenshotBuffer)(screenshotBuffer, {
1194
+ label: 'Screenshot',
1195
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1196
+ });
1197
+ } catch (validationError) {
1198
+ debugDevice('Invalid screenshot buffer detected: %s', validationError instanceof Error ? validationError.message : String(validationError));
1198
1199
  this.takeScreenshotFailCount++;
1199
- throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
1200
+ throw validationError;
1200
1201
  }
1201
1202
  this.takeScreenshotFailCount = 0;
1202
1203
  } else {
1203
1204
  if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
1204
1205
  throw new Error('Using shell screencap directly');
1205
1206
  }
1206
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1207
- if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
1208
- debugDevice(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1209
- throw new Error(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1210
- }
1211
1207
  } catch (error) {
1212
1208
  debugDevice(`Taking screenshot via adb.takeScreenshot failed or was skipped: ${error}`);
1213
1209
  const screenshotPath = (0, utils_namespaceObject.getTmpFile)('png');
@@ -1228,9 +1224,10 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1228
1224
  await adb.pull(androidScreenshotPath, screenshotPath);
1229
1225
  debugDevice(`adb.pull completed, local path: ${screenshotPath}`);
1230
1226
  screenshotBuffer = await external_node_fs_default().promises.readFile(screenshotPath);
1231
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1232
- if (!screenshotBuffer || validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) throw new Error(`Fallback screenshot validation failed: buffer size ${screenshotBuffer?.length || 0} bytes (minimum: ${validScreenshotBufferSize})`);
1233
- if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
1227
+ (0, img_namespaceObject.validateScreenshotBuffer)(screenshotBuffer, {
1228
+ label: 'Fallback screenshot',
1229
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1230
+ });
1234
1231
  debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
1235
1232
  } finally{
1236
1233
  const adbPath = adb.executable?.path ?? 'adb';
@@ -1716,6 +1713,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1716
1713
  }
1717
1714
  }
1718
1715
  device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
1716
+ device_define_property(AndroidDevice, "DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE", 1024);
1719
1717
  const runAdbShellParamSchema = core_namespaceObject.z.object({
1720
1718
  command: core_namespaceObject.z.string().describe('ADB shell command to execute')
1721
1719
  });
@@ -1282,25 +1282,21 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1282
1282
  debugDevice('Taking screenshot via adb.takeScreenshot');
1283
1283
  screenshotBuffer = await adb.takeScreenshot(null);
1284
1284
  debugDevice('adb.takeScreenshot completed');
1285
- if (!screenshotBuffer) {
1286
- this.takeScreenshotFailCount++;
1287
- throw new Error('Failed to capture screenshot: screenshotBuffer is null');
1288
- }
1289
- if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) {
1290
- debugDevice('Invalid image buffer detected: not a valid image format');
1285
+ try {
1286
+ (0, img_namespaceObject.validateScreenshotBuffer)(screenshotBuffer, {
1287
+ label: 'Screenshot',
1288
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1289
+ });
1290
+ } catch (validationError) {
1291
+ debugDevice('Invalid screenshot buffer detected: %s', validationError instanceof Error ? validationError.message : String(validationError));
1291
1292
  this.takeScreenshotFailCount++;
1292
- throw new Error('Screenshot buffer has invalid format: could not find valid image signature');
1293
+ throw validationError;
1293
1294
  }
1294
1295
  this.takeScreenshotFailCount = 0;
1295
1296
  } else {
1296
1297
  if (this.takeScreenshotFailCount >= AndroidDevice.TAKE_SCREENSHOT_FAIL_THRESHOLD) debugDevice('Skipping takeScreenshot (failed %d consecutive times), using shell screencap directly', this.takeScreenshotFailCount);
1297
1298
  throw new Error('Using shell screencap directly');
1298
1299
  }
1299
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1300
- if (validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) {
1301
- debugDevice(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1302
- throw new Error(`Screenshot buffer too small: ${screenshotBuffer.length} bytes (minimum: ${validScreenshotBufferSize})`);
1303
- }
1304
1300
  } catch (error) {
1305
1301
  debugDevice(`Taking screenshot via adb.takeScreenshot failed or was skipped: ${error}`);
1306
1302
  const screenshotPath = (0, core_utils_namespaceObject.getTmpFile)('png');
@@ -1321,9 +1317,10 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1321
1317
  await adb.pull(androidScreenshotPath, screenshotPath);
1322
1318
  debugDevice(`adb.pull completed, local path: ${screenshotPath}`);
1323
1319
  screenshotBuffer = await external_node_fs_default().promises.readFile(screenshotPath);
1324
- const validScreenshotBufferSize = this.options?.minScreenshotBufferSize ?? 10240;
1325
- if (!screenshotBuffer || validScreenshotBufferSize > 0 && screenshotBuffer.length < validScreenshotBufferSize) throw new Error(`Fallback screenshot validation failed: buffer size ${screenshotBuffer?.length || 0} bytes (minimum: ${validScreenshotBufferSize})`);
1326
- if (!(0, img_namespaceObject.isValidImageBuffer)(screenshotBuffer)) throw new Error('Fallback screenshot buffer has invalid PNG format');
1320
+ (0, img_namespaceObject.validateScreenshotBuffer)(screenshotBuffer, {
1321
+ label: 'Fallback screenshot',
1322
+ minBufferSize: this.options?.minScreenshotBufferSize ?? AndroidDevice.DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE
1323
+ });
1327
1324
  debugDevice(`Fallback screenshot validated successfully: ${screenshotBuffer.length} bytes`);
1328
1325
  } finally{
1329
1326
  const adbPath = adb.executable?.path ?? 'adb';
@@ -1809,6 +1806,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1809
1806
  }
1810
1807
  }
1811
1808
  device_define_property(AndroidDevice, "TAKE_SCREENSHOT_FAIL_THRESHOLD", 3);
1809
+ device_define_property(AndroidDevice, "DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE", 1024);
1812
1810
  const runAdbShellParamSchema = core_namespaceObject.z.object({
1813
1811
  command: core_namespaceObject.z.string().describe('ADB shell command to execute')
1814
1812
  });
@@ -2053,7 +2051,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
2053
2051
  constructor(toolsManager){
2054
2052
  super({
2055
2053
  name: '@midscene/android-mcp',
2056
- version: "1.7.10-beta-20260507123827.0",
2054
+ version: "1.7.10",
2057
2055
  description: 'Control the Android device using natural language commands'
2058
2056
  }, toolsManager);
2059
2057
  }
@@ -91,6 +91,7 @@ export declare class AndroidDevice implements AbstractInterface {
91
91
  private cachedAdjustScale;
92
92
  private takeScreenshotFailCount;
93
93
  private static readonly TAKE_SCREENSHOT_FAIL_THRESHOLD;
94
+ private static readonly DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE;
94
95
  interfaceType: InterfaceType;
95
96
  uri: string | undefined;
96
97
  options?: AndroidDeviceOpt;
@@ -83,6 +83,7 @@ declare class AndroidDevice implements AbstractInterface {
83
83
  private cachedAdjustScale;
84
84
  private takeScreenshotFailCount;
85
85
  private static readonly TAKE_SCREENSHOT_FAIL_THRESHOLD;
86
+ private static readonly DEFAULT_MIN_SCREENSHOT_BUFFER_SIZE;
86
87
  interfaceType: InterfaceType;
87
88
  uri: string | undefined;
88
89
  options?: AndroidDeviceOpt;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/android",
3
- "version": "1.7.10-beta-20260507123827.0",
3
+ "version": "1.7.10",
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": "2.1.0",
42
42
  "appium-adb": "12.12.1",
43
43
  "sharp": "^0.34.3",
44
- "@midscene/core": "1.7.10-beta-20260507123827.0",
45
- "@midscene/shared": "1.7.10-beta-20260507123827.0"
44
+ "@midscene/core": "1.7.10",
45
+ "@midscene/shared": "1.7.10"
46
46
  },
47
47
  "optionalDependencies": {
48
48
  "@ffmpeg-installer/ffmpeg": "^1.1.0"
@@ -56,7 +56,7 @@
56
56
  "undici": "^6.0.0",
57
57
  "vitest": "3.0.5",
58
58
  "zod": "^3.25.1",
59
- "@midscene/playground": "1.7.10-beta-20260507123827.0"
59
+ "@midscene/playground": "1.7.10"
60
60
  },
61
61
  "license": "MIT",
62
62
  "scripts": {