@midscene/computer 1.13.1-beta-20260921032526.0 → 1.13.1-beta-20260921075813.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 CHANGED
@@ -425,20 +425,6 @@ $midsceneSetDpiMethod.SetImplementationFlags(
425
425
  $midsceneSetDpiMethod.GetMethodImplementationFlags() -bor
426
426
  [System.Reflection.MethodImplAttributes]::PreserveSig
427
427
  )
428
- $midsceneGetDpiForSystemMethod = $midsceneType.DefinePInvokeMethod(
429
- 'GetDpiForSystem',
430
- 'user32.dll',
431
- $midsceneMethodAttributes,
432
- [System.Reflection.CallingConventions]::Standard,
433
- [uint32],
434
- [System.Type[]]@(),
435
- [System.Runtime.InteropServices.CallingConvention]::Winapi,
436
- [System.Runtime.InteropServices.CharSet]::None
437
- )
438
- $midsceneGetDpiForSystemMethod.SetImplementationFlags(
439
- $midsceneGetDpiForSystemMethod.GetMethodImplementationFlags() -bor
440
- [System.Reflection.MethodImplAttributes]::PreserveSig
441
- )
442
428
  $midsceneGetForegroundWindowMethod = $midsceneType.DefinePInvokeMethod(
443
429
  'GetForegroundWindow',
444
430
  'user32.dll',
@@ -475,8 +461,12 @@ if ($midscenePreviousDpiContext -eq [System.IntPtr]::Zero) {
475
461
  throw 'Unable to enter the Per-Monitor V2 DPI awareness context.'
476
462
  }
477
463
  `.trim();
478
- function runWindowsPowershellScript(script) {
479
- const encoded = Buffer.from(script, 'utf16le').toString('base64');
464
+ function runWindowsPhysicalPixelPowershell(script) {
465
+ const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
466
+ $ErrorActionPreference = 'Stop'
467
+ ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
468
+ ${script}`;
469
+ const encoded = Buffer.from(physicalPixelScript, 'utf16le').toString('base64');
480
470
  return execFileSync('powershell.exe', [
481
471
  '-NoProfile',
482
472
  '-NonInteractive',
@@ -489,130 +479,6 @@ function runWindowsPowershellScript(script) {
489
479
  windowsHide: true
490
480
  });
491
481
  }
492
- function runWindowsPowershellCommand(script) {
493
- return execFileSync('powershell.exe', [
494
- '-NoProfile',
495
- '-Command',
496
- script
497
- ], {
498
- encoding: 'utf8',
499
- timeout: POWERSHELL_TIMEOUT_MS,
500
- maxBuffer: POWERSHELL_MAX_BUFFER,
501
- windowsHide: true
502
- });
503
- }
504
- function runWindowsPowershell(script) {
505
- return runWindowsPowershellCommand(`$ProgressPreference = 'SilentlyContinue'
506
- $ErrorActionPreference = 'Stop'
507
- ${script}`);
508
- }
509
- function runWindowsPhysicalPixelPowershell(script) {
510
- const physicalPixelScript = `$ProgressPreference = 'SilentlyContinue'
511
- $ErrorActionPreference = 'Stop'
512
- ${WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE}
513
- ${script}`;
514
- return runWindowsPowershellScript(physicalPixelScript);
515
- }
516
- class WindowsDisplayEnumerationEmptyError extends Error {
517
- }
518
- function isFiniteNumber(value) {
519
- return 'number' == typeof value && Number.isFinite(value);
520
- }
521
- function isWindowsDisplayGeometry(value) {
522
- if (!value || 'object' != typeof value) return false;
523
- const candidate = value;
524
- const bounds = candidate.bounds;
525
- return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && !!bounds && isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
526
- }
527
- function readWindowsDisplayGeometriesWith(runPowershell, context) {
528
- const serializeScreens = 'legacy' === context ? 'ConvertTo-Json -InputObject $screens -Compress' : '[Console]::Out.Write((ConvertTo-Json -InputObject $screens -Compress))';
529
- const script = `
530
- Add-Type -AssemblyName System.Windows.Forms
531
- $screens = @([System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
532
- $bounds = $_.Bounds
533
- [PSCustomObject]@{
534
- id = $_.DeviceName
535
- name = $_.DeviceName
536
- primary = $_.Primary
537
- bounds = [PSCustomObject]@{
538
- x = $bounds.X
539
- y = $bounds.Y
540
- width = $bounds.Width
541
- height = $bounds.Height
542
- }
543
- }
544
- })
545
- ${serializeScreens}
546
- `.trim();
547
- const output = runPowershell(script).trim();
548
- if (!output) throw new WindowsDisplayEnumerationEmptyError(`Windows ${context} display enumeration returned no data`);
549
- const parsed = JSON.parse(output);
550
- if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
551
- const displays = parsed.filter(isWindowsDisplayGeometry);
552
- if (displays.length !== parsed.length) throw new Error('Windows display enumeration returned invalid geometry');
553
- if (0 === displays.length) throw new WindowsDisplayEnumerationEmptyError(`Windows ${context} display enumeration returned no displays`);
554
- return displays;
555
- }
556
- function readWindowsDisplayGeometries() {
557
- return readWindowsDisplayGeometriesWith(runWindowsPhysicalPixelPowershell, 'physical');
558
- }
559
- function discoverWindowsDisplays(runners = {
560
- physical: runWindowsPhysicalPixelPowershell,
561
- legacy: runWindowsPowershell
562
- }) {
563
- try {
564
- return {
565
- geometries: readWindowsDisplayGeometriesWith(runners.physical, 'physical'),
566
- coordinateMode: 'physical'
567
- };
568
- } catch (error) {
569
- if (!(error instanceof WindowsDisplayEnumerationEmptyError)) throw error;
570
- const geometries = readWindowsDisplayGeometriesWith(runners.legacy, 'legacy');
571
- return {
572
- geometries,
573
- coordinateMode: 'legacy'
574
- };
575
- }
576
- }
577
- function readPngDimensions(dataUri) {
578
- const prefix = 'data:image/png;base64,';
579
- if (!dataUri.startsWith(prefix)) throw new Error('Screenshot is not a PNG data URI');
580
- const buffer = Buffer.from(dataUri.slice(prefix.length), 'base64');
581
- const pngSignature = Buffer.from([
582
- 137,
583
- 80,
584
- 78,
585
- 71,
586
- 13,
587
- 10,
588
- 26,
589
- 10
590
- ]);
591
- if (buffer.length < 24 || !buffer.subarray(0, pngSignature.length).equals(pngSignature)) throw new Error('Screenshot returned invalid PNG data');
592
- const width = buffer.readUInt32BE(16);
593
- const height = buffer.readUInt32BE(20);
594
- if (width <= 0 || height <= 0) throw new Error('Screenshot returned invalid PNG dimensions');
595
- return {
596
- width,
597
- height
598
- };
599
- }
600
- function assertLegacyWindowsCoordinateCompatibility({ geometry, screenshotBase64, inputSize }) {
601
- if (!geometry?.primary) throw new Error('Windows legacy coordinate compatibility mode only supports the primary display');
602
- if (0 !== geometry.bounds.x || 0 !== geometry.bounds.y) throw new Error(`Windows legacy coordinate compatibility mode requires a primary display origin of (0, 0), got (${geometry.bounds.x}, ${geometry.bounds.y})`);
603
- const screenshotSize = readPngDimensions(screenshotBase64);
604
- const displaySize = {
605
- width: Math.round(geometry.bounds.width),
606
- height: Math.round(geometry.bounds.height)
607
- };
608
- const sizesMatch = screenshotSize.width === displaySize.width && screenshotSize.height === displaySize.height && inputSize.width === displaySize.width && inputSize.height === displaySize.height;
609
- if (!sizesMatch) throw new Error(`Windows legacy coordinate compatibility check failed: display=${displaySize.width}x${displaySize.height}, screenshot=${screenshotSize.width}x${screenshotSize.height}, input=${inputSize.width}x${inputSize.height}. Refusing to continue because clicks may use incorrect coordinates.`);
610
- }
611
- function resolveWindowsDisplayGeometryFromList(displayId, displays) {
612
- if (!displays.length) return;
613
- if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
614
- return displays.find((display)=>display.id === displayId);
615
- }
616
482
  function windows_pointer_define_property(obj, key, value) {
617
483
  if (key in obj) Object.defineProperty(obj, key, {
618
484
  value: value,
@@ -930,6 +796,28 @@ const EDGE_SCROLL_SPEC = {
930
796
  function escapePowershellSingleQuoted(value) {
931
797
  return value.replace(/'/g, "''");
932
798
  }
799
+ function readWindowsDisplayGeometries() {
800
+ const script = `
801
+ Add-Type -AssemblyName System.Windows.Forms
802
+ $s = [System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
803
+ $b = $_.Bounds
804
+ [PSCustomObject]@{
805
+ id = $_.DeviceName
806
+ name = $_.DeviceName
807
+ primary = $_.Primary
808
+ bounds = [PSCustomObject]@{ x = $b.X; y = $b.Y; width = $b.Width; height = $b.Height }
809
+ }
810
+ }
811
+ ConvertTo-Json @($s) -Compress
812
+ `.trim();
813
+ const output = runWindowsPhysicalPixelPowershell(script).trim();
814
+ if (!output) throw new Error('Windows display enumeration returned no data');
815
+ const parsed = JSON.parse(output);
816
+ if (!Array.isArray(parsed)) throw new Error('Windows display enumeration returned invalid data');
817
+ const displays = parsed.filter(isWindowsDisplayGeometry);
818
+ if (displays.length !== parsed.length || 0 === displays.length) throw new Error('Windows display enumeration returned invalid geometry');
819
+ return displays;
820
+ }
933
821
  function listWindowsDisplays(geometries = readWindowsDisplayGeometries()) {
934
822
  return geometries.map((display)=>({
935
823
  id: display.id,
@@ -1033,13 +921,23 @@ function getDisplayInfoBinary() {
1033
921
  displayInfoBinaryPath = binPath;
1034
922
  return binPath;
1035
923
  }
1036
- function device_isFiniteNumber(value) {
924
+ function isFiniteNumber(value) {
1037
925
  return 'number' == typeof value && Number.isFinite(value);
1038
926
  }
927
+ function isDisplayBounds(value) {
928
+ if (!value || 'object' != typeof value) return false;
929
+ const bounds = value;
930
+ return isFiniteNumber(bounds.x) && isFiniteNumber(bounds.y) && isFiniteNumber(bounds.width) && isFiniteNumber(bounds.height) && bounds.width > 0 && bounds.height > 0;
931
+ }
932
+ function isWindowsDisplayGeometry(value) {
933
+ if (!value || 'object' != typeof value) return false;
934
+ const candidate = value;
935
+ return 'string' == typeof candidate.id && candidate.id.length > 0 && 'string' == typeof candidate.name && 'boolean' == typeof candidate.primary && isDisplayBounds(candidate.bounds);
936
+ }
1039
937
  function isDarwinDisplayGeometry(value) {
1040
938
  if (!value || 'object' != typeof value) return false;
1041
939
  const candidate = value;
1042
- return Number.isInteger(candidate.screenIndex) && Number.isInteger(candidate.cgDisplayId) && 'boolean' == typeof candidate.primary && !!candidate.bounds && device_isFiniteNumber(candidate.bounds.x) && device_isFiniteNumber(candidate.bounds.y) && device_isFiniteNumber(candidate.bounds.width) && device_isFiniteNumber(candidate.bounds.height);
940
+ return Number.isInteger(candidate.screenIndex) && Number.isInteger(candidate.cgDisplayId) && 'boolean' == typeof candidate.primary && !!candidate.bounds && isFiniteNumber(candidate.bounds.x) && isFiniteNumber(candidate.bounds.y) && isFiniteNumber(candidate.bounds.width) && isFiniteNumber(candidate.bounds.height);
1043
941
  }
1044
942
  function readDarwinDisplayGeometries() {
1045
943
  const bin = getDisplayInfoBinary();
@@ -1109,6 +1007,11 @@ function resolveDarwinDisplayGeometryFromList(displayId, displays) {
1109
1007
  if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays.find((display)=>0 === display.screenIndex) || displays[0];
1110
1008
  return displays.find((display)=>display.screenIndex === screenIndex) || displays.find((display)=>display.cgDisplayId === screenIndex);
1111
1009
  }
1010
+ function resolveWindowsDisplayGeometryFromList(displayId, displays) {
1011
+ if (!displays.length) return;
1012
+ if (void 0 === displayId || '' === displayId) return displays.find((display)=>display.primary) || displays[0];
1013
+ return displays.find((display)=>display.id === displayId);
1014
+ }
1112
1015
  function resolveDisplayGeometry(displayId, windowsDisplays) {
1113
1016
  if ('darwin' === process.platform) return resolveDarwinDisplayGeometryFromList(displayId, readDarwinDisplayGeometries());
1114
1017
  if ('win32' === process.platform) {
@@ -1201,24 +1104,13 @@ function normalizePrimaryKey(key) {
1201
1104
  return KEY_NAME_MAP[lowerKey] || lowerKey;
1202
1105
  }
1203
1106
  class ComputerDevice {
1204
- usesPhysicalWindowsCoordinates() {
1205
- return 'win32' === process.platform && 'physical' === this.windowsCoordinateContext.mode;
1206
- }
1207
- assertLegacyWindowsCoordinateCompatibility(screenshotBase64) {
1208
- if ('win32' !== process.platform || 'legacy' !== this.windowsCoordinateContext.mode) return;
1209
- assertLegacyWindowsCoordinateCompatibility({
1210
- geometry: this.displayGeometry,
1211
- screenshotBase64,
1212
- inputSize: this.inputDriver.getScreenSize()
1213
- });
1214
- }
1215
1107
  async moveGlobalPointer(point, context, smooth) {
1216
1108
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
1217
1109
  const target = {
1218
1110
  x: Math.round(point.x),
1219
1111
  y: Math.round(point.y)
1220
1112
  };
1221
- if (this.usesPhysicalWindowsCoordinates()) {
1113
+ if ('win32' === process.platform) {
1222
1114
  const actual = this.windowsPointerDriver.moveTo(target, {
1223
1115
  smoothSteps: smooth?.smoothSteps,
1224
1116
  smoothDelayMs: smooth?.smoothDelay
@@ -1270,7 +1162,7 @@ class ComputerDevice {
1270
1162
  }
1271
1163
  static async listDisplays() {
1272
1164
  try {
1273
- if ('win32' === process.platform) return listWindowsDisplays(discoverWindowsDisplays().geometries);
1165
+ if ('win32' === process.platform) return listWindowsDisplays();
1274
1166
  const displays = await screenshot_desktop.listDisplays();
1275
1167
  return displays.map((d)=>({
1276
1168
  id: String(d.id),
@@ -1308,14 +1200,7 @@ class ComputerDevice {
1308
1200
  }
1309
1201
  }
1310
1202
  device_libnut = await getLibnut();
1311
- const windowsDisplayDiscovery = 'win32' === process.platform ? discoverWindowsDisplays() : void 0;
1312
- const windowsDisplayGeometries = windowsDisplayDiscovery?.geometries;
1313
- if (windowsDisplayDiscovery?.coordinateMode === 'legacy') warnDevice('Windows display enumeration returned no data in the Per-Monitor V2 DPI context; using the legacy Windows coordinate path for this device connection.');
1314
- this.windowsCoordinateContext = windowsDisplayDiscovery?.coordinateMode === 'legacy' ? {
1315
- mode: 'legacy'
1316
- } : {
1317
- mode: 'physical'
1318
- };
1203
+ const windowsDisplayGeometries = 'win32' === process.platform ? readWindowsDisplayGeometries() : void 0;
1319
1204
  this.displayGeometry = resolveDisplayGeometry(this.displayId, windowsDisplayGeometries);
1320
1205
  const size = await this.size();
1321
1206
  const displays = windowsDisplayGeometries ? listWindowsDisplays(windowsDisplayGeometries) : await ComputerDevice.listDisplays();
@@ -1326,7 +1211,6 @@ Platform: ${process.platform}
1326
1211
  Display: ${this.displayId || 'Primary'}
1327
1212
  Screen Size: ${size.width}x${size.height}
1328
1213
  Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ') : 'Unknown'}${headlessInfo}
1329
- ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordinateContext.mode}` : ''}
1330
1214
  `;
1331
1215
  debugDevice('Computer device connected', this.description);
1332
1216
  await this.healthCheck(displays);
@@ -1350,7 +1234,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1350
1234
  }
1351
1235
  async healthCheck(displays) {
1352
1236
  console.log('[HealthCheck] Starting health check...');
1353
- console.log("[HealthCheck] @midscene/computer v1.13.1-beta-20260921032526.0");
1237
+ console.log("[HealthCheck] @midscene/computer v1.13.1-beta-20260921075813.0");
1354
1238
  console.log('[HealthCheck] Taking screenshot...');
1355
1239
  const screenshotTimeout = 15000;
1356
1240
  let timeoutId;
@@ -1362,12 +1246,10 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1362
1246
  timeoutPromise
1363
1247
  ]);
1364
1248
  console.log(`[HealthCheck] Screenshot succeeded (length=${base64.length})`);
1365
- this.assertLegacyWindowsCoordinateCompatibility(base64);
1366
1249
  console.log('[HealthCheck] Verifying mouse control...');
1367
- const usePhysicalWindowsCoordinates = this.usesPhysicalWindowsCoordinates();
1368
- const startPos = usePhysicalWindowsCoordinates ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1250
+ const startPos = 'win32' === process.platform ? this.windowsPointerDriver.getPosition() : this.inputDriver.getMousePos();
1369
1251
  console.log(`[HealthCheck] Current mouse position: (${startPos.x}, ${startPos.y})`);
1370
- if (usePhysicalWindowsCoordinates) {
1252
+ if ('win32' === process.platform) {
1371
1253
  if (!this.displayGeometry) throw new Error('Windows display geometry is unavailable');
1372
1254
  const bounds = this.displayGeometry.bounds;
1373
1255
  const target = {
@@ -1433,7 +1315,7 @@ ${'win32' === process.platform ? `Windows Coordinate Mode: ${this.windowsCoordin
1433
1315
  debugDevice('Taking screenshot', {
1434
1316
  displayId: this.displayId
1435
1317
  });
1436
- if (this.usesPhysicalWindowsCoordinates()) return this.screenshotViaPowershell();
1318
+ if ('win32' === process.platform) return this.screenshotViaPowershell();
1437
1319
  const options = {
1438
1320
  format: 'png'
1439
1321
  };
@@ -1596,7 +1478,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1596
1478
  this.inputDriver.sendKey(key, modifiers);
1597
1479
  }
1598
1480
  resolveUntargetedScrollPoint(screenSize) {
1599
- if (this.usesPhysicalWindowsCoordinates()) {
1481
+ if ('win32' === process.platform) {
1600
1482
  const activeWindowRect = this.windowsPointerDriver.getActiveWindowRect();
1601
1483
  if (activeWindowRect) {
1602
1484
  const activeWindowCenter = {
@@ -1740,9 +1622,6 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1740
1622
  device_define_property(this, "options", void 0);
1741
1623
  device_define_property(this, "displayId", void 0);
1742
1624
  device_define_property(this, "displayGeometry", void 0);
1743
- device_define_property(this, "windowsCoordinateContext", {
1744
- mode: 'physical'
1745
- });
1746
1625
  device_define_property(this, "description", void 0);
1747
1626
  device_define_property(this, "destroyed", false);
1748
1627
  device_define_property(this, "xvfbInstance", void 0);
@@ -2844,7 +2723,7 @@ const tools = new ComputerMidsceneTools({
2844
2723
  });
2845
2724
  runToolsCLI(tools, 'midscene-computer', {
2846
2725
  stripPrefix: 'computer_',
2847
- version: "1.13.1-beta-20260921032526.0",
2726
+ version: "1.13.1-beta-20260921075813.0",
2848
2727
  extraCommands: createReportCliCommands()
2849
2728
  }).catch((e)=>{
2850
2729
  process.exit(reportCLIError(e));