usecomputer 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +338 -0
  3. package/build.zig +1 -0
  4. package/dist/bridge-contract.test.js +124 -63
  5. package/dist/bridge.d.ts.map +1 -1
  6. package/dist/bridge.js +241 -46
  7. package/dist/cli-parsing.test.js +34 -11
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +328 -22
  10. package/dist/coord-map.d.ts +14 -0
  11. package/dist/coord-map.d.ts.map +1 -0
  12. package/dist/coord-map.js +75 -0
  13. package/dist/coord-map.test.d.ts +2 -0
  14. package/dist/coord-map.test.d.ts.map +1 -0
  15. package/dist/coord-map.test.js +157 -0
  16. package/dist/darwin-arm64/usecomputer.node +0 -0
  17. package/dist/darwin-x64/usecomputer.node +0 -0
  18. package/dist/debug-point-image.d.ts +8 -0
  19. package/dist/debug-point-image.d.ts.map +1 -0
  20. package/dist/debug-point-image.js +43 -0
  21. package/dist/debug-point-image.test.d.ts +2 -0
  22. package/dist/debug-point-image.test.d.ts.map +1 -0
  23. package/dist/debug-point-image.test.js +44 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3 -1
  27. package/dist/lib.d.ts +26 -0
  28. package/dist/lib.d.ts.map +1 -0
  29. package/dist/lib.js +88 -0
  30. package/dist/native-click-smoke.test.js +69 -29
  31. package/dist/native-lib.d.ts +59 -1
  32. package/dist/native-lib.d.ts.map +1 -1
  33. package/dist/terminal-table.d.ts +10 -0
  34. package/dist/terminal-table.d.ts.map +1 -0
  35. package/dist/terminal-table.js +55 -0
  36. package/dist/terminal-table.test.d.ts +2 -0
  37. package/dist/terminal-table.test.d.ts.map +1 -0
  38. package/dist/terminal-table.test.js +41 -0
  39. package/dist/types.d.ts +45 -0
  40. package/dist/types.d.ts.map +1 -1
  41. package/package.json +16 -4
  42. package/src/bridge-contract.test.ts +140 -69
  43. package/src/bridge.ts +293 -53
  44. package/src/cli-parsing.test.ts +61 -0
  45. package/src/cli.ts +401 -25
  46. package/src/coord-map.test.ts +178 -0
  47. package/src/coord-map.ts +105 -0
  48. package/src/debug-point-image.test.ts +50 -0
  49. package/src/debug-point-image.ts +69 -0
  50. package/src/index.ts +3 -1
  51. package/src/lib.ts +125 -0
  52. package/src/native-click-smoke.test.ts +81 -63
  53. package/src/native-lib.ts +39 -1
  54. package/src/terminal-table.test.ts +44 -0
  55. package/src/terminal-table.ts +88 -0
  56. package/src/types.ts +50 -0
  57. package/zig/src/lib.zig +1280 -163
  58. package/zig/src/scroll.zig +213 -0
  59. package/zig/src/window.zig +123 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@
4
4
 
5
5
  All notable changes to `usecomputer` will be documented in this file.
6
6
 
7
+ ## 0.0.3
8
+
9
+ - Implement real screenshot capture + PNG file writing on macOS.
10
+ - Screenshot path handling now uses the requested output path reliably.
11
+ - Unimplemented commands now return explicit `TODO not implemented: ...` errors.
12
+ - Clarify `--display` index behavior as 0-based in help/docs.
13
+
14
+ ## 0.0.2
15
+
16
+ - Publish macOS native binaries for both `darwin-arm64` and `darwin-x64`.
17
+ - Add package metadata/docs for npm distribution.
18
+ - Improve CLI coordinate input with `-x` / `-y` flags.
19
+
7
20
  ## 0.0.1
8
21
 
9
22
  - Initial npm package release for macOS.
package/README.md CHANGED
@@ -7,6 +7,14 @@
7
7
  It can move the mouse, click, drag, and query cursor position using native
8
8
  Quartz events through a Zig N-API module.
9
9
 
10
+ Keyboard synthesis (`type` and `press`) is also available. The native backend
11
+ includes platform-specific key injection paths for macOS, Windows, and Linux
12
+ X11.
13
+
14
+ The package also exports the native commands as plain library functions, so you
15
+ can `import * as usecomputer from "usecomputer"` and reuse the same screenshot,
16
+ mouse, keyboard, and coord-map behavior from Node.js.
17
+
10
18
  ## Install
11
19
 
12
20
  ```bash
@@ -24,8 +32,321 @@ npm install -g usecomputer
24
32
  usecomputer mouse position --json
25
33
  usecomputer mouse move -x 500 -y 500
26
34
  usecomputer click -x 500 -y 500 --button left --count 1
35
+ usecomputer type "hello"
36
+ usecomputer press "cmd+s"
37
+ ```
38
+
39
+ ## Library usage
40
+
41
+ ```ts
42
+ import * as usecomputer from 'usecomputer'
43
+
44
+ const screenshot = await usecomputer.screenshot({
45
+ path: './tmp/shot.png',
46
+ display: null,
47
+ window: null,
48
+ region: null,
49
+ annotate: null,
50
+ })
51
+
52
+ const coordMap = usecomputer.parseCoordMapOrThrow(screenshot.coordMap)
53
+ const point = usecomputer.mapPointFromCoordMap({
54
+ point: { x: 400, y: 220 },
55
+ coordMap,
56
+ })
57
+
58
+ await usecomputer.click({
59
+ point,
60
+ button: 'left',
61
+ count: 1,
62
+ })
63
+ ```
64
+
65
+ These exported functions intentionally mirror the native command shapes used by
66
+ the Zig N-API module. Optional native fields are passed as `null` when absent.
67
+
68
+ ## OpenAI computer tool example
69
+
70
+ ```ts
71
+ import fs from 'node:fs'
72
+ import * as usecomputer from 'usecomputer'
73
+
74
+ async function sendComputerScreenshot() {
75
+ const screenshot = await usecomputer.screenshot({
76
+ path: './tmp/computer-tool.png',
77
+ display: null,
78
+ window: null,
79
+ region: null,
80
+ annotate: null,
81
+ })
82
+
83
+ return {
84
+ screenshot,
85
+ imageBase64: await fs.promises.readFile(screenshot.path, 'base64'),
86
+ }
87
+ }
88
+
89
+ async function runComputerAction(action, coordMap) {
90
+ if (action.type === 'click') {
91
+ await usecomputer.click({
92
+ point: usecomputer.mapPointFromCoordMap({
93
+ point: { x: action.x, y: action.y },
94
+ coordMap: usecomputer.parseCoordMapOrThrow(coordMap),
95
+ }),
96
+ button: action.button ?? 'left',
97
+ count: 1,
98
+ })
99
+ return
100
+ }
101
+
102
+ if (action.type === 'double_click') {
103
+ await usecomputer.click({
104
+ point: usecomputer.mapPointFromCoordMap({
105
+ point: { x: action.x, y: action.y },
106
+ coordMap: usecomputer.parseCoordMapOrThrow(coordMap),
107
+ }),
108
+ button: action.button ?? 'left',
109
+ count: 2,
110
+ })
111
+ return
112
+ }
113
+
114
+ if (action.type === 'scroll') {
115
+ await usecomputer.scroll({
116
+ direction: action.scrollY && action.scrollY < 0 ? 'up' : 'down',
117
+ amount: Math.abs(action.scrollY ?? 0),
118
+ at: typeof action.x === 'number' && typeof action.y === 'number'
119
+ ? usecomputer.mapPointFromCoordMap({
120
+ point: { x: action.x, y: action.y },
121
+ coordMap: usecomputer.parseCoordMapOrThrow(coordMap),
122
+ })
123
+ : null,
124
+ })
125
+ return
126
+ }
127
+
128
+ if (action.type === 'keypress') {
129
+ await usecomputer.press({
130
+ key: action.keys.join('+'),
131
+ count: 1,
132
+ delayMs: null,
133
+ })
134
+ return
135
+ }
136
+
137
+ if (action.type === 'type') {
138
+ await usecomputer.typeText({
139
+ text: action.text,
140
+ delayMs: null,
141
+ })
142
+ }
143
+ }
27
144
  ```
28
145
 
146
+ ## Anthropic computer use example
147
+
148
+ Anthropic's computer tool uses action names like `left_click`, `double_click`,
149
+ `mouse_move`, `key`, `type`, `scroll`, and `screenshot`. `usecomputer`
150
+ provides the execution layer for those actions.
151
+
152
+ ```ts
153
+ import fs from 'node:fs'
154
+ import Anthropic from '@anthropic-ai/sdk'
155
+ import type {
156
+ BetaToolResultBlockParam,
157
+ BetaToolUseBlock,
158
+ } from '@anthropic-ai/sdk/resources/beta/messages/messages'
159
+ import * as usecomputer from 'usecomputer'
160
+
161
+ const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
162
+
163
+ const message = await anthropic.beta.messages.create({
164
+ model: 'claude-opus-4-6',
165
+ max_tokens: 1024,
166
+ tools: [
167
+ {
168
+ type: 'computer_20251124',
169
+ name: 'computer',
170
+ display_width_px: 1024,
171
+ display_height_px: 768,
172
+ display_number: 1,
173
+ },
174
+ ],
175
+ messages: [{ role: 'user', content: 'Open Safari and search for usecomputer.' }],
176
+ betas: ['computer-use-2025-11-24'],
177
+ })
178
+
179
+ for (const block of message.content) {
180
+ if (block.type !== 'tool_use' || block.name !== 'computer') {
181
+ continue
182
+ }
183
+
184
+ const toolUse = block as BetaToolUseBlock
185
+ await usecomputer.screenshot({
186
+ path: './tmp/claude-current-screen.png',
187
+ display: null,
188
+ window: null,
189
+ region: null,
190
+ annotate: null,
191
+ })
192
+ const coordinate = Array.isArray(toolUse.input.coordinate)
193
+ ? toolUse.input.coordinate
194
+ : null
195
+ const point = coordinate
196
+ ? { x: coordinate[0] ?? 0, y: coordinate[1] ?? 0 }
197
+ : null
198
+
199
+ switch (toolUse.input.action) {
200
+ case 'screenshot': {
201
+ break
202
+ }
203
+ case 'left_click': {
204
+ if (point) {
205
+ await usecomputer.click({ point, button: 'left', count: 1 })
206
+ }
207
+ break
208
+ }
209
+ case 'double_click': {
210
+ if (point) {
211
+ await usecomputer.click({ point, button: 'left', count: 2 })
212
+ }
213
+ break
214
+ }
215
+ case 'mouse_move': {
216
+ if (point) {
217
+ await usecomputer.mouseMove(point)
218
+ }
219
+ break
220
+ }
221
+ case 'type': {
222
+ if (typeof toolUse.input.text === 'string') {
223
+ await usecomputer.typeText({ text: toolUse.input.text, delayMs: null })
224
+ }
225
+ break
226
+ }
227
+ case 'key': {
228
+ if (typeof toolUse.input.text === 'string') {
229
+ await usecomputer.press({ key: toolUse.input.text, count: 1, delayMs: null })
230
+ }
231
+ break
232
+ }
233
+ case 'scroll': {
234
+ await usecomputer.scroll({
235
+ direction: toolUse.input.scroll_direction === 'up' || toolUse.input.scroll_direction === 'down' || toolUse.input.scroll_direction === 'left' || toolUse.input.scroll_direction === 'right'
236
+ ? toolUse.input.scroll_direction
237
+ : 'down',
238
+ amount: typeof toolUse.input.scroll_amount === 'number' ? toolUse.input.scroll_amount : 3,
239
+ at: point,
240
+ })
241
+ break
242
+ }
243
+ default: {
244
+ throw new Error(`Unsupported Claude computer action: ${String(toolUse.input.action)}`)
245
+ }
246
+ }
247
+
248
+ const afterActionScreenshot = await usecomputer.screenshot({
249
+ path: './tmp/claude-computer-tool.png',
250
+ display: null,
251
+ window: null,
252
+ region: null,
253
+ annotate: null,
254
+ })
255
+ const imageBase64 = await fs.promises.readFile(afterActionScreenshot.path, 'base64')
256
+ const toolResult: BetaToolResultBlockParam = {
257
+ type: 'tool_result',
258
+ tool_use_id: toolUse.id,
259
+ content: [
260
+ {
261
+ type: 'image',
262
+ source: {
263
+ type: 'base64',
264
+ media_type: 'image/png',
265
+ data: imageBase64,
266
+ },
267
+ },
268
+ ],
269
+ }
270
+ // Append toolResult to the next user message in your agent loop.
271
+ }
272
+ ```
273
+
274
+ ## Screenshot scaling and coord-map
275
+
276
+ `usecomputer screenshot` always scales the output image so the longest edge is
277
+ at most `1568` px. This keeps screenshots in a model-friendly size for
278
+ computer-use agents.
279
+
280
+ Screenshot output includes:
281
+
282
+ - `desktopIndex` (display index used for capture)
283
+ - `coordMap` in the form `captureX,captureY,captureWidth,captureHeight,imageWidth,imageHeight`
284
+ - `hint` with usage text for coordinate mapping
285
+
286
+ Always pass the exact `--coord-map` value emitted by `usecomputer screenshot`
287
+ to pointer commands when you are clicking coordinates from that screenshot.
288
+ This maps screenshot-space coordinates back to real screen coordinates:
289
+
290
+ ```bash
291
+ usecomputer screenshot ./shot.png --json
292
+ usecomputer click -x 400 -y 220 --coord-map "0,0,1600,900,1568,882"
293
+ usecomputer mouse move -x 100 -y 80 --coord-map "0,0,1600,900,1568,882"
294
+ ```
295
+
296
+ To validate a target before clicking, use `debug-point`. It takes the same
297
+ coordinates and `--coord-map`, captures a fresh full-desktop screenshot, and
298
+ draws a red marker where the click would land. When `--coord-map` is present,
299
+ it captures that same region so the overlay matches the screenshot you are
300
+ targeting:
301
+
302
+ ```bash
303
+ usecomputer debug-point -x 400 -y 220 --coord-map "0,0,1600,900,1568,882"
304
+ ```
305
+
306
+ ## Keyboard commands
307
+
308
+ ### Type text
309
+
310
+ ```bash
311
+ # Short text
312
+ usecomputer type "hello from usecomputer"
313
+
314
+ # Type from stdin (good for multiline or very long text)
315
+ cat ./notes.txt | usecomputer type --stdin --chunk-size 4000 --chunk-delay 15
316
+
317
+ # Simulate slower typing for apps that drop fast input
318
+ usecomputer type "hello" --delay 20
319
+ ```
320
+
321
+ `--delay` is the per-character delay in milliseconds.
322
+
323
+ For very long text, prefer `--stdin` + `--chunk-size` so shell argument limits
324
+ and app input buffers are less likely to cause dropped characters.
325
+
326
+ ### Press keys and shortcuts
327
+
328
+ ```bash
329
+ # Single key
330
+ usecomputer press "enter"
331
+
332
+ # Chords
333
+ usecomputer press "cmd+s"
334
+ usecomputer press "cmd+shift+p"
335
+ usecomputer press "ctrl+s"
336
+
337
+ # Repeats
338
+ usecomputer press "down" --count 10 --delay 30
339
+ ```
340
+
341
+ Modifier aliases: `cmd`/`command`/`meta`, `ctrl`/`control`, `alt`/`option`,
342
+ `shift`, `fn`.
343
+
344
+ Platform note:
345
+
346
+ - macOS: `cmd` maps to Command.
347
+ - Windows/Linux: `cmd` maps to Win/Super.
348
+ - For app shortcuts that should work on Windows/Linux too, prefer `ctrl+...`.
349
+
29
350
  ## Coordinate options
30
351
 
31
352
  Commands that target coordinates accept `-x` and `-y` flags:
@@ -34,4 +355,21 @@ Commands that target coordinates accept `-x` and `-y` flags:
34
355
  - `usecomputer hover -x <n> -y <n>`
35
356
  - `usecomputer mouse move -x <n> -y <n>`
36
357
 
358
+ `mouse move` is optional before `click` when click coordinates are already
359
+ provided.
360
+
37
361
  Legacy coordinate forms are also accepted where available.
362
+
363
+ ## Display index options
364
+
365
+ For commands that accept `--display`, the index is 0-based:
366
+
367
+ - `0` = first display
368
+ - `1` = second display
369
+ - `2` = third display
370
+
371
+ Example:
372
+
373
+ ```bash
374
+ usecomputer screenshot ./shot.png --display 0 --json
375
+ ```
package/build.zig CHANGED
@@ -29,6 +29,7 @@ pub fn build(b: *std.Build) void {
29
29
  if (target.result.os.tag == .macos) {
30
30
  lib.root_module.linkFramework("CoreGraphics", .{});
31
31
  lib.root_module.linkFramework("CoreFoundation", .{});
32
+ lib.root_module.linkFramework("ImageIO", .{});
32
33
  }
33
34
 
34
35
  napigen.setup(lib);
@@ -1,74 +1,135 @@
1
- // Contract tests for command names and payloads emitted to the native bridge.
1
+ // Contract tests for direct native method calls emitted by the TS bridge.
2
+ // These tests intentionally call the real Zig native module.
2
3
  import { describe, expect, test } from 'vitest';
3
4
  import { createBridgeFromNative } from './bridge.js';
4
- function createFakeNative({ calls }) {
5
- return {
6
- execute(command, payloadJson) {
7
- const payload = JSON.parse(payloadJson);
8
- calls.push({ command, payload });
9
- if (command === 'mouse-position') {
10
- return JSON.stringify({ ok: true, data: { x: 10, y: 20 } });
11
- }
12
- if (command === 'display-list') {
13
- return JSON.stringify({
14
- ok: true,
15
- data: [
16
- { id: 1, name: 'Built-in', x: 0, y: 0, width: 1512, height: 982, scale: 2, isPrimary: true },
17
- ],
18
- });
19
- }
20
- if (command === 'clipboard-get') {
21
- return JSON.stringify({ ok: true, data: { text: 'hello' } });
22
- }
23
- if (command === 'screenshot') {
24
- return JSON.stringify({ ok: true, data: { path: '/tmp/test.png' } });
25
- }
26
- return JSON.stringify({ ok: true, data: null });
27
- },
28
- };
29
- }
5
+ import { native } from './native-lib.js';
30
6
  describe('native bridge contract', () => {
31
- test('maps high-level calls to native commands', async () => {
32
- const calls = [];
33
- const bridge = createBridgeFromNative({ nativeModule: createFakeNative({ calls }) });
7
+ test('bridge calls hit real Zig module', async () => {
8
+ expect(native).toBeTruthy();
9
+ if (!native) {
10
+ return;
11
+ }
12
+ const bridge = createBridgeFromNative({ nativeModule: native });
13
+ const safeTarget = {
14
+ x: 0,
15
+ y: 0,
16
+ };
34
17
  await bridge.click({
35
- point: { x: 100, y: 200 },
18
+ point: safeTarget,
36
19
  button: 'left',
37
- count: 2,
38
- modifiers: ['cmd'],
20
+ count: 1,
21
+ modifiers: [],
39
22
  });
40
- await bridge.typeText({ text: 'hello', delayMs: 30 });
41
- await bridge.press({ key: 'enter', count: 1 });
42
- await bridge.scroll({ direction: 'down', amount: 300 });
43
- await bridge.drag({ from: { x: 10, y: 10 }, to: { x: 200, y: 120 }, button: 'left' });
44
- await bridge.hover({ x: 33, y: 44 });
45
- await bridge.mouseMove({ x: 60, y: 70 });
23
+ await bridge.hover(safeTarget);
24
+ await bridge.mouseMove(safeTarget);
46
25
  await bridge.mouseDown({ button: 'left' });
47
26
  await bridge.mouseUp({ button: 'left' });
48
- await bridge.mousePosition();
49
- await bridge.displayList();
50
- await bridge.clipboardGet();
51
- await bridge.clipboardSet({ text: 'copied' });
52
- await bridge.screenshot({ path: './out.png' });
53
- expect(calls.map((call) => {
54
- return call.command;
55
- })).toMatchInlineSnapshot(`
56
- [
57
- "click",
58
- "type-text",
59
- "press",
60
- "scroll",
61
- "drag",
62
- "hover",
63
- "mouse-move",
64
- "mouse-down",
65
- "mouse-up",
66
- "mouse-position",
67
- "display-list",
68
- "clipboard-get",
69
- "clipboard-set",
70
- "screenshot",
71
- ]
27
+ await bridge.drag({
28
+ from: safeTarget,
29
+ to: { x: safeTarget.x + 6, y: safeTarget.y + 6 },
30
+ button: 'left',
31
+ durationMs: 10,
32
+ });
33
+ const screenshot = await bridge.screenshot({ path: `${process.cwd()}/tmp/bridge-contract-shot.png` });
34
+ await bridge.typeText({ text: 'h', delayMs: 30 });
35
+ await bridge.press({ key: 'backspace', count: 1 });
36
+ const scrollResult = await bridge.scroll({ direction: 'down', amount: 1 }).then(() => {
37
+ return 'ok';
38
+ }, (error) => {
39
+ return error instanceof Error ? error.message : String(error);
40
+ });
41
+ const scrollAtResult = await bridge.scroll({ direction: 'right', amount: 1, at: safeTarget }).then(() => {
42
+ return 'ok';
43
+ }, (error) => {
44
+ return error instanceof Error ? error.message : String(error);
45
+ });
46
+ const displays = await bridge.displayList();
47
+ const windows = await bridge.windowList();
48
+ const clipboardGetResult = await bridge.clipboardGet().then(() => {
49
+ return 'ok';
50
+ }, (error) => {
51
+ return error instanceof Error ? error.message : String(error);
52
+ });
53
+ const clipboardSetResult = await bridge.clipboardSet({ text: 'copied' }).then(() => {
54
+ return 'ok';
55
+ }, (error) => {
56
+ return error instanceof Error ? error.message : String(error);
57
+ });
58
+ const isOkOrTodo = ({ value }) => {
59
+ return value === 'ok' || value.includes('TODO not implemented');
60
+ };
61
+ expect({
62
+ screenshotShape: {
63
+ path: screenshot.path,
64
+ desktopIndex: typeof screenshot.desktopIndex,
65
+ captureX: typeof screenshot.captureX,
66
+ captureY: typeof screenshot.captureY,
67
+ captureWidth: screenshot.captureWidth > 0,
68
+ captureHeight: screenshot.captureHeight > 0,
69
+ imageWidth: screenshot.imageWidth > 0,
70
+ imageHeight: screenshot.imageHeight > 0,
71
+ coordMapHasSixValues: screenshot.coordMap.split(',').length === 6,
72
+ hint: screenshot.hint,
73
+ },
74
+ firstDisplayShape: displays[0]
75
+ ? {
76
+ id: typeof displays[0].id,
77
+ index: typeof displays[0].index,
78
+ width: displays[0].width > 0,
79
+ height: displays[0].height > 0,
80
+ }
81
+ : null,
82
+ firstWindowShape: windows[0]
83
+ ? {
84
+ id: typeof windows[0].id,
85
+ ownerName: typeof windows[0].ownerName,
86
+ desktopIndex: typeof windows[0].desktopIndex,
87
+ }
88
+ : null,
89
+ optionalCommandOutcomes: {
90
+ scrollResult: isOkOrTodo({ value: scrollResult }),
91
+ scrollAtResult: isOkOrTodo({ value: scrollAtResult }),
92
+ clipboardGetResult: isOkOrTodo({ value: clipboardGetResult }),
93
+ clipboardSetResult: isOkOrTodo({ value: clipboardSetResult }),
94
+ },
95
+ }).toMatchInlineSnapshot(`
96
+ {
97
+ "firstDisplayShape": {
98
+ "height": true,
99
+ "id": "number",
100
+ "index": "number",
101
+ "width": true,
102
+ },
103
+ "firstWindowShape": {
104
+ "desktopIndex": "number",
105
+ "id": "number",
106
+ "ownerName": "string",
107
+ },
108
+ "optionalCommandOutcomes": {
109
+ "clipboardGetResult": true,
110
+ "clipboardSetResult": true,
111
+ "scrollAtResult": true,
112
+ "scrollResult": true,
113
+ },
114
+ "screenshotShape": {
115
+ "captureHeight": true,
116
+ "captureWidth": true,
117
+ "captureX": "number",
118
+ "captureY": "number",
119
+ "coordMapHasSixValues": true,
120
+ "desktopIndex": "number",
121
+ "hint": "ALWAYS pass this exact coord map to click, hover, drag, and mouse move when using coordinates from this screenshot:
122
+ --coord-map "0,0,3440,1440,1568,656"
123
+
124
+ Example:
125
+ usecomputer click -x 400 -y 220 --coord-map "0,0,3440,1440,1568,656"",
126
+ "imageHeight": true,
127
+ "imageWidth": true,
128
+ "path": "/Users/morse/Documents/GitHub/kimakivoice/usecomputer/tmp/bridge-contract-shot.png",
129
+ },
130
+ }
72
131
  `);
132
+ expect(displays.length).toBeGreaterThan(0);
133
+ expect(windows.length).toBeGreaterThan(0);
73
134
  });
74
135
  });
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC3D,OAAO,KAAK,EASV,iBAAiB,EAElB,MAAM,YAAY,CAAA;AA6CnB,wBAAgB,sBAAsB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,EAAE,YAAY,GAAG,IAAI,CAAA;CAAE,GAAG,iBAAiB,CA+FjH;AAED,wBAAgB,YAAY,IAAI,iBAAiB,CAEhD"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE3D,OAAO,KAAK,EAaV,iBAAiB,EAElB,MAAM,YAAY,CAAA;AAsHnB,wBAAgB,sBAAsB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,EAAE,YAAY,GAAG,IAAI,CAAA;CAAE,GAAG,iBAAiB,CAiQjH;AAED,wBAAgB,YAAY,IAAI,iBAAiB,CAEhD"}