@midscene/computer 1.9.8 → 1.10.1-beta-20260624112700.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/dist/es/cli.mjs +83 -11
- package/dist/es/index.mjs +83 -11
- package/dist/lib/cli.js +83 -11
- package/dist/lib/index.js +83 -11
- package/dist/types/index.d.ts +19 -5
- package/package.json +3 -8
- package/dist/es/mcp-server.mjs +0 -2088
- package/dist/lib/mcp-server.js +0 -2141
- package/dist/types/mcp-server.d.ts +0 -245
package/dist/lib/index.js
CHANGED
|
@@ -424,6 +424,42 @@ function sendKeyViaAppleScript(key, modifiers = []) {
|
|
|
424
424
|
script
|
|
425
425
|
]);
|
|
426
426
|
}
|
|
427
|
+
const POWERSHELL_TIMEOUT_MS = 15000;
|
|
428
|
+
const POWERSHELL_MAX_BUFFER = 67108864;
|
|
429
|
+
function escapePowershellSingleQuoted(value) {
|
|
430
|
+
return value.replace(/'/g, "''");
|
|
431
|
+
}
|
|
432
|
+
function runPowershell(script) {
|
|
433
|
+
const encoded = Buffer.from(script, 'utf16le').toString('base64');
|
|
434
|
+
return (0, external_node_child_process_namespaceObject.execFileSync)('powershell.exe', [
|
|
435
|
+
'-NoProfile',
|
|
436
|
+
'-NonInteractive',
|
|
437
|
+
'-ExecutionPolicy',
|
|
438
|
+
'Bypass',
|
|
439
|
+
'-EncodedCommand',
|
|
440
|
+
encoded
|
|
441
|
+
], {
|
|
442
|
+
encoding: 'utf8',
|
|
443
|
+
timeout: POWERSHELL_TIMEOUT_MS,
|
|
444
|
+
maxBuffer: POWERSHELL_MAX_BUFFER,
|
|
445
|
+
windowsHide: true
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
function listWindowsDisplays() {
|
|
449
|
+
const script = `
|
|
450
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
451
|
+
$s = [System.Windows.Forms.Screen]::AllScreens | ForEach-Object {
|
|
452
|
+
[PSCustomObject]@{ id = $_.DeviceName; name = $_.DeviceName; primary = $_.Primary }
|
|
453
|
+
}
|
|
454
|
+
ConvertTo-Json @($s) -Compress
|
|
455
|
+
`.trim();
|
|
456
|
+
const parsed = JSON.parse(runPowershell(script).trim());
|
|
457
|
+
return parsed.map((d)=>({
|
|
458
|
+
id: String(d.id),
|
|
459
|
+
name: d.name || String(d.id),
|
|
460
|
+
primary: d.primary || false
|
|
461
|
+
}));
|
|
462
|
+
}
|
|
427
463
|
let device_libnut = null;
|
|
428
464
|
let libnutLoadError = null;
|
|
429
465
|
async function getLibnut() {
|
|
@@ -690,6 +726,7 @@ class ComputerDevice {
|
|
|
690
726
|
}
|
|
691
727
|
static async listDisplays() {
|
|
692
728
|
try {
|
|
729
|
+
if ('win32' === process.platform) return listWindowsDisplays();
|
|
693
730
|
const displays = await external_screenshot_desktop_default().listDisplays();
|
|
694
731
|
return displays.map((d)=>({
|
|
695
732
|
id: String(d.id),
|
|
@@ -747,7 +784,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
747
784
|
}
|
|
748
785
|
async healthCheck() {
|
|
749
786
|
console.log('[HealthCheck] Starting health check...');
|
|
750
|
-
console.log("[HealthCheck] @midscene/computer v1.
|
|
787
|
+
console.log("[HealthCheck] @midscene/computer v1.10.1-beta-20260624112700.0");
|
|
751
788
|
console.log('[HealthCheck] Taking screenshot...');
|
|
752
789
|
const screenshotTimeout = 15000;
|
|
753
790
|
let timeoutId;
|
|
@@ -816,6 +853,7 @@ Available Displays: ${displays.length > 0 ? displays.map((d)=>d.name).join(', ')
|
|
|
816
853
|
debugDevice('Taking screenshot', {
|
|
817
854
|
displayId: this.displayId
|
|
818
855
|
});
|
|
856
|
+
if ('win32' === process.platform) return this.screenshotViaPowershell();
|
|
819
857
|
const options = {
|
|
820
858
|
format: 'png'
|
|
821
859
|
};
|
|
@@ -849,6 +887,40 @@ Please follow these steps:
|
|
|
849
887
|
Original error: ${lastRawMessage}`);
|
|
850
888
|
throw new Error(`Failed to take screenshot: ${lastRawMessage}`);
|
|
851
889
|
}
|
|
890
|
+
screenshotViaPowershell() {
|
|
891
|
+
const deviceName = this.displayId ? String(this.displayId) : '';
|
|
892
|
+
const target = deviceName ? `[System.Windows.Forms.Screen]::AllScreens | Where-Object { $_.DeviceName -eq '${escapePowershellSingleQuoted(deviceName)}' } | Select-Object -First 1` : '$null';
|
|
893
|
+
const script = `
|
|
894
|
+
$ErrorActionPreference = 'Stop'
|
|
895
|
+
Add-Type -AssemblyName System.Windows.Forms, System.Drawing
|
|
896
|
+
Add-Type @"
|
|
897
|
+
using System;
|
|
898
|
+
using System.Runtime.InteropServices;
|
|
899
|
+
public class NutDpi { [DllImport("user32.dll")] public static extern bool SetProcessDPIAware(); }
|
|
900
|
+
"@
|
|
901
|
+
[NutDpi]::SetProcessDPIAware() | Out-Null
|
|
902
|
+
$screen = ${target}
|
|
903
|
+
if (-not $screen) { $screen = [System.Windows.Forms.Screen]::PrimaryScreen }
|
|
904
|
+
$b = $screen.Bounds
|
|
905
|
+
$bmp = New-Object System.Drawing.Bitmap($b.Width, $b.Height)
|
|
906
|
+
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
|
907
|
+
$g.CopyFromScreen($b.X, $b.Y, 0, 0, $bmp.Size)
|
|
908
|
+
$ms = New-Object System.IO.MemoryStream
|
|
909
|
+
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
|
|
910
|
+
[Console]::Out.Write([Convert]::ToBase64String($ms.ToArray()))
|
|
911
|
+
$g.Dispose(); $bmp.Dispose(); $ms.Dispose()
|
|
912
|
+
`.trim();
|
|
913
|
+
let stdout;
|
|
914
|
+
try {
|
|
915
|
+
stdout = runPowershell(script);
|
|
916
|
+
} catch (error) {
|
|
917
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
918
|
+
throw new Error(`Failed to take screenshot on Windows: ${message}`);
|
|
919
|
+
}
|
|
920
|
+
const body = stdout.trim();
|
|
921
|
+
if (!body) throw new Error('Failed to take screenshot on Windows: PowerShell returned no image data');
|
|
922
|
+
return (0, img_namespaceObject.createImgBase64ByFormat)('png', body);
|
|
923
|
+
}
|
|
852
924
|
async size() {
|
|
853
925
|
if (this.displayGeometry) return {
|
|
854
926
|
width: Math.round(this.displayGeometry.bounds.width),
|
|
@@ -1972,9 +2044,9 @@ async function agentForRDPComputer(opts) {
|
|
|
1972
2044
|
return new ComputerAgent(device, opts);
|
|
1973
2045
|
}
|
|
1974
2046
|
const core_namespaceObject = require("@midscene/core");
|
|
1975
|
-
const agent_behavior_init_args_namespaceObject = require("@midscene/shared/
|
|
1976
|
-
const base_tools_namespaceObject = require("@midscene/shared/
|
|
1977
|
-
function
|
|
2047
|
+
const agent_behavior_init_args_namespaceObject = require("@midscene/shared/agent-tools/agent-behavior-init-args");
|
|
2048
|
+
const base_tools_namespaceObject = require("@midscene/shared/agent-tools/base-tools");
|
|
2049
|
+
function agent_tools_define_property(obj, key, value) {
|
|
1978
2050
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
1979
2051
|
value: value,
|
|
1980
2052
|
enumerable: true,
|
|
@@ -1984,7 +2056,7 @@ function mcp_tools_define_property(obj, key, value) {
|
|
|
1984
2056
|
else obj[key] = value;
|
|
1985
2057
|
return obj;
|
|
1986
2058
|
}
|
|
1987
|
-
const
|
|
2059
|
+
const agent_tools_debug = (0, logger_namespaceObject.getDebug)('agent-tools:computer');
|
|
1988
2060
|
const RDP_SECURITY_PROTOCOLS = [
|
|
1989
2061
|
'auto',
|
|
1990
2062
|
'tls',
|
|
@@ -2052,14 +2124,14 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
|
|
|
2052
2124
|
try {
|
|
2053
2125
|
await this.agent.destroy?.();
|
|
2054
2126
|
} catch (error) {
|
|
2055
|
-
|
|
2127
|
+
agent_tools_debug('Failed to destroy agent during cleanup:', error);
|
|
2056
2128
|
}
|
|
2057
2129
|
this.agent = void 0;
|
|
2058
2130
|
}
|
|
2059
2131
|
if (this.agent) return this.agent;
|
|
2060
2132
|
const reportOptions = this.readCliReportAgentOptions();
|
|
2061
2133
|
if (opts?.mode === 'rdp') {
|
|
2062
|
-
|
|
2134
|
+
agent_tools_debug('Creating RDP Computer agent for host:', opts.host);
|
|
2063
2135
|
const { mode: _mode, ...rdpFields } = opts;
|
|
2064
2136
|
const agent = await agentForRDPComputer({
|
|
2065
2137
|
...rdpFields,
|
|
@@ -2071,7 +2143,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
|
|
|
2071
2143
|
}
|
|
2072
2144
|
const displayId = opts?.mode === 'local' ? opts.displayId : void 0;
|
|
2073
2145
|
const headless = opts?.mode === 'local' ? opts.headless : void 0;
|
|
2074
|
-
|
|
2146
|
+
agent_tools_debug('Creating Computer agent with displayId:', displayId || 'primary');
|
|
2075
2147
|
const agentOpts = {
|
|
2076
2148
|
...displayId ? {
|
|
2077
2149
|
displayId
|
|
@@ -2102,7 +2174,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
|
|
|
2102
2174
|
try {
|
|
2103
2175
|
await this.agent.destroy?.();
|
|
2104
2176
|
} catch (error) {
|
|
2105
|
-
|
|
2177
|
+
agent_tools_debug('Failed to destroy agent during connect:', error);
|
|
2106
2178
|
}
|
|
2107
2179
|
this.agent = void 0;
|
|
2108
2180
|
this.lastInitArgsSignature = void 0;
|
|
@@ -2145,7 +2217,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
|
|
|
2145
2217
|
];
|
|
2146
2218
|
}
|
|
2147
2219
|
constructor(...args){
|
|
2148
|
-
super(...args),
|
|
2220
|
+
super(...args), agent_tools_define_property(this, "lastInitArgsSignature", void 0), agent_tools_define_property(this, "initArgSpec", {
|
|
2149
2221
|
namespace: 'computer',
|
|
2150
2222
|
shape: computerInitArgShape,
|
|
2151
2223
|
cli: {
|
|
@@ -2157,7 +2229,7 @@ class ComputerMidsceneTools extends base_tools_namespaceObject.BaseMidsceneTools
|
|
|
2157
2229
|
}
|
|
2158
2230
|
const env_namespaceObject = require("@midscene/shared/env");
|
|
2159
2231
|
function version() {
|
|
2160
|
-
const currentVersion = "1.
|
|
2232
|
+
const currentVersion = "1.10.1-beta-20260624112700.0";
|
|
2161
2233
|
console.log(`@midscene/computer v${currentVersion}`);
|
|
2162
2234
|
return currentVersion;
|
|
2163
2235
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { AbstractInterface } from '@midscene/core/device';
|
|
2
2
|
import { Agent } from '@midscene/core/agent';
|
|
3
|
-
import { AgentBehaviorInitArgs } from '@midscene/shared/
|
|
3
|
+
import { AgentBehaviorInitArgs } from '@midscene/shared/agent-tools/agent-behavior-init-args';
|
|
4
4
|
import { AgentOpt } from '@midscene/core/agent';
|
|
5
|
-
import { BaseMidsceneTools } from '@midscene/shared/
|
|
5
|
+
import { BaseMidsceneTools } from '@midscene/shared/agent-tools/base-tools';
|
|
6
6
|
import { ChildProcessWithoutNullStreams } from 'node:child_process';
|
|
7
7
|
import { ComputerInputPrimitives } from '@midscene/core/device';
|
|
8
8
|
import type { DeviceAction } from '@midscene/core';
|
|
9
|
-
import { InitArgSpec } from '@midscene/shared/
|
|
9
|
+
import { InitArgSpec } from '@midscene/shared/agent-tools/base-tools';
|
|
10
10
|
import type { InterfaceType } from '@midscene/core';
|
|
11
11
|
import { overrideAIConfig } from '@midscene/shared/env';
|
|
12
12
|
import type { Size } from '@midscene/core';
|
|
13
13
|
import { SpawnOptionsWithoutStdio } from 'node:child_process';
|
|
14
|
-
import type { ToolDefinition } from '@midscene/shared/
|
|
14
|
+
import type { ToolDefinition } from '@midscene/shared/agent-tools/types';
|
|
15
15
|
|
|
16
16
|
declare interface AccessibilityCheckResult {
|
|
17
17
|
hasPermission: boolean;
|
|
@@ -101,6 +101,20 @@ export declare class ComputerDevice implements AbstractInterface {
|
|
|
101
101
|
*/
|
|
102
102
|
private isRunningAsAdmin;
|
|
103
103
|
screenshotBase64(): Promise<string>;
|
|
104
|
+
/**
|
|
105
|
+
* Windows screenshot path that bypasses screenshot-desktop's polyglot .bat
|
|
106
|
+
* (see screenshotBase64 for the rationale). Captures via PowerShell +
|
|
107
|
+
* System.Drawing, which honors `displayId` by matching the monitor's
|
|
108
|
+
* DeviceName and captures in virtual-desktop coordinates, so secondary
|
|
109
|
+
* displays — including those at negative offsets — are supported.
|
|
110
|
+
*
|
|
111
|
+
* Note: the script makes the process system-DPI-aware (SetProcessDPIAware)
|
|
112
|
+
* so captures return physical pixels. On mixed-DPI multi-monitor setups a
|
|
113
|
+
* non-primary monitor may still be off by its per-monitor scale factor;
|
|
114
|
+
* system DPI awareness covers the common single-scale and uniform-scale
|
|
115
|
+
* cases that #2150 reports.
|
|
116
|
+
*/
|
|
117
|
+
private screenshotViaPowershell;
|
|
104
118
|
size(): Promise<Size>;
|
|
105
119
|
private toGlobalPoint;
|
|
106
120
|
/**
|
|
@@ -153,7 +167,7 @@ export declare interface ComputerDeviceOpt {
|
|
|
153
167
|
/**
|
|
154
168
|
* Discriminated union describing the two ways `computer_*` tools can spawn an
|
|
155
169
|
* agent. `mode` is filled in by `initArgSpec.adapt` based on whether `host` is
|
|
156
|
-
* set, so callers (CLI/
|
|
170
|
+
* set, so callers (CLI/YAML) never have to provide it explicitly.
|
|
157
171
|
*/
|
|
158
172
|
declare type ComputerInitArgs = ComputerLocalInitArgs | ComputerRDPInitArgs;
|
|
159
173
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/computer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.1-beta-20260624112700.0",
|
|
4
4
|
"description": "Midscene.js Computer Desktop Automation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,19 +27,14 @@
|
|
|
27
27
|
"import": "./dist/es/index.mjs",
|
|
28
28
|
"require": "./dist/lib/index.js"
|
|
29
29
|
},
|
|
30
|
-
"./mcp-server": {
|
|
31
|
-
"types": "./dist/types/mcp-server.d.ts",
|
|
32
|
-
"import": "./dist/es/mcp-server.mjs",
|
|
33
|
-
"require": "./dist/lib/mcp-server.js"
|
|
34
|
-
},
|
|
35
30
|
"./package.json": "./package.json"
|
|
36
31
|
},
|
|
37
32
|
"dependencies": {
|
|
38
33
|
"@computer-use/libnut": "^4.2.0",
|
|
39
34
|
"clipboardy": "^4.0.0",
|
|
40
35
|
"screenshot-desktop": "^1.15.3",
|
|
41
|
-
"@midscene/
|
|
42
|
-
"@midscene/
|
|
36
|
+
"@midscene/shared": "1.10.1-beta-20260624112700.0",
|
|
37
|
+
"@midscene/core": "1.10.1-beta-20260624112700.0"
|
|
43
38
|
},
|
|
44
39
|
"optionalDependencies": {
|
|
45
40
|
"node-mac-permissions": "2.5.0"
|