@midscene/computer 1.12.4-beta-20260904041024.0 → 1.12.4

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
@@ -7,30 +7,6 @@ Midscene.js Computer Desktop Automation - AI-powered desktop automation for:
7
7
 
8
8
  See <https://midscenejs.com/platforms/desktop>.
9
9
 
10
- ## VNC keyboard input on macOS
11
-
12
- When Midscene runs on macOS and controls a foreground VNC client, enable
13
- physical keyboard events so modifier keys are sent as explicit key-down and
14
- key-up transitions. Text must also use sequential input; a positive
15
- `keyboardTypeDelay` enables that behavior in the default `legacy` input mode:
16
-
17
- ```ts
18
- import { agentForComputer } from '@midscene/computer';
19
-
20
- const agent = await agentForComputer({
21
- keyboardEventMode: 'physical',
22
- keyboardTypeDelay: 80,
23
- });
24
- ```
25
-
26
- The default `keyboardEventMode: 'logical'` keeps the standard AppleScript
27
- behavior for non-VNC applications. This option is ignored outside macOS and
28
- when `keyboardDriver` is set to `libnut`.
29
-
30
- Use `physical` only for a VNC client with matching en-US keyboard layouts. Its
31
- shifted-punctuation mapping is not layout-independent, and native macOS apps
32
- may interpret the base key directly—for example, `!@#` can become `123`.
33
-
34
10
  ## RDP support
35
11
 
36
12
  Use `agentForRDPComputer()`:
package/dist/es/cli.mjs CHANGED
@@ -19,210 +19,6 @@ 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
- const debugKeyboard = getDebug('computer:keyboard');
109
- const APPLE_SCRIPT_KEY_CODES = {
110
- return: 36,
111
- enter: 36,
112
- tab: 48,
113
- space: 49,
114
- backspace: 51,
115
- delete: 51,
116
- escape: 53,
117
- forwarddelete: 117,
118
- left: 123,
119
- right: 124,
120
- down: 125,
121
- up: 126,
122
- home: 115,
123
- end: 119,
124
- pageup: 116,
125
- pagedown: 121,
126
- f1: 122,
127
- f2: 120,
128
- f3: 99,
129
- f4: 118,
130
- f5: 96,
131
- f6: 97,
132
- f7: 98,
133
- f8: 100,
134
- f9: 101,
135
- f10: 109,
136
- f11: 103,
137
- f12: 111
138
- };
139
- const APPLE_SCRIPT_MODIFIER_KEYS = {
140
- command: 'command',
141
- cmd: 'command',
142
- control: 'control',
143
- ctrl: 'control',
144
- shift: 'shift',
145
- alt: 'option',
146
- option: 'option',
147
- meta: 'command'
148
- };
149
- function buildKeyCommand(key) {
150
- const keyCode = APPLE_SCRIPT_KEY_CODES[key.toLowerCase()];
151
- if (void 0 !== keyCode) return `key code ${keyCode}`;
152
- const escapedKey = key.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
153
- return `keystroke "${escapedKey}"`;
154
- }
155
- function resolveModifierKeys(modifiers) {
156
- return modifiers.map((modifier)=>APPLE_SCRIPT_MODIFIER_KEYS[modifier.toLowerCase()]).filter((modifier)=>void 0 !== modifier);
157
- }
158
- function buildLogicalKeyPress(key, modifiers) {
159
- const modifierKeys = resolveModifierKeys(modifiers);
160
- const modifierClause = modifierKeys.length ? ` using {${modifierKeys.map((modifier)=>`${modifier} down`).join(', ')}}` : '';
161
- return `tell application "System Events" to ${buildKeyCommand(key)}${modifierClause}`;
162
- }
163
- function resolvePhysicalKey(key, modifiers) {
164
- const resolvedModifiers = [
165
- ...modifiers
166
- ];
167
- const shiftedBaseKey = US_SHIFTED_CHARACTER_KEYS.get(key);
168
- if (/^[A-Z]$/.test(key)) {
169
- resolvedModifiers.push('shift');
170
- return {
171
- key: key.toLowerCase(),
172
- modifiers: resolvedModifiers
173
- };
174
- }
175
- if (void 0 !== shiftedBaseKey) {
176
- resolvedModifiers.push('shift');
177
- return {
178
- key: shiftedBaseKey,
179
- modifiers: resolvedModifiers
180
- };
181
- }
182
- return {
183
- key,
184
- modifiers: resolvedModifiers
185
- };
186
- }
187
- function buildPhysicalKeyPress(key, modifiers) {
188
- const resolved = resolvePhysicalKey(key, modifiers);
189
- const modifierKeys = [
190
- ...new Set(resolveModifierKeys(resolved.modifiers))
191
- ];
192
- const keyCommand = buildKeyCommand(resolved.key);
193
- if (0 === modifierKeys.length) return `tell application "System Events" to ${keyCommand}`;
194
- const releaseCommands = [
195
- ...modifierKeys
196
- ].reverse().map((modifier)=>`key up ${modifier}`);
197
- return [
198
- 'tell application "System Events"',
199
- 'try',
200
- ...modifierKeys.map((modifier)=>`key down ${modifier}`),
201
- keyCommand,
202
- 'on error errorMessage number errorNumber',
203
- ...releaseCommands,
204
- 'error errorMessage number errorNumber',
205
- 'end try',
206
- ...releaseCommands,
207
- 'end tell'
208
- ].join('\n');
209
- }
210
- function buildAppleScriptKeyPress(key, modifiers = [], eventMode = 'logical') {
211
- return 'physical' === eventMode ? buildPhysicalKeyPress(key, modifiers) : buildLogicalKeyPress(key, modifiers);
212
- }
213
- function sendKeyViaAppleScript(key, modifiers = [], eventMode = 'logical') {
214
- const script = buildAppleScriptKeyPress(key, modifiers, eventMode);
215
- debugKeyboard('sendKeyViaAppleScript', {
216
- key,
217
- modifiers,
218
- eventMode,
219
- script
220
- });
221
- execFileSync("osascript", [
222
- '-e',
223
- script
224
- ]);
225
- }
226
22
  function _define_property(obj, key, value) {
227
23
  if (key in obj) Object.defineProperty(obj, key, {
228
24
  value: value,
@@ -745,6 +541,92 @@ const LIBNUT_FALLBACK_PIXELS_PER_DETENT = 100;
745
541
  const LIBNUT_FALLBACK_TICK_DELAY_MS = 30;
746
542
  const LIBNUT_FALLBACK_MAX_DETENTS = 200;
747
543
  const LIBNUT_FALLBACK_DETENT_AMOUNT = 'win32' === process.platform ? 120 : 1;
544
+ const LINUX_SHIFTED_CHARACTER_KEYS = new Map([
545
+ [
546
+ '~',
547
+ '`'
548
+ ],
549
+ [
550
+ '!',
551
+ '1'
552
+ ],
553
+ [
554
+ '@',
555
+ '2'
556
+ ],
557
+ [
558
+ '#',
559
+ '3'
560
+ ],
561
+ [
562
+ '$',
563
+ '4'
564
+ ],
565
+ [
566
+ '%',
567
+ '5'
568
+ ],
569
+ [
570
+ '^',
571
+ '6'
572
+ ],
573
+ [
574
+ '&',
575
+ '7'
576
+ ],
577
+ [
578
+ '*',
579
+ '8'
580
+ ],
581
+ [
582
+ '(',
583
+ '9'
584
+ ],
585
+ [
586
+ ')',
587
+ '0'
588
+ ],
589
+ [
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
+ ]);
748
630
  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)));
749
631
  const DEFAULT_SCROLL_VIEWPORT_RATIO = 0.7;
750
632
  const EDGE_SCROLL_SPEC = {
@@ -781,6 +663,67 @@ const EDGE_SCROLL_SPEC = {
781
663
  ]
782
664
  }
783
665
  };
666
+ const APPLESCRIPT_KEY_CODE_MAP = {
667
+ return: 36,
668
+ enter: 36,
669
+ tab: 48,
670
+ space: 49,
671
+ backspace: 51,
672
+ delete: 51,
673
+ escape: 53,
674
+ forwarddelete: 117,
675
+ left: 123,
676
+ right: 124,
677
+ down: 125,
678
+ up: 126,
679
+ home: 115,
680
+ end: 119,
681
+ pageup: 116,
682
+ pagedown: 121,
683
+ f1: 122,
684
+ f2: 120,
685
+ f3: 99,
686
+ f4: 118,
687
+ f5: 96,
688
+ f6: 97,
689
+ f7: 98,
690
+ f8: 100,
691
+ f9: 101,
692
+ f10: 109,
693
+ f11: 103,
694
+ f12: 111
695
+ };
696
+ const APPLESCRIPT_MODIFIER_MAP = {
697
+ command: 'command down',
698
+ cmd: 'command down',
699
+ control: 'control down',
700
+ ctrl: 'control down',
701
+ shift: 'shift down',
702
+ alt: 'option down',
703
+ option: 'option down',
704
+ meta: 'command down'
705
+ };
706
+ function sendKeyViaAppleScript(key, modifiers = []) {
707
+ const lowerKey = key.toLowerCase();
708
+ const keyCode = APPLESCRIPT_KEY_CODE_MAP[lowerKey];
709
+ const modifierParts = modifiers.map((m)=>APPLESCRIPT_MODIFIER_MAP[m.toLowerCase()]).filter(Boolean);
710
+ const modifierStr = modifierParts.length > 0 ? ` using {${modifierParts.join(', ')}}` : '';
711
+ let script;
712
+ if (void 0 !== keyCode) script = `tell application "System Events" to key code ${keyCode}${modifierStr}`;
713
+ else {
714
+ const escapedKey = key.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
715
+ script = `tell application "System Events" to keystroke "${escapedKey}"${modifierStr}`;
716
+ }
717
+ debugDevice('sendKeyViaAppleScript', {
718
+ key,
719
+ modifiers,
720
+ script
721
+ });
722
+ execFileSync("osascript", [
723
+ '-e',
724
+ script
725
+ ]);
726
+ }
784
727
  function escapePowershellSingleQuoted(value) {
785
728
  return value.replace(/'/g, "''");
786
729
  }
@@ -1208,7 +1151,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
1208
1151
  }
1209
1152
  async healthCheck(displays) {
1210
1153
  console.log('[HealthCheck] Starting health check...');
1211
- console.log("[HealthCheck] @midscene/computer v1.12.4-beta-20260904041024.0");
1154
+ console.log("[HealthCheck] @midscene/computer v1.12.4");
1212
1155
  console.log('[HealthCheck] Taking screenshot...');
1213
1156
  const screenshotTimeout = 15000;
1214
1157
  let timeoutId;
@@ -1403,7 +1346,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1403
1346
  async typeStringWithDelay(text, keyboardTypeDelay) {
1404
1347
  await sendTextSequentially(text.replace(/\r\n?/g, '\n'), {
1405
1348
  sendCharacter: (character)=>{
1406
- const linuxShiftedKey = 'linux' === process.platform ? US_SHIFTED_CHARACTER_KEYS.get(character) : void 0;
1349
+ const linuxShiftedKey = 'linux' === process.platform ? LINUX_SHIFTED_CHARACTER_KEYS.get(character) : void 0;
1407
1350
  if ('\n' === character) this.inputDriver.sendKey('return');
1408
1351
  else if ('\t' === character) this.inputDriver.sendKey('tab');
1409
1352
  else if (' ' === character) this.inputDriver.sendKey('space');
@@ -1597,7 +1540,7 @@ $g.Dispose(); $bmp.Dispose(); $ms.Dispose()
1597
1540
  device_define_property(this, "inputDriver", new ComputerInputDriver({
1598
1541
  getLibnut: ()=>device_libnut,
1599
1542
  useAppleScript: ()=>this.useAppleScript,
1600
- sendKeyViaAppleScript: (key, modifiers)=>sendKeyViaAppleScript(key, modifiers, this.options?.keyboardEventMode ?? 'logical'),
1543
+ sendKeyViaAppleScript,
1601
1544
  runPhasedScroll,
1602
1545
  debug: (message)=>debugDevice(message)
1603
1546
  }));
@@ -2422,7 +2365,6 @@ function createLocalComputerDevice(opts) {
2422
2365
  keyboardTypeDelay: opts?.keyboardTypeDelay,
2423
2366
  inputStrategy: opts?.inputStrategy,
2424
2367
  keyboardDriver: opts?.keyboardDriver,
2425
- keyboardEventMode: opts?.keyboardEventMode,
2426
2368
  headless: opts?.headless,
2427
2369
  xvfbResolution: opts?.xvfbResolution,
2428
2370
  keepXvfbAliveUntilProcessExit: opts?.keepXvfbAliveUntilProcessExit
@@ -2480,10 +2422,6 @@ const computerInitArgShape = {
2480
2422
  headless: z.boolean().optional().describe('Start virtual display via Xvfb (Linux local mode only). Ignored when host is set.'),
2481
2423
  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.'),
2482
2424
  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.'),
2483
- keyboardEventMode: z["enum"]([
2484
- 'logical',
2485
- 'physical'
2486
- ]).optional().describe('macOS AppleScript keyboard event mode for local control. "logical" (default) targets native apps; "physical" is only for VNC clients, 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.'),
2487
2425
  host: z.string().optional().describe('RDP host (FQDN or IP). Set this to switch into RDP mode.'),
2488
2426
  port: z.number().optional().describe('RDP port (default 3389). Requires host.'),
2489
2427
  username: z.string().optional().describe('RDP username. Requires host.'),
@@ -2500,7 +2438,7 @@ const computerInitArgShape = {
2500
2438
  function adaptComputerInitArgs(extracted) {
2501
2439
  if (!extracted || 0 === Object.keys(extracted).length) return;
2502
2440
  if (extracted.host) {
2503
- const { displayId: _d, headless: _h, keyboardEventMode: _k, ...rdpFields } = extracted;
2441
+ const { displayId: _d, headless: _h, ...rdpFields } = extracted;
2504
2442
  const host = normalizeRdpHost(extracted.host);
2505
2443
  return {
2506
2444
  mode: 'rdp',
@@ -2514,7 +2452,6 @@ function adaptComputerInitArgs(extracted) {
2514
2452
  headless: extracted.headless,
2515
2453
  keyboardTypeDelay: extracted.keyboardTypeDelay,
2516
2454
  inputStrategy: extracted.inputStrategy,
2517
- keyboardEventMode: extracted.keyboardEventMode,
2518
2455
  ...extractAgentBehaviorInitArgs(extracted) ?? {}
2519
2456
  };
2520
2457
  }
@@ -2566,7 +2503,6 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
2566
2503
  const headless = opts?.mode === 'local' ? opts.headless : void 0;
2567
2504
  const keyboardTypeDelay = opts?.keyboardTypeDelay;
2568
2505
  const inputStrategy = opts?.inputStrategy;
2569
- const keyboardEventMode = opts?.mode === 'local' ? opts.keyboardEventMode : void 0;
2570
2506
  agent_tools_debug('Creating Computer agent with displayId:', displayId || 'primary');
2571
2507
  const agentOpts = {
2572
2508
  ...displayId ? {
@@ -2581,9 +2517,6 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
2581
2517
  ...void 0 !== inputStrategy ? {
2582
2518
  inputStrategy
2583
2519
  } : {},
2584
- ...void 0 !== keyboardEventMode ? {
2585
- keyboardEventMode
2586
- } : {},
2587
2520
  ...this.options.keepXvfbAliveUntilProcessExit ? {
2588
2521
  keepXvfbAliveUntilProcessExit: true
2589
2522
  } : {},
@@ -2668,7 +2601,7 @@ const tools = new ComputerMidsceneTools({
2668
2601
  });
2669
2602
  runToolsCLI(tools, 'midscene-computer', {
2670
2603
  stripPrefix: 'computer_',
2671
- version: "1.12.4-beta-20260904041024.0",
2604
+ version: "1.12.4",
2672
2605
  extraCommands: createReportCliCommands()
2673
2606
  }).catch((e)=>{
2674
2607
  process.exit(reportCLIError(e));