@bastani/atomic 0.9.56-alpha.1 → 0.9.57-alpha.1
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/CHANGELOG.md +12 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +24 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/agent-desktop/SKILL.md +83 -0
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +12 -0
- package/dist/builtin/workflows/builtin/adversarial-verification.js +3 -3
- package/dist/builtin/workflows/builtin/{chunk-49kkbdpr.js → chunk-2f1shjah.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-dcxscfnb.js → chunk-37gm3bzk.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-2jfst7e4.js → chunk-45fn5q5p.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-hx8v4p97.js → chunk-4ek3v2wm.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-z3pajrfs.js → chunk-8d40nyz9.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-qhm35ntx.js → chunk-g3b2zf8r.js} +2 -2
- package/dist/builtin/workflows/builtin/{chunk-6jpwc09k.js → chunk-h6bt0r0g.js} +2 -2
- package/dist/builtin/workflows/builtin/{chunk-9cm2ckq2.js → chunk-x25rjw4y.js} +4 -4
- package/dist/builtin/workflows/builtin/{chunk-apagcs4r.js → chunk-xqcy5nve.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-w4xp1w1f.js → chunk-yb55w6me.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-k5q3t7je.js → chunk-yjgfnbgd.js} +1 -1
- package/dist/builtin/workflows/builtin/classify-and-act.js +3 -3
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -3
- package/dist/builtin/workflows/builtin/generate-and-filter.js +3 -3
- package/dist/builtin/workflows/builtin/goal.js +3 -3
- package/dist/builtin/workflows/builtin/index.js +11 -11
- package/dist/builtin/workflows/builtin/loop-until-done.js +3 -3
- package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +3 -3
- package/dist/builtin/workflows/builtin/steering-context.js +1 -1
- package/dist/builtin/workflows/builtin/tournament.js +3 -3
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +7 -7
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +4 -4
- package/dist/builtin/workflows/src/index.js +4 -4
- package/dist/builtin/workflows/src/local-worker-entry.mjs +4 -4
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +2 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/docs/computer-use.md +119 -98
- package/docs/getting-started/first-session.md +1 -1
- package/docs/skills.md +2 -2
- package/docs/usage.md +1 -1
- package/docs/workflows/authoring.md +105 -141
- package/docs/workflows/verification.md +14 -13
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/dist/builtin/subagents/skills/cua-driver/BROWSER.md +0 -562
- package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +0 -685
- package/dist/builtin/subagents/skills/cua-driver/LINUX.md +0 -412
- package/dist/builtin/subagents/skills/cua-driver/MACOS.md +0 -996
- package/dist/builtin/subagents/skills/cua-driver/README.md +0 -123
- package/dist/builtin/subagents/skills/cua-driver/RECORDING.md +0 -132
- package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +0 -115
- package/dist/builtin/subagents/skills/cua-driver/SKILL.md +0 -108
- package/dist/builtin/subagents/skills/cua-driver/VISUAL.md +0 -125
- package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +0 -832
- package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +0 -226
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
# cua-driver: Linux
|
|
2
|
-
|
|
3
|
-
Start with `cua-driver doctor` in the graphical user's session. X11,
|
|
4
|
-
XWayland, and native Wayland expose different capture and input facilities;
|
|
5
|
-
successful discovery does not prove either input delivery or window capture.
|
|
6
|
-
Use [WORKFLOW.md](WORKFLOW.md) for exact targets and verification and
|
|
7
|
-
[RUNTIME.md](RUNTIME.md) for transport and permission ownership.
|
|
8
|
-
|
|
9
|
-
On X11, `set_window_frame({pid, window_id, x, y, width, height})` sends an
|
|
10
|
-
EWMH window-manager request and confirms it against `list_windows` geometry.
|
|
11
|
-
Wayland has no portable protocol for setting another application's top-level
|
|
12
|
-
geometry, so this tool refuses there unless a future compositor-owned adapter
|
|
13
|
-
can provide exact targeting and readback.
|
|
14
|
-
|
|
15
|
-
AT-SPI is talked to natively over D-Bus (the `atspi`/zbus crate): no
|
|
16
|
-
`pyatspi` or GObject-introspection typelibs are required at runtime.
|
|
17
|
-
|
|
18
|
-
## Delivery
|
|
19
|
-
|
|
20
|
-
Background window input must not activate or raise the target. AT-SPI actions
|
|
21
|
-
can reach semantic controls without raw pointer delivery; X11 pixel dispatch
|
|
22
|
-
can use AT-SPI hit-testing or a virtual-pointer route. Do not assume all input
|
|
23
|
-
uses XSendEvent or that every toolkit accepts it. Inspect the result's public
|
|
24
|
-
route and independently verify the application.
|
|
25
|
-
|
|
26
|
-
`delivery_mode:"foreground"` is a user-visible takeover. Never select it automatically.
|
|
27
|
-
Use explicitly authorized `delivery_mode:"foreground"` only after evidence
|
|
28
|
-
that the chosen background route is unavailable or ineffective. Target-specific
|
|
29
|
-
activation and restoration depend on the compositor adapter. If activation
|
|
30
|
-
cannot be proven, accept the refusal instead of sending keys to whatever is focused.
|
|
31
|
-
|
|
32
|
-
The overlay is separate from the physical pointer; cursor-bearing and
|
|
33
|
-
keyboard actions re-show it automatically. Distinct overlays do not isolate
|
|
34
|
-
desktop input. Keep one controller for a global-input workflow.
|
|
35
|
-
|
|
36
|
-
## Capture recovery
|
|
37
|
-
|
|
38
|
-
`get_window_state` requests both AT-SPI and a window screenshot by default.
|
|
39
|
-
A valid image is not guaranteed. If `screenshot_error.code` is
|
|
40
|
-
`surface_identity_unproven`, the driver cannot attest that output pixels
|
|
41
|
-
belong to the requested surface. Preserve that distinction from an empty or
|
|
42
|
-
untrusted accessibility tree. Never crop a desktop image and label it an
|
|
43
|
-
attested window capture.
|
|
44
|
-
|
|
45
|
-
1. Read any returned tree and `degraded_reason`; semantic interaction may still
|
|
46
|
-
be possible without pixels.
|
|
47
|
-
2. Do not retry a window-pixel action without a valid window image. Changing
|
|
48
|
-
`capture_mode`, inventing bounds, or repeatedly increasing timeouts cannot
|
|
49
|
-
establish surface identity.
|
|
50
|
-
3. If the task permits full-display capture and visible desktop control,
|
|
51
|
-
explain the broader scope and obtain authorization if not already given.
|
|
52
|
-
Use `get_desktop_state`, then
|
|
53
|
-
`target:{"kind":"desktop","display_id":"primary"}` on input, and verify
|
|
54
|
-
through another desktop snapshot. See [the desktop loop](WORKFLOW.md#desktop-loop).
|
|
55
|
-
4. If desktop scope is not admitted, report the limitation and stop that route.
|
|
56
|
-
|
|
57
|
-
A capture request may be waiting for an OS/portal permission dialog. Inspect
|
|
58
|
-
window discovery for a pending prompt, or ask the user to check the desktop.
|
|
59
|
-
Let the user approve or deny it. Do not repeatedly start captures, automate
|
|
60
|
-
approval, or change security settings as a workaround. After approval, take a
|
|
61
|
-
fresh capture and verify its dimensions/content before continuing. A timeout
|
|
62
|
-
alone does not prove which permission or backend failed.
|
|
63
|
-
|
|
64
|
-
Supporting smoke evidence: Driver 0.23.2 on KDE/KWin Wayland opened an Electron
|
|
65
|
-
music app, searched, selected an album track, and showed playback through this
|
|
66
|
-
desktop route after user screenshot approval. The window route returned
|
|
67
|
-
`surface_identity_unproven`; desktop actions returned `global_input` and
|
|
68
|
-
`unverifiable`, so screenshots and user confirmation established the result.
|
|
69
|
-
This is not certification of background targeting, other compositors, or video.
|
|
70
|
-
|
|
71
|
-
## X11 observation and input details
|
|
72
|
-
|
|
73
|
-
**What is open over the window.** `get_window_state` lists the pid's transient
|
|
74
|
-
dialogs (`dialogs: [{window_id, title, transient_for, modal, bounds}]`) and
|
|
75
|
-
override-redirect popups (`popups: [...]`) that are mapped, with a `follow_up`
|
|
76
|
-
sentence naming the call that targets each one
|
|
77
|
-
(`get_window_state(pid, window_id=<that id>)`). When one overlaps the window
|
|
78
|
-
the screenshot is taken from the screen (`screenshot_composited:true`) so the
|
|
79
|
-
menu or dialog is visible; the window's own drawable never shows them. The
|
|
80
|
-
payload states its frame (`coordinate_frame:"window"`, plus `frame_note` with `verbose:true`): `x`/`y`
|
|
81
|
-
of the pointer tools are pixels of THIS screenshot. Closed menus are listed
|
|
82
|
-
with a `description` ("closed menu with N items…") and are not walked;
|
|
83
|
-
click the menu (a real press) and read the popup by its window_id.
|
|
84
|
-
`press_key` / `hotkey` that map a new top-level report it as `window_opened`
|
|
85
|
-
with `window_change` evidence. Action results carry the same text as
|
|
86
|
-
`summary` inside `structuredContent`, for clients that only show that.
|
|
87
|
-
|
|
88
|
-
**Screenshot scale.** The window screenshot is delivered at or below 1.15
|
|
89
|
-
megapixels (long edge ≤ `max_image_dimension`, 1568 by default): larger
|
|
90
|
-
images are downsized before a model reads them, and its pixel coordinates
|
|
91
|
-
would then be uniformly short. Pointer `x`/`y` and each element's
|
|
92
|
-
`screenshot_frame` are pixels of the delivered image (the element's `frame`
|
|
93
|
-
stays in screen coordinates, as on every platform); `frame_scale` < 1 and
|
|
94
|
-
`screenshot_original_width` report the downsizing, and the driver scales your
|
|
95
|
-
pixels back to the window.
|
|
96
|
-
An explicit per-call `max_image_dimension` (0 = native) replaces this cap.
|
|
97
|
-
|
|
98
|
-
**Budget the pixels before you aim.** The cap is a pixel budget, so on a
|
|
99
|
-
high-resolution window the delivered image is a small fraction of native and
|
|
100
|
-
fine controls stop being readable. Measured on a 3840x2342 window: `frame_scale`
|
|
101
|
-
0.357, so a 24px toolbar icon arrives at ~8.6px and a 1px border at ~0.36px:
|
|
102
|
-
sub-pixel for any reader, sighted or not. Check `frame_scale` in the
|
|
103
|
-
`get_window_state` payload and, when a target is smaller than roughly 30px, frame
|
|
104
|
-
it with `zoom` before choosing a coordinate. Zooming a 196x728 window-px region
|
|
105
|
-
returned a 235x873 image (about 1.2x native), which restores a 24px icon to
|
|
106
|
-
~29px. `zoom` takes screenshot pixels and the follow-up action needs
|
|
107
|
-
`from_zoom: true`. It also requires a screenshot-owning snapshot from the same
|
|
108
|
-
session first, and refuses with `screenshot_context_missing` otherwise, so
|
|
109
|
-
`get_window_state` with a screenshot must precede the first `zoom`.
|
|
110
|
-
|
|
111
|
-
**When the active model takes no images.** Some clients drop image content
|
|
112
|
-
entirely, so `get_window_state` and `zoom` return an image the reader never sees.
|
|
113
|
-
The loop still closes for most questions, and none of this needs a vision model:
|
|
114
|
-
`verify_state` proves state and returns a real `satisfied` / `unsatisfied` /
|
|
115
|
-
`unknown` verdict; an out-of-band read such as
|
|
116
|
-
`xprop -root _NET_ACTIVE_WINDOW` proves which window holds focus; and scanning the
|
|
117
|
-
written capture for colour transitions (PIL or equivalent) proves coarse layout.
|
|
118
|
-
What none of them prove is that a specific small control was activated. For that
|
|
119
|
-
use the `cua-perception` extension (see `VISUAL.md`) or an app that exposes a
|
|
120
|
-
usable accessibility tree.
|
|
121
|
-
|
|
122
|
-
**Windows without `_NET_WM_PID`.** Tk, many Java/AWT builds, Wine, and legacy
|
|
123
|
-
Xlib/Xt clients do not publish `_NET_WM_PID`. On X11, `list_windows` then asks
|
|
124
|
-
the X server's X-Resource extension (XRes 1.2 `LocalClientPID`) which local
|
|
125
|
-
process created the window, so these windows still carry a `pid` and accept
|
|
126
|
-
`get_window_state` / `click` by `pid` + `window_id`. The driver never guesses:
|
|
127
|
-
`pid` stays `null` when XRes is missing or older than 1.2, when the client
|
|
128
|
-
is remote (TCP, or SSH-forwarded with a `WM_CLIENT_MACHINE` naming another
|
|
129
|
-
host), or when the X server cannot report the driver's own PID correctly
|
|
130
|
-
(remote `DISPLAY`, container PID namespace). A `pid: null` window can only be
|
|
131
|
-
reached through desktop scope. An SSH-forwarded client that publishes
|
|
132
|
-
neither `_NET_WM_PID` nor `WM_CLIENT_MACHINE` is attributed to the local
|
|
133
|
-
`ssh` process, because that is the socket peer the server sees.
|
|
134
|
-
|
|
135
|
-
**Keys while the app's own popup is open.** A Qt combo list / completer or a
|
|
136
|
-
GTK/VCL menu holds a keyboard grab that makes the X server drop keys from the
|
|
137
|
-
virtual keyboard. `press_key` / `hotkey` / `type_text` / `set_value` then go
|
|
138
|
-
through the core keyboard (`path: "xtest_core_grab"`, the result names the
|
|
139
|
-
popup and states that the core focus and active window were verified
|
|
140
|
-
unchanged), or, when another application holds the core focus, are refused
|
|
141
|
-
with `code: "popup_keyboard_grab"` and a hint: dismiss the popup (click
|
|
142
|
-
outside it, or click one of its rows by element_token after
|
|
143
|
-
`get_window_state(pid, window_id=<popup>)`) and retry. Typing an absolute path
|
|
144
|
-
into a Qt file dialog opens its completer after the first `/`; prefer
|
|
145
|
-
`set_value` on the "File name" field, which writes the path in one go.
|
|
146
|
-
|
|
147
|
-
**Popup walks, labels, descriptions.** `get_window_state(pid, window_id=<popup>)`
|
|
148
|
-
returns the popup's own rows (list / tree / menu items), never the main
|
|
149
|
-
window's menubar. Elements carry `description` when the toolkit publishes one
|
|
150
|
-
(Qt keeps a button's tooltip there: `push button "" (description "Pause")`;
|
|
151
|
-
`label` falls back to it). A control's `label` is never its value: a spin
|
|
152
|
-
button or slider nobody names is `unlabelled: true` with its place in
|
|
153
|
-
`description` (`unlabelled spin button; 3rd of 4 spin buttons in this panel`,
|
|
154
|
-
in visual order). `parent_index` is the nearest indexed real ancestor.
|
|
155
|
-
|
|
156
|
-
**Grid presses.** After a click that lands on a table cell (LibreOffice Calc),
|
|
157
|
-
the result appends `focus: cell D2` (`focused_cell`, evidence) read from the
|
|
158
|
-
focus log, so a one-row miss is visible before you type.
|
|
159
|
-
|
|
160
|
-
**Multi-click.** `click` takes `count: 2` (double) or `count: 3` (triple, a
|
|
161
|
-
line/paragraph selection in editors) as one press train with real double-click
|
|
162
|
-
cadence in both delivery modes; there is no `triple_click` tool.
|
|
163
|
-
|
|
164
|
-
**Typing throughput.** Key-event typing (XTest in foreground, the virtual
|
|
165
|
-
keyboard in background) runs at roughly 45-60 characters per second, so a
|
|
166
|
-
1,300-character script takes about 30 s: scale a client-side `type_text`
|
|
167
|
-
deadline with the text length instead of using a flat one (0.04 s per
|
|
168
|
-
character leaves margin over those rates). A terminal can still be echoing when the call returns; read the
|
|
169
|
-
result again before retyping text that looks truncated.
|
|
170
|
-
|
|
171
|
-
**Cross-application drops.** A pointer action whose point lies over another
|
|
172
|
-
application's window (a drag dropped onto VLC) reports that window's title
|
|
173
|
-
change and the windows its pid opened as `foreign_window` / `window_change`
|
|
174
|
-
evidence; the focus guard alone only watches the target pid.
|
|
175
|
-
|
|
176
|
-
## Native application menus
|
|
177
|
-
|
|
178
|
-
Use `invoke_menu({pid, window_id, path:[...]})` for a known GTK/Qt application
|
|
179
|
-
menu command. It activates the exact target only for the duration of the
|
|
180
|
-
operation, resolves each labelled AT-SPI menu descendant again after the prior
|
|
181
|
-
menu expands, and refuses missing, duplicate, disabled, or non-actionable
|
|
182
|
-
segments. It works through AT-SPI on both X11 and Wayland and never falls back
|
|
183
|
-
to coordinates. Verify the command's semantic effect from fresh state; the
|
|
184
|
-
native `do_action` acknowledgement alone is not task completion.
|
|
185
|
-
|
|
186
|
-
## AT-SPI needs the session bus (headless / containers / `runuser`)
|
|
187
|
-
|
|
188
|
-
AT-SPI (the accessibility tree behind `get_window_state`, `element_token`
|
|
189
|
-
clicks, and focus-free `type_text`) lives **entirely on the desktop
|
|
190
|
-
session's D-Bus**. cua-driver reaches it via `DBUS_SESSION_BUS_ADDRESS`. When
|
|
191
|
-
the daemon is started _inside_ a normal desktop login that variable is already
|
|
192
|
-
exported and everything works. When it is started **outside** the session
|
|
193
|
-
(a container entrypoint, a headless box, `runuser`/`su` into the desktop user,
|
|
194
|
-
a systemd _system_ unit, or a VNC session running its own ad-hoc bus), the
|
|
195
|
-
variable is unset, the AT-SPI registry walk comes back empty, and
|
|
196
|
-
`get_window_state` reports **every** window as having no elements.
|
|
197
|
-
|
|
198
|
-
cua-driver now **auto-discovers the session bus at startup** (mirroring the
|
|
199
|
-
`XAUTHORITY` recovery): if `DBUS_SESSION_BUS_ADDRESS` is unset it adopts
|
|
200
|
-
`/run/user/<uid>/bus`, or reads the address out of a running desktop-session
|
|
201
|
-
process's `/proc/<pid>/environ` (`xfce4-session`, `gnome-session`, …). So the
|
|
202
|
-
common headless cases now "just work". The two things that still must be true:
|
|
203
|
-
|
|
204
|
-
1. **An accessibility bus must be running** in that session, and
|
|
205
|
-
**`toolkit-accessibility` must be on**: cua-driver advertises a screen
|
|
206
|
-
reader at startup to flip it, but a session with no a11y bus at all
|
|
207
|
-
(`/usr/libexec/at-spi-bus-launcher`) can't expose a tree. `cua-driver
|
|
208
|
-
doctor` now probes `org.a11y.Bus` for real (not just "is there a bus?")
|
|
209
|
-
and tells you which of the two is missing.
|
|
210
|
-
2. The daemon must run **as the desktop user** (so it can read that user's
|
|
211
|
-
session-process environ and the `/run/user/<uid>/bus` socket). Running the
|
|
212
|
-
daemon as root against a user session is the Linux analogue of the Windows
|
|
213
|
-
"Session 0" isolation problem.
|
|
214
|
-
|
|
215
|
-
`get_window_state` returns one compact markdown tree capped at 250 actionable
|
|
216
|
-
nodes by default (`full_output:true` restores 5 000 nodes and both forms), and
|
|
217
|
-
`since:<snapshot_id>` returns only added/changed/removed rows. The focused
|
|
218
|
-
element is not reported on Linux yet, so an unchanged read says only
|
|
219
|
-
`no change since …`.
|
|
220
|
-
|
|
221
|
-
An empty AT-SPI walk is now surfaced honestly: `get_window_state` sets
|
|
222
|
-
`degraded: true` + a `degraded_reason` (instead of a bare `elements: []`) so a
|
|
223
|
-
caller can tell "this window genuinely has no controls" apart from "the a11y
|
|
224
|
-
bridge isn't up / the daemon isn't on the session bus".
|
|
225
|
-
|
|
226
|
-
## The validated modality matrix (X11 / XFCE)
|
|
227
|
-
|
|
228
|
-
Each input rung and its stable public route:
|
|
229
|
-
|
|
230
|
-
| Modality | `delivery_mode` | `route` | Postcondition proof |
|
|
231
|
-
| ------------------------------- | ------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------- |
|
|
232
|
-
| Element click (`element_token`) | `background` | `accessibility` | Use `verify_state`; invocation alone is not confirmation |
|
|
233
|
-
| **element px action (x,y)** | `background` | `accessibility` when AT-SPI-at-point lands, otherwise `global_input` | Use `verify_state` or multimodal reading |
|
|
234
|
-
| Pixel (px) click, escalated | `foreground` | `global_input` | Use `verify_state` or multimodal reading |
|
|
235
|
-
| `type_text` into editable | `background` | `accessibility` | `confirmed` only with `value_readback` evidence |
|
|
236
|
-
| `type_text`, non-editable focus | `background`/`foreground` | `synthetic_events` or `global_input` | Use `verify_state` or multimodal reading |
|
|
237
|
-
|
|
238
|
-
**A background element px action does land on X11**: for an AX-exposing app it
|
|
239
|
-
takes the focus-free AT-SPI `do_action`-at-point path (`x11_atspi`), exactly
|
|
240
|
-
like the macOS/Windows background pixel click. It falls to the MPX
|
|
241
|
-
virtual-pointer path (`x11_pixel`) only for non-AX surfaces, **and that path
|
|
242
|
-
needs a real Xorg + `/dev/uinput`**: under Xvnc / minimal containers without
|
|
243
|
-
uinput, escalate to `delivery_mode:"foreground"`. The AT-SPI path only fires
|
|
244
|
-
a control under the point: when the hit test finds nothing deeper than the
|
|
245
|
-
application's own frame or window (Chromium page content before its AT-SPI
|
|
246
|
-
tree is populated), no action is fired. Chromium/Electron targets without a
|
|
247
|
-
real focus-free pointer return `background_unavailable` before the capture is
|
|
248
|
-
consumed, so retry the same capture-bound click with
|
|
249
|
-
`delivery_mode:"foreground"` when foreground input is authorized. (`type_text` in the
|
|
250
|
-
`background` rung is focus-dependent for non-editable widgets; that's the one
|
|
251
|
-
genuine background limitation, and `foreground` is the documented escalation.)
|
|
252
|
-
|
|
253
|
-
## Wayland
|
|
254
|
-
|
|
255
|
-
Set `CUA_DRIVER_RS_ENABLE_WAYLAND=1` to enable native Wayland support. The
|
|
256
|
-
driver selects a backend from compositor capabilities:
|
|
257
|
-
|
|
258
|
-
- Sway and other wlroots compositors use foreign-toplevel discovery,
|
|
259
|
-
wlr-screencopy, virtual pointer, and virtual keyboard protocols.
|
|
260
|
-
- Hyprland has separate discovery and capture adapters. Its optional plugin
|
|
261
|
-
defaults to discovery-only; the opt-in input v3 source candidate has the
|
|
262
|
-
qualification and validation limits below. Do not inherit Sway coverage.
|
|
263
|
-
- GNOME/Mutter uses the bundled WinRects Shell helper for target geometry and
|
|
264
|
-
activation, plus portal/libei for foreground raw input.
|
|
265
|
-
- KDE/KWin uses AT-SPI and portal facilities where available. Target-specific
|
|
266
|
-
foreground activation remains experimental, so unsafe raw input refuses.
|
|
267
|
-
- The optional `cua-compositor` is a separate nested session enabled
|
|
268
|
-
explicitly for controlled automation. GNOME and KDE never switch into it.
|
|
269
|
-
|
|
270
|
-
Sway recording works through the wlroots recorder path and is exercised by the
|
|
271
|
-
canonical harness runner. Portal-backed GNOME recording is still an evidence
|
|
272
|
-
gap. Capture and recording availability therefore depend on the compositor,
|
|
273
|
-
installed helpers, and portal grant.
|
|
274
|
-
|
|
275
|
-
Standard Wayland has no general client protocol for raw input to an arbitrary
|
|
276
|
-
occluded surface. Background AX actions can still deliver through AT-SPI, and
|
|
277
|
-
a PX left click can deliver when hit-testing resolves to an actionable AT-SPI
|
|
278
|
-
control. Other focus-bound background pointer and keyboard shapes return an
|
|
279
|
-
exact `background_unavailable` result. They do not report success after a
|
|
280
|
-
silent drop.
|
|
281
|
-
|
|
282
|
-
Outside an explicitly enabled, qualified compositor-owned background route,
|
|
283
|
-
raw Wayland input requires explicitly authorized `delivery_mode:"foreground"`.
|
|
284
|
-
The driver activates the selected target through a verified compositor adapter
|
|
285
|
-
before dispatch. If
|
|
286
|
-
the compositor has no target-addressable activation or input backend, the call
|
|
287
|
-
refuses before sending input. Reconstructing coordinates alone does not make
|
|
288
|
-
raw background PX possible on a standard compositor.
|
|
289
|
-
|
|
290
|
-
### Hyprland input v3 source candidate
|
|
291
|
-
|
|
292
|
-
[PR #3572](https://github.com/trycua/cua/pull/3572) records dated, exact-source
|
|
293
|
-
validation results for the experimental opt-in input v3 candidate. Acceptance
|
|
294
|
-
requires the unchanged complete Linux canonical runner on native Hyprland and
|
|
295
|
-
separate bounded qualified-app proof. The default plugin build remains
|
|
296
|
-
discovery-only.
|
|
297
|
-
The candidate source reports Driver `0.23.2`; published Driver `0.23.2` does not
|
|
298
|
-
include these branch changes. Switching Driver channels does not install or
|
|
299
|
-
enable the plugin. Build and loading require the exact Hyprland ABI and compiler
|
|
300
|
-
toolchain; v3 uses `CUA_HYPRLAND_INPUT=ON`, separate from the historical
|
|
301
|
-
`CUA_HYPRLAND_TEST_INPUT` experiment.
|
|
302
|
-
|
|
303
|
-
Driver admits each action through its normal shared permission, resource, and
|
|
304
|
-
lifecycle policy. There is no additional Omarchy approval panel or external
|
|
305
|
-
signer. The plugin accepts the trusted desktop account over same-user local
|
|
306
|
-
sockets; this does not sandbox native code running as that user. Application
|
|
307
|
-
qualification is a compatibility check, not authorization.
|
|
308
|
-
|
|
309
|
-
The initial native qualification scope is Calc from `libreoffice-fresh 26.2.5-3`
|
|
310
|
-
and Inkscape `1.4.4-6`, subject to per-operation native evidence. Before each
|
|
311
|
-
action, Driver matches `/proc/<pid>/exe` to the canonical executable path
|
|
312
|
-
(`/usr/lib/libreoffice/program/soffice.bin` or `/usr/bin/inkscape`), checks the
|
|
313
|
-
exact package name and version in the local pacman database and its executable
|
|
314
|
-
file listing, and rechecks process identity. Unknown or unavailable package
|
|
315
|
-
identity refuses. Package eligibility does not certify every LibreOffice
|
|
316
|
-
application or operation.
|
|
317
|
-
|
|
318
|
-
The plugin separately binds the exact live native surface and checks geometry,
|
|
319
|
-
desktop availability, and primary-client and other-lane conflicts. Each
|
|
320
|
-
background lane publishes a private canonical `evdev`/`pc105`/`us` keymap, so
|
|
321
|
-
user options such as Caps Lock remapped to Ctrl or Super do not alter agent key
|
|
322
|
-
semantics. A physical keymap transition cancels existing authority; use a fresh
|
|
323
|
-
action afterward. Multiple agent layout groups, Unicode, IME input, arbitrary
|
|
324
|
-
held-key streams, and modified pointer gestures remain outside this scope.
|
|
325
|
-
Chromium, Electron, and XWayland raw background input are outside this scope.
|
|
326
|
-
AT-SPI routes retain their separate behavior.
|
|
327
|
-
|
|
328
|
-
Two compositor seats, `Cua-Agent` and `Cua-Agent-2`, persist across configuration
|
|
329
|
-
disable/re-enable. Each connection claims one lane, and each admitted action
|
|
330
|
-
requires a fresh target binding. Plugin replacement requires a desktop restart;
|
|
331
|
-
do not treat historical experiment reload workarounds as a supported lifecycle.
|
|
332
|
-
Refusals never authorize a hidden foreground fallback, display wake, or session
|
|
333
|
-
unlock. A dispatch acknowledgement is `effect:"unverifiable"`; verify the
|
|
334
|
-
application effect from fresh state. Do not replay canceled, partial, or unknown
|
|
335
|
-
actions.
|
|
336
|
-
|
|
337
|
-
The candidate also adds an explicitly requested foreground route, advertised
|
|
338
|
-
by the plugin as `foreground_target:true`. It binds the exact native top-level
|
|
339
|
-
surface on the compositor thread and intentionally changes primary focus and,
|
|
340
|
-
for pointer actions, cursor position. It does not restore the previous focus or
|
|
341
|
-
cursor. This route has no Calc/Inkscape background package gate. The canonical
|
|
342
|
-
native harness covers defined GTK3, Electron, and Tauri foreground cases. It refuses
|
|
343
|
-
held physical input, grabs, constraints, drag-and-drop, ambiguous primary seat
|
|
344
|
-
bindings, and non-neutral keyboard modifiers. Background refusal never selects
|
|
345
|
-
this route automatically. Driver expands bounded ASCII text under the exact
|
|
346
|
-
US keymap; Unicode and IME remain outside its raw-input scope. Foreground
|
|
347
|
-
pointer-only actions are layout-independent. Foreground keyboard actions leave
|
|
348
|
-
the user's Num Lock and Caps Lock untouched. They work with Num Lock on and with
|
|
349
|
-
keymap options that leave every typing and modifier key unchanged, such as
|
|
350
|
-
`compose:caps`. They refuse before any input under Caps Lock
|
|
351
|
-
(`foreground_keyboard_caps_lock`), for a keypad key that Num Lock changes
|
|
352
|
-
(`foreground_keyboard_numlock_keypad`), and for a different layout or remapped
|
|
353
|
-
key (`foreground_unsupported_layout`). Ask the user to turn Caps Lock off, or
|
|
354
|
-
use the equivalent non-keypad key, instead of retrying the same call.
|
|
355
|
-
|
|
356
|
-
The retained bounded app evidence at source
|
|
357
|
-
`f180e8828b8f31cc153e3c44eaa89a9c13c5bc68` includes instrumented Calc/Inkscape
|
|
358
|
-
proof on both seats and an uninstrumented smoke. The plugin tree and
|
|
359
|
-
uninstrumented module hash are unchanged at
|
|
360
|
-
`1133a06e4f205cf80188a7ac9e41102f37611fea`. The proof covers recorded actions
|
|
361
|
-
and observation intervals, not every application operation or release package.
|
|
362
|
-
Portable tests and historical experiments do not replace complete native
|
|
363
|
-
harness acceptance. Compatible release artifacts and final image
|
|
364
|
-
packaging and lifecycle validation require separate evidence. Physical Omarchy
|
|
365
|
-
parity requires separate acceptance; it is not a gate for publishing a validated
|
|
366
|
-
image.
|
|
367
|
-
|
|
368
|
-
## Quick triage
|
|
369
|
-
|
|
370
|
-
If a tool call surprises you on Linux:
|
|
371
|
-
|
|
372
|
-
1. `cua-driver doctor`: reports the display server (X11 / Wayland),
|
|
373
|
-
**whether `org.a11y.Bus` actually answers on the session bus** (not just
|
|
374
|
-
"is there a bus"), the discovered `DBUS_SESSION_BUS_ADDRESS`, and
|
|
375
|
-
`ffmpeg` availability (for recording).
|
|
376
|
-
2. Check `XDG_SESSION_TYPE`: X11 still has toolkit-specific delivery limits; `wayland`
|
|
377
|
-
needs `CUA_DRIVER_RS_ENABLE_WAYLAND=1` for the native backend,
|
|
378
|
-
else XWayland.
|
|
379
|
-
3. **Empty AT-SPI tree** (`get_window_state` returns `degraded:true`): in
|
|
380
|
-
order of likelihood: (a) the daemon isn't on the desktop session bus
|
|
381
|
-
(headless / container / `runuser` / root-against-user-session; see
|
|
382
|
-
_AT-SPI needs the session bus_ above; doctor will say
|
|
383
|
-
`DBUS_SESSION_BUS_ADDRESS unset`); (b) the a11y bridge is off
|
|
384
|
-
(`gsettings set org.gnome.desktop.interface toolkit-accessibility true`);
|
|
385
|
-
(c) GTK4 / Qt6 / Chromium populate lazily: re-snapshot after an
|
|
386
|
-
interaction or an AX-enable settle.
|
|
387
|
-
|
|
388
|
-
## Forbidden vectors
|
|
389
|
-
|
|
390
|
-
Same idea as macOS / Windows: don't shell out to anything that
|
|
391
|
-
foregrounds a target:
|
|
392
|
-
|
|
393
|
-
- `wmctrl -a <window>` / `wmctrl -R <window>`: activates / raises.
|
|
394
|
-
- `xdotool windowactivate <wid>`: activates.
|
|
395
|
-
- `xdotool key --window <wid> alt+Tab`: focus churn.
|
|
396
|
-
|
|
397
|
-
Prefer cua-driver tools with an explicit `window_id`. When in doubt,
|
|
398
|
-
ask the user.
|
|
399
|
-
|
|
400
|
-
## What to expect
|
|
401
|
-
|
|
402
|
-
| Environment | Proven baseline | Main limits |
|
|
403
|
-
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
404
|
-
| X11/Openbox | AT-SPI trees and actions, foreground pointer and keyboard input, window and desktop capture, and video | Raw background delivery remains toolkit-specific; unsupported shapes refuse |
|
|
405
|
-
| Sway/wlroots | AT-SPI, native discovery, full-display and cropped-window screencopy, foreground input, semantic background actions, and video | Raw background pointer and keyboard input remains focus-bound |
|
|
406
|
-
| Hyprland/Omarchy | Experimental source candidate with separate discovery-foundation and bounded two-seat app evidence | Default plugin is discovery-only; raw background v3 qualification is limited to the exact native Calc/Inkscape packages and a private agent US keymap; user Caps-to-Ctrl/Super remaps do not alter agent semantics; complete native harness and release acceptance are separate gates |
|
|
407
|
-
| GNOME/Mutter | AT-SPI, WinRects geometry and activation, capture, and portal/libei foreground input | Requires the helper and portal grant; portal video parity remains open |
|
|
408
|
-
| KDE/KWin | AT-SPI and generic discovery where exposed | Target-specific activation and behavioral coverage remain experimental |
|
|
409
|
-
| Nested `cua-compositor` | Versioned direct per-surface input, native GTK 31/31, capture/scope 5/5, and partial Electron coverage | The complete shared matrix remains experimental; do not infer standard-Wayland support |
|
|
410
|
-
|
|
411
|
-
See [WORKFLOW.md](WORKFLOW.md) for exact targeting and verification and `RECORDING.md` for session
|
|
412
|
-
recording.
|