@melra/computer-runtime 0.3.0-alpha.10 → 0.3.0-alpha.12
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 +3 -1
- package/package.json +3 -3
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -259
- package/dist/index.test.js.map +0 -1
- package/dist/windows.test.d.ts +0 -2
- package/dist/windows.test.d.ts.map +0 -1
- package/dist/windows.test.js +0 -129
- package/dist/windows.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Screen and input control for [MELRA](https://github.com/XAGI-Lab/melra):
|
|
4
4
|
capabilities, inspect, screenshot, click, move, drag, type, key, and scroll,
|
|
5
|
-
driven through the host's own automation tooling
|
|
5
|
+
driven through the host's own automation tooling: native scripts on macOS,
|
|
6
|
+
Windows PowerShell and .NET on Windows, and screenshot tools plus `xdotool` on
|
|
7
|
+
Linux/X11.
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
npm install @melra/computer-runtime
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@melra/computer-runtime",
|
|
3
|
-
"version": "0.3.0-alpha.
|
|
3
|
+
"version": "0.3.0-alpha.12",
|
|
4
4
|
"description": "Computer-use reference effect adapter for the MELRA kernel.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"dist"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@melra/protocol": "0.3.0-alpha.
|
|
24
|
+
"@melra/protocol": "0.3.0-alpha.12"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
27
|
"build": "tsc -p tsconfig.json",
|
|
28
28
|
"clean": "rm -rf dist",
|
|
29
29
|
"test": "vitest run",
|
|
30
|
-
"typecheck": "tsc -p tsconfig.json
|
|
30
|
+
"typecheck": "tsc -p tsconfig.test.json"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/dist/index.test.d.ts
DELETED
package/dist/index.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
package/dist/index.test.js
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 XAGI Labs Private Limited
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
import { ComputerOperationSchema } from "@melra/protocol";
|
|
5
|
-
import { ComputerRuntime, matchElement, parseOcrElements, parseSecureInput, } from "./index.js";
|
|
6
|
-
class TestAdapter {
|
|
7
|
-
overrides;
|
|
8
|
-
calls = [];
|
|
9
|
-
operations = [];
|
|
10
|
-
/** What `inspect` reports back; a live desktop is the only other source. */
|
|
11
|
-
elements = [];
|
|
12
|
-
constructor(overrides = {}) {
|
|
13
|
-
this.overrides = overrides;
|
|
14
|
-
}
|
|
15
|
-
async capabilities() {
|
|
16
|
-
return {
|
|
17
|
-
platform: "darwin",
|
|
18
|
-
adapter: "macos-native",
|
|
19
|
-
available: true,
|
|
20
|
-
screenshot: true,
|
|
21
|
-
pointer: true,
|
|
22
|
-
keyboard: true,
|
|
23
|
-
scroll: true,
|
|
24
|
-
inspect: true,
|
|
25
|
-
elements: true,
|
|
26
|
-
ocr: false,
|
|
27
|
-
drag: true,
|
|
28
|
-
coordinateSpaces: ["normalized", "pixel"],
|
|
29
|
-
limitations: [],
|
|
30
|
-
...this.overrides,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
async execute(operation) {
|
|
34
|
-
this.calls.push(operation.action);
|
|
35
|
-
this.operations.push(operation);
|
|
36
|
-
return {
|
|
37
|
-
success: true,
|
|
38
|
-
action: operation.action,
|
|
39
|
-
...(operation.action === "inspect" ? { elements: this.elements } : {}),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
const BUTTON = (name, x) => ({
|
|
44
|
-
role: "AXButton",
|
|
45
|
-
name,
|
|
46
|
-
x,
|
|
47
|
-
y: 40,
|
|
48
|
-
width: 80,
|
|
49
|
-
height: 20,
|
|
50
|
-
});
|
|
51
|
-
describe("ComputerRuntime", () => {
|
|
52
|
-
it("reports adapter capabilities without a mutation", async () => {
|
|
53
|
-
const adapter = new TestAdapter();
|
|
54
|
-
const runtime = new ComputerRuntime({
|
|
55
|
-
artifactDirectory: "/tmp",
|
|
56
|
-
adapter,
|
|
57
|
-
});
|
|
58
|
-
const result = await runtime.execute(ComputerOperationSchema.parse({
|
|
59
|
-
kind: "computer",
|
|
60
|
-
action: "capabilities",
|
|
61
|
-
}));
|
|
62
|
-
expect(result.available).toBe(true);
|
|
63
|
-
expect(adapter.calls).toEqual([]);
|
|
64
|
-
});
|
|
65
|
-
it("requires explicit bounded coordinates for pointer actions", async () => {
|
|
66
|
-
const runtime = new ComputerRuntime({
|
|
67
|
-
artifactDirectory: "/tmp",
|
|
68
|
-
adapter: new TestAdapter(),
|
|
69
|
-
});
|
|
70
|
-
await expect(runtime.execute(ComputerOperationSchema.parse({
|
|
71
|
-
kind: "computer",
|
|
72
|
-
action: "click",
|
|
73
|
-
}))).rejects.toThrow("computer_click_requires_coordinates");
|
|
74
|
-
await expect(runtime.execute(ComputerOperationSchema.parse({
|
|
75
|
-
kind: "computer",
|
|
76
|
-
action: "click",
|
|
77
|
-
coordinateSpace: "normalized",
|
|
78
|
-
x: 2,
|
|
79
|
-
y: 0.5,
|
|
80
|
-
}))).rejects.toThrow("computer_normalized_coordinates_out_of_range");
|
|
81
|
-
});
|
|
82
|
-
it.each([
|
|
83
|
-
["screenshot", "screenshot", "computer_screenshot_unavailable"],
|
|
84
|
-
["inspect", "inspect", "computer_inspect_unavailable"],
|
|
85
|
-
["click", "pointer", "computer_pointer_unavailable"],
|
|
86
|
-
["drag", "drag", "computer_drag_unavailable"],
|
|
87
|
-
["type", "keyboard", "computer_keyboard_unavailable"],
|
|
88
|
-
["scroll", "scroll", "computer_scroll_unavailable"],
|
|
89
|
-
])("rejects %s when its adapter capability is unavailable", async (action, capability, error) => {
|
|
90
|
-
const adapter = new TestAdapter({ [capability]: false });
|
|
91
|
-
const runtime = new ComputerRuntime({
|
|
92
|
-
artifactDirectory: "/tmp",
|
|
93
|
-
adapter,
|
|
94
|
-
});
|
|
95
|
-
const operation = {
|
|
96
|
-
kind: "computer",
|
|
97
|
-
action,
|
|
98
|
-
...(action === "click"
|
|
99
|
-
? { coordinateSpace: "pixel", x: 10, y: 10 }
|
|
100
|
-
: {}),
|
|
101
|
-
...(action === "drag"
|
|
102
|
-
? { coordinateSpace: "pixel", x: 10, y: 10, toX: 40, toY: 40 }
|
|
103
|
-
: {}),
|
|
104
|
-
...(action === "type" ? { text: "safe" } : {}),
|
|
105
|
-
};
|
|
106
|
-
await expect(runtime.execute(ComputerOperationSchema.parse(operation))).rejects.toThrow(error);
|
|
107
|
-
expect(adapter.calls).toEqual([]);
|
|
108
|
-
});
|
|
109
|
-
it("requires a destination for a drag and bounds it like the press point", async () => {
|
|
110
|
-
const adapter = new TestAdapter();
|
|
111
|
-
const runtime = new ComputerRuntime({
|
|
112
|
-
artifactDirectory: "/tmp",
|
|
113
|
-
adapter,
|
|
114
|
-
});
|
|
115
|
-
await expect(runtime.execute(ComputerOperationSchema.parse({
|
|
116
|
-
kind: "computer",
|
|
117
|
-
action: "drag",
|
|
118
|
-
coordinateSpace: "pixel",
|
|
119
|
-
x: 10,
|
|
120
|
-
y: 10,
|
|
121
|
-
}))).rejects.toThrow("computer_drag_requires_destination");
|
|
122
|
-
// The destination shares the coordinate space, so it has to be bounded by
|
|
123
|
-
// the same rule — an out-of-range `toY` used to slip through untouched.
|
|
124
|
-
await expect(runtime.execute(ComputerOperationSchema.parse({
|
|
125
|
-
kind: "computer",
|
|
126
|
-
action: "drag",
|
|
127
|
-
coordinateSpace: "normalized",
|
|
128
|
-
x: 0.1,
|
|
129
|
-
y: 0.1,
|
|
130
|
-
toX: 0.5,
|
|
131
|
-
toY: 4,
|
|
132
|
-
}))).rejects.toThrow("computer_normalized_coordinates_out_of_range");
|
|
133
|
-
expect(adapter.calls).toEqual([]);
|
|
134
|
-
});
|
|
135
|
-
it("passes a bounded drag and a read-only inspect to the adapter", async () => {
|
|
136
|
-
const adapter = new TestAdapter();
|
|
137
|
-
const runtime = new ComputerRuntime({
|
|
138
|
-
artifactDirectory: "/tmp",
|
|
139
|
-
adapter,
|
|
140
|
-
});
|
|
141
|
-
await runtime.execute(ComputerOperationSchema.parse({ kind: "computer", action: "inspect" }));
|
|
142
|
-
await runtime.execute(ComputerOperationSchema.parse({
|
|
143
|
-
kind: "computer",
|
|
144
|
-
action: "drag",
|
|
145
|
-
coordinateSpace: "normalized",
|
|
146
|
-
x: 0.1,
|
|
147
|
-
y: 0.2,
|
|
148
|
-
toX: 0.8,
|
|
149
|
-
toY: 0.9,
|
|
150
|
-
}));
|
|
151
|
-
expect(adapter.calls).toEqual(["inspect", "drag"]);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
describe("matchElement", () => {
|
|
155
|
-
const elements = [
|
|
156
|
-
BUTTON("Save", 0),
|
|
157
|
-
BUTTON("Save As…", 100),
|
|
158
|
-
{ role: "AXTextField", name: "Save", x: 200, y: 40, width: 60, height: 20 },
|
|
159
|
-
];
|
|
160
|
-
it("prefers an exact name over the substring it is a prefix of", () => {
|
|
161
|
-
expect(matchElement(elements, { role: "AXButton", name: "Save" }).x).toBe(0);
|
|
162
|
-
});
|
|
163
|
-
it("matches a role case-insensitively and a name by substring", () => {
|
|
164
|
-
expect(matchElement(elements, { role: "axbutton", name: "as…" }).x).toBe(100);
|
|
165
|
-
});
|
|
166
|
-
it("refuses rather than guessing between equally good candidates", () => {
|
|
167
|
-
// Two exact "Save" matches across roles: picking either would be a coin
|
|
168
|
-
// flip on which control gets clicked.
|
|
169
|
-
expect(() => matchElement(elements, { name: "Save" })).toThrow("computer_target_ambiguous");
|
|
170
|
-
expect(() => matchElement(elements, { name: "Print" })).toThrow("computer_target_not_found");
|
|
171
|
-
expect(() => matchElement(elements, {})).toThrow("computer_target_requires_role_or_name");
|
|
172
|
-
});
|
|
173
|
-
it("refuses to click a reading it is not sure of", () => {
|
|
174
|
-
// Reported by `inspect` — a caller may want to know the word is there — but
|
|
175
|
-
// not clickable, because the point under a doubtful reading is a guess.
|
|
176
|
-
const read = [{ ...BUTTON("Delete", 0), role: "text", confidence: 0.42 }];
|
|
177
|
-
expect(() => matchElement(read, { name: "Delete" })).toThrow("computer_target_confidence_too_low");
|
|
178
|
-
expect(matchElement([{ ...read[0], confidence: 0.91 }], { name: "Delete" }).x).toBe(0);
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
describe("parseOcrElements", () => {
|
|
182
|
-
// Real `tesseract 5 … tsv` output, trimmed: a page row, the block/para/line
|
|
183
|
-
// rows above a word, and the words themselves.
|
|
184
|
-
const tsv = [
|
|
185
|
-
"level\tpage_num\tblock_num\tpar_num\tline_num\tword_num\tleft\ttop\twidth\theight\tconf\ttext",
|
|
186
|
-
"1\t1\t0\t0\t0\t0\t0\t0\t2940\t1912\t-1\t",
|
|
187
|
-
"4\t1\t1\t1\t1\t0\t42\t15\t167\t31\t-1\t",
|
|
188
|
-
"5\t1\t1\t1\t1\t1\t100\t40\t80\t20\t96.720352\tSave",
|
|
189
|
-
"5\t1\t1\t1\t1\t2\t300\t40\t90\t20\t41.5\tCancel",
|
|
190
|
-
"5\t1\t1\t1\t1\t3\t500\t40\t60\t20\t12.25\tl1lI",
|
|
191
|
-
"5\t1\t1\t1\t1\t4\t600\t40\t60\t20\t95.0\t ",
|
|
192
|
-
].join("\n");
|
|
193
|
-
it("scales a Retina capture back onto the display it came from", () => {
|
|
194
|
-
// The image measured 2940 wide, the display is 1470: every box halves, so a
|
|
195
|
-
// click computed from one lands where the word actually is.
|
|
196
|
-
expect(parseOcrElements(tsv, 1470)).toEqual([
|
|
197
|
-
{ role: "text", name: "Save", x: 50, y: 20, width: 40, height: 10, confidence: 0.97 },
|
|
198
|
-
{ role: "text", name: "Cancel", x: 150, y: 20, width: 45, height: 10, confidence: 0.42 },
|
|
199
|
-
]);
|
|
200
|
-
});
|
|
201
|
-
it("drops noise and reads nothing at all from a capture with no page row", () => {
|
|
202
|
-
// `l1lI` is under the reporting floor and the blank token has no name;
|
|
203
|
-
// without a page row there is no scale, and guessing one would move a click.
|
|
204
|
-
expect(parseOcrElements(tsv, 1470).map((e) => e.name)).not.toContain("l1lI");
|
|
205
|
-
expect(parseOcrElements("level\tpage_num\n4\t1", 1470)).toEqual([]);
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
describe("named targets", () => {
|
|
209
|
-
const click = (target, extra = {}) => ComputerOperationSchema.parse({
|
|
210
|
-
kind: "computer",
|
|
211
|
-
action: "click",
|
|
212
|
-
target,
|
|
213
|
-
...extra,
|
|
214
|
-
});
|
|
215
|
-
it("inspects, then clicks the centre of the resolved element", async () => {
|
|
216
|
-
const adapter = new TestAdapter();
|
|
217
|
-
adapter.elements = [BUTTON("Save", 300)];
|
|
218
|
-
const runtime = new ComputerRuntime({ artifactDirectory: "/tmp", adapter });
|
|
219
|
-
const result = await runtime.execute(click({ name: "Save" }));
|
|
220
|
-
expect(adapter.calls).toEqual(["inspect", "click"]);
|
|
221
|
-
const acted = adapter.operations[1];
|
|
222
|
-
// 300 + 80/2, 40 + 20/2 — in pixels, because that is what the tree measures.
|
|
223
|
-
expect([acted.coordinateSpace, acted.x, acted.y]).toEqual(["pixel", 340, 50]);
|
|
224
|
-
expect(acted.target).toBe(undefined);
|
|
225
|
-
expect(result.element).toEqual(BUTTON("Save", 300));
|
|
226
|
-
});
|
|
227
|
-
it("refuses a target the platform or the request cannot support", async () => {
|
|
228
|
-
const adapter = new TestAdapter();
|
|
229
|
-
const runtime = new ComputerRuntime({ artifactDirectory: "/tmp", adapter });
|
|
230
|
-
adapter.elements = [BUTTON("Save", 300)];
|
|
231
|
-
await expect(runtime.execute(click({ name: "Save" }, { x: 10, y: 10 }))).rejects.toThrow("computer_target_conflicts_with_coordinates");
|
|
232
|
-
adapter.elements = [];
|
|
233
|
-
await expect(runtime.execute(click({ name: "Save" }))).rejects.toThrow("computer_elements_unavailable");
|
|
234
|
-
const blind = new ComputerRuntime({
|
|
235
|
-
artifactDirectory: "/tmp",
|
|
236
|
-
adapter: new TestAdapter({ elements: false }),
|
|
237
|
-
});
|
|
238
|
-
await expect(blind.execute(click({ name: "Save" }))).rejects.toThrow("computer_elements_unavailable");
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
describe("parseSecureInput", () => {
|
|
242
|
-
// Trimmed from real `ioreg -l -d 1 -w 0 -r -c IOResources` output on macOS 26.
|
|
243
|
-
const session = '"IOConsoleUsers" = ({"kCGSSessionOnConsoleKey"=Yes,"kSCSecuritySessionID"=100024,' +
|
|
244
|
-
'"kCGSSessionIDKey"=257,"kCGSSessionUserNameKey"="dheeraj"';
|
|
245
|
-
it("reads a held secure-input session as active", () => {
|
|
246
|
-
expect(parseSecureInput(`${session},"kCGSSessionSecureInputPID"=843})`)).toBe(true);
|
|
247
|
-
});
|
|
248
|
-
it("reads a session without the key, or with it cleared, as inactive", () => {
|
|
249
|
-
expect(parseSecureInput(`${session}})`)).toBe(false);
|
|
250
|
-
expect(parseSecureInput(`${session},"kCGSSessionSecureInputPID"=0})`)).toBe(false);
|
|
251
|
-
});
|
|
252
|
-
it("reports no reading at all when no console session was dumped", () => {
|
|
253
|
-
// Absence of the key in output that never described a session is not
|
|
254
|
-
// evidence that secure input is off — reporting `false` here would let a
|
|
255
|
-
// keystroke-swallowing state through as verified.
|
|
256
|
-
expect(parseSecureInput("+-o Root <class IORegistryEntry>")).toBe(undefined);
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
//# sourceMappingURL=index.test.js.map
|
package/dist/index.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
|
package/dist/windows.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"windows.test.d.ts","sourceRoot":"","sources":["../src/windows.test.ts"],"names":[],"mappings":""}
|
package/dist/windows.test.js
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
// Copyright 2026 XAGI Labs Private Limited
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { mkdtemp, rm, stat } from "node:fs/promises";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { ComputerOperationSchema } from "@melra/protocol";
|
|
7
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
8
|
-
import { ComputerRuntime, createSystemComputerAdapter, escapeSendKeys } from "./index.js";
|
|
9
|
-
/**
|
|
10
|
-
* Windows computer use was entirely absent: the factory had no `win32` branch,
|
|
11
|
-
* so `capabilities` reported `unavailable` and every input action threw a bare
|
|
12
|
-
* `computer_use_unavailable`. CI ran on `windows-latest` and stayed green
|
|
13
|
-
* because nothing exercised Windows behaviour — which is why the adapter tests
|
|
14
|
-
* below run for real on Windows rather than against a stub.
|
|
15
|
-
*/
|
|
16
|
-
const onWindows = process.platform === "win32";
|
|
17
|
-
const roots = [];
|
|
18
|
-
/**
|
|
19
|
-
* Two clocks, and both have to clear the same wait: vitest's own default killed
|
|
20
|
-
* these tests at 5s, and once that was raised the operation's `timeoutMs` cap
|
|
21
|
-
* killed them at 30s — which is why the schema now allows 120s for a computer
|
|
22
|
-
* action like every other operation kind.
|
|
23
|
-
*
|
|
24
|
-
* The wait is real, not slack. A computer action spawns a whole interpreter:
|
|
25
|
-
* `powershell.exe` cold-starts in seconds, the pointer script's
|
|
26
|
-
* `Add-Type -TypeDefinition` runs the C# compiler to build the P/Invoke shim,
|
|
27
|
-
* and the first such spawn after boot pays for a cold disk on top. That cost is
|
|
28
|
-
* per-process, so it is paid on every action, and a caller who leaves
|
|
29
|
-
* `timeoutMs` at its 10s default is closer to the edge on a cold or loaded
|
|
30
|
-
* machine than the number suggests.
|
|
31
|
-
*/
|
|
32
|
-
const POWERSHELL_TEST_TIMEOUT_MS = 120_000;
|
|
33
|
-
afterEach(async () => {
|
|
34
|
-
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
35
|
-
});
|
|
36
|
-
async function workspace() {
|
|
37
|
-
const root = await mkdtemp(join(tmpdir(), "melra-computer-"));
|
|
38
|
-
roots.push(root);
|
|
39
|
-
return root;
|
|
40
|
-
}
|
|
41
|
-
describe("escapeSendKeys", () => {
|
|
42
|
-
it("neutralizes the characters SendKeys reads as modifiers", () => {
|
|
43
|
-
// Unescaped, `+` is Shift, `^` is Ctrl, `%` is Alt, `~` is Enter, and the
|
|
44
|
-
// brackets group — so this password would have typed a chord and pressed
|
|
45
|
-
// Enter instead of entering any of these characters.
|
|
46
|
-
expect(escapeSendKeys("a+b^c%d~e")).toBe("a{+}b{^}c{%}d{~}e");
|
|
47
|
-
expect(escapeSendKeys("({x})[y]")).toBe("{(}{{}x{}}{)}{[}y{]}");
|
|
48
|
-
});
|
|
49
|
-
it("leaves ordinary text alone", () => {
|
|
50
|
-
expect(escapeSendKeys("Hello, world 123")).toBe("Hello, world 123");
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
describe.runIf(onWindows)("Windows computer adapter", () => {
|
|
54
|
-
it("reports itself as available rather than unavailable", async () => {
|
|
55
|
-
const runtime = new ComputerRuntime({
|
|
56
|
-
artifactDirectory: await workspace(),
|
|
57
|
-
adapter: createSystemComputerAdapter(),
|
|
58
|
-
});
|
|
59
|
-
const observed = await runtime.execute(ComputerOperationSchema.parse({ kind: "computer", action: "capabilities" }));
|
|
60
|
-
expect(observed.platform).toBe("win32");
|
|
61
|
-
expect(observed.adapter).toBe("windows-powershell");
|
|
62
|
-
expect(observed.available).toBe(true);
|
|
63
|
-
expect(observed.screenshot).toBe(true);
|
|
64
|
-
expect(observed.pointer).toBe(true);
|
|
65
|
-
// The honest ceiling of SendKeys-based input, stated rather than implied.
|
|
66
|
-
expect(observed.limitations.join(" ")).toContain("focus");
|
|
67
|
-
});
|
|
68
|
-
it("captures a real screenshot to the artifact directory", async () => {
|
|
69
|
-
const artifactDirectory = join(await workspace(), "artifacts");
|
|
70
|
-
const runtime = new ComputerRuntime({
|
|
71
|
-
artifactDirectory,
|
|
72
|
-
adapter: createSystemComputerAdapter(),
|
|
73
|
-
});
|
|
74
|
-
const observed = await runtime.execute(ComputerOperationSchema.parse({
|
|
75
|
-
kind: "computer",
|
|
76
|
-
action: "screenshot",
|
|
77
|
-
timeoutMs: 90_000,
|
|
78
|
-
}));
|
|
79
|
-
expect(observed.captured).toBe(true);
|
|
80
|
-
expect(String(observed.path).startsWith(artifactDirectory)).toBe(true);
|
|
81
|
-
const written = await stat(String(observed.path));
|
|
82
|
-
expect(written.size).toBeGreaterThan(0);
|
|
83
|
-
expect(observed.size).toBe(written.size);
|
|
84
|
-
expect(String(observed.sha256)).toHaveLength(64);
|
|
85
|
-
}, POWERSHELL_TEST_TIMEOUT_MS);
|
|
86
|
-
it("resolves a normalized coordinate against the virtual desktop", async () => {
|
|
87
|
-
const runtime = new ComputerRuntime({
|
|
88
|
-
artifactDirectory: await workspace(),
|
|
89
|
-
adapter: createSystemComputerAdapter(),
|
|
90
|
-
});
|
|
91
|
-
// A pointer move is the P/Invoke path — the part most likely to be wrong —
|
|
92
|
-
// and moving the cursor on a headless runner has no side effect worth
|
|
93
|
-
// avoiding. Clicking would, so this does not click.
|
|
94
|
-
const observed = await runtime.execute(ComputerOperationSchema.parse({
|
|
95
|
-
kind: "computer",
|
|
96
|
-
action: "move",
|
|
97
|
-
x: 0.5,
|
|
98
|
-
y: 0.5,
|
|
99
|
-
coordinateSpace: "normalized",
|
|
100
|
-
timeoutMs: 90_000,
|
|
101
|
-
}));
|
|
102
|
-
expect(observed.success).toBe(true);
|
|
103
|
-
// The pixel point comes back from the script rather than being recomputed
|
|
104
|
-
// here, so a normalized centre must land somewhere other than the origin.
|
|
105
|
-
expect(observed.x).toBeGreaterThan(0);
|
|
106
|
-
expect(observed.y).toBeGreaterThan(0);
|
|
107
|
-
}, POWERSHELL_TEST_TIMEOUT_MS);
|
|
108
|
-
it("names a timeout as a timeout instead of echoing the script", async () => {
|
|
109
|
-
const runtime = new ComputerRuntime({
|
|
110
|
-
artifactDirectory: await workspace(),
|
|
111
|
-
adapter: createSystemComputerAdapter(),
|
|
112
|
-
});
|
|
113
|
-
/**
|
|
114
|
-
* This is how the screenshot failure first presented: Node builds the
|
|
115
|
-
* rejection message from the whole command line, so the caller received
|
|
116
|
-
* fifteen lines of echoed PowerShell with an empty stderr and no way to
|
|
117
|
-
* tell a killed helper from a script that failed instantly.
|
|
118
|
-
*
|
|
119
|
-
* 100ms is unreachable for a process that has to load the CLR, so this is a
|
|
120
|
-
* timeout by construction rather than by timing luck.
|
|
121
|
-
*/
|
|
122
|
-
await expect(runtime.execute(ComputerOperationSchema.parse({
|
|
123
|
-
kind: "computer",
|
|
124
|
-
action: "screenshot",
|
|
125
|
-
timeoutMs: 100,
|
|
126
|
-
}))).rejects.toThrow(/^computer_helper_timeout:powershell\.exe:100ms$/);
|
|
127
|
-
}, POWERSHELL_TEST_TIMEOUT_MS);
|
|
128
|
-
});
|
|
129
|
-
//# sourceMappingURL=windows.test.js.map
|
package/dist/windows.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"windows.test.js","sourceRoot":"","sources":["../src/windows.test.ts"],"names":[],"mappings":"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"}
|