@midscene/computer 1.9.2-beta-20260608092543.0 → 1.9.2

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
@@ -4,7 +4,7 @@ import { getDebug } from "@midscene/shared/logger";
4
4
  import { BaseMidsceneTools } from "@midscene/shared/mcp/base-tools";
5
5
  import { Agent } from "@midscene/core/agent";
6
6
  import { execFileSync, execSync, spawn, spawnSync } from "node:child_process";
7
- import { existsSync } from "node:fs";
7
+ import { chmodSync, existsSync, statSync } from "node:fs";
8
8
  import { createRequire } from "node:module";
9
9
  import { dirname, resolve as external_node_path_resolve } from "node:path";
10
10
  import { fileURLToPath } from "node:url";
@@ -350,9 +350,13 @@ async function getLibnut() {
350
350
  }
351
351
  }
352
352
  const debugDevice = getDebug('computer:device');
353
+ const warnDevice = getDebug('computer:device', {
354
+ console: true
355
+ });
353
356
  const debugComputerInput = getDebug('computer:input', {
354
357
  console: true
355
358
  });
359
+ const WINDOWS_UIPI_DOC_URL = 'https://midscenejs.com/computer-getting-started#windows-clicks-have-no-effect-on-some-apps';
356
360
  function resolvePackageRoot(helperName) {
357
361
  const require = createRequire(import.meta.url);
358
362
  let pkgRoot = null;
@@ -392,6 +396,15 @@ function getPhasedScrollBinary() {
392
396
  phasedScrollBinaryPath = null;
393
397
  return null;
394
398
  }
399
+ try {
400
+ const st = statSync(binPath);
401
+ if ((73 & st.mode) === 0) {
402
+ chmodSync(binPath, 493);
403
+ debugDevice('phased-scroll: restored executable bit on', binPath);
404
+ }
405
+ } catch (err) {
406
+ debugDevice('phased-scroll: chmod self-heal failed', err);
407
+ }
395
408
  phasedScrollBinaryPath = binPath;
396
409
  return binPath;
397
410
  }
@@ -519,9 +532,10 @@ function runPhasedScroll(direction, pixels, steps) {
519
532
  if (0 === res.status) return true;
520
533
  if (!phasedScrollExecWarned) {
521
534
  phasedScrollExecWarned = true;
522
- console.warn(`[@midscene/computer] phased-scroll helper exited with status ${res.status}; falling back to keyboard/libnut. This usually means Accessibility permission has not been granted to the host process.`);
535
+ const hint = null === res.status ? `signal ${res.signal ?? 'unknown'}; the binary may not be executable (npm tarball extraction can drop the +x bit) or may be blocked by quarantine. Try: chmod +x "${bin}"` : 'this usually means Accessibility permission has not been granted to the host process (System Settings → Privacy & Security → Accessibility)';
536
+ console.warn(`[@midscene/computer] phased-scroll helper failed (exit=${res.status}, signal=${res.signal ?? 'none'}); falling back to keyboard/libnut. ${hint}`);
523
537
  }
524
- debugDevice('phased-scroll exited non-zero', res.status, res.error);
538
+ debugDevice('phased-scroll exited non-zero', res.status, res.signal, res.error);
525
539
  return false;
526
540
  } catch (err) {
527
541
  if (!phasedScrollExecWarned) {
@@ -642,7 +656,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
642
656
  }
643
657
  async healthCheck() {
644
658
  console.log('[HealthCheck] Starting health check...');
645
- console.log("[HealthCheck] @midscene/computer v1.9.2-beta-20260608092543.0");
659
+ console.log("[HealthCheck] @midscene/computer v1.9.2");
646
660
  console.log('[HealthCheck] Taking screenshot...');
647
661
  const screenshotTimeout = 15000;
648
662
  let timeoutId;
@@ -670,13 +684,15 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
670
684
  const deltaY = Math.abs(movedPos.y - targetY);
671
685
  if (deltaX > 5 || deltaY > 5) {
672
686
  const msg = `[HealthCheck] WARNING: Mouse control may not be working. Expected (${targetX}, ${targetY}), got (${movedPos.x}, ${movedPos.y}), delta=(${deltaX}, ${deltaY})`;
673
- console.warn(msg);
674
- debugDevice(msg);
675
- if ('win32' === process.platform && !this.isRunningAsAdmin()) {
676
- const hint = "Midscene is NOT running as Administrator. Windows blocks mouse/keyboard input to elevated (admin) applications from non-admin processes (UIPI). Please run your terminal or Node.js as Administrator and try again.";
677
- console.error(`\n[HealthCheck] ${hint}\n`);
678
- debugDevice(hint);
679
- }
687
+ warnDevice(msg);
688
+ }
689
+ if ('win32' === process.platform && !this.isRunningAsAdmin()) {
690
+ const hint = [
691
+ 'Heads-up: Midscene is not running as Administrator.',
692
+ 'If clicks or key presses have no effect while the cursor still moves to the right position,',
693
+ `see the Windows permission troubleshooting guide: ${WINDOWS_UIPI_DOC_URL}`
694
+ ].join(' ');
695
+ warnDevice(`[HealthCheck] ${hint}`);
680
696
  }
681
697
  this.inputDriver.moveMouse(startPos.x, startPos.y);
682
698
  console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
@@ -693,14 +709,16 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
693
709
  }
694
710
  isRunningAsAdmin() {
695
711
  if ('win32' !== process.platform) return false;
712
+ if (void 0 !== this.adminCheckCache) return this.adminCheckCache;
696
713
  try {
697
714
  execSync('net session', {
698
715
  stdio: 'pipe'
699
716
  });
700
- return true;
717
+ this.adminCheckCache = true;
701
718
  } catch {
702
- return false;
719
+ this.adminCheckCache = false;
703
720
  }
721
+ return this.adminCheckCache;
704
722
  }
705
723
  async screenshotBase64() {
706
724
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
@@ -945,6 +963,7 @@ Original error: ${lastRawMessage}`);
945
963
  debug: (message)=>debugDevice(message)
946
964
  }));
947
965
  device_define_property(this, "useAppleScript", void 0);
966
+ device_define_property(this, "adminCheckCache", void 0);
948
967
  device_define_property(this, "uri", void 0);
949
968
  device_define_property(this, "inputPrimitives", {
950
969
  pointer: {
@@ -1893,7 +1912,7 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
1893
1912
  const tools = new ComputerMidsceneTools();
1894
1913
  runToolsCLI(tools, 'midscene-computer', {
1895
1914
  stripPrefix: 'computer_',
1896
- version: "1.9.2-beta-20260608092543.0",
1915
+ version: "1.9.2",
1897
1916
  extraCommands: createReportCliCommands()
1898
1917
  }).catch((e)=>{
1899
1918
  process.exit(reportCLIError(e));
package/dist/es/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { execFileSync, execSync, spawn, spawnSync } from "node:child_process";
2
- import { existsSync } from "node:fs";
2
+ import { chmodSync, existsSync, statSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
4
  import { dirname, resolve as external_node_path_resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -350,9 +350,13 @@ async function getLibnut() {
350
350
  }
351
351
  }
352
352
  const debugDevice = getDebug('computer:device');
353
+ const warnDevice = getDebug('computer:device', {
354
+ console: true
355
+ });
353
356
  const debugComputerInput = getDebug('computer:input', {
354
357
  console: true
355
358
  });
359
+ const WINDOWS_UIPI_DOC_URL = 'https://midscenejs.com/computer-getting-started#windows-clicks-have-no-effect-on-some-apps';
356
360
  function resolvePackageRoot(helperName) {
357
361
  const require = createRequire(import.meta.url);
358
362
  let pkgRoot = null;
@@ -392,6 +396,15 @@ function getPhasedScrollBinary() {
392
396
  phasedScrollBinaryPath = null;
393
397
  return null;
394
398
  }
399
+ try {
400
+ const st = statSync(binPath);
401
+ if ((73 & st.mode) === 0) {
402
+ chmodSync(binPath, 493);
403
+ debugDevice('phased-scroll: restored executable bit on', binPath);
404
+ }
405
+ } catch (err) {
406
+ debugDevice('phased-scroll: chmod self-heal failed', err);
407
+ }
395
408
  phasedScrollBinaryPath = binPath;
396
409
  return binPath;
397
410
  }
@@ -519,9 +532,10 @@ function runPhasedScroll(direction, pixels, steps) {
519
532
  if (0 === res.status) return true;
520
533
  if (!phasedScrollExecWarned) {
521
534
  phasedScrollExecWarned = true;
522
- console.warn(`[@midscene/computer] phased-scroll helper exited with status ${res.status}; falling back to keyboard/libnut. This usually means Accessibility permission has not been granted to the host process.`);
535
+ const hint = null === res.status ? `signal ${res.signal ?? 'unknown'}; the binary may not be executable (npm tarball extraction can drop the +x bit) or may be blocked by quarantine. Try: chmod +x "${bin}"` : 'this usually means Accessibility permission has not been granted to the host process (System Settings → Privacy & Security → Accessibility)';
536
+ console.warn(`[@midscene/computer] phased-scroll helper failed (exit=${res.status}, signal=${res.signal ?? 'none'}); falling back to keyboard/libnut. ${hint}`);
523
537
  }
524
- debugDevice('phased-scroll exited non-zero', res.status, res.error);
538
+ debugDevice('phased-scroll exited non-zero', res.status, res.signal, res.error);
525
539
  return false;
526
540
  } catch (err) {
527
541
  if (!phasedScrollExecWarned) {
@@ -642,7 +656,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
642
656
  }
643
657
  async healthCheck() {
644
658
  console.log('[HealthCheck] Starting health check...');
645
- console.log("[HealthCheck] @midscene/computer v1.9.2-beta-20260608092543.0");
659
+ console.log("[HealthCheck] @midscene/computer v1.9.2");
646
660
  console.log('[HealthCheck] Taking screenshot...');
647
661
  const screenshotTimeout = 15000;
648
662
  let timeoutId;
@@ -670,13 +684,15 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
670
684
  const deltaY = Math.abs(movedPos.y - targetY);
671
685
  if (deltaX > 5 || deltaY > 5) {
672
686
  const msg = `[HealthCheck] WARNING: Mouse control may not be working. Expected (${targetX}, ${targetY}), got (${movedPos.x}, ${movedPos.y}), delta=(${deltaX}, ${deltaY})`;
673
- console.warn(msg);
674
- debugDevice(msg);
675
- if ('win32' === process.platform && !this.isRunningAsAdmin()) {
676
- const hint = "Midscene is NOT running as Administrator. Windows blocks mouse/keyboard input to elevated (admin) applications from non-admin processes (UIPI). Please run your terminal or Node.js as Administrator and try again.";
677
- console.error(`\n[HealthCheck] ${hint}\n`);
678
- debugDevice(hint);
679
- }
687
+ warnDevice(msg);
688
+ }
689
+ if ('win32' === process.platform && !this.isRunningAsAdmin()) {
690
+ const hint = [
691
+ 'Heads-up: Midscene is not running as Administrator.',
692
+ 'If clicks or key presses have no effect while the cursor still moves to the right position,',
693
+ `see the Windows permission troubleshooting guide: ${WINDOWS_UIPI_DOC_URL}`
694
+ ].join(' ');
695
+ warnDevice(`[HealthCheck] ${hint}`);
680
696
  }
681
697
  this.inputDriver.moveMouse(startPos.x, startPos.y);
682
698
  console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
@@ -693,14 +709,16 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
693
709
  }
694
710
  isRunningAsAdmin() {
695
711
  if ('win32' !== process.platform) return false;
712
+ if (void 0 !== this.adminCheckCache) return this.adminCheckCache;
696
713
  try {
697
714
  execSync('net session', {
698
715
  stdio: 'pipe'
699
716
  });
700
- return true;
717
+ this.adminCheckCache = true;
701
718
  } catch {
702
- return false;
719
+ this.adminCheckCache = false;
703
720
  }
721
+ return this.adminCheckCache;
704
722
  }
705
723
  async screenshotBase64() {
706
724
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
@@ -945,6 +963,7 @@ Original error: ${lastRawMessage}`);
945
963
  debug: (message)=>debugDevice(message)
946
964
  }));
947
965
  device_define_property(this, "useAppleScript", void 0);
966
+ device_define_property(this, "adminCheckCache", void 0);
948
967
  device_define_property(this, "uri", void 0);
949
968
  device_define_property(this, "inputPrimitives", {
950
969
  pointer: {
@@ -1934,7 +1953,7 @@ class ComputerMidsceneTools extends BaseMidsceneTools {
1934
1953
  }
1935
1954
  }
1936
1955
  function version() {
1937
- const currentVersion = "1.9.2-beta-20260608092543.0";
1956
+ const currentVersion = "1.9.2";
1938
1957
  console.log(`@midscene/computer v${currentVersion}`);
1939
1958
  return currentVersion;
1940
1959
  }
@@ -1,7 +1,7 @@
1
1
  import { BaseMCPServer, createMCPServerLauncher } from "@midscene/shared/mcp";
2
2
  import { Agent } from "@midscene/core/agent";
3
3
  import { execFileSync, execSync, spawn, spawnSync } from "node:child_process";
4
- import { existsSync } from "node:fs";
4
+ import { chmodSync, existsSync, statSync } from "node:fs";
5
5
  import { createRequire } from "node:module";
6
6
  import { dirname, resolve as external_node_path_resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
@@ -350,9 +350,13 @@ async function getLibnut() {
350
350
  }
351
351
  }
352
352
  const debugDevice = getDebug('computer:device');
353
+ const warnDevice = getDebug('computer:device', {
354
+ console: true
355
+ });
353
356
  const debugComputerInput = getDebug('computer:input', {
354
357
  console: true
355
358
  });
359
+ const WINDOWS_UIPI_DOC_URL = 'https://midscenejs.com/computer-getting-started#windows-clicks-have-no-effect-on-some-apps';
356
360
  function resolvePackageRoot(helperName) {
357
361
  const require = createRequire(import.meta.url);
358
362
  let pkgRoot = null;
@@ -392,6 +396,15 @@ function getPhasedScrollBinary() {
392
396
  phasedScrollBinaryPath = null;
393
397
  return null;
394
398
  }
399
+ try {
400
+ const st = statSync(binPath);
401
+ if ((73 & st.mode) === 0) {
402
+ chmodSync(binPath, 493);
403
+ debugDevice('phased-scroll: restored executable bit on', binPath);
404
+ }
405
+ } catch (err) {
406
+ debugDevice('phased-scroll: chmod self-heal failed', err);
407
+ }
395
408
  phasedScrollBinaryPath = binPath;
396
409
  return binPath;
397
410
  }
@@ -519,9 +532,10 @@ function runPhasedScroll(direction, pixels, steps) {
519
532
  if (0 === res.status) return true;
520
533
  if (!phasedScrollExecWarned) {
521
534
  phasedScrollExecWarned = true;
522
- console.warn(`[@midscene/computer] phased-scroll helper exited with status ${res.status}; falling back to keyboard/libnut. This usually means Accessibility permission has not been granted to the host process.`);
535
+ const hint = null === res.status ? `signal ${res.signal ?? 'unknown'}; the binary may not be executable (npm tarball extraction can drop the +x bit) or may be blocked by quarantine. Try: chmod +x "${bin}"` : 'this usually means Accessibility permission has not been granted to the host process (System Settings → Privacy & Security → Accessibility)';
536
+ console.warn(`[@midscene/computer] phased-scroll helper failed (exit=${res.status}, signal=${res.signal ?? 'none'}); falling back to keyboard/libnut. ${hint}`);
523
537
  }
524
- debugDevice('phased-scroll exited non-zero', res.status, res.error);
538
+ debugDevice('phased-scroll exited non-zero', res.status, res.signal, res.error);
525
539
  return false;
526
540
  } catch (err) {
527
541
  if (!phasedScrollExecWarned) {
@@ -642,7 +656,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
642
656
  }
643
657
  async healthCheck() {
644
658
  console.log('[HealthCheck] Starting health check...');
645
- console.log("[HealthCheck] @midscene/computer v1.9.2-beta-20260608092543.0");
659
+ console.log("[HealthCheck] @midscene/computer v1.9.2");
646
660
  console.log('[HealthCheck] Taking screenshot...');
647
661
  const screenshotTimeout = 15000;
648
662
  let timeoutId;
@@ -670,13 +684,15 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
670
684
  const deltaY = Math.abs(movedPos.y - targetY);
671
685
  if (deltaX > 5 || deltaY > 5) {
672
686
  const msg = `[HealthCheck] WARNING: Mouse control may not be working. Expected (${targetX}, ${targetY}), got (${movedPos.x}, ${movedPos.y}), delta=(${deltaX}, ${deltaY})`;
673
- console.warn(msg);
674
- debugDevice(msg);
675
- if ('win32' === process.platform && !this.isRunningAsAdmin()) {
676
- const hint = "Midscene is NOT running as Administrator. Windows blocks mouse/keyboard input to elevated (admin) applications from non-admin processes (UIPI). Please run your terminal or Node.js as Administrator and try again.";
677
- console.error(`\n[HealthCheck] ${hint}\n`);
678
- debugDevice(hint);
679
- }
687
+ warnDevice(msg);
688
+ }
689
+ if ('win32' === process.platform && !this.isRunningAsAdmin()) {
690
+ const hint = [
691
+ 'Heads-up: Midscene is not running as Administrator.',
692
+ 'If clicks or key presses have no effect while the cursor still moves to the right position,',
693
+ `see the Windows permission troubleshooting guide: ${WINDOWS_UIPI_DOC_URL}`
694
+ ].join(' ');
695
+ warnDevice(`[HealthCheck] ${hint}`);
680
696
  }
681
697
  this.inputDriver.moveMouse(startPos.x, startPos.y);
682
698
  console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
@@ -693,14 +709,16 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
693
709
  }
694
710
  isRunningAsAdmin() {
695
711
  if ('win32' !== process.platform) return false;
712
+ if (void 0 !== this.adminCheckCache) return this.adminCheckCache;
696
713
  try {
697
714
  execSync('net session', {
698
715
  stdio: 'pipe'
699
716
  });
700
- return true;
717
+ this.adminCheckCache = true;
701
718
  } catch {
702
- return false;
719
+ this.adminCheckCache = false;
703
720
  }
721
+ return this.adminCheckCache;
704
722
  }
705
723
  async screenshotBase64() {
706
724
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
@@ -945,6 +963,7 @@ Original error: ${lastRawMessage}`);
945
963
  debug: (message)=>debugDevice(message)
946
964
  }));
947
965
  device_define_property(this, "useAppleScript", void 0);
966
+ device_define_property(this, "adminCheckCache", void 0);
948
967
  device_define_property(this, "uri", void 0);
949
968
  device_define_property(this, "inputPrimitives", {
950
969
  pointer: {
@@ -1897,7 +1916,7 @@ class ComputerMCPServer extends BaseMCPServer {
1897
1916
  constructor(toolsManager){
1898
1917
  super({
1899
1918
  name: '@midscene/computer-mcp',
1900
- version: "1.9.2-beta-20260608092543.0",
1919
+ version: "1.9.2",
1901
1920
  description: 'Control the computer desktop using natural language commands'
1902
1921
  }, toolsManager);
1903
1922
  }
package/dist/lib/cli.js CHANGED
@@ -376,9 +376,13 @@ async function getLibnut() {
376
376
  }
377
377
  }
378
378
  const debugDevice = (0, logger_namespaceObject.getDebug)('computer:device');
379
+ const warnDevice = (0, logger_namespaceObject.getDebug)('computer:device', {
380
+ console: true
381
+ });
379
382
  const debugComputerInput = (0, logger_namespaceObject.getDebug)('computer:input', {
380
383
  console: true
381
384
  });
385
+ const WINDOWS_UIPI_DOC_URL = 'https://midscenejs.com/computer-getting-started#windows-clicks-have-no-effect-on-some-apps';
382
386
  function resolvePackageRoot(helperName) {
383
387
  const require1 = (0, external_node_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
384
388
  let pkgRoot = null;
@@ -418,6 +422,15 @@ function getPhasedScrollBinary() {
418
422
  phasedScrollBinaryPath = null;
419
423
  return null;
420
424
  }
425
+ try {
426
+ const st = (0, external_node_fs_namespaceObject.statSync)(binPath);
427
+ if ((73 & st.mode) === 0) {
428
+ (0, external_node_fs_namespaceObject.chmodSync)(binPath, 493);
429
+ debugDevice('phased-scroll: restored executable bit on', binPath);
430
+ }
431
+ } catch (err) {
432
+ debugDevice('phased-scroll: chmod self-heal failed', err);
433
+ }
421
434
  phasedScrollBinaryPath = binPath;
422
435
  return binPath;
423
436
  }
@@ -545,9 +558,10 @@ function runPhasedScroll(direction, pixels, steps) {
545
558
  if (0 === res.status) return true;
546
559
  if (!phasedScrollExecWarned) {
547
560
  phasedScrollExecWarned = true;
548
- console.warn(`[@midscene/computer] phased-scroll helper exited with status ${res.status}; falling back to keyboard/libnut. This usually means Accessibility permission has not been granted to the host process.`);
561
+ const hint = null === res.status ? `signal ${res.signal ?? 'unknown'}; the binary may not be executable (npm tarball extraction can drop the +x bit) or may be blocked by quarantine. Try: chmod +x "${bin}"` : 'this usually means Accessibility permission has not been granted to the host process (System Settings → Privacy & Security → Accessibility)';
562
+ console.warn(`[@midscene/computer] phased-scroll helper failed (exit=${res.status}, signal=${res.signal ?? 'none'}); falling back to keyboard/libnut. ${hint}`);
549
563
  }
550
- debugDevice('phased-scroll exited non-zero', res.status, res.error);
564
+ debugDevice('phased-scroll exited non-zero', res.status, res.signal, res.error);
551
565
  return false;
552
566
  } catch (err) {
553
567
  if (!phasedScrollExecWarned) {
@@ -668,7 +682,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
668
682
  }
669
683
  async healthCheck() {
670
684
  console.log('[HealthCheck] Starting health check...');
671
- console.log("[HealthCheck] @midscene/computer v1.9.2-beta-20260608092543.0");
685
+ console.log("[HealthCheck] @midscene/computer v1.9.2");
672
686
  console.log('[HealthCheck] Taking screenshot...');
673
687
  const screenshotTimeout = 15000;
674
688
  let timeoutId;
@@ -696,13 +710,15 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
696
710
  const deltaY = Math.abs(movedPos.y - targetY);
697
711
  if (deltaX > 5 || deltaY > 5) {
698
712
  const msg = `[HealthCheck] WARNING: Mouse control may not be working. Expected (${targetX}, ${targetY}), got (${movedPos.x}, ${movedPos.y}), delta=(${deltaX}, ${deltaY})`;
699
- console.warn(msg);
700
- debugDevice(msg);
701
- if ('win32' === process.platform && !this.isRunningAsAdmin()) {
702
- const hint = "Midscene is NOT running as Administrator. Windows blocks mouse/keyboard input to elevated (admin) applications from non-admin processes (UIPI). Please run your terminal or Node.js as Administrator and try again.";
703
- console.error(`\n[HealthCheck] ${hint}\n`);
704
- debugDevice(hint);
705
- }
713
+ warnDevice(msg);
714
+ }
715
+ if ('win32' === process.platform && !this.isRunningAsAdmin()) {
716
+ const hint = [
717
+ 'Heads-up: Midscene is not running as Administrator.',
718
+ 'If clicks or key presses have no effect while the cursor still moves to the right position,',
719
+ `see the Windows permission troubleshooting guide: ${WINDOWS_UIPI_DOC_URL}`
720
+ ].join(' ');
721
+ warnDevice(`[HealthCheck] ${hint}`);
706
722
  }
707
723
  this.inputDriver.moveMouse(startPos.x, startPos.y);
708
724
  console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
@@ -719,14 +735,16 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
719
735
  }
720
736
  isRunningAsAdmin() {
721
737
  if ('win32' !== process.platform) return false;
738
+ if (void 0 !== this.adminCheckCache) return this.adminCheckCache;
722
739
  try {
723
740
  (0, external_node_child_process_namespaceObject.execSync)('net session', {
724
741
  stdio: 'pipe'
725
742
  });
726
- return true;
743
+ this.adminCheckCache = true;
727
744
  } catch {
728
- return false;
745
+ this.adminCheckCache = false;
729
746
  }
747
+ return this.adminCheckCache;
730
748
  }
731
749
  async screenshotBase64() {
732
750
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
@@ -971,6 +989,7 @@ Original error: ${lastRawMessage}`);
971
989
  debug: (message)=>debugDevice(message)
972
990
  }));
973
991
  device_define_property(this, "useAppleScript", void 0);
992
+ device_define_property(this, "adminCheckCache", void 0);
974
993
  device_define_property(this, "uri", void 0);
975
994
  device_define_property(this, "inputPrimitives", {
976
995
  pointer: {
@@ -1920,7 +1939,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
1920
1939
  const tools = new ComputerMidsceneTools();
1921
1940
  (0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-computer', {
1922
1941
  stripPrefix: 'computer_',
1923
- version: "1.9.2-beta-20260608092543.0",
1942
+ version: "1.9.2",
1924
1943
  extraCommands: (0, core_namespaceObject.createReportCliCommands)()
1925
1944
  }).catch((e)=>{
1926
1945
  process.exit((0, cli_namespaceObject.reportCLIError)(e));
package/dist/lib/index.js CHANGED
@@ -403,9 +403,13 @@ async function getLibnut() {
403
403
  }
404
404
  }
405
405
  const debugDevice = (0, logger_namespaceObject.getDebug)('computer:device');
406
+ const warnDevice = (0, logger_namespaceObject.getDebug)('computer:device', {
407
+ console: true
408
+ });
406
409
  const debugComputerInput = (0, logger_namespaceObject.getDebug)('computer:input', {
407
410
  console: true
408
411
  });
412
+ const WINDOWS_UIPI_DOC_URL = 'https://midscenejs.com/computer-getting-started#windows-clicks-have-no-effect-on-some-apps';
409
413
  function resolvePackageRoot(helperName) {
410
414
  const require1 = (0, external_node_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
411
415
  let pkgRoot = null;
@@ -445,6 +449,15 @@ function getPhasedScrollBinary() {
445
449
  phasedScrollBinaryPath = null;
446
450
  return null;
447
451
  }
452
+ try {
453
+ const st = (0, external_node_fs_namespaceObject.statSync)(binPath);
454
+ if ((73 & st.mode) === 0) {
455
+ (0, external_node_fs_namespaceObject.chmodSync)(binPath, 493);
456
+ debugDevice('phased-scroll: restored executable bit on', binPath);
457
+ }
458
+ } catch (err) {
459
+ debugDevice('phased-scroll: chmod self-heal failed', err);
460
+ }
448
461
  phasedScrollBinaryPath = binPath;
449
462
  return binPath;
450
463
  }
@@ -572,9 +585,10 @@ function runPhasedScroll(direction, pixels, steps) {
572
585
  if (0 === res.status) return true;
573
586
  if (!phasedScrollExecWarned) {
574
587
  phasedScrollExecWarned = true;
575
- console.warn(`[@midscene/computer] phased-scroll helper exited with status ${res.status}; falling back to keyboard/libnut. This usually means Accessibility permission has not been granted to the host process.`);
588
+ const hint = null === res.status ? `signal ${res.signal ?? 'unknown'}; the binary may not be executable (npm tarball extraction can drop the +x bit) or may be blocked by quarantine. Try: chmod +x "${bin}"` : 'this usually means Accessibility permission has not been granted to the host process (System Settings → Privacy & Security → Accessibility)';
589
+ console.warn(`[@midscene/computer] phased-scroll helper failed (exit=${res.status}, signal=${res.signal ?? 'none'}); falling back to keyboard/libnut. ${hint}`);
576
590
  }
577
- debugDevice('phased-scroll exited non-zero', res.status, res.error);
591
+ debugDevice('phased-scroll exited non-zero', res.status, res.signal, res.error);
578
592
  return false;
579
593
  } catch (err) {
580
594
  if (!phasedScrollExecWarned) {
@@ -695,7 +709,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
695
709
  }
696
710
  async healthCheck() {
697
711
  console.log('[HealthCheck] Starting health check...');
698
- console.log("[HealthCheck] @midscene/computer v1.9.2-beta-20260608092543.0");
712
+ console.log("[HealthCheck] @midscene/computer v1.9.2");
699
713
  console.log('[HealthCheck] Taking screenshot...');
700
714
  const screenshotTimeout = 15000;
701
715
  let timeoutId;
@@ -723,13 +737,15 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
723
737
  const deltaY = Math.abs(movedPos.y - targetY);
724
738
  if (deltaX > 5 || deltaY > 5) {
725
739
  const msg = `[HealthCheck] WARNING: Mouse control may not be working. Expected (${targetX}, ${targetY}), got (${movedPos.x}, ${movedPos.y}), delta=(${deltaX}, ${deltaY})`;
726
- console.warn(msg);
727
- debugDevice(msg);
728
- if ('win32' === process.platform && !this.isRunningAsAdmin()) {
729
- const hint = "Midscene is NOT running as Administrator. Windows blocks mouse/keyboard input to elevated (admin) applications from non-admin processes (UIPI). Please run your terminal or Node.js as Administrator and try again.";
730
- console.error(`\n[HealthCheck] ${hint}\n`);
731
- debugDevice(hint);
732
- }
740
+ warnDevice(msg);
741
+ }
742
+ if ('win32' === process.platform && !this.isRunningAsAdmin()) {
743
+ const hint = [
744
+ 'Heads-up: Midscene is not running as Administrator.',
745
+ 'If clicks or key presses have no effect while the cursor still moves to the right position,',
746
+ `see the Windows permission troubleshooting guide: ${WINDOWS_UIPI_DOC_URL}`
747
+ ].join(' ');
748
+ warnDevice(`[HealthCheck] ${hint}`);
733
749
  }
734
750
  this.inputDriver.moveMouse(startPos.x, startPos.y);
735
751
  console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
@@ -746,14 +762,16 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
746
762
  }
747
763
  isRunningAsAdmin() {
748
764
  if ('win32' !== process.platform) return false;
765
+ if (void 0 !== this.adminCheckCache) return this.adminCheckCache;
749
766
  try {
750
767
  (0, external_node_child_process_namespaceObject.execSync)('net session', {
751
768
  stdio: 'pipe'
752
769
  });
753
- return true;
770
+ this.adminCheckCache = true;
754
771
  } catch {
755
- return false;
772
+ this.adminCheckCache = false;
756
773
  }
774
+ return this.adminCheckCache;
757
775
  }
758
776
  async screenshotBase64() {
759
777
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
@@ -998,6 +1016,7 @@ Original error: ${lastRawMessage}`);
998
1016
  debug: (message)=>debugDevice(message)
999
1017
  }));
1000
1018
  device_define_property(this, "useAppleScript", void 0);
1019
+ device_define_property(this, "adminCheckCache", void 0);
1001
1020
  device_define_property(this, "uri", void 0);
1002
1021
  device_define_property(this, "inputPrimitives", {
1003
1022
  pointer: {
@@ -1992,7 +2011,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
1992
2011
  }
1993
2012
  const env_namespaceObject = require("@midscene/shared/env");
1994
2013
  function version() {
1995
- const currentVersion = "1.9.2-beta-20260608092543.0";
2014
+ const currentVersion = "1.9.2";
1996
2015
  console.log(`@midscene/computer v${currentVersion}`);
1997
2016
  return currentVersion;
1998
2017
  }
@@ -390,9 +390,13 @@ async function getLibnut() {
390
390
  }
391
391
  }
392
392
  const debugDevice = (0, logger_namespaceObject.getDebug)('computer:device');
393
+ const warnDevice = (0, logger_namespaceObject.getDebug)('computer:device', {
394
+ console: true
395
+ });
393
396
  const debugComputerInput = (0, logger_namespaceObject.getDebug)('computer:input', {
394
397
  console: true
395
398
  });
399
+ const WINDOWS_UIPI_DOC_URL = 'https://midscenejs.com/computer-getting-started#windows-clicks-have-no-effect-on-some-apps';
396
400
  function resolvePackageRoot(helperName) {
397
401
  const require1 = (0, external_node_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
398
402
  let pkgRoot = null;
@@ -432,6 +436,15 @@ function getPhasedScrollBinary() {
432
436
  phasedScrollBinaryPath = null;
433
437
  return null;
434
438
  }
439
+ try {
440
+ const st = (0, external_node_fs_namespaceObject.statSync)(binPath);
441
+ if ((73 & st.mode) === 0) {
442
+ (0, external_node_fs_namespaceObject.chmodSync)(binPath, 493);
443
+ debugDevice('phased-scroll: restored executable bit on', binPath);
444
+ }
445
+ } catch (err) {
446
+ debugDevice('phased-scroll: chmod self-heal failed', err);
447
+ }
435
448
  phasedScrollBinaryPath = binPath;
436
449
  return binPath;
437
450
  }
@@ -559,9 +572,10 @@ function runPhasedScroll(direction, pixels, steps) {
559
572
  if (0 === res.status) return true;
560
573
  if (!phasedScrollExecWarned) {
561
574
  phasedScrollExecWarned = true;
562
- console.warn(`[@midscene/computer] phased-scroll helper exited with status ${res.status}; falling back to keyboard/libnut. This usually means Accessibility permission has not been granted to the host process.`);
575
+ const hint = null === res.status ? `signal ${res.signal ?? 'unknown'}; the binary may not be executable (npm tarball extraction can drop the +x bit) or may be blocked by quarantine. Try: chmod +x "${bin}"` : 'this usually means Accessibility permission has not been granted to the host process (System Settings → Privacy & Security → Accessibility)';
576
+ console.warn(`[@midscene/computer] phased-scroll helper failed (exit=${res.status}, signal=${res.signal ?? 'none'}); falling back to keyboard/libnut. ${hint}`);
563
577
  }
564
- debugDevice('phased-scroll exited non-zero', res.status, res.error);
578
+ debugDevice('phased-scroll exited non-zero', res.status, res.signal, res.error);
565
579
  return false;
566
580
  } catch (err) {
567
581
  if (!phasedScrollExecWarned) {
@@ -682,7 +696,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
682
696
  }
683
697
  async healthCheck() {
684
698
  console.log('[HealthCheck] Starting health check...');
685
- console.log("[HealthCheck] @midscene/computer v1.9.2-beta-20260608092543.0");
699
+ console.log("[HealthCheck] @midscene/computer v1.9.2");
686
700
  console.log('[HealthCheck] Taking screenshot...');
687
701
  const screenshotTimeout = 15000;
688
702
  let timeoutId;
@@ -710,13 +724,15 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
710
724
  const deltaY = Math.abs(movedPos.y - targetY);
711
725
  if (deltaX > 5 || deltaY > 5) {
712
726
  const msg = `[HealthCheck] WARNING: Mouse control may not be working. Expected (${targetX}, ${targetY}), got (${movedPos.x}, ${movedPos.y}), delta=(${deltaX}, ${deltaY})`;
713
- console.warn(msg);
714
- debugDevice(msg);
715
- if ('win32' === process.platform && !this.isRunningAsAdmin()) {
716
- const hint = "Midscene is NOT running as Administrator. Windows blocks mouse/keyboard input to elevated (admin) applications from non-admin processes (UIPI). Please run your terminal or Node.js as Administrator and try again.";
717
- console.error(`\n[HealthCheck] ${hint}\n`);
718
- debugDevice(hint);
719
- }
727
+ warnDevice(msg);
728
+ }
729
+ if ('win32' === process.platform && !this.isRunningAsAdmin()) {
730
+ const hint = [
731
+ 'Heads-up: Midscene is not running as Administrator.',
732
+ 'If clicks or key presses have no effect while the cursor still moves to the right position,',
733
+ `see the Windows permission troubleshooting guide: ${WINDOWS_UIPI_DOC_URL}`
734
+ ].join(' ');
735
+ warnDevice(`[HealthCheck] ${hint}`);
720
736
  }
721
737
  this.inputDriver.moveMouse(startPos.x, startPos.y);
722
738
  console.log(`[HealthCheck] Mouse restored to (${startPos.x}, ${startPos.y})`);
@@ -733,14 +749,16 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
733
749
  }
734
750
  isRunningAsAdmin() {
735
751
  if ('win32' !== process.platform) return false;
752
+ if (void 0 !== this.adminCheckCache) return this.adminCheckCache;
736
753
  try {
737
754
  (0, external_node_child_process_namespaceObject.execSync)('net session', {
738
755
  stdio: 'pipe'
739
756
  });
740
- return true;
757
+ this.adminCheckCache = true;
741
758
  } catch {
742
- return false;
759
+ this.adminCheckCache = false;
743
760
  }
761
+ return this.adminCheckCache;
744
762
  }
745
763
  async screenshotBase64() {
746
764
  if (this.destroyed) throw new Error('ComputerDevice has been destroyed');
@@ -985,6 +1003,7 @@ Original error: ${lastRawMessage}`);
985
1003
  debug: (message)=>debugDevice(message)
986
1004
  }));
987
1005
  device_define_property(this, "useAppleScript", void 0);
1006
+ device_define_property(this, "adminCheckCache", void 0);
988
1007
  device_define_property(this, "uri", void 0);
989
1008
  device_define_property(this, "inputPrimitives", {
990
1009
  pointer: {
@@ -1940,7 +1959,7 @@ class ComputerMCPServer extends mcp_namespaceObject.BaseMCPServer {
1940
1959
  constructor(toolsManager){
1941
1960
  super({
1942
1961
  name: '@midscene/computer-mcp',
1943
- version: "1.9.2-beta-20260608092543.0",
1962
+ version: "1.9.2",
1944
1963
  description: 'Control the computer desktop using natural language commands'
1945
1964
  }, toolsManager);
1946
1965
  }
@@ -78,6 +78,8 @@ export declare class ComputerDevice implements AbstractInterface {
78
78
  * to avoid focus issues with system overlays (e.g. Spotlight).
79
79
  */
80
80
  private useAppleScript;
81
+ /** Cached result of the elevation check; see isRunningAsAdmin(). */
82
+ private adminCheckCache?;
81
83
  uri?: string;
82
84
  readonly inputPrimitives: ComputerInputPrimitives;
83
85
  constructor(options?: ComputerDeviceOpt);
@@ -91,6 +93,10 @@ export declare class ComputerDevice implements AbstractInterface {
91
93
  /**
92
94
  * Check if the current process is running with Administrator privileges.
93
95
  * Uses "net session" which succeeds only when elevated.
96
+ *
97
+ * The result is cached because elevation cannot change during the process
98
+ * lifetime, and the underlying `execSync('net session')` is a blocking
99
+ * subprocess spawn that should not run on every connect / health check.
94
100
  */
95
101
  private isRunningAsAdmin;
96
102
  screenshotBase64(): Promise<string>;
@@ -30,6 +30,8 @@ declare class ComputerDevice implements AbstractInterface {
30
30
  * to avoid focus issues with system overlays (e.g. Spotlight).
31
31
  */
32
32
  private useAppleScript;
33
+ /** Cached result of the elevation check; see isRunningAsAdmin(). */
34
+ private adminCheckCache?;
33
35
  uri?: string;
34
36
  readonly inputPrimitives: ComputerInputPrimitives;
35
37
  constructor(options?: ComputerDeviceOpt);
@@ -43,6 +45,10 @@ declare class ComputerDevice implements AbstractInterface {
43
45
  /**
44
46
  * Check if the current process is running with Administrator privileges.
45
47
  * Uses "net session" which succeeds only when elevated.
48
+ *
49
+ * The result is cached because elevation cannot change during the process
50
+ * lifetime, and the underlying `execSync('net session')` is a blocking
51
+ * subprocess spawn that should not run on every connect / health check.
46
52
  */
47
53
  private isRunningAsAdmin;
48
54
  screenshotBase64(): Promise<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/computer",
3
- "version": "1.9.2-beta-20260608092543.0",
3
+ "version": "1.9.2",
4
4
  "description": "Midscene.js Computer Desktop Automation",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,8 +38,8 @@
38
38
  "@computer-use/libnut": "^4.2.0",
39
39
  "clipboardy": "^4.0.0",
40
40
  "screenshot-desktop": "^1.15.3",
41
- "@midscene/core": "1.9.2-beta-20260608092543.0",
42
- "@midscene/shared": "1.9.2-beta-20260608092543.0"
41
+ "@midscene/core": "1.9.2",
42
+ "@midscene/shared": "1.9.2"
43
43
  },
44
44
  "optionalDependencies": {
45
45
  "node-mac-permissions": "2.5.0"