@agent-sh/computer-use-linux 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,6 +61,23 @@ Screenshot payloads are size-bounded by default before they are returned to the
61
61
  - `press_key` — keys / chords; can focus a window or terminal first
62
62
  - `type_text` — literal text input, optionally targeted at a window or terminal
63
63
 
64
+ For a plain left `click` by element index or selector, a recognized native
65
+ AT-SPI `click`, `press`, or `toggle` action takes precedence
66
+ over bounds. Entry `activate` and slider `jump` must be requested explicitly
67
+ with `perform_action`; they are never a substitute for a pointer click, even
68
+ when bounds are missing.
69
+ This avoids pointer conversion for GTK3 HiDPI
70
+ extents and GTK4 zero-origin bounds when the element exposes such an action.
71
+ The preference does not substitute an arbitrary action name for a coordinate
72
+ click. Explicit `x`/`y`, right clicks, and double/multiple clicks retain pointer
73
+ semantics. Re-check application state after either kind of activation.
74
+
75
+ For coordinate `click` or `scroll` with `relative: true`, select a target window
76
+ and measure from its clipped screenshot crop origin. Divide preview `x` and
77
+ `y` by the returned screenshot `scale` before passing them. These are not raw
78
+ GDK surface or widget-local coordinates; decorations and clipping can change
79
+ the origin. A missing window target is rejected.
80
+
64
81
  Targeted `press_key`/`type_text` results append focused-element feedback from AT-SPI (role, name, editable) and warn when no editable element holds focus. Click/screenshot/input results warn when the target window or coordinate is partially or fully off-screen. `get_app_state` returns a compact readiness block by default; pass `verbose: true` for the full diagnostics report.
65
82
 
66
83
  **Semantic actions**
@@ -75,6 +92,8 @@ Targeted `press_key`/`type_text` results append focused-element feedback from AT
75
92
 
76
93
  **Conditional host execution**
77
94
 
95
+ - `complete_interaction` - optional desktop completion notification, registered only with `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE=1`. Repeated calls can create repeated notifications; it does not provide desktop exclusivity.
96
+
78
97
  - `run_shell` — same-user `/bin/sh -c` execution without login-profile loading, registered only when the server operator starts the MCP process with `COMPUTER_USE_LINUX_ENABLE_SHELL=1`. It is deliberately absent by default and is not a sandbox.
79
98
 
80
99
  ### MCP safety contract
@@ -99,6 +118,7 @@ The binary also exposes the same capabilities from the CLI for scripting and deb
99
118
  computer-use-linux mcp # stdio MCP server
100
119
  computer-use-linux doctor # JSON readiness report
101
120
  computer-use-linux setup # enable AT-SPI
121
+ computer-use-linux guard-accessibility # explicit foreground GNOME accessibility guard
102
122
  computer-use-linux setup-window-targeting # install GNOME Shell extension
103
123
  computer-use-linux apps
104
124
  computer-use-linux state [APP_NAME]
@@ -358,6 +378,7 @@ Most setups need none of these — `doctor` and the installers pick sensible def
358
378
 
359
379
  | Variable | Effect |
360
380
  | --- | --- |
381
+ | `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE` | Set exactly to `1` to expose the optional `complete_interaction` notification tool. Requires `notify-send` and a desktop notification service; disabled by default. |
361
382
  | `COMPUTER_USE_LINUX_COSMIC_HELPER` | Path to the `computer-use-linux-cosmic` helper when it isn't next to the binary or on `PATH`. |
362
383
  | `CU_DISABLE_ABS_POINTER` | Disable the uinput absolute pointer and click through `ydotool` instead for setups where the abs-pointer device misbehaves. |
363
384
  | `COMPUTER_USE_LINUX_FORCE_PORTAL_POINTER` / `…_KEYBOARD` | Always route pointer / keyboard through the RemoteDesktop portal on Wayland, skipping auto-detection. |
@@ -408,6 +429,44 @@ If you're running this on a shared workstation, set `ydotoold`'s socket permissi
408
429
 
409
430
  ## Troubleshooting
410
431
 
432
+ To receive an explicit completion cue, start the MCP server with
433
+ `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE=1`. This exposes `complete_interaction`,
434
+ a parameter-free tool the agent calls once after finishing its desktop work.
435
+ It submits a notification through `notify-send` with a two-second execution
436
+ limit and bounded process cleanup. Missing services, errors, or timeouts return
437
+ `cue: "skipped"`; notification settings may suppress a submitted cue. This does
438
+ not reserve the desktop or prove that other clients have stopped sending input.
439
+ No sound or additional desktop settings are enabled by this option.
440
+ This option currently applies only to directly spawned MCP hosts. The native Pi
441
+ extension does not forward the flag or include this optional tool in its catalog.
442
+
443
+ `setup` and `setup_accessibility` write and read back GNOME's
444
+ `org.gnome.desktop.interface toolkit-accessibility` setting, even if AT-SPI
445
+ is already enabled at runtime. A runtime-only success is reported as a warning:
446
+ newly launched GTK apps may still have no tree. Enabling the saved key may
447
+ require restarting target apps. Other accessibility tools can change that key
448
+ later; setup does not continuously override user settings.
449
+
450
+ For an explicit foreground guard while using desktop automation, run:
451
+
452
+ ```bash
453
+ computer-use-linux guard-accessibility
454
+ ```
455
+
456
+ The guard registers a passive AT-SPI window-activation listener and watches
457
+ GNOME's saved `toolkit-accessibility` key. It re-enables the key after a reset
458
+ and verifies it by readback, with periodic checks as well as change monitoring.
459
+ This affects all applications using the current user's GNOME setting, not just
460
+ the target app. It does not start a screen reader or change focus.
461
+
462
+ `mcp`, `setup`, `setup_accessibility`, and `get_app_state` never start this guard.
463
+ Stop it with Ctrl-C or SIGTERM **before** intentionally disabling accessibility.
464
+ Stopping ends setting writes and removes its listener without disabling other
465
+ accessibility clients or restoring an old saved value. A reset and reassertion
466
+ are not atomic: an app launched in that interval may still need restarting.
467
+ This is an opt-in mitigation, not a guarantee that every GNOME toggle sequence
468
+ preserves application accessibility trees.
469
+
411
470
  `computer-use-linux doctor` is the source of truth. Common failure modes and fixes:
412
471
 
413
472
  - **`accessibility.at_spi_bus.ok = false`** — AT-SPI registry isn't running or the toolkit bridge is off. Fix: `computer-use-linux setup` (or call the `setup_accessibility` MCP tool). Restart the apps you want to drive.
@@ -419,9 +478,30 @@ If you're running this on a shared workstation, set `ydotoold`'s socket permissi
419
478
  - **KWin / Hyprland / i3 / COSMIC / X11 windowing is unavailable** — check `doctor.windowing.backends`. KWin needs session-bus scripting; Hyprland needs `hyprctl`; i3 needs `i3-msg` and its IPC socket; generic X11 needs `wmctrl` and `xprop`. COSMIC needs `computer-use-linux-cosmic`, which the standard installers provide automatically; if you copied binaries by hand, copy the helper too or set `COMPUTER_USE_LINUX_COSMIC_HELPER`.
420
479
  - **Screenshots return black frames on multi-monitor setups** — known portal / compositor edge case. Use `get_app_state` with `include_screenshot: false` and rely on AT-SPI until the portal backend is healthy.
421
480
  - **`type_text` types into the wrong window** — pass an explicit target (`window_id`, `pid`, `wm_class`, `title`, or for terminals `tty` / `terminal_pid` / `terminal_command` / `terminal_cwd`). Without a target, input goes to whatever window currently has compositor focus.
481
+ - **Wayland pointer actions miss an unfocused window** — injected pointer input is subject to the compositor's input-focus rules. Call `activate_window` for the target before `click`, `drag`, or coordinate `scroll`; a pointer can land at the requested coordinate without the unfocused surface receiving the action.
422
482
 
423
483
  If `doctor` is green and a specific tool still misbehaves, file an issue with the JSON output of `doctor` and the failing tool's request payload.
424
484
 
485
+ For coordinate calibration, launch [the GTK4 probe](examples/coordinate_probe.py)
486
+ in your test desktop and take a targeted screenshot. Choose the center of its
487
+ green 10x10 square from that screenshot, convert by `scale`, and click relative
488
+ to the same target window. The probe's delivered-event `hit: true` is the
489
+ acceptance condition. Do not pass its widget-local `(85, 85)` directly as a
490
+ window-relative click: margins and decorations belong to different spaces.
491
+
492
+ [The semantic-click regression](scripts/semantic_click_test.py) runs against a
493
+ built binary in an isolated graphical display and checks actual GTK3 button
494
+ activation through MCP at scales 1 and 2. This does not establish correctness
495
+ of Mutter 46 EWMH move/resize, all mixed-output layouts, or GNOME 50.4 pointer
496
+ clicks.
497
+
498
+ Native Wayland qualification on GNOME 50.1 at 133.3% display scale used the
499
+ same green target for both modes: crop-relative `(122, 145)` and desktop
500
+ `(2140, 193)` both delivered widget coordinates approximately `(84.81, 84.78)`
501
+ with `hit: true` through uinput. These are one capture's measured coordinates,
502
+ not reusable offsets. Raw surface coordinates must still be transformed before
503
+ comparing them with a widget-local target.
504
+
425
505
  ## Related
426
506
 
427
507
  - [agent-workspace-linux](https://github.com/agent-sh/agent-workspace-linux) — the sibling MCP that gives an agent its **own** isolated Linux desktop (a hidden Xvfb display with its own apps and browser) instead of driving yours. It is the inverse of this project: `computer-use-linux` automates the desktop you are already on; `agent-workspace-linux` sandboxes the agent in a separate one. Use them together.
package/npm/README.md CHANGED
@@ -9,6 +9,17 @@ mutating and can change real application state. The MCP tool list includes
9
9
  `ToolAnnotations` so hosts can distinguish read-only observation from mutating
10
10
  desktop actions.
11
11
 
12
+ Plain left `click` by element index or selector prefers a native AT-SPI
13
+ `click`, `press`, or `toggle` action over toolkit bounds,
14
+ avoiding pointer-coordinate conversion when that action is available. Explicit
15
+ `activate`/`jump` requests belong in `perform_action`, not `click`, even when
16
+ bounds are missing. Explicit
17
+ `x`/`y`, right clicks, and multi-clicks retain pointer semantics. For coordinate
18
+ `click` or `scroll` with `relative: true`, use the clipped target-window
19
+ screenshot crop origin and divide preview coordinates by screenshot `scale`.
20
+ Do not use widget-local or raw GDK surface coordinates. A window target is
21
+ required.
22
+
12
23
  ```bash
13
24
  npm install -g @agent-sh/computer-use-linux
14
25
  computer-use-linux doctor
@@ -20,6 +31,28 @@ hermes mcp test computer-use-linux
20
31
  hermes mcp configure computer-use-linux
21
32
  ```
22
33
 
34
+ For an optional MCP completion notification, set
35
+ `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE=1` in the server environment and have the
36
+ agent call `complete_interaction` after its desktop work. `notify-send` must be
37
+ installed with an available desktop notification service. The cue is best effort
38
+ and does not provide exclusive desktop ownership.
39
+ This cue is available only to directly spawned MCP hosts; the native Pi extension
40
+ does not yet forward the flag or include the tool in its catalog.
41
+
42
+ If accessibility is disabled, run `computer-use-linux setup`. Setup writes and
43
+ reads back GNOME's `toolkit-accessibility` setting and warns if only runtime
44
+ accessibility is available. Restart target apps if their trees remain empty.
45
+
46
+ To explicitly keep that saved setting enabled during desktop automation, run
47
+ `computer-use-linux guard-accessibility` in a foreground terminal. It registers
48
+ a passive AT-SPI window-activation listener and reasserts the current user's
49
+ GNOME `toolkit-accessibility` key after resets, verifying each write by readback.
50
+ This affects other apps using the same user setting. MCP, setup, and
51
+ `get_app_state` never start it automatically. Stop with Ctrl-C or SIGTERM before
52
+ disabling accessibility; stopping removes its listener and ends writes without
53
+ disabling other clients or restoring an old value. An app launched during a
54
+ reset may still need restarting, so this is not a complete GNOME toggle fix.
55
+
23
56
  The generated Hermes config should look like this:
24
57
 
25
58
  ```yaml
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-sh/computer-use-linux",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Linux desktop-control MCP server: AT-SPI accessibility trees, Wayland/X11 input, screenshots, and compositor window targeting.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -7,9 +7,9 @@ export interface GeneratedMcpToolDefinition {
7
7
  annotations: Record<string, unknown>;
8
8
  }
9
9
 
10
- export const GENERATED_SERVER_VERSION = "0.5.0";
11
- export const GENERATED_TOOL_CATALOG_HASH = "3dd52d53c100e240fe2789dd1818ef80fd30202331c0aca2718212e2a79e47ff";
12
- export const GENERATED_SHELL_TOOL_CATALOG_HASH = "13406c87ad78dbdea7e5480e3e482be14c97687fa92320fde8e16f2efbbd3339";
10
+ export const GENERATED_SERVER_VERSION = "0.6.0";
11
+ export const GENERATED_TOOL_CATALOG_HASH = "9107297df765ce3b907540db172cc7823b7664586255db1064a40a44483d6fd6";
12
+ export const GENERATED_SHELL_TOOL_CATALOG_HASH = "e0bc41db617ea6d10d812cbddce6ef78036e44251360f5fac9c207dd0d5ce392";
13
13
  export const GENERATED_MCP_TOOLS =
14
14
  [
15
15
  {
@@ -102,7 +102,7 @@ export const GENERATED_MCP_TOOLS =
102
102
  "openWorldHint": true,
103
103
  "readOnlyHint": false
104
104
  },
105
- "description": "Click an element by index, semantic selector, or desktop coordinate pixels from screenshot metadata.",
105
+ "description": "Click an element by index, semantic selector, or desktop coordinate pixels from screenshot metadata. Plain left activation prefers a native AT-SPI click/press/toggle action, avoiding toolkit coordinate scaling. Entry activate and slider jump actions are not substituted for pointer clicks. Explicit coordinates, right clicks, and multi-clicks retain pointer semantics.",
106
106
  "inputSchema": {
107
107
  "$schema": "https://json-schema.org/draft/2020-12/schema",
108
108
  "properties": {
@@ -153,7 +153,7 @@ export const GENERATED_MCP_TOOLS =
153
153
  },
154
154
  "relative": {
155
155
  "default": null,
156
- "description": "Interpret `x`/`y` as relative to the targeted window's top-left corner\n(the same coordinate space as a window-cropped `screenshot`). Requires a\nwindow target; ignored otherwise.",
156
+ "description": "Interpret `x`/`y` from the clipped window screenshot crop origin, in\ncoordinate pixels before preview resizing. Divide preview pixels by its\nscale first. This is not a toolkit widget or raw GDK surface origin.\nRequires a window target; missing targets are rejected.",
157
157
  "type": [
158
158
  "boolean",
159
159
  "null"
@@ -1043,7 +1043,7 @@ export const GENERATED_MCP_TOOLS =
1043
1043
  },
1044
1044
  "relative": {
1045
1045
  "default": null,
1046
- "description": "Interpret `x`/`y` as relative to the targeted window's top-left corner\n(the same coordinate space as a window-cropped `screenshot`). Requires a\nwindow target; ignored otherwise.",
1046
+ "description": "Interpret `x`/`y` from the clipped window screenshot crop origin, in\ncoordinate pixels before preview resizing. Divide preview pixels by its\nscale first. This is not a toolkit widget or raw GDK surface origin.\nRequires a window target; missing targets are rejected.",
1047
1047
  "type": [
1048
1048
  "boolean",
1049
1049
  "null"
@@ -56,6 +56,31 @@ If `doctor` selects ydotool as the input backend, also enable its per-user daemo
56
56
 
57
57
  On GNOME Wayland, log out and back in after `setup-window-targeting` if the GNOME Shell extension was newly installed.
58
58
 
59
+ For MCP hosts with `COMPUTER_USE_LINUX_NOTIFY_ON_COMPLETE=1`, call the optional
60
+ `complete_interaction` tool once after finishing desktop interaction. A skipped
61
+ cue is not a task failure. This notification does not guarantee exclusive
62
+ desktop ownership or that other clients have stopped sending input.
63
+ This applies only to directly spawned MCP hosts, not the native Pi extension.
64
+
65
+ `setup_accessibility` verifies the saved GNOME `toolkit-accessibility` key
66
+ separately from runtime AT-SPI. Inspect its warning and readback before assuming
67
+ new apps can expose trees. Other accessibility tools may change the key later;
68
+ setup does not hold it enabled continuously.
69
+
70
+ ### Optional foreground accessibility guard
71
+
72
+ Skip unless: the user explicitly wants GNOME's saved `toolkit-accessibility`
73
+ setting kept enabled while desktop automation runs.
74
+
75
+ Run `computer-use-linux guard-accessibility` in a foreground terminal. It
76
+ registers a passive AT-SPI window-activation listener and watches/reasserts the
77
+ saved key with readback. The setting affects all apps for the current user.
78
+ `mcp`, setup, and `get_app_state` never start this guard automatically.
79
+ Stop with Ctrl-C or SIGTERM before intentionally disabling accessibility.
80
+ Stopping ends writes and removes its listener without disabling other clients
81
+ or restoring a previous saved value. Apps launched during a reset/reassertion
82
+ race may still need restarting; do not claim a complete GNOME toggle fix.
83
+
59
84
  ## Configure Your Agent
60
85
 
61
86
  The `computer-use-linux` binary is an MCP server. Configure it as a stdio MCP server in your agent of choice:
@@ -87,6 +112,26 @@ If the binary is not on `PATH`, use the absolute path (typically `~/.local/bin/c
87
112
  9. For text input, prefer `type_text` with a target selector (`window_id`, `pid`, `app_id`, `wm_class`, `title`, `tty`, `terminal_pid`, `terminal_command`, or `terminal_cwd`) rather than relying on current focus.
88
113
  10. After mutating actions, re-check state with `get_app_state`, `focused_window`, or an app-specific readback.
89
114
 
115
+ Plain left element/index/selector `click` prefers native AT-SPI `click`,
116
+ `press`, or `toggle` over toolkit bounds, avoiding coordinate
117
+ conversion when available. This preference does not replace a coordinate click
118
+ with an arbitrary action name. Explicit `x`/`y`, right clicks, and double/multiple
119
+ clicks retain pointer semantics.
120
+ Use `perform_action` explicitly for entry `activate` or slider `jump`; `click`
121
+ never substitutes those actions, including when bounds are unavailable.
122
+
123
+ ### Screenshot-relative coordinates
124
+
125
+ Skip unless: a coordinate `click` or `scroll` uses `relative: true`.
126
+
127
+ Select a target window and use its clipped screenshot crop origin. Divide
128
+ preview `x`/`y` by screenshot `scale` first. Widget-local and raw GDK surface
129
+ coordinates are not interchangeable with that origin; missing window targets
130
+ are rejected. For calibration, use the repository's
131
+ `examples/coordinate_probe.py`: select the green square from the screenshot
132
+ and require a delivered-event `hit: true`. Do not pass widget-local `(85, 85)`
133
+ directly to a window-relative click.
134
+
90
135
  ## Pitfalls
91
136
 
92
137
  - Already-running GTK, Qt, and Electron apps may need a restart after AT-SPI is enabled.