@midscene/computer 1.12.7-beta-20260911063016.0 → 1.12.7

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/README.md CHANGED
@@ -1,53 +1,5 @@
1
1
  # @midscene/computer
2
2
 
3
- Midscene.js Computer Desktop Automation - AI-powered desktop automation for:
4
-
5
- - local desktop control on Windows, macOS, and Linux
6
- - remote Windows desktop control over the RDP protocol
3
+ Desktop automation library for Midscene, providing AI-powered testing and automation capabilities for Windows, macOS, and Linux, with RDP support for remote Windows desktops.
7
4
 
8
5
  See <https://midscenejs.com/platforms/desktop>.
9
-
10
- ## RDP support
11
-
12
- Use `agentForRDPComputer()`:
13
-
14
- ```ts
15
- import { agentForRDPComputer } from '@midscene/computer';
16
-
17
- const agent = await agentForRDPComputer({
18
- host: '10.0.0.10',
19
- username: 'Admin',
20
- password: 'secret',
21
- ignoreCertificate: true,
22
- });
23
- ```
24
-
25
- When the machine running Midscene has multiple outbound routes, pass
26
- `localAddress` to bind the RDP TCP connection to a specific local source IP:
27
-
28
- ```ts
29
- const agent = await agentForRDPComputer({
30
- host: '10.0.0.10',
31
- username: 'Admin',
32
- password: 'secret',
33
- localAddress: '10.0.0.20',
34
- ignoreCertificate: true,
35
- });
36
- ```
37
-
38
- RDP usage requires:
39
-
40
- - a reachable Windows machine with RDP enabled
41
- - [FreeRDP](https://www.freerdp.com/) installed on the machine running your script
42
-
43
- If you need to rebuild the native helper locally from source:
44
-
45
- ```bash
46
- pnpm --filter @midscene/computer run build:native
47
- ```
48
-
49
- Run RDP AI tests:
50
-
51
- ```bash
52
- pnpm --filter @midscene/computer run test:ai:rdp
53
- ```
Binary file
Binary file
package/dist/es/cli.mjs CHANGED
@@ -19,6 +19,73 @@ import node_assert from "node:assert";
19
19
  import { hasActiveCliInterruptWaiter } from "@midscene/shared/cli/interrupt";
20
20
  import { once } from "node:events";
21
21
  import { createInterface } from "node:readline";
22
+ const debugKeyboard = getDebug('computer:keyboard');
23
+ const APPLE_SCRIPT_KEY_CODES = {
24
+ return: 36,
25
+ enter: 36,
26
+ tab: 48,
27
+ space: 49,
28
+ backspace: 51,
29
+ delete: 51,
30
+ escape: 53,
31
+ forwarddelete: 117,
32
+ left: 123,
33
+ right: 124,
34
+ down: 125,
35
+ up: 126,
36
+ home: 115,
37
+ end: 119,
38
+ pageup: 116,
39
+ pagedown: 121,
40
+ f1: 122,
41
+ f2: 120,
42
+ f3: 99,
43
+ f4: 118,
44
+ f5: 96,
45
+ f6: 97,
46
+ f7: 98,
47
+ f8: 100,
48
+ f9: 101,
49
+ f10: 109,
50
+ f11: 103,
51
+ f12: 111
52
+ };
53
+ const APPLE_SCRIPT_MODIFIER_KEYS = {
54
+ command: 'command',
55
+ cmd: 'command',
56
+ control: 'control',
57
+ ctrl: 'control',
58
+ shift: 'shift',
59
+ alt: 'option',
60
+ option: 'option',
61
+ meta: 'command'
62
+ };
63
+ function buildKeyCommand(key) {
64
+ const keyCode = APPLE_SCRIPT_KEY_CODES[key.toLowerCase()];
65
+ if (void 0 !== keyCode) return `key code ${keyCode}`;
66
+ const escapedKey = key.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
67
+ return `keystroke "${escapedKey}"`;
68
+ }
69
+ function resolveModifierKeys(modifiers) {
70
+ return modifiers.map((modifier)=>APPLE_SCRIPT_MODIFIER_KEYS[modifier.toLowerCase()]).filter((modifier)=>void 0 !== modifier);
71
+ }
72
+ function buildAppleScriptKeyPress(key, modifiers = []) {
73
+ const modifierKeys = resolveModifierKeys(modifiers);
74
+ const modifierClause = modifierKeys.length ? ` using {${modifierKeys.map((modifier)=>`${modifier} down`).join(', ')}}` : '';
75
+ return `tell application "System Events" to ${buildKeyCommand(key)}${modifierClause}`;
76
+ }
77
+ function sendKeyViaAppleScript(key, modifiers = []) {
78
+ const script = buildAppleScriptKeyPress(key, modifiers);
79
+ debugKeyboard('sendKeyViaAppleScript', {
80
+ key,
81
+ modifiers,
82
+ script
83
+ });
84
+ execFileSync("osascript", [
85
+ '-e',
86
+ script
87
+ ]);
88
+ }
22
89
  function _define_property(obj, key, value) {
23
90
  if (key in obj) Object.defineProperty(obj, key, {
24
91
  value: value,
@@ -91,6 +158,41 @@ class ComputerInputDriver {
91
158
  if (void 0 !== modifiers) lib.keyTap(key, modifiers);
92
159
  else lib.keyTap(key);
93
160
  }
161
+ keyToggle(key, state, modifiers) {
162
+ const lib = this.getLibnutOrThrow('keyToggle');
163
+ if (void 0 !== modifiers) lib.keyToggle(key, state, modifiers);
164
+ else lib.keyToggle(key, state);
165
+ }
166
+ async keyTapWithModifierDelay(key, modifiers, delayMs) {
167
+ const uniqueModifiers = [
168
+ ...new Set(modifiers)
169
+ ];
170
+ if (0 === uniqueModifiers.length) return void this.keyTap(key);
171
+ if (0 === delayMs) return void this.keyTap(key, uniqueModifiers);
172
+ const pressedModifiers = [];
173
+ let failure;
174
+ try {
175
+ for (const modifier of uniqueModifiers){
176
+ this.keyToggle(modifier, 'down');
177
+ pressedModifiers.push(modifier);
178
+ await this.delay(delayMs);
179
+ }
180
+ this.keyTap(key);
181
+ await this.delay(delayMs);
182
+ } catch (error) {
183
+ failure = error;
184
+ }
185
+ for (const modifier of pressedModifiers.reverse()){
186
+ const releaseFailure = this.tryReleaseKey(modifier);
187
+ if (void 0 === failure && void 0 !== releaseFailure) failure = releaseFailure;
188
+ if (void 0 === failure) try {
189
+ await this.delay(delayMs);
190
+ } catch (error) {
191
+ failure = error;
192
+ }
193
+ }
194
+ if (void 0 !== failure) throw failure;
195
+ }
94
196
  typeString(text) {
95
197
  this.getLibnutOrThrow('typeString').typeString(text);
96
198
  }
@@ -163,6 +265,20 @@ class ComputerInputDriver {
163
265
  this.options.debug(`Failed to release mouse button ${button}: ${error}`);
164
266
  }
165
267
  }
268
+ tryReleaseKey(key) {
269
+ try {
270
+ const libnut = this.options.getLibnut();
271
+ node_assert(libnut, 'libnut not initialized');
272
+ libnut.keyToggle(key, 'up');
273
+ return;
274
+ } catch (error) {
275
+ const releaseError = new Error(`Failed to release modifier key "${key}"`, {
276
+ cause: error
277
+ });
278
+ this.options.debug(`${releaseError.message}: ${error}`);
279
+ return releaseError;
280
+ }
281
+ }
166
282
  rejectPendingInputDelays() {
167
283
  const error = this.createDestroyedError('in-flight input');
168
284
  for (const waitRef of this.pendingInputDelayWaits){
@@ -180,6 +296,96 @@ class ComputerInputDriver {
180
296
  this.pendingInputDelayWaits = new Set();
181
297
  }
182
298
  }
299
+ const US_SHIFTED_CHARACTER_KEYS = new Map([
300
+ [
301
+ '~',
302
+ '`'
303
+ ],
304
+ [
305
+ '!',
306
+ '1'
307
+ ],
308
+ [
309
+ '@',
310
+ '2'
311
+ ],
312
+ [
313
+ '#',
314
+ '3'
315
+ ],
316
+ [
317
+ '$',
318
+ '4'
319
+ ],
320
+ [
321
+ '%',
322
+ '5'
323
+ ],
324
+ [
325
+ '^',
326
+ '6'
327
+ ],
328
+ [
329
+ '&',
330
+ '7'
331
+ ],
332
+ [
333
+ '*',
334
+ '8'
335
+ ],
336
+ [
337
+ '(',
338
+ '9'
339
+ ],
340
+ [
341
+ ')',
342
+ '0'
343
+ ],
344
+ [
345
+ '_',
346
+ '-'
347
+ ],
348
+ [
349
+ '+',
350
+ '='
351
+ ],
352
+ [
353
+ '{',
354
+ '['
355
+ ],
356
+ [
357
+ '}',
358
+ ']'
359
+ ],
360
+ [
361
+ '|',
362
+ '\\'
363
+ ],
364
+ [
365
+ ':',
366
+ ';'
367
+ ],
368
+ [
369
+ '"',
370
+ "'"
371
+ ],
372
+ [
373
+ '<',
374
+ ','
375
+ ],
376
+ [
377
+ '>',
378
+ '.'
379
+ ],
380
+ [
381
+ '?',
382
+ '/'
383
+ ]
384
+ ]);
385
+ function resolveShiftedKey(character, keyboardLayout) {
386
+ if (/^[A-Z]$/.test(character)) return character.toLowerCase();
387
+ return 'en-US' === keyboardLayout ? US_SHIFTED_CHARACTER_KEYS.get(character) : void 0;
388
+ }
183
389
  const POWERSHELL_TIMEOUT_MS = 15000;
184
390
  const POWERSHELL_MAX_BUFFER = 67108864;
185
391
  const WINDOWS_PHYSICAL_PIXEL_POWERSHELL_PREAMBLE = `
@@ -543,92 +749,6 @@ const LIBNUT_FALLBACK_PIXELS_PER_DETENT = 100;
543
749
  const LIBNUT_FALLBACK_TICK_DELAY_MS = 30;
544
750
  const LIBNUT_FALLBACK_MAX_DETENTS = 200;
545
751
  const LIBNUT_FALLBACK_DETENT_AMOUNT = 'win32' === process.platform ? 120 : 1;
546
- const LINUX_SHIFTED_CHARACTER_KEYS = new Map([
547
- [
548
- '~',
549
- '`'
550
- ],
551
- [
552
- '!',
553
- '1'
554
- ],
555
- [
556
- '@',
557
- '2'
558
- ],
559
- [
560
- '#',
561
- '3'
562
- ],
563
- [
564
- '$',
565
- '4'
566
- ],
567
- [
568
- '%',
569
- '5'
570
- ],
571
- [
572
- '^',
573
- '6'
574
- ],
575
- [
576
- '&',
577
- '7'
578
- ],
579
- [
580
- '*',
581
- '8'
582
- ],
583
- [
584
- '(',
585
- '9'
586
- ],
587
- [
588
- ')',
589
- '0'
590
- ],
591
- [
592
- '_',
593
- '-'
594
- ],
595
- [
596
- '+',
597
- '='
598
- ],
599
- [
600
- '{',
601
- '['
602
- ],
603
- [
604
- '}',
605
- ']'
606
- ],
607
- [
608
- '|',
609
- '\\'
610
- ],
611
- [
612
- ':',
613
- ';'
614
- ],
615
- [
616
- '"',
617
- "'"
618
- ],
619
- [
620
- '<',
621
- ','
622
- ],
623
- [
624
- '>',
625
- '.'
626
- ],
627
- [
628
- '?',
629
- '/'
630
- ]
631
- ]);
632
752
  const LIBNUT_FALLBACK_EDGE_DETENTS = Math.min(LIBNUT_FALLBACK_MAX_DETENTS, Math.max(1, Math.ceil(EDGE_SCROLL_TOTAL_PX / LIBNUT_FALLBACK_PIXELS_PER_DETENT)));
633
753
  const DEFAULT_SCROLL_VIEWPORT_RATIO = 0.7;
634
754
  const EDGE_SCROLL_SPEC = {
@@ -665,67 +785,6 @@ const EDGE_SCROLL_SPEC = {
665
785
  ]
666
786
  }
667
787
  };
668
- const APPLESCRIPT_KEY_CODE_MAP = {
669
- return: 36,
670
- enter: 36,
671
- tab: 48,
672
- space: 49,
673
- backspace: 51,
674
- delete: 51,
675
- escape: 53,
676
- forwarddelete: 117,
677
- left: 123,
678
- right: 124,
679
- down: 125,
680
- up: 126,
681
- home: 115,
682
- end: 119,
683
- pageup: 116,
684
- pagedown: 121,
685
- f1: 122,
686
- f2: 120,
687
- f3: 99,
688
- f4: 118,
689
- f5: 96,
690
- f6: 97,
691
- f7: 98,
692
- f8: 100,
693
- f9: 101,
694
- f10: 109,
695
- f11: 103,
696
- f12: 111
697
- };
698
- const APPLESCRIPT_MODIFIER_MAP = {
699
- command: 'command down',
700
- cmd: 'command down',
701
- control: 'control down',
702
- ctrl: 'control down',
703
- shift: 'shift down',
704
- alt: 'option down',
705
- option: 'option down',
706
- meta: 'command down'
707
- };
708
- function sendKeyViaAppleScript(key, modifiers = []) {
709
- const lowerKey = key.toLowerCase();
710
- const keyCode = APPLESCRIPT_KEY_CODE_MAP[lowerKey];
711
- const modifierParts = modifiers.map((m)=>APPLESCRIPT_MODIFIER_MAP[m.toLowerCase()]).filter(Boolean);
712
- const modifierStr = modifierParts.length > 0 ? ` using {${modifierParts.join(', ')}}` : '';
713
- let script;
714
- if (void 0 !== keyCode) script = `tell application "System Events" to key code ${keyCode}${modifierStr}`;
715
- else {
716
- const escapedKey = key.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
717
- script = `tell application "System Events" to keystroke "${escapedKey}"${modifierStr}`;
718
- }
719
- debugDevice('sendKeyViaAppleScript', {
720
- key,
721
- modifiers,
722
- script
723
- });
724
- execFileSync("osascript", [
725
- '-e',
726
- script
727
- ]);
728
- }
729
788
  function escapePowershellSingleQuoted(value) {
730
789
  return value.replace(/'/g, "''");
731
790
  }
@@ -1153,7 +1212,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
1153
1212
  }
1154
1213
  async healthCheck(displays) {
1155
1214
  console.log('[HealthCheck] Starting health check...');
1156
- console.log("[HealthCheck] @midscene/computer v1.12.7-beta-20260911063016.0");
1215
+ console.log("[HealthCheck] @midscene/computer v1.12.7");
1157
1216
  console.log('[HealthCheck] Taking screenshot...');
1158
1217
  const screenshotTimeout = 15000;
1159
1218
  let timeoutId;
@@ -1330,9 +1389,9 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1330
1389
  ]);
1331
1390
  else {
1332
1391
  const modifier = 'darwin' === process.platform ? 'command' : 'control';
1333
- this.inputDriver.keyTap('v', [
1392
+ await this.inputDriver.keyTapWithModifierDelay('v', [
1334
1393
  modifier
1335
- ]);
1394
+ ], this.options?.keyboardModifierDelay ?? 0);
1336
1395
  }
1337
1396
  await this.inputDriver.delay(100);
1338
1397
  } finally{
@@ -1347,12 +1406,16 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1347
1406
  }
1348
1407
  async typeStringWithDelay(text, keyboardTypeDelay) {
1349
1408
  await sendTextSequentially(text.replace(/\r\n?/g, '\n'), {
1350
- sendCharacter: (character)=>{
1351
- const linuxShiftedKey = 'linux' === process.platform ? LINUX_SHIFTED_CHARACTER_KEYS.get(character) : void 0;
1409
+ sendCharacter: async (character)=>{
1410
+ const linuxShiftedKey = 'linux' === process.platform ? US_SHIFTED_CHARACTER_KEYS.get(character) : void 0;
1411
+ const pacedShiftedKey = !this.useAppleScript && (this.options?.keyboardModifierDelay ?? 0) > 0 ? resolveShiftedKey(character, this.options?.keyboardLayout) : void 0;
1352
1412
  if ('\n' === character) this.inputDriver.sendKey('return');
1353
1413
  else if ('\t' === character) this.inputDriver.sendKey('tab');
1354
1414
  else if (' ' === character) this.inputDriver.sendKey('space');
1355
1415
  else if (this.useAppleScript) this.inputDriver.sendKeyViaAppleScript(character);
1416
+ else if (void 0 !== pacedShiftedKey) await this.inputDriver.keyTapWithModifierDelay(pacedShiftedKey, [
1417
+ 'shift'
1418
+ ], this.options?.keyboardModifierDelay ?? 0);
1356
1419
  else if (void 0 !== linuxShiftedKey) this.inputDriver.keyTap(linuxShiftedKey, [
1357
1420
  'shift'
1358
1421
  ]);
@@ -1373,9 +1436,9 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1373
1436
  return;
1374
1437
  }
1375
1438
  const modifier = 'darwin' === process.platform ? 'command' : 'control';
1376
- this.inputDriver.keyTap('a', [
1439
+ await this.inputDriver.keyTapWithModifierDelay('a', [
1377
1440
  modifier
1378
- ]);
1441
+ ], this.options?.keyboardModifierDelay ?? 0);
1379
1442
  await this.inputDriver.delay(50);
1380
1443
  this.inputDriver.keyTap('backspace');
1381
1444
  }
@@ -1389,6 +1452,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1389
1452
  modifiers,
1390
1453
  driver: this.useAppleScript ? "applescript" : 'libnut'
1391
1454
  });
1455
+ if (!this.useAppleScript && modifiers.length > 0 && (this.options?.keyboardModifierDelay ?? 0) > 0) return void await this.inputDriver.keyTapWithModifierDelay(key, modifiers, this.options?.keyboardModifierDelay ?? 0);
1392
1456
  this.inputDriver.sendKey(key, modifiers);
1393
1457
  }
1394
1458
  resolveUntargetedScrollPoint(screenSize) {
@@ -1542,7 +1606,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1542
1606
  device_define_property(this, "inputDriver", new ComputerInputDriver({
1543
1607
  getLibnut: ()=>device_libnut,
1544
1608
  useAppleScript: ()=>this.useAppleScript,
1545
- sendKeyViaAppleScript,
1609
+ sendKeyViaAppleScript: sendKeyViaAppleScript,
1546
1610
  runPhasedScroll,
1547
1611
  debug: (message)=>debugDevice(message)
1548
1612
  }));
@@ -1668,6 +1732,8 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1668
1732
  }
1669
1733
  }
1670
1734
  });
1735
+ if (options?.keyboardModifierDelay !== void 0 && (!Number.isFinite(options.keyboardModifierDelay) || options.keyboardModifierDelay < 0)) throw new Error('keyboardModifierDelay must be a finite non-negative number');
1736
+ if (options?.keyboardLayout !== void 0 && 'en-US' !== options.keyboardLayout) throw new Error('keyboardLayout must be "en-US" when specified');
1671
1737
  this.options = options;
1672
1738
  this.displayId = options?.displayId;
1673
1739
  this.useAppleScript = 'darwin' === process.platform && options?.keyboardDriver !== 'libnut';
@@ -2370,6 +2436,8 @@ function createLocalComputerDevice(opts) {
2370
2436
  keyboardTypeDelay: opts?.keyboardTypeDelay,
2371
2437
  inputStrategy: opts?.inputStrategy,
2372
2438
  keyboardDriver: opts?.keyboardDriver,
2439
+ keyboardModifierDelay: opts?.keyboardModifierDelay,
2440
+ keyboardLayout: opts?.keyboardLayout,
2373
2441
  headless: opts?.headless,
2374
2442
  xvfbResolution: opts?.xvfbResolution,
2375
2443
  keepXvfbAliveUntilProcessExit: opts?.keepXvfbAliveUntilProcessExit
@@ -2427,6 +2495,10 @@ const computerInitArgShape = {
2427
2495
  headless: z.boolean().optional().describe('Start virtual display via Xvfb (Linux local mode only). Ignored when host is set.'),
2428
2496
  keyboardTypeDelay: z.number().finite().nonnegative().optional().describe('Finite non-negative delay in milliseconds between keystrokes. In "legacy" mode, positive values enable key-by-key input; zero or omitted uses clipboard input.'),
2429
2497
  inputStrategy: z["enum"](inputStrategies).optional().describe('Text input strategy. "legacy" (default) preserves current Computer behavior, "sequential" sends one Unicode code point at a time, and "bulk" uses one backend input operation. "bulk" requires keyboardTypeDelay to be omitted or set to 0.'),
2498
+ keyboardModifierDelay: z.number().finite().nonnegative().optional().describe('Finite non-negative delay in milliseconds after each modifier transition and the main key for local libnut keyboard events. Positive values pace shortcuts and the implicit Shift used by uppercase letters during sequential input. Layout-dependent punctuation also requires keyboardLayout. Ignored in RDP mode and by the macOS AppleScript driver.'),
2499
+ keyboardLayout: z["enum"]([
2500
+ 'en-US'
2501
+ ]).optional().describe('Keyboard layout used to resolve layout-dependent shifted punctuation to base keys during sequential local libnut input. Currently only "en-US" is supported. Ignored in RDP mode and by the macOS AppleScript driver.'),
2430
2502
  host: z.string().optional().describe('RDP host (FQDN or IP). Set this to switch into RDP mode.'),
2431
2503
  port: z.number().optional().describe('RDP port (default 3389). Requires host.'),
2432
2504
  username: z.string().optional().describe('RDP username. Requires host.'),
@@ -2443,7 +2515,7 @@ const computerInitArgShape = {
2443
2515
  function adaptComputerInitArgs(extracted) {
2444
2516
  if (!extracted || 0 === Object.keys(extracted).length) return;
2445
2517
  if (extracted.host) {
2446
- const { displayId: _d, headless: _h, ...rdpFields } = extracted;
2518
+ const { displayId: _d, headless: _h, keyboardModifierDelay: _s, keyboardLayout: _l, ...rdpFields } = extracted;
2447
2519
  const host = normalizeRdpHost(extracted.host);
2448
2520
  return {
2449
2521
  mode: 'rdp',
@@ -2457,6 +2529,8 @@ function adaptComputerInitArgs(extracted) {
2457
2529
  headless: extracted.headless,
2458
2530
  keyboardTypeDelay: extracted.keyboardTypeDelay,
2459
2531
  inputStrategy: extracted.inputStrategy,
2532
+ keyboardModifierDelay: extracted.keyboardModifierDelay,
2533
+ keyboardLayout: extracted.keyboardLayout,
2460
2534
  ...extractAgentBehaviorInitArgs(extracted) ?? {}
2461
2535
  };
2462
2536
  }
@@ -2508,6 +2582,8 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
2508
2582
  const headless = opts?.mode === 'local' ? opts.headless : void 0;
2509
2583
  const keyboardTypeDelay = opts?.keyboardTypeDelay;
2510
2584
  const inputStrategy = opts?.inputStrategy;
2585
+ const keyboardModifierDelay = opts?.mode === 'local' ? opts.keyboardModifierDelay : void 0;
2586
+ const keyboardLayout = opts?.mode === 'local' ? opts.keyboardLayout : void 0;
2511
2587
  agent_tools_debug('Creating Computer agent with displayId:', displayId || 'primary');
2512
2588
  const agentOpts = {
2513
2589
  ...displayId ? {
@@ -2522,6 +2598,12 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
2522
2598
  ...void 0 !== inputStrategy ? {
2523
2599
  inputStrategy
2524
2600
  } : {},
2601
+ ...void 0 !== keyboardModifierDelay ? {
2602
+ keyboardModifierDelay
2603
+ } : {},
2604
+ ...void 0 !== keyboardLayout ? {
2605
+ keyboardLayout
2606
+ } : {},
2525
2607
  ...this.options.keepXvfbAliveUntilProcessExit ? {
2526
2608
  keepXvfbAliveUntilProcessExit: true
2527
2609
  } : {},
@@ -2606,7 +2688,7 @@ const tools = new ComputerMidsceneTools({
2606
2688
  });
2607
2689
  runToolsCLI(tools, 'midscene-computer', {
2608
2690
  stripPrefix: 'computer_',
2609
- version: "1.12.7-beta-20260911063016.0",
2691
+ version: "1.12.7",
2610
2692
  extraCommands: createReportCliCommands()
2611
2693
  }).catch((e)=>{
2612
2694
  process.exit(reportCLIError(e));