@midscene/computer 1.9.3-beta-20260610061213.0 → 1.9.3-beta-20260610071913.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
@@ -22,19 +22,6 @@ const agent = await agentForRDPComputer({
22
22
  });
23
23
  ```
24
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
25
  RDP usage requires:
39
26
 
40
27
  - a reachable Windows machine with RDP enabled
Binary file
Binary file
package/dist/es/cli.mjs CHANGED
@@ -40,6 +40,33 @@ class ComputerInputDriver {
40
40
  moveMouse(x, y) {
41
41
  this.getLibnutOrThrow('moveMouse').moveMouse(x, y);
42
42
  }
43
+ focusActiveWindow() {
44
+ const lib = this.getLibnutOrThrow('focusActiveWindow');
45
+ if ('function' != typeof lib.getActiveWindow || 'function' != typeof lib.focusWindow) return false;
46
+ try {
47
+ const handle = lib.getActiveWindow();
48
+ if (!handle) return false;
49
+ lib.focusWindow(handle);
50
+ return true;
51
+ } catch (error) {
52
+ this.options.debug(`focusActiveWindow failed: ${error}`);
53
+ return false;
54
+ }
55
+ }
56
+ getActiveWindowRect() {
57
+ const lib = this.getLibnutOrThrow('getActiveWindowRect');
58
+ if ('function' != typeof lib.getActiveWindow || 'function' != typeof lib.getWindowRect) return null;
59
+ try {
60
+ const handle = lib.getActiveWindow();
61
+ if (!handle) return null;
62
+ const rect = lib.getWindowRect(handle);
63
+ if (!Number.isFinite(rect.x) || !Number.isFinite(rect.y) || !Number.isFinite(rect.width) || !Number.isFinite(rect.height) || rect.width <= 0 || rect.height <= 0) return null;
64
+ return rect;
65
+ } catch (error) {
66
+ this.options.debug(`getActiveWindowRect failed: ${error}`);
67
+ return null;
68
+ }
69
+ }
43
70
  mouseClick(button, double) {
44
71
  const lib = this.getLibnutOrThrow('mouseClick');
45
72
  if (void 0 !== double) lib.mouseClick(button, double);
@@ -52,6 +79,13 @@ class ComputerInputDriver {
52
79
  scrollMouse(x, y) {
53
80
  this.getLibnutOrThrow('scrollMouse').scrollMouse(x, y);
54
81
  }
82
+ async emitScrollDetents(dx, dy, detents, delayMs) {
83
+ this.assertActive('emitScrollDetents');
84
+ for(let i = 0; i < detents; i++){
85
+ this.scrollMouse(dx, dy);
86
+ if (i < detents - 1) await this.delay(delayMs);
87
+ }
88
+ }
55
89
  keyTap(key, modifiers) {
56
90
  const lib = this.getLibnutOrThrow('keyTap');
57
91
  if (void 0 !== modifiers) lib.keyTap(key, modifiers);
@@ -230,13 +264,17 @@ const CLICK_HOLD_DURATION = 100;
230
264
  const CLICK_FOCUS_SETTLE_DELAY = 120;
231
265
  const INPUT_FOCUS_DELAY = 300;
232
266
  const INPUT_CLEAR_DELAY = 150;
233
- const SCROLL_REPEAT_COUNT = 10;
234
267
  const SCROLL_STEP_DELAY = 100;
235
268
  const SCROLL_COMPLETE_DELAY = 500;
236
269
  const EDGE_SCROLL_TOTAL_PX = 50000;
237
270
  const EDGE_SCROLL_STEPS = 400;
238
271
  const PHASED_PIXELS_PER_STEP = 30;
239
272
  const PHASED_MIN_STEPS = 10;
273
+ const LIBNUT_FALLBACK_PIXELS_PER_DETENT = 100;
274
+ const LIBNUT_FALLBACK_TICK_DELAY_MS = 30;
275
+ const LIBNUT_FALLBACK_MAX_DETENTS = 200;
276
+ const LIBNUT_FALLBACK_DETENT_AMOUNT = 'win32' === process.platform ? 120 : 1;
277
+ 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)));
240
278
  const DEFAULT_SCROLL_VIEWPORT_RATIO = 0.7;
241
279
  const EDGE_SCROLL_SPEC = {
242
280
  scrollToTop: {
@@ -244,7 +282,7 @@ const EDGE_SCROLL_SPEC = {
244
282
  key: 'home',
245
283
  libnut: [
246
284
  0,
247
- 10
285
+ 1
248
286
  ]
249
287
  },
250
288
  scrollToBottom: {
@@ -252,14 +290,14 @@ const EDGE_SCROLL_SPEC = {
252
290
  key: 'end',
253
291
  libnut: [
254
292
  0,
255
- -10
293
+ -1
256
294
  ]
257
295
  },
258
296
  scrollToLeft: {
259
297
  direction: 'left',
260
298
  key: 'home',
261
299
  libnut: [
262
- -10,
300
+ -1,
263
301
  0
264
302
  ]
265
303
  },
@@ -267,7 +305,7 @@ const EDGE_SCROLL_SPEC = {
267
305
  direction: 'right',
268
306
  key: 'end',
269
307
  libnut: [
270
- 10,
308
+ 1,
271
309
  0
272
310
  ]
273
311
  }
@@ -656,7 +694,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
656
694
  }
657
695
  async healthCheck() {
658
696
  console.log('[HealthCheck] Starting health check...');
659
- console.log("[HealthCheck] @midscene/computer v1.9.3-beta-20260610061213.0");
697
+ console.log("[HealthCheck] @midscene/computer v1.9.3-beta-20260610071913.0");
660
698
  console.log('[HealthCheck] Taking screenshot...');
661
699
  const screenshotTimeout = 15000;
662
700
  let timeoutId;
@@ -834,7 +872,20 @@ Original error: ${lastRawMessage}`);
834
872
  });
835
873
  this.inputDriver.sendKey(key, modifiers);
836
874
  }
837
- async performScroll(param) {
875
+ resolveUntargetedScrollPoint(screenSize) {
876
+ if ('win32' === process.platform) {
877
+ const activeWindowRect = this.inputDriver.getActiveWindowRect();
878
+ if (activeWindowRect) return {
879
+ x: activeWindowRect.x + activeWindowRect.width / 2,
880
+ y: activeWindowRect.y + activeWindowRect.height / 2
881
+ };
882
+ }
883
+ return this.toGlobalPoint({
884
+ x: screenSize.width / 2,
885
+ y: screenSize.height / 2
886
+ });
887
+ }
888
+ async moveMouseToScrollTarget(param) {
838
889
  if (param.locate) {
839
890
  const element = param.locate;
840
891
  const [x, y] = element.center;
@@ -843,7 +894,17 @@ Original error: ${lastRawMessage}`);
843
894
  y
844
895
  });
845
896
  this.inputDriver.moveMouse(Math.round(point.x), Math.round(point.y));
897
+ return;
846
898
  }
899
+ const screenSize = await this.size();
900
+ if ('win32' === process.platform && this.inputDriver.focusActiveWindow()) await this.inputDriver.delay(CLICK_FOCUS_SETTLE_DELAY);
901
+ const point = this.resolveUntargetedScrollPoint(screenSize);
902
+ this.inputDriver.moveMouse(Math.round(point.x), Math.round(point.y));
903
+ await this.inputDriver.delay(MOUSE_MOVE_EFFECT_WAIT);
904
+ return screenSize;
905
+ }
906
+ async performScroll(param) {
907
+ let screenSize = await this.moveMouseToScrollTarget(param);
847
908
  const scrollType = param?.scrollType;
848
909
  const edgeSpec = scrollType && scrollType in EDGE_SCROLL_SPEC ? EDGE_SCROLL_SPEC[scrollType] : null;
849
910
  if (edgeSpec) {
@@ -853,11 +914,8 @@ Original error: ${lastRawMessage}`);
853
914
  await this.inputDriver.delay(SCROLL_COMPLETE_DELAY);
854
915
  return;
855
916
  }
856
- const [dx, dy] = edgeSpec.libnut;
857
- for(let i = 0; i < SCROLL_REPEAT_COUNT; i++){
858
- this.inputDriver.scrollMouse(dx, dy);
859
- await this.inputDriver.delay(SCROLL_STEP_DELAY);
860
- }
917
+ const [ux, uy] = edgeSpec.libnut;
918
+ await this.inputDriver.emitScrollDetents(ux * LIBNUT_FALLBACK_DETENT_AMOUNT, uy * LIBNUT_FALLBACK_DETENT_AMOUNT, LIBNUT_FALLBACK_EDGE_DETENTS, LIBNUT_FALLBACK_TICK_DELAY_MS);
861
919
  return;
862
920
  }
863
921
  if ('singleAction' === scrollType || !scrollType) {
@@ -865,9 +923,8 @@ Original error: ${lastRawMessage}`);
865
923
  const isKnownDirection = 'up' === direction || 'down' === direction || 'left' === direction || 'right' === direction;
866
924
  const isHorizontal = 'left' === direction || 'right' === direction;
867
925
  let distance = param?.distance ?? void 0;
868
- let screenSize;
869
926
  if (!distance) {
870
- screenSize = await this.size();
927
+ screenSize ??= await this.size();
871
928
  const base = isHorizontal ? screenSize.width : screenSize.height;
872
929
  distance = Math.max(1, Math.round(base * DEFAULT_SCROLL_VIEWPORT_RATIO));
873
930
  }
@@ -886,30 +943,30 @@ Original error: ${lastRawMessage}`);
886
943
  await this.inputDriver.delay(SCROLL_COMPLETE_DELAY);
887
944
  return;
888
945
  }
889
- const ticks = Math.ceil(distance / 100);
890
- const directionMap = {
946
+ const detents = Math.min(LIBNUT_FALLBACK_MAX_DETENTS, Math.max(1, Math.ceil(distance / LIBNUT_FALLBACK_PIXELS_PER_DETENT)));
947
+ const directionUnit = {
891
948
  up: [
892
949
  0,
893
- ticks
950
+ 1
894
951
  ],
895
952
  down: [
896
953
  0,
897
- -ticks
954
+ -1
898
955
  ],
899
956
  left: [
900
- -ticks,
957
+ -1,
901
958
  0
902
959
  ],
903
960
  right: [
904
- ticks,
961
+ 1,
905
962
  0
906
963
  ]
907
964
  };
908
- const [dx, dy] = directionMap[direction] || [
965
+ const [ux, uy] = directionUnit[direction] || [
909
966
  0,
910
- -ticks
967
+ -1
911
968
  ];
912
- this.inputDriver.scrollMouse(dx, dy);
969
+ await this.inputDriver.emitScrollDetents(ux * LIBNUT_FALLBACK_DETENT_AMOUNT, uy * LIBNUT_FALLBACK_DETENT_AMOUNT, detents, LIBNUT_FALLBACK_TICK_DELAY_MS);
913
970
  await this.inputDriver.delay(SCROLL_COMPLETE_DELAY);
914
971
  return;
915
972
  }
@@ -1114,27 +1171,6 @@ function createPlatformActions() {
1114
1171
  })
1115
1172
  };
1116
1173
  }
1117
- function normalizeRdpHost(host) {
1118
- const trimmed = host.trim();
1119
- if (trimmed.length >= 2 && trimmed.startsWith('[') && trimmed.endsWith(']') && trimmed.includes(':')) return trimmed.slice(1, -1);
1120
- return trimmed;
1121
- }
1122
- function formatRdpHost(host) {
1123
- const normalizedHost = normalizeRdpHost(host);
1124
- return normalizedHost.includes(':') ? `[${normalizedHost}]` : normalizedHost;
1125
- }
1126
- function formatRdpServerAddress(host, port) {
1127
- return `${formatRdpHost(host)}:${port}`;
1128
- }
1129
- function normalizeRdpConnectionConfig(config) {
1130
- return {
1131
- ...config,
1132
- host: normalizeRdpHost(config.host),
1133
- ...config.localAddress ? {
1134
- localAddress: config.localAddress.trim()
1135
- } : {}
1136
- };
1137
- }
1138
1174
  const platformBinaryMap = {
1139
1175
  darwin: {
1140
1176
  directory: 'darwin',
@@ -1182,14 +1218,14 @@ function backend_client_define_property(obj, key, value) {
1182
1218
  }
1183
1219
  const debug = getDebug('rdp:backend');
1184
1220
  const HELPER_SHUTDOWN_TIMEOUT_MS = 3000;
1185
- const HELPER_WRITE_ERROR_DIAGNOSTIC_DELAY_MS = 50;
1186
- const MAX_STDERR_CHARS = 16384;
1221
+ const MAX_STDERR_LINES = 40;
1187
1222
  class HelperProcessRDPBackendClient {
1188
1223
  async connect(config) {
1189
1224
  this.fatalHelperError = void 0;
1225
+ await this.ensureHelperStarted();
1190
1226
  const response = await this.send({
1191
1227
  type: 'connect',
1192
- config: normalizeRdpConnectionConfig(config)
1228
+ config
1193
1229
  });
1194
1230
  if ('connected' !== response.type) throw new Error(`Expected connected response, got ${response.type}`);
1195
1231
  this.connected = true;
@@ -1273,8 +1309,8 @@ class HelperProcessRDPBackendClient {
1273
1309
  });
1274
1310
  this.expectOk(response, 'clearInput');
1275
1311
  }
1276
- ensureHelperStarted() {
1277
- if (this.child && null === this.child.exitCode) return this.child;
1312
+ async ensureHelperStarted() {
1313
+ if (this.child && null === this.child.exitCode) return;
1278
1314
  const helperPath = this.resolveHelperPath();
1279
1315
  debug('starting rdp helper', {
1280
1316
  helperPath
@@ -1289,111 +1325,66 @@ class HelperProcessRDPBackendClient {
1289
1325
  child.stdout.setEncoding('utf8');
1290
1326
  child.stderr.setEncoding('utf8');
1291
1327
  this.child = child;
1292
- const diagnostics = {
1293
- path: helperPath,
1294
- pid: child.pid,
1295
- stderrBuffer: ''
1296
- };
1297
- this.helperDiagnostics.set(child, diagnostics);
1298
- debug('started rdp helper', {
1299
- helperPath,
1300
- pid: child.pid
1301
- });
1328
+ this.stderrLines.length = 0;
1302
1329
  this.stdoutReader = createInterface({
1303
1330
  input: child.stdout,
1304
1331
  crlfDelay: 1 / 0
1305
1332
  });
1306
- this.stdoutReader.on('line', (line)=>{
1307
- this.handleStdoutLine(child, line, diagnostics);
1308
- });
1309
- child.stderr.on('data', (chunk)=>{
1310
- this.captureStderrChunk(chunk, diagnostics);
1311
- });
1312
- child.stdin.on('error', (error)=>{
1313
- this.handleHelperStreamError(child, 'stdin', error, diagnostics);
1333
+ this.stderrReader = createInterface({
1334
+ input: child.stderr,
1335
+ crlfDelay: 1 / 0
1314
1336
  });
1315
- child.stdout.on('error', (error)=>{
1316
- this.handleHelperStreamError(child, 'stdout', error, diagnostics);
1337
+ this.stdoutReader.on('line', (line)=>{
1338
+ this.handleStdoutLine(line);
1317
1339
  });
1318
- child.stderr.on('error', (error)=>{
1319
- this.handleHelperStreamError(child, 'stderr', error, diagnostics);
1340
+ this.stderrReader.on('line', (line)=>{
1341
+ this.captureStderrLine(line);
1320
1342
  });
1321
1343
  child.on('exit', (code, signal)=>{
1322
- diagnostics.exit = {
1323
- code,
1324
- signal
1325
- };
1326
- debug('rdp helper exited', {
1327
- helperPath: diagnostics.path,
1328
- pid: diagnostics.pid,
1329
- code,
1330
- signal
1331
- });
1332
- const helperError = this.createHelperError(`RDP helper exited unexpectedly (code=${code}, signal=${signal})`, void 0, diagnostics);
1333
- this.rejectPendingForChild(child, helperError);
1334
- if (this.child === child) {
1335
- this.connected = false;
1336
- this.fatalHelperError = helperError;
1337
- this.disposeReaders();
1338
- this.child = void 0;
1339
- }
1344
+ this.connected = false;
1345
+ const error = this.createHelperError(`RDP helper exited unexpectedly (code=${code}, signal=${signal})`);
1346
+ this.fatalHelperError = error;
1347
+ this.rejectPending(error);
1348
+ this.disposeReaders();
1349
+ this.child = void 0;
1340
1350
  });
1341
1351
  child.on('error', (error)=>{
1342
- const helperError = this.createHelperError(`Failed to start RDP helper: ${error.message}`, void 0, diagnostics);
1343
- this.rejectPendingForChild(child, helperError);
1344
- if (this.child === child) {
1345
- this.connected = false;
1346
- this.fatalHelperError = helperError;
1347
- this.disposeReaders();
1348
- this.child = void 0;
1349
- }
1352
+ this.connected = false;
1353
+ const helperError = this.createHelperError(`Failed to start RDP helper: ${error.message}`);
1354
+ this.fatalHelperError = helperError;
1355
+ this.rejectPending(helperError);
1356
+ this.disposeReaders();
1357
+ this.child = void 0;
1350
1358
  });
1351
- return child;
1352
- }
1353
- handleHelperStreamError(child, streamName, error, diagnostics) {
1354
- const nodeError = error;
1355
- const helperError = this.createHelperError(`RDP helper ${streamName} stream error: ${error.message}`, nodeError.code, diagnostics);
1356
- this.rejectPendingForChild(child, helperError);
1357
- if (this.child !== child) return;
1358
- this.connected = false;
1359
- this.fatalHelperError = helperError;
1360
- if (null === child.exitCode) child.kill('SIGTERM');
1361
- this.child = void 0;
1362
1359
  }
1363
- handleStdoutLine(child, line, diagnostics) {
1360
+ handleStdoutLine(line) {
1364
1361
  if (!line.trim()) return;
1365
1362
  let parsed;
1366
1363
  try {
1367
1364
  parsed = JSON.parse(line);
1368
1365
  } catch (error) {
1369
- const protocolError = this.createHelperError(`RDP helper emitted malformed JSON: ${line}`, void 0, diagnostics);
1370
- this.rejectPendingForChild(child, protocolError);
1371
- if (this.child === child) this.shutdownHelper(protocolError);
1366
+ const protocolError = this.createHelperError(`RDP helper emitted malformed JSON: ${line}`);
1367
+ this.rejectPending(protocolError);
1368
+ this.shutdownHelper(protocolError);
1372
1369
  return;
1373
1370
  }
1374
1371
  const pending = this.pending.get(parsed.id);
1375
1372
  if (!pending) return void debug('dropping response for unknown request id', parsed);
1376
1373
  this.pending.delete(parsed.id);
1377
1374
  if (parsed.ok) return void pending.resolve(parsed.payload);
1378
- pending.reject(this.createHelperError(parsed.error.message, parsed.error.code, diagnostics));
1379
- }
1380
- captureStderrChunk(chunk, diagnostics) {
1381
- const text = chunk.toString();
1382
- if (!text.trim()) return;
1383
- debug('rdp helper stderr', {
1384
- helperPath: diagnostics.path,
1385
- pid: diagnostics.pid,
1386
- stderr: text.trim()
1387
- });
1388
- diagnostics.stderrBuffer += text;
1389
- if (diagnostics.stderrBuffer.length > MAX_STDERR_CHARS) diagnostics.stderrBuffer = diagnostics.stderrBuffer.slice(-MAX_STDERR_CHARS);
1375
+ pending.reject(this.createHelperError(parsed.error.message, parsed.error.code));
1376
+ }
1377
+ captureStderrLine(line) {
1378
+ if (!line.trim()) return;
1379
+ this.stderrLines.push(line);
1380
+ if (this.stderrLines.length > MAX_STDERR_LINES) this.stderrLines.shift();
1390
1381
  }
1391
1382
  async send(payload) {
1392
1383
  if ('connect' !== payload.type && this.fatalHelperError && (!this.child || null !== this.child.exitCode)) throw this.fatalHelperError;
1393
- const child = this.ensureHelperStarted();
1394
- if (null !== child.exitCode) throw this.createHelperError('RDP helper is not running');
1384
+ await this.ensureHelperStarted();
1385
+ const child = this.child;
1386
+ if (!child || null !== child.exitCode) throw this.createHelperError('RDP helper is not running');
1395
1387
  const id = `req-${++this.nextRequestId}`;
1396
- const diagnostics = this.helperDiagnostics.get(child);
1397
1388
  const request = {
1398
1389
  id,
1399
1390
  payload
@@ -1401,17 +1392,12 @@ class HelperProcessRDPBackendClient {
1401
1392
  return new Promise((resolve, reject)=>{
1402
1393
  this.pending.set(id, {
1403
1394
  resolve,
1404
- reject,
1405
- child
1395
+ reject
1406
1396
  });
1407
1397
  child.stdin.write(`${JSON.stringify(request)}\n`, (error)=>{
1408
1398
  if (!error) return;
1409
1399
  this.pending.delete(id);
1410
- const nodeError = error;
1411
- const timer = setTimeout(()=>{
1412
- reject(this.createHelperError(`Failed to send ${payload.type} request to RDP helper: ${error.message}`, nodeError.code, diagnostics));
1413
- }, HELPER_WRITE_ERROR_DIAGNOSTIC_DELAY_MS);
1414
- timer.unref?.();
1400
+ reject(this.createHelperError(`Failed to send ${payload.type} request to RDP helper: ${error.message}`));
1415
1401
  });
1416
1402
  });
1417
1403
  }
@@ -1422,28 +1408,18 @@ class HelperProcessRDPBackendClient {
1422
1408
  for (const { reject } of this.pending.values())reject(error);
1423
1409
  this.pending.clear();
1424
1410
  }
1425
- rejectPendingForChild(child, error) {
1426
- for (const [id, pending] of this.pending)if (pending.child === child) {
1427
- pending.reject(error);
1428
- this.pending.delete(id);
1429
- }
1430
- }
1431
- createHelperError(message, code, diagnostics) {
1432
- const diagnosticParts = [
1433
- diagnostics?.path ? `path=${diagnostics.path}` : void 0,
1434
- 'number' == typeof diagnostics?.pid ? `pid=${diagnostics.pid}` : void 0,
1435
- diagnostics?.exit ? `exitCode=${diagnostics.exit.code}, signal=${diagnostics.exit.signal}` : void 0
1436
- ].filter(Boolean);
1437
- const diagnosticsSuffix = diagnosticParts.length > 0 ? `\nHelper diagnostics: ${diagnosticParts.join(', ')}` : '';
1438
- const stderrSummary = diagnostics?.stderrBuffer.trim();
1439
- const stderrSuffix = stderrSummary ? `\nHelper stderr:\n${stderrSummary}` : '';
1440
- const error = new Error(`${message}${diagnosticsSuffix}${stderrSuffix}`);
1411
+ createHelperError(message, code) {
1412
+ const stderrSummary = this.stderrLines.join('\n').trim();
1413
+ const suffix = stderrSummary ? `\nHelper stderr:\n${stderrSummary}` : '';
1414
+ const error = new Error(`${message}${suffix}`);
1441
1415
  if (code) error.name = code;
1442
1416
  return error;
1443
1417
  }
1444
1418
  disposeReaders() {
1445
1419
  this.stdoutReader?.close();
1420
+ this.stderrReader?.close();
1446
1421
  this.stdoutReader = void 0;
1422
+ this.stderrReader = void 0;
1447
1423
  }
1448
1424
  async shutdownHelper(rootError) {
1449
1425
  const child = this.child;
@@ -1478,8 +1454,9 @@ class HelperProcessRDPBackendClient {
1478
1454
  backend_client_define_property(this, "resolveHelperPath", void 0);
1479
1455
  backend_client_define_property(this, "child", void 0);
1480
1456
  backend_client_define_property(this, "stdoutReader", void 0);
1457
+ backend_client_define_property(this, "stderrReader", void 0);
1481
1458
  backend_client_define_property(this, "pending", new Map());
1482
- backend_client_define_property(this, "helperDiagnostics", new WeakMap());
1459
+ backend_client_define_property(this, "stderrLines", []);
1483
1460
  backend_client_define_property(this, "nextRequestId", 0);
1484
1461
  backend_client_define_property(this, "connected", false);
1485
1462
  backend_client_define_property(this, "fatalHelperError", void 0);
@@ -1522,10 +1499,9 @@ const DEFAULT_SCROLL_STEP_AMOUNT = 120;
1522
1499
  class RDPDevice {
1523
1500
  describe() {
1524
1501
  const port = this.options.port || 3389;
1525
- const server = formatRdpServerAddress(this.options.host, port);
1526
1502
  const username = this.options.username ? ` as ${this.options.username}` : '';
1527
1503
  const session = this.connectionInfo?.sessionId ? ` [session ${this.connectionInfo.sessionId}]` : '';
1528
- return `RDP Device ${server}${username}${session}`;
1504
+ return `RDP Device ${this.options.host}:${port}${username}${session}`;
1529
1505
  }
1530
1506
  async connect() {
1531
1507
  this.throwIfDestroyed();
@@ -1565,11 +1541,10 @@ class RDPDevice {
1565
1541
  call: async ()=>{
1566
1542
  this.assertConnected();
1567
1543
  const size = await this.size();
1568
- const server = this.connectionInfo?.server || formatRdpServerAddress(this.options.host, this.options.port || 3389);
1569
1544
  return [
1570
1545
  {
1571
1546
  id: this.connectionInfo?.sessionId || this.options.host,
1572
- name: `RDP ${server} (${size.width}x${size.height})`,
1547
+ name: `RDP ${this.connectionInfo?.server || this.options.host} (${size.width}x${size.height})`,
1573
1548
  primary: true
1574
1549
  }
1575
1550
  ];
@@ -1767,12 +1742,11 @@ class RDPDevice {
1767
1742
  }
1768
1743
  }
1769
1744
  });
1770
- const normalizedOptions = normalizeRdpConnectionConfig(options);
1771
1745
  this.options = {
1772
1746
  port: 3389,
1773
1747
  securityProtocol: 'auto',
1774
1748
  ignoreCertificate: false,
1775
- ...normalizedOptions
1749
+ ...options
1776
1750
  };
1777
1751
  this.backend = options.backend || createDefaultRDPBackendClient();
1778
1752
  }
@@ -1795,7 +1769,6 @@ function createRDPComputerDevice(opts) {
1795
1769
  username: opts.username,
1796
1770
  password: opts.password,
1797
1771
  domain: opts.domain,
1798
- localAddress: opts.localAddress,
1799
1772
  adminSession: opts.adminSession,
1800
1773
  ignoreCertificate: opts.ignoreCertificate,
1801
1774
  securityProtocol: opts.securityProtocol,
@@ -1841,7 +1814,6 @@ const computerInitArgShape = {
1841
1814
  username: z.string().optional().describe('RDP username. Requires host.'),
1842
1815
  password: z.string().optional().describe('RDP password. Requires host. Prefer setting via environment or a secrets manager.'),
1843
1816
  domain: z.string().optional().describe('RDP domain. Requires host.'),
1844
- localAddress: z.string().optional().describe('Local source IP address for the RDP TCP connection. Requires host.'),
1845
1817
  adminSession: z.boolean().optional().describe('Attach to the RDP admin/console session. Requires host.'),
1846
1818
  ignoreCertificate: z.boolean().optional().describe('Skip TLS certificate validation. Requires host.'),
1847
1819
  securityProtocol: z["enum"](RDP_SECURITY_PROTOCOLS).optional().describe('RDP security protocol negotiation (default auto). Requires host.'),
@@ -1852,11 +1824,10 @@ function adaptComputerInitArgs(extracted) {
1852
1824
  if (!extracted || 0 === Object.keys(extracted).length) return;
1853
1825
  if (extracted.host) {
1854
1826
  const { displayId: _d, headless: _h, ...rdpFields } = extracted;
1855
- const host = normalizeRdpHost(extracted.host);
1856
1827
  return {
1857
1828
  mode: 'rdp',
1858
1829
  ...rdpFields,
1859
- host
1830
+ host: extracted.host
1860
1831
  };
1861
1832
  }
1862
1833
  return {
@@ -1872,15 +1843,15 @@ function shouldRetargetAgent(opts) {
1872
1843
  }
1873
1844
  function describeConnectTarget(opts) {
1874
1845
  if (opts?.mode === 'rdp') {
1875
- const target = opts.port ? formatRdpServerAddress(opts.host, opts.port) : formatRdpHost(opts.host);
1846
+ const portSuffix = opts.port ? `:${opts.port}` : '';
1876
1847
  const userSuffix = opts.username ? ` as ${opts.username}` : '';
1877
- return ` via RDP (${target}${userSuffix})`;
1848
+ return ` via RDP (${opts.host}${portSuffix}${userSuffix})`;
1878
1849
  }
1879
1850
  if (opts?.mode === 'local' && opts.displayId) return ` (Display: ${opts.displayId})`;
1880
1851
  return ' (Primary display)';
1881
1852
  }
1882
1853
  function getCliReportSessionTarget(opts) {
1883
- if (opts?.mode === 'rdp') return `rdp:${formatRdpHost(opts.host)}`;
1854
+ if (opts?.mode === 'rdp') return `rdp:${opts.host}`;
1884
1855
  if (opts?.mode === 'local' && opts.displayId) return opts.displayId;
1885
1856
  return 'primary';
1886
1857
  }
@@ -1932,7 +1903,7 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
1932
1903
  return [
1933
1904
  {
1934
1905
  name: 'computer_connect',
1935
- description: "Connect to a computer desktop. Default (local) mode controls the local machine; pass displayId to target a specific local display (see computer_list_displays). Pass host to switch to RDP mode and connect to a remote Windows desktop via the RDP helper binary. RDP-related options (port/username/password/domain/localAddress/securityProtocol/ignoreCertificate/adminSession/desktopWidth/desktopHeight) only take effect when host is set.",
1906
+ description: "Connect to a computer desktop. Default (local) mode controls the local machine; pass displayId to target a specific local display (see computer_list_displays). Pass host to switch to RDP mode and connect to a remote Windows desktop via the RDP helper binary. RDP-related options (port/username/password/domain/securityProtocol/ignoreCertificate/adminSession/desktopWidth/desktopHeight) only take effect when host is set.",
1936
1907
  schema: this.getAgentInitArgSchema(),
1937
1908
  cli: this.getAgentInitArgCliMetadata(),
1938
1909
  handler: async (args)=>{
@@ -1998,7 +1969,7 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
1998
1969
  const tools = new ComputerMidsceneTools();
1999
1970
  runToolsCLI(tools, 'midscene-computer', {
2000
1971
  stripPrefix: 'computer_',
2001
- version: "1.9.3-beta-20260610061213.0",
1972
+ version: "1.9.3-beta-20260610071913.0",
2002
1973
  extraCommands: createReportCliCommands()
2003
1974
  }).catch((e)=>{
2004
1975
  process.exit(reportCLIError(e));