@midscene/computer 1.12.5 → 1.12.6-beta-20260909033030.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/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
- ```
package/dist/es/cli.mjs CHANGED
@@ -19,6 +19,207 @@ 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 US_SHIFTED_CHARACTER_KEYS = new Map([
23
+ [
24
+ '~',
25
+ '`'
26
+ ],
27
+ [
28
+ '!',
29
+ '1'
30
+ ],
31
+ [
32
+ '@',
33
+ '2'
34
+ ],
35
+ [
36
+ '#',
37
+ '3'
38
+ ],
39
+ [
40
+ '$',
41
+ '4'
42
+ ],
43
+ [
44
+ '%',
45
+ '5'
46
+ ],
47
+ [
48
+ '^',
49
+ '6'
50
+ ],
51
+ [
52
+ '&',
53
+ '7'
54
+ ],
55
+ [
56
+ '*',
57
+ '8'
58
+ ],
59
+ [
60
+ '(',
61
+ '9'
62
+ ],
63
+ [
64
+ ')',
65
+ '0'
66
+ ],
67
+ [
68
+ '_',
69
+ '-'
70
+ ],
71
+ [
72
+ '+',
73
+ '='
74
+ ],
75
+ [
76
+ '{',
77
+ '['
78
+ ],
79
+ [
80
+ '}',
81
+ ']'
82
+ ],
83
+ [
84
+ '|',
85
+ '\\'
86
+ ],
87
+ [
88
+ ':',
89
+ ';'
90
+ ],
91
+ [
92
+ '"',
93
+ "'"
94
+ ],
95
+ [
96
+ '<',
97
+ ','
98
+ ],
99
+ [
100
+ '>',
101
+ '.'
102
+ ],
103
+ [
104
+ '?',
105
+ '/'
106
+ ]
107
+ ]);
108
+ function resolveUSShiftedKey(character) {
109
+ if (/^[A-Z]$/.test(character)) return character.toLowerCase();
110
+ return US_SHIFTED_CHARACTER_KEYS.get(character);
111
+ }
112
+ const debugKeyboard = getDebug('computer:keyboard');
113
+ const APPLE_SCRIPT_KEY_CODES = {
114
+ return: 36,
115
+ enter: 36,
116
+ tab: 48,
117
+ space: 49,
118
+ backspace: 51,
119
+ delete: 51,
120
+ escape: 53,
121
+ forwarddelete: 117,
122
+ left: 123,
123
+ right: 124,
124
+ down: 125,
125
+ up: 126,
126
+ home: 115,
127
+ end: 119,
128
+ pageup: 116,
129
+ pagedown: 121,
130
+ f1: 122,
131
+ f2: 120,
132
+ f3: 99,
133
+ f4: 118,
134
+ f5: 96,
135
+ f6: 97,
136
+ f7: 98,
137
+ f8: 100,
138
+ f9: 101,
139
+ f10: 109,
140
+ f11: 103,
141
+ f12: 111
142
+ };
143
+ const APPLE_SCRIPT_MODIFIER_KEYS = {
144
+ command: 'command',
145
+ cmd: 'command',
146
+ control: 'control',
147
+ ctrl: 'control',
148
+ shift: 'shift',
149
+ alt: 'option',
150
+ option: 'option',
151
+ meta: 'command'
152
+ };
153
+ function buildKeyCommand(key) {
154
+ const keyCode = APPLE_SCRIPT_KEY_CODES[key.toLowerCase()];
155
+ if (void 0 !== keyCode) return `key code ${keyCode}`;
156
+ const escapedKey = key.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
157
+ return `keystroke "${escapedKey}"`;
158
+ }
159
+ function resolveModifierKeys(modifiers) {
160
+ return modifiers.map((modifier)=>APPLE_SCRIPT_MODIFIER_KEYS[modifier.toLowerCase()]).filter((modifier)=>void 0 !== modifier);
161
+ }
162
+ function buildLogicalKeyPress(key, modifiers) {
163
+ const modifierKeys = resolveModifierKeys(modifiers);
164
+ const modifierClause = modifierKeys.length ? ` using {${modifierKeys.map((modifier)=>`${modifier} down`).join(', ')}}` : '';
165
+ return `tell application "System Events" to ${buildKeyCommand(key)}${modifierClause}`;
166
+ }
167
+ function resolvePhysicalKey(key, modifiers) {
168
+ const resolvedModifiers = [
169
+ ...modifiers
170
+ ];
171
+ const shiftedBaseKey = resolveUSShiftedKey(key);
172
+ if (void 0 !== shiftedBaseKey) {
173
+ resolvedModifiers.push('shift');
174
+ return {
175
+ key: shiftedBaseKey,
176
+ modifiers: resolvedModifiers
177
+ };
178
+ }
179
+ return {
180
+ key,
181
+ modifiers: resolvedModifiers
182
+ };
183
+ }
184
+ function buildPhysicalKeyPress(key, modifiers) {
185
+ const resolved = resolvePhysicalKey(key, modifiers);
186
+ const modifierKeys = [
187
+ ...new Set(resolveModifierKeys(resolved.modifiers))
188
+ ];
189
+ const keyCommand = buildKeyCommand(resolved.key);
190
+ if (0 === modifierKeys.length) return `tell application "System Events" to ${keyCommand}`;
191
+ const releaseCommands = [
192
+ ...modifierKeys
193
+ ].reverse().map((modifier)=>`key up ${modifier}`);
194
+ return [
195
+ 'tell application "System Events"',
196
+ 'try',
197
+ ...modifierKeys.map((modifier)=>`key down ${modifier}`),
198
+ keyCommand,
199
+ 'on error errorMessage number errorNumber',
200
+ ...releaseCommands,
201
+ 'error errorMessage number errorNumber',
202
+ 'end try',
203
+ ...releaseCommands,
204
+ 'end tell'
205
+ ].join('\n');
206
+ }
207
+ function buildAppleScriptKeyPress(key, modifiers = [], eventMode = 'logical') {
208
+ return 'physical' === eventMode ? buildPhysicalKeyPress(key, modifiers) : buildLogicalKeyPress(key, modifiers);
209
+ }
210
+ function sendKeyViaAppleScript(key, modifiers = [], eventMode = 'logical') {
211
+ const script = buildAppleScriptKeyPress(key, modifiers, eventMode);
212
+ debugKeyboard('sendKeyViaAppleScript', {
213
+ key,
214
+ modifiers,
215
+ eventMode,
216
+ script
217
+ });
218
+ execFileSync("osascript", [
219
+ '-e',
220
+ script
221
+ ]);
222
+ }
22
223
  function _define_property(obj, key, value) {
23
224
  if (key in obj) Object.defineProperty(obj, key, {
24
225
  value: value,
@@ -91,6 +292,29 @@ class ComputerInputDriver {
91
292
  if (void 0 !== modifiers) lib.keyTap(key, modifiers);
92
293
  else lib.keyTap(key);
93
294
  }
295
+ keyToggle(key, state, modifiers) {
296
+ const lib = this.getLibnutOrThrow('keyToggle');
297
+ if (void 0 !== modifiers) lib.keyToggle(key, state, modifiers);
298
+ else lib.keyToggle(key, state);
299
+ }
300
+ async keyTapWithExplicitModifiers(key, modifiers, delayMs) {
301
+ const uniqueModifiers = [
302
+ ...new Set(modifiers)
303
+ ];
304
+ if (0 === uniqueModifiers.length) return void this.keyTap(key);
305
+ const pressedModifiers = [];
306
+ try {
307
+ for (const modifier of uniqueModifiers){
308
+ this.keyToggle(modifier, 'down');
309
+ pressedModifiers.push(modifier);
310
+ }
311
+ await this.delay(delayMs);
312
+ this.keyTap(key);
313
+ await this.delay(delayMs);
314
+ } finally{
315
+ for (const modifier of pressedModifiers.reverse())this.releaseKey(modifier);
316
+ }
317
+ }
94
318
  typeString(text) {
95
319
  this.getLibnutOrThrow('typeString').typeString(text);
96
320
  }
@@ -163,6 +387,15 @@ class ComputerInputDriver {
163
387
  this.options.debug(`Failed to release mouse button ${button}: ${error}`);
164
388
  }
165
389
  }
390
+ releaseKey(key) {
391
+ try {
392
+ const libnut = this.options.getLibnut();
393
+ node_assert(libnut, 'libnut not initialized');
394
+ libnut.keyToggle(key, 'up');
395
+ } catch (error) {
396
+ this.options.debug(`Failed to release key ${key}: ${error}`);
397
+ }
398
+ }
166
399
  rejectPendingInputDelays() {
167
400
  const error = this.createDestroyedError('in-flight input');
168
401
  for (const waitRef of this.pendingInputDelayWaits){
@@ -543,92 +776,6 @@ const LIBNUT_FALLBACK_PIXELS_PER_DETENT = 100;
543
776
  const LIBNUT_FALLBACK_TICK_DELAY_MS = 30;
544
777
  const LIBNUT_FALLBACK_MAX_DETENTS = 200;
545
778
  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
779
  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
780
  const DEFAULT_SCROLL_VIEWPORT_RATIO = 0.7;
634
781
  const EDGE_SCROLL_SPEC = {
@@ -665,67 +812,6 @@ const EDGE_SCROLL_SPEC = {
665
812
  ]
666
813
  }
667
814
  };
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
815
  function escapePowershellSingleQuoted(value) {
730
816
  return value.replace(/'/g, "''");
731
817
  }
@@ -1153,7 +1239,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
1153
1239
  }
1154
1240
  async healthCheck(displays) {
1155
1241
  console.log('[HealthCheck] Starting health check...');
1156
- console.log("[HealthCheck] @midscene/computer v1.12.5");
1242
+ console.log("[HealthCheck] @midscene/computer v1.12.6-beta-20260909033030.0");
1157
1243
  console.log('[HealthCheck] Taking screenshot...');
1158
1244
  const screenshotTimeout = 15000;
1159
1245
  let timeoutId;
@@ -1330,7 +1416,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1330
1416
  ]);
1331
1417
  else {
1332
1418
  const modifier = 'darwin' === process.platform ? 'command' : 'control';
1333
- this.inputDriver.keyTap('v', [
1419
+ await this.sendLocalModifiedKey('v', [
1334
1420
  modifier
1335
1421
  ]);
1336
1422
  }
@@ -1347,12 +1433,16 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1347
1433
  }
1348
1434
  async typeStringWithDelay(text, keyboardTypeDelay) {
1349
1435
  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;
1436
+ sendCharacter: async (character)=>{
1437
+ const linuxShiftedKey = 'linux' === process.platform ? US_SHIFTED_CHARACTER_KEYS.get(character) : void 0;
1438
+ const pacedShiftedKey = !this.useAppleScript && (this.options?.keyboardShortcutDelay ?? 0) > 0 ? resolveUSShiftedKey(character) : void 0;
1352
1439
  if ('\n' === character) this.inputDriver.sendKey('return');
1353
1440
  else if ('\t' === character) this.inputDriver.sendKey('tab');
1354
1441
  else if (' ' === character) this.inputDriver.sendKey('space');
1355
1442
  else if (this.useAppleScript) this.inputDriver.sendKeyViaAppleScript(character);
1443
+ else if (void 0 !== pacedShiftedKey) await this.sendLocalModifiedKey(pacedShiftedKey, [
1444
+ 'shift'
1445
+ ]);
1356
1446
  else if (void 0 !== linuxShiftedKey) this.inputDriver.keyTap(linuxShiftedKey, [
1357
1447
  'shift'
1358
1448
  ]);
@@ -1373,12 +1463,17 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1373
1463
  return;
1374
1464
  }
1375
1465
  const modifier = 'darwin' === process.platform ? 'command' : 'control';
1376
- this.inputDriver.keyTap('a', [
1466
+ await this.sendLocalModifiedKey('a', [
1377
1467
  modifier
1378
1468
  ]);
1379
1469
  await this.inputDriver.delay(50);
1380
1470
  this.inputDriver.keyTap('backspace');
1381
1471
  }
1472
+ async sendLocalModifiedKey(key, modifiers) {
1473
+ const shortcutDelay = this.options?.keyboardShortcutDelay ?? 0;
1474
+ if (modifiers.length > 0 && shortcutDelay > 0) return void await this.inputDriver.keyTapWithExplicitModifiers(key, modifiers, shortcutDelay);
1475
+ this.inputDriver.keyTap(key, modifiers);
1476
+ }
1382
1477
  async pressKeyboardShortcut(keyName) {
1383
1478
  const keys = keyName.split('+');
1384
1479
  const modifiers = keys.slice(0, -1).map(normalizeKeyName);
@@ -1389,6 +1484,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1389
1484
  modifiers,
1390
1485
  driver: this.useAppleScript ? "applescript" : 'libnut'
1391
1486
  });
1487
+ if (!this.useAppleScript && modifiers.length > 0 && (this.options?.keyboardShortcutDelay ?? 0) > 0) return void await this.sendLocalModifiedKey(key, modifiers);
1392
1488
  this.inputDriver.sendKey(key, modifiers);
1393
1489
  }
1394
1490
  resolveUntargetedScrollPoint(screenSize) {
@@ -1542,7 +1638,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1542
1638
  device_define_property(this, "inputDriver", new ComputerInputDriver({
1543
1639
  getLibnut: ()=>device_libnut,
1544
1640
  useAppleScript: ()=>this.useAppleScript,
1545
- sendKeyViaAppleScript,
1641
+ sendKeyViaAppleScript: (key, modifiers)=>sendKeyViaAppleScript(key, modifiers, this.options?.keyboardEventMode ?? 'logical'),
1546
1642
  runPhasedScroll,
1547
1643
  debug: (message)=>debugDevice(message)
1548
1644
  }));
@@ -1668,6 +1764,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1668
1764
  }
1669
1765
  }
1670
1766
  });
1767
+ if (options?.keyboardShortcutDelay !== void 0 && (!Number.isFinite(options.keyboardShortcutDelay) || options.keyboardShortcutDelay < 0)) throw new Error('keyboardShortcutDelay must be a finite non-negative number');
1671
1768
  this.options = options;
1672
1769
  this.displayId = options?.displayId;
1673
1770
  this.useAppleScript = 'darwin' === process.platform && options?.keyboardDriver !== 'libnut';
@@ -2370,6 +2467,8 @@ function createLocalComputerDevice(opts) {
2370
2467
  keyboardTypeDelay: opts?.keyboardTypeDelay,
2371
2468
  inputStrategy: opts?.inputStrategy,
2372
2469
  keyboardDriver: opts?.keyboardDriver,
2470
+ keyboardEventMode: opts?.keyboardEventMode,
2471
+ keyboardShortcutDelay: opts?.keyboardShortcutDelay,
2373
2472
  headless: opts?.headless,
2374
2473
  xvfbResolution: opts?.xvfbResolution,
2375
2474
  keepXvfbAliveUntilProcessExit: opts?.keepXvfbAliveUntilProcessExit
@@ -2427,6 +2526,11 @@ const computerInitArgShape = {
2427
2526
  headless: z.boolean().optional().describe('Start virtual display via Xvfb (Linux local mode only). Ignored when host is set.'),
2428
2527
  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
2528
  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.'),
2529
+ keyboardEventMode: z["enum"]([
2530
+ 'logical',
2531
+ 'physical'
2532
+ ]).optional().describe('macOS AppleScript keyboard event mode for local control. "logical" (default) uses a compact keystroke command; "physical" sends explicit modifier transitions for foreground apps that require separate key state changes. Both modes use AppleScript, and "physical" is not hardware input. It assumes an en-US layout for shifted punctuation and requires sequential text input or a positive keyboardTypeDelay. Ignored in RDP mode and outside the macOS AppleScript driver.'),
2533
+ keyboardShortcutDelay: z.number().finite().nonnegative().optional().describe('Finite non-negative delay in milliseconds around modifier transitions for local libnut keyboard events. Positive values pace shortcuts and the implicit Shift used by uppercase or en-US punctuation during sequential input. Ignored in RDP mode and by the macOS AppleScript driver.'),
2430
2534
  host: z.string().optional().describe('RDP host (FQDN or IP). Set this to switch into RDP mode.'),
2431
2535
  port: z.number().optional().describe('RDP port (default 3389). Requires host.'),
2432
2536
  username: z.string().optional().describe('RDP username. Requires host.'),
@@ -2443,7 +2547,7 @@ const computerInitArgShape = {
2443
2547
  function adaptComputerInitArgs(extracted) {
2444
2548
  if (!extracted || 0 === Object.keys(extracted).length) return;
2445
2549
  if (extracted.host) {
2446
- const { displayId: _d, headless: _h, ...rdpFields } = extracted;
2550
+ const { displayId: _d, headless: _h, keyboardEventMode: _k, keyboardShortcutDelay: _s, ...rdpFields } = extracted;
2447
2551
  const host = normalizeRdpHost(extracted.host);
2448
2552
  return {
2449
2553
  mode: 'rdp',
@@ -2457,6 +2561,8 @@ function adaptComputerInitArgs(extracted) {
2457
2561
  headless: extracted.headless,
2458
2562
  keyboardTypeDelay: extracted.keyboardTypeDelay,
2459
2563
  inputStrategy: extracted.inputStrategy,
2564
+ keyboardEventMode: extracted.keyboardEventMode,
2565
+ keyboardShortcutDelay: extracted.keyboardShortcutDelay,
2460
2566
  ...extractAgentBehaviorInitArgs(extracted) ?? {}
2461
2567
  };
2462
2568
  }
@@ -2508,6 +2614,8 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
2508
2614
  const headless = opts?.mode === 'local' ? opts.headless : void 0;
2509
2615
  const keyboardTypeDelay = opts?.keyboardTypeDelay;
2510
2616
  const inputStrategy = opts?.inputStrategy;
2617
+ const keyboardEventMode = opts?.mode === 'local' ? opts.keyboardEventMode : void 0;
2618
+ const keyboardShortcutDelay = opts?.mode === 'local' ? opts.keyboardShortcutDelay : void 0;
2511
2619
  agent_tools_debug('Creating Computer agent with displayId:', displayId || 'primary');
2512
2620
  const agentOpts = {
2513
2621
  ...displayId ? {
@@ -2522,6 +2630,12 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
2522
2630
  ...void 0 !== inputStrategy ? {
2523
2631
  inputStrategy
2524
2632
  } : {},
2633
+ ...void 0 !== keyboardEventMode ? {
2634
+ keyboardEventMode
2635
+ } : {},
2636
+ ...void 0 !== keyboardShortcutDelay ? {
2637
+ keyboardShortcutDelay
2638
+ } : {},
2525
2639
  ...this.options.keepXvfbAliveUntilProcessExit ? {
2526
2640
  keepXvfbAliveUntilProcessExit: true
2527
2641
  } : {},
@@ -2606,7 +2720,7 @@ const tools = new ComputerMidsceneTools({
2606
2720
  });
2607
2721
  runToolsCLI(tools, 'midscene-computer', {
2608
2722
  stripPrefix: 'computer_',
2609
- version: "1.12.5",
2723
+ version: "1.12.6-beta-20260909033030.0",
2610
2724
  extraCommands: createReportCliCommands()
2611
2725
  }).catch((e)=>{
2612
2726
  process.exit(reportCLIError(e));