@bastani/atomic 0.9.39 → 0.9.40-alpha.2
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 +35 -0
- package/dist/builtin/intercom/CHANGELOG.md +14 -0
- package/dist/builtin/intercom/broker/broker.ts +523 -72
- package/dist/builtin/intercom/broker/client.ts +136 -5
- package/dist/builtin/intercom/broker/database-wake-up-bus.ts +274 -0
- package/dist/builtin/intercom/broker/group-membership.ts +2 -2
- package/dist/builtin/intercom/broker/multinode-router.ts +1500 -0
- package/dist/builtin/intercom/broker/multinode-state-store.ts +569 -0
- package/dist/builtin/intercom/broker/open-broker-state.ts +160 -0
- package/dist/builtin/intercom/broker/paths.ts +6 -0
- package/dist/builtin/intercom/broker/pending-send-registry.ts +14 -0
- package/dist/builtin/intercom/broker/recipient-receipts.ts +93 -0
- package/dist/builtin/intercom/broker/restoring-recipients.ts +263 -0
- package/dist/builtin/intercom/broker/send-handler.ts +241 -25
- package/dist/builtin/intercom/broker/session-id-reclaim.ts +41 -0
- package/dist/builtin/intercom/broker/socket-writes.ts +47 -0
- package/dist/builtin/intercom/broker/spawn.ts +10 -2
- package/dist/builtin/intercom/broker/sql-held-send-store.ts +96 -0
- package/dist/builtin/intercom/broker/sql-known-session-store.ts +129 -0
- package/dist/builtin/intercom/broker/sql-lease-store.ts +194 -0
- package/dist/builtin/intercom/broker/sql-outbox-store.ts +249 -0
- package/dist/builtin/intercom/broker/sql-pending-ask-store.ts +105 -0
- package/dist/builtin/intercom/broker/sql-restoring-reservation-store.ts +295 -0
- package/dist/builtin/intercom/broker/sql-sent-message-authority.ts +126 -0
- package/dist/builtin/intercom/broker/supervisor-channel.ts +10 -0
- package/dist/builtin/intercom/broker/wake-up-bus.ts +60 -0
- package/dist/builtin/intercom/index.bundle.mjs +793 -91
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/retry-policy.ts +4 -0
- package/dist/builtin/intercom/session-target.ts +24 -0
- package/dist/builtin/intercom/types.ts +57 -3
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +31 -0
- package/dist/builtin/subagents/README.md +18 -12
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/agent-browser/SKILL.md +1 -1
- package/dist/builtin/subagents/skills/cua-driver/BROWSER.md +55 -8
- package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +7 -2
- package/dist/builtin/subagents/skills/cua-driver/LINUX.md +7 -1
- package/dist/builtin/subagents/skills/cua-driver/MACOS.md +151 -27
- package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +1 -1
- package/dist/builtin/subagents/skills/cua-driver/SKILL.md +33 -17
- package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +5 -0
- package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +46 -8
- package/dist/builtin/subagents/skills/subagent/SKILL.md +18 -20
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +8032 -6034
- package/dist/builtin/web-access/CHANGELOG.md +6 -0
- package/dist/builtin/web-access/README.md +1 -1
- package/dist/builtin/web-access/index.bundle.mjs +2 -5
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +24 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/impeccable/SKILL.md +8 -8
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/audit.md +4 -2
- package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +2 -2
- package/dist/builtin/workflows/skills/impeccable/reference/craft-floor.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/critique.md +22 -9
- package/dist/builtin/workflows/skills/impeccable/reference/degraded/finish-reviewer.md +2 -2
- package/dist/builtin/workflows/skills/impeccable/reference/distill.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/extract.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/harden.md +2 -4
- package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +4 -4
- package/dist/builtin/workflows/skills/impeccable/reference/live.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/new-work.md +6 -6
- package/dist/builtin/workflows/skills/impeccable/reference/onboard.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/optimize.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/overdrive.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/quieter.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +10 -0
- package/dist/builtin/workflows/skills/impeccable/reference/visualize.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/VERSION +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/impeccable +6 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/impeccable.cmd +47 -22
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-dom.js +34 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-session.js +25 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +33 -8
- package/dist/builtin/workflows/src/durable/journal/resolution.d.ts +7 -7
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +22715 -22159
- package/dist/builtin/workflows/src/index.js +106 -35
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +17 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts +2 -0
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +6 -6
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +6 -3
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts +7 -2
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +29 -12
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-recovery.d.ts +14 -0
- package/dist/core/agent-session-recovery.d.ts.map +1 -0
- package/dist/core/agent-session-recovery.js +83 -0
- package/dist/core/agent-session-recovery.js.map +1 -0
- package/dist/core/agent-session-tasks.d.ts.map +1 -1
- package/dist/core/agent-session-tasks.js +4 -6
- package/dist/core/agent-session-tasks.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +13 -0
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +4 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +3 -2
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.html +1 -0
- package/dist/core/export-html/template.js +37 -20
- package/dist/core/export-html/vendor/marked-cjk-friendly.min.js +6 -0
- package/dist/core/export-html/vendor/marked.min.js +76 -3
- package/dist/core/extensions/api-types.d.ts +6 -2
- package/dist/core/extensions/api-types.d.ts.map +1 -1
- package/dist/core/extensions/api-types.js.map +1 -1
- package/dist/core/extensions/event-results.d.ts +21 -0
- package/dist/core/extensions/event-results.d.ts.map +1 -1
- package/dist/core/extensions/event-results.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-api.d.ts.map +1 -1
- package/dist/core/extensions/loader-api.js +4 -0
- package/dist/core/extensions/loader-api.js.map +1 -1
- package/dist/core/extensions/runner-events.d.ts +9 -2
- package/dist/core/extensions/runner-events.d.ts.map +1 -1
- package/dist/core/extensions/runner-events.js +29 -0
- package/dist/core/extensions/runner-events.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -3
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +7 -2
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/runtime-types.d.ts +1 -0
- package/dist/core/extensions/runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/runtime-types.js.map +1 -1
- package/dist/core/extensions/session-events.d.ts +30 -2
- package/dist/core/extensions/session-events.d.ts.map +1 -1
- package/dist/core/extensions/session-events.js.map +1 -1
- package/dist/core/sdk-types.d.ts +3 -2
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-storage.d.ts.map +1 -1
- package/dist/core/session-storage.js +15 -9
- package/dist/core/session-storage.js.map +1 -1
- package/dist/core/storage/process-selection.d.ts +39 -0
- package/dist/core/storage/process-selection.d.ts.map +1 -0
- package/dist/core/storage/process-selection.js +154 -0
- package/dist/core/storage/process-selection.js.map +1 -0
- package/dist/core/storage/provider.d.ts +6 -1
- package/dist/core/storage/provider.d.ts.map +1 -1
- package/dist/core/storage/provider.js +3 -2
- package/dist/core/storage/provider.js.map +1 -1
- package/dist/core/storage/selection.d.ts +1 -1
- package/dist/core/storage/selection.d.ts.map +1 -1
- package/dist/core/storage/selection.js.map +1 -1
- package/dist/core/storage/session/jsonl-session-store.d.ts +2 -0
- package/dist/core/storage/session/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/storage/session/jsonl-session-store.js +38 -2
- package/dist/core/storage/session/jsonl-session-store.js.map +1 -1
- package/dist/core/tasks/completion.d.ts +11 -2
- package/dist/core/tasks/completion.d.ts.map +1 -1
- package/dist/core/tasks/completion.js +40 -16
- package/dist/core/tasks/completion.js.map +1 -1
- package/dist/core/tasks/pause.d.ts +4 -1
- package/dist/core/tasks/pause.d.ts.map +1 -1
- package/dist/core/tasks/pause.js +8 -5
- package/dist/core/tasks/pause.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +7 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js +11 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +2 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +2 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.js +4 -0
- package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +3 -0
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +2 -0
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.d.ts +2 -1
- package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.js +29 -0
- package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +4 -1
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive-engine/engine-args.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-args.js +4 -0
- package/dist/modes/interactive-engine/engine-args.js.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.js +4 -4
- package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +4 -0
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +4 -1
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +4 -0
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +3 -0
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-command-timeouts.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-timeouts.js +1 -0
- package/dist/modes/rpc/rpc-command-timeouts.js.map +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js +6 -1
- package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +12 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +44 -11
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/tools-manager.js +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/background-tasks.md +5 -3
- package/docs/computer-use.md +2 -2
- package/docs/environment-variables.md +4 -1
- package/docs/extensions/events.md +29 -2
- package/docs/getting-started/first-session.md +1 -1
- package/docs/guides/intercom.md +1 -1
- package/docs/intercom/operations.md +103 -1
- package/docs/intercom/reference.md +10 -3
- package/docs/intercom.md +8 -6
- package/docs/keybindings.md +1 -1
- package/docs/models.md +1 -1
- package/docs/providers.md +5 -3
- package/docs/reference/cli.md +5 -0
- package/docs/rpc/protocol.md +19 -0
- package/docs/rpc.md +3 -0
- package/docs/sdk/web-server.md +1 -1
- package/docs/sdk.md +5 -2
- package/docs/sessions.md +17 -1
- package/docs/settings.md +6 -4
- package/docs/skills.md +1 -1
- package/docs/storage.md +54 -3
- package/docs/subagents.md +49 -9
- package/docs/usage.md +1 -1
- package/docs/windows.md +14 -4
- package/docs/workflows/api-reference.md +1 -1
- package/docs/workflows/authoring.md +1 -1
- package/docs/workflows/operations.md +10 -6
- package/npm-shrinkwrap.json +40 -40
- package/package.json +6 -6
- package/dist/core/export-html/template-js/data-tree.js +0 -287
- package/dist/core/export-html/template-js/entries-navigation.js +0 -434
- package/dist/core/export-html/template-js/initialization.js +0 -335
- package/dist/core/export-html/template-js/message-tools.js +0 -428
- package/dist/core/export-html/template-js/tree-filter-render.js +0 -419
- package/dist/core/export-html/template-script.d.ts +0 -3
- package/dist/core/export-html/template-script.d.ts.map +0 -1
- package/dist/core/export-html/template-script.js +0 -13
- package/dist/core/export-html/template-script.js.map +0 -1
|
@@ -83,8 +83,20 @@ frontmost is true'`). Mutating it is not.
|
|
|
83
83
|
**Corollary: the AXMenuBar rule.** Do not manually drive a background
|
|
84
84
|
application's `AXMenuBarItem`: the visible macOS menu bar belongs to the
|
|
85
85
|
frontmost app, and command items may be disabled otherwise. Use `invoke_menu`
|
|
86
|
-
for a known application-menu path.
|
|
87
|
-
|
|
86
|
+
for a known application-menu path. With the app in the background it resolves
|
|
87
|
+
the whole path without opening a menu and never activates the app; if macOS
|
|
88
|
+
keeps the item unavailable to a background app it refuses with
|
|
89
|
+
`background_unavailable` (then, if the user allows it, `bring_to_front` first).
|
|
90
|
+
One exception: a disabled Save (the ⌘S item) of a document window is saved
|
|
91
|
+
through the app's scripting interface instead, still in the background, and the
|
|
92
|
+
result says so; TextEdit disables Save whenever it is behind the user's window.
|
|
93
|
+
A Save is verified on disk. A background `hotkey` whose combo is a menu item's
|
|
94
|
+
key equivalent (⌘S, ⌘W, ⌘C, ...) in a native app takes the same route, because
|
|
95
|
+
background key events never reach an app's menus; no keys are sent. macOS asks
|
|
96
|
+
the user once to allow Cua Driver to control the app (Automation) the first
|
|
97
|
+
time a scripting route runs; when that is off, the call refuses and nothing is
|
|
98
|
+
saved.
|
|
99
|
+
With the app already in front it resolves every AX level live. Prefer an in-window
|
|
88
100
|
element action when the same command has an ordinary control, and prefer
|
|
89
101
|
`set_window_frame` for exact geometry. Full rationale is in “Navigating native
|
|
90
102
|
menu bars” below.
|
|
@@ -109,10 +121,13 @@ is safe even for apps that normally foreground on media-load
|
|
|
109
121
|
| Enumerate an app's windows | `list_windows({pid})`: or read the `windows` array `launch_app` already returns | `osascript 'every window of app …'` |
|
|
110
122
|
| Move or resize one exact window | `set_window_frame({pid, window_id, x, y, width, height})` | `osascript` position/size writes or title-bar dragging |
|
|
111
123
|
| Click / type / scroll / keys | `click`, `type_text`, `scroll`, `press_key`, `hotkey` | `osascript`, `cliclick`, raw `CGEvent`, `open <url>` |
|
|
112
|
-
|
|
|
124
|
+
| Loop, branch or retry over app actions | `run_script({script})` (sandboxed JavaScript over the `cua` API, one call); `run_steps` for a fixed list | an AppleScript or shell loop around `osascript` or `cua-driver` calls |
|
|
125
|
+
| Drag / drag-and-drop / marquee select | `drag({pid, window_id, from_x, from_y, to_x, to_y})` in the background (pixel-only: macOS AX has no semantic drag). Verify with a screenshot; `delivery_mode:"foreground"` only if nothing changed. A bound browser tab: `browser_pointer` `action:"drag"` | `cliclick dd:`, `osascript drag`, refusing a drag-only step as "needs the window in front" |
|
|
126
|
+
| Hover (reveal a hover-only control) | Window-targeted `move_cursor`; its result says whether it hovered (AX alternate UI or an Electron page). A web page in Chrome, Edge or Brave: `browser_pointer` hover after `get_browser_state`. If not, look for the same command elsewhere (menu item, context menu, shortcut, help text in `get_window_state`); only `move_cursor({scope:"desktop", delivery_mode:"foreground"})` (moves the user's pointer) or `bring_to_front` reveals it, and only if the user allows it | assuming a window-targeted `move_cursor` hovered when its result says the app sees no hover; a desktop `move_cursor` over a background browser page |
|
|
113
127
|
| Screenshot | `get_window_state` (window) or authorized `get_desktop_state` (desktop) | `screencapture` |
|
|
114
128
|
| Quit an app | ask the user first, then `hotkey({pid, keys:["cmd","q"]})` | `kill`, `killall`, `pkill` |
|
|
115
129
|
| Hand a file/URL to an app | `launch_app({bundle_id, urls:[<path>]})` | `open -a <App> <path>`, `open <url>` |
|
|
130
|
+
| View a local file in the GUI | `launch_app({bundle_id, urls:["file:///…"]})` | typing `file://` into the omnibox |
|
|
116
131
|
|
|
117
132
|
### The narrow carve-out
|
|
118
133
|
|
|
@@ -122,6 +137,11 @@ For authorized foreground input, use the Cua action's
|
|
|
122
137
|
|
|
123
138
|
When a cua-driver call surprises you, diagnose cua-driver first:
|
|
124
139
|
|
|
140
|
+
- **Large tree or repeated reads?** `get_window_state` returns one compact
|
|
141
|
+
markdown tree capped at 250 nodes; pass `since:"latest"` for a diff
|
|
142
|
+
(`no change since …; focused element is …` names the focused row on macOS)
|
|
143
|
+
and `tree_format:"elements"` for structured rows. `full_output:true` restores
|
|
144
|
+
the old payload (both forms, `_note`, `background_input`, 2 000 nodes).
|
|
125
145
|
- **Empty `tree_markdown`?** `get_window_state` returns **both** the
|
|
126
146
|
AX tree and a screenshot by default: there's nothing to configure and
|
|
127
147
|
no capture mode to pick. An empty tree means the surface isn't AX (a
|
|
@@ -158,8 +178,10 @@ response, and only switch _dispatch rung_ on a real signal:
|
|
|
158
178
|
1. **Re-snapshot and read the tree diff**: a changed `AXValue`, a new
|
|
159
179
|
element, a collapsed menu, a disabled button. If the tree shows the
|
|
160
180
|
change, you're done. When you only need the tree diff and don't need
|
|
161
|
-
fresh pixels, pass `include_screenshot:false` to
|
|
162
|
-
**perf** knob, not a mode flip.
|
|
181
|
+
fresh pixels, pass `since:"latest"` and `include_screenshot:false` to
|
|
182
|
+
skip the grab: a **perf** knob, not a mode flip. The window keeps its
|
|
183
|
+
last screenshot's pixel frame while its size is unchanged, so `x,y`
|
|
184
|
+
from that screenshot still work afterwards.
|
|
163
185
|
2. **Trust the screenshot and do an element px action** when the tree
|
|
164
186
|
**lies**: the action response carried `effect:"suspected_noop"`, the
|
|
165
187
|
re-snapshot came back `degraded` (empty tree), or the tree looks
|
|
@@ -279,14 +301,75 @@ permission prompt the agent loop shouldn't be burning on app launch.
|
|
|
279
301
|
|
|
280
302
|
The pixel click is routed through SkyLight's per-pid event path
|
|
281
303
|
(`SLEventPostToPid`), not the system HID stream. The dispatch recipe
|
|
282
|
-
is the backgrounded "noraise" sequence: focus-without-raise
|
|
283
|
-
SLPS event
|
|
284
|
-
and the real click. The target
|
|
285
|
-
routing but
|
|
286
|
-
z-stack,
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
304
|
+
is the backgrounded "noraise" sequence: a focus-without-raise
|
|
305
|
+
SLPS event record to the target window, followed by an off-screen
|
|
306
|
+
user-activation primer and the real click. The target window becomes
|
|
307
|
+
AppKit-key for event routing, but it does **not** rise to the front of
|
|
308
|
+
the z-stack, macOS's "switch to Space with windows for app" follow is
|
|
309
|
+
suppressed, and the user's front window keeps key status, so their
|
|
310
|
+
typing keeps landing there.
|
|
311
|
+
|
|
312
|
+
### Menus opened in the background keep the user's keyboard
|
|
313
|
+
|
|
314
|
+
A popup button, a `<select>`, or a context menu opened in a background
|
|
315
|
+
app takes key focus from the user's front window for as long as the menu
|
|
316
|
+
is open (AppKit's menu tracking steals it). While a background action
|
|
317
|
+
runs, Cua Driver watches for that and hands key focus straight back, so
|
|
318
|
+
the user's window never loses it. The menu stays open and its items are
|
|
319
|
+
chosen with `click` on the `AXMenuItem` (or in one call with
|
|
320
|
+
`set_value` on the popup). Keyboard navigation of such a menu with
|
|
321
|
+
`press_key` is not the route; pick the item by element.
|
|
322
|
+
|
|
323
|
+
### Apps that activate themselves
|
|
324
|
+
|
|
325
|
+
Some apps activate themselves in answer to input, even in the background:
|
|
326
|
+
Chrome when `cmd+L` focuses its address bar, GnuCash on a double-click in
|
|
327
|
+
its account tree. No client can stop that. After a background
|
|
328
|
+
action Cua Driver checks WindowServer's front process and, if the target
|
|
329
|
+
made itself frontmost, re-activates the user's app and hands its window
|
|
330
|
+
key focus back within a few tens of milliseconds. Prefer routes that do
|
|
331
|
+
not ask the app to come forward: `set_value` on the address field or
|
|
332
|
+
`browser_navigate` instead of `cmd+L`, and `AXOpen` through
|
|
333
|
+
`double_click` on an element instead of a pixel double-click.
|
|
334
|
+
### Hover in the background
|
|
335
|
+
|
|
336
|
+
macOS apps track hover and show tooltips (help tags) from the real
|
|
337
|
+
pointer. Pointer-move and enter events posted to a background app reach
|
|
338
|
+
the app but never its tracking areas, so most hover-only controls and all
|
|
339
|
+
native tooltips cannot be revealed in the background. A window-targeted
|
|
340
|
+
`move_cursor` on a background app tries the two routes that leave the
|
|
341
|
+
real pointer, focus and z-order alone. Its result says whether it hovered
|
|
342
|
+
and how:
|
|
343
|
+
|
|
344
|
+
- `ax_alternate_ui`: the element under the point (or an ancestor) lists
|
|
345
|
+
`showalternateui`, as sidebar section headers in Finder, Mail, Music and
|
|
346
|
+
System Settings do. The hover-only controls appear in the next
|
|
347
|
+
`get_window_state`; hovering elsewhere hides them. The same element can
|
|
348
|
+
be driven directly with `click` and `action:"show_alternate_ui"` /
|
|
349
|
+
`"show_default_ui"`.
|
|
350
|
+
- `electron_input`: an Electron page gets `mouseEnter`/`mouseMove` through
|
|
351
|
+
the app's main process, so page hover effects update. Native tooltips do
|
|
352
|
+
not show.
|
|
353
|
+
|
|
354
|
+
For a web page in Chrome, Edge or Brave use `browser_pointer` hover: a
|
|
355
|
+
window-target `move_cursor` there says the page saw no hover and names
|
|
356
|
+
`get_browser_state` as the next call. Otherwise `move_cursor` moves only the
|
|
357
|
+
agent cursor and says so. Look for the same command elsewhere first: a menu
|
|
358
|
+
item, a context menu, a keyboard shortcut, or the control's help text in
|
|
359
|
+
`get_window_state` (toolbar tooltips are usually there as `help=`).
|
|
360
|
+
Otherwise the step needs the user's pointer (`move_cursor` with
|
|
361
|
+
`scope:"desktop"` and `delivery_mode:"foreground"`) or the app in front
|
|
362
|
+
(`bring_to_front`); use either only if the user allows it, and say which.
|
|
363
|
+
|
|
364
|
+
### Desktop-target pointer input over a background app
|
|
365
|
+
|
|
366
|
+
`move_cursor`, `click`, `drag` and `scroll` with a desktop target move the
|
|
367
|
+
user's real pointer. When the point lands on a window of an app that is not
|
|
368
|
+
in front, they refuse with `background_unavailable` before sending anything,
|
|
369
|
+
unless the call passes `delivery_mode:"foreground"`. Over a web browser the
|
|
370
|
+
refusal names the browser tools (`get_browser_state`, then
|
|
371
|
+
`browser_pointer`, `browser_click` or `browser_type`) instead of foreground.
|
|
372
|
+
Points over the app in front, or over no window, behave as before.
|
|
290
373
|
|
|
291
374
|
### `delivery_mode` on the pointer family (macOS)
|
|
292
375
|
|
|
@@ -300,12 +383,31 @@ surface that only accepts events while frontmost (the canvas/viewport/game
|
|
|
300
383
|
case below). Unmodified `element_token` (AX) actions remain background-capable
|
|
301
384
|
and hold the no-foreground contract without the flag.
|
|
302
385
|
|
|
303
|
-
`drag`
|
|
304
|
-
`
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
386
|
+
`drag` runs in the background too. A window-scoped `drag` (`pid` and
|
|
387
|
+
`window_id`) makes the window key without raising it, posts the press, the
|
|
388
|
+
interpolated drags and the release to that window's process, and hands focus
|
|
389
|
+
back to the user's window. The real pointer does not move. It reaches
|
|
390
|
+
controls that follow the drag events: native sliders and canvases, and
|
|
391
|
+
pointer-event sliders, canvases and boards on web pages in Chrome. The
|
|
392
|
+
result is not driver-verified: check the outcome with a screenshot or the
|
|
393
|
+
tree. Only if nothing changed, retry with `delivery_mode:"foreground"`,
|
|
394
|
+
which fronts the window, moves the physical pointer along the path, and
|
|
395
|
+
restores the prior frontmost app.
|
|
396
|
+
|
|
397
|
+
A native `<input type="range">` in Chrome does not follow a background drag
|
|
398
|
+
(pointer-event widgets do). Use `set_value` on its slider element, or
|
|
399
|
+
`browser_pointer` `action:"drag"` on a bound tab, which sends the drag
|
|
400
|
+
through CDP `Input.dispatchMouseEvent` with the button held.
|
|
401
|
+
|
|
402
|
+
A drag that starts a macOS drag-and-drop session (reordering a list by drag
|
|
403
|
+
and drop, moving a file, HTML5 `draggable` content) cannot drop in the
|
|
404
|
+
background: macOS tracks those sessions with the real pointer. The driver
|
|
405
|
+
sees the session start, releases at once, and returns
|
|
406
|
+
`background_unavailable` with `reason: "drag_and_drop_session"`. Look for a
|
|
407
|
+
non-drag route first (Move Up/Down, a menu or context-menu command, a
|
|
408
|
+
shortcut, cut and paste), then foreground if the user allows it. Toolkits that read the hardware pointer (Tk) or drop routed
|
|
409
|
+
mouse events (LibreOffice) refuse the background drag with
|
|
410
|
+
`background_unavailable` before anything is sent.
|
|
309
411
|
|
|
310
412
|
A foreground window-scoped **pixel** `click`, `double_click`, or
|
|
311
413
|
`right_click` (`x`/`y` with `window_id`) is delivered like a desktop-scope click, not through the per-pid path: Cua Driver
|
|
@@ -390,6 +492,16 @@ There is no backgrounded path that reaches these apps today.
|
|
|
390
492
|
AX-addressable elements (links, buttons, toolbar items), use
|
|
391
493
|
`right_click({pid, element_token})` instead.
|
|
392
494
|
|
|
495
|
+
### A value write the app does not apply (LibreOffice)
|
|
496
|
+
|
|
497
|
+
Some apps accept an accessibility value write and ignore it. LibreOffice
|
|
498
|
+
Calc cells do: `set_value` returns success at the AX level and the cell
|
|
499
|
+
keeps its old content. `set_value` re-reads the value, and when it has
|
|
500
|
+
not moved it fails with `code:"write_not_applied"` and
|
|
501
|
+
`effect:"not_applied"`, so a `run_script` stops there. LibreOffice also
|
|
502
|
+
ignores background pointer input, so address it with `window_id` and type
|
|
503
|
+
instead (see "LibreOffice, Numbers and other editors in the background").
|
|
504
|
+
|
|
393
505
|
### Known text-input limits (Catalyst + Electron)
|
|
394
506
|
|
|
395
507
|
On **Catalyst** apps (WhatsApp, Reminders, Notes-via-Catalyst,
|
|
@@ -455,6 +567,10 @@ and the refusal says whether any menu window it opened is still on screen. If
|
|
|
455
567
|
the refusal says the menu may still be open, press `escape` on the window
|
|
456
568
|
before other input.
|
|
457
569
|
|
|
570
|
+
A `get_window_state` read lists only the menu bar's titles and says
|
|
571
|
+
`menus collapsed`; pass `query` to find an item in any menu, or run it with
|
|
572
|
+
`invoke_menu`. A missed path segment lists the items at that level.
|
|
573
|
+
|
|
458
574
|
```bash
|
|
459
575
|
cua-driver invoke_menu \
|
|
460
576
|
'{"pid":844,"window_id":10725,"path":["Window","Move & Resize","Left"]}'
|
|
@@ -486,11 +602,11 @@ window, and PID-routes its bounded checkbox-pixel fallback. The same control's
|
|
|
486
602
|
state must verify after mutation; unsupported appearance, scale, zoom,
|
|
487
603
|
window-size, or toolbar geometry refuses without a click.
|
|
488
604
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
605
|
+
CDP's trusted pointer route (the `browser_click` and `browser_pointer`
|
|
606
|
+
default) stays in the background on macOS Chrome: it delivers trusted events
|
|
607
|
+
to the bound tab, even an inactive one, without activating or raising the
|
|
608
|
+
browser window. Use `input_route:"dom_event"` only when synthetic events are
|
|
609
|
+
acceptable; controls that check `event.isTrusted` ignore it. Embedded Electron has a separately bounded route;
|
|
494
610
|
do not infer that route for arbitrary WKWebView or Tauri hosts.
|
|
495
611
|
|
|
496
612
|
For a declared session, typed browser click, type, and pointer mutations animate
|
|
@@ -518,8 +634,8 @@ starting point for new browser workflows.
|
|
|
518
634
|
| `Accessibility permission not granted` | TCC not granted | Stop; tell user to grant in System Settings |
|
|
519
635
|
| `Screen Recording permission not granted` | TCC not granted for capture | Screenshots and pixel actions are unavailable. If the task is AX-completable, use `get_window_state({include_screenshot:false})` and `element_token` actions; otherwise stop and ask the user to run `cua-driver permissions grant` |
|
|
520
636
|
| `AX action failed: ... returned -25200` (or -25205, -25206) | The app may have acted anyway: some AppKit controls return these after a press they performed | Re-read with `get_window_state` before retrying; a second press on a checkbox toggles it back. A radio button or checkbox whose AXValue settles on the pressed state is reported as performed, naming the error |
|
|
521
|
-
| `set_value refused (file_name_needs_rename)` | A file's name
|
|
522
|
-
| `
|
|
637
|
+
| `set_value refused (file_name_needs_rename)` | A file's name in Finder's Get Info window (AXIdentifier `Name`): an AXValue write changes only the field | `set_value` the full new name on the file's name cell in a Finder window that lists it (renamed through Finder in the background and read back from disk) |
|
|
638
|
+
| `Background input refused (no_focused_text_input)` | Untargeted background `type_text` while the window's focused element is not a text input or an editing surface (spreadsheet grid, document canvas: `AXLayoutArea`, `AXScrollArea`, `AXTable`, `AXCell`, `AXGroup`; not in Finder/Dock); keys would drive the view (Finder type-to-select) | pass the field's `element_token`, or `x,y` to pixel-focus it first; to rename a Finder file, `set_value` its name cell |
|
|
523
639
|
|
|
524
640
|
## Example end-to-end task (macOS)
|
|
525
641
|
|
|
@@ -537,4 +653,12 @@ starting point for new browser workflows.
|
|
|
537
653
|
|
|
538
654
|
If the user instead asks to navigate _within_ an already-open Finder
|
|
539
655
|
window, use the menu-bar flow from "Navigating native menu bars"
|
|
540
|
-
above (
|
|
656
|
+
above (`invoke_menu` with a path such as `["Go", "Downloads"]`).
|
|
657
|
+
|
|
658
|
+
### LibreOffice, Numbers and other editors in the background
|
|
659
|
+
|
|
660
|
+
With `window_id`, `type_text`, `press_key` and `hotkey` post keys to that exact window: the driver makes it the app's key window through in-app key-window records (no raise, no activation, real pointer untouched), confirms that the app's focused window and focused element are in that window, posts, and hands key back. This also covers another window or dialog of the app holding focus, and a LibreOffice that was never activated. When the switch cannot be confirmed the call is refused with `window_not_key` and no key is sent. A second window of the same app (Find & Replace, another document) is no longer `same_pid_keyboard_ambiguity`. A command key whose menu route is refused (item disabled while the app is in the background) falls through to key events in that window. Recipe: pass `window_id` on every call; go to the cell with Name Box navigation (`type_text` `A1\n`), type with `\n` and `\t`, read the cell back; run commands (Paste Special, Format, Save) with `invoke_menu({pid, window_id, path})` rather than clicking the menu bar. A `background_unavailable` refusal here means use `get_window_state` and act by element, not stop.
|
|
661
|
+
|
|
662
|
+
### Preview: export before resizing
|
|
663
|
+
|
|
664
|
+
Duplicate is disabled in a background Preview, so work on an export: File > Export (`invoke_menu`) to the destination, then resize or edit the exported copy. Do not resize the original first.
|
|
@@ -98,7 +98,7 @@ Pixel `click` already animates the cursor. Do not precede it with `move_cursor`
|
|
|
98
98
|
|
|
99
99
|
The default theme provides session-colored pointer/glow, action marks, and activity animations. Named sessions have stable palette colors. Native hosts own delivery/target badges separately from theme artwork; cursor state is scoped to the private lifecycle.
|
|
100
100
|
|
|
101
|
-
`set_agent_cursor_enabled` controls idle visibility. `set_agent_cursor_motion` takes `style` (`signature_arc` default, `spring_settle`, `magnetic`, `comet_swoop`, `adaptive`, `classic`), `timing` (`native`, `fitts`, `fixed`), `effects` (`trail`, `glow`, `magnet`, `ripple`, `squish`
|
|
101
|
+
`set_agent_cursor_enabled` controls idle visibility. `set_agent_cursor_motion` takes `style` (`signature_arc` default, `spring_settle`, `magnetic`, `comet_swoop`, `adaptive`, `classic`), `timing` (`native`, `fitts`, `fixed`), `effects` (`trail`, `glow`, `magnet`, `ripple`, `squish` as `on`, `off`, or `default`; `default` restores the style default, and an omitted effect keeps its current setting), and the arc knobs `start_handle`, `end_handle`, `arc_size`, `arc_flow` (bezier styles) plus `spring` and `turn_radius` (`classic`) where advertised. Choose preinstalled artwork with `set_agent_cursor_theme`; `cursor_id` on input tools is not a theme selector. Never supply inline theme code or arbitrary source paths through agent tools. The trusted local `cursor-theme` workflow owns validation, compilation, preview, installation, and removal.
|
|
102
102
|
|
|
103
103
|
Overlay operations need a suitable UI event loop. macOS direct SDK/MCP runtimes without a certified host main-thread adapter can return `facility_unavailable`; do not report that as a successful move. See [EMBEDDING.md](EMBEDDING.md).
|
|
104
104
|
|
|
@@ -4,16 +4,26 @@ description: Drive a native GUI app (macOS, Windows, Linux) via the cua-driver C
|
|
|
4
4
|
hidden: true
|
|
5
5
|
metadata:
|
|
6
6
|
github-path: libs/cua-driver/rust/Skills/cua-driver
|
|
7
|
-
github-ref: refs/tags/cua-driver-rs-v0.
|
|
7
|
+
github-ref: refs/tags/cua-driver-rs-v0.36.0
|
|
8
8
|
github-repo: https://github.com/trycua/cua
|
|
9
|
-
github-tree-sha:
|
|
9
|
+
github-tree-sha: 229cf71d61810fb3fe25771705478985640d93a0
|
|
10
10
|
name: cua-driver
|
|
11
|
-
version: 0.
|
|
11
|
+
version: 0.36.0
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# cua-driver
|
|
15
15
|
|
|
16
|
-
Operate one exact target, observe
|
|
16
|
+
Operate one exact target, observe it narrowly, act by element, and verify the user's postcondition at checkpoints.
|
|
17
|
+
|
|
18
|
+
## Efficient loop
|
|
19
|
+
|
|
20
|
+
The MCP server instructions carry the same rules, so they apply even when this file is not opened.
|
|
21
|
+
|
|
22
|
+
1. Start with a targeted read: `get_window_state({pid, window_id, query:"Save"})` returns about 2K chars where a full snapshot is about 42K. Bound large trees with `max_elements` / `max_depth`. Widen only if the target is missing.
|
|
23
|
+
2. Act by `element_token`: row `[N]` of a read is `<snapshot_id>:N` (for example `"s0000002a:11"`, not `"11"`). Use pixels only for surfaces missing from the tree.
|
|
24
|
+
3. Act through `run_steps` with `observe:{}`, even for a single step. It runs the steps, stops at the first failure, and returns only what changed since your last read, so you do not need a separate read after acting; see [Workflow](WORKFLOW.md#batch-known-actions). When the flow needs logic between actions (a loop, a branch on what the app shows, a retry), write it as one `run_script` instead; see [Workflow](WORKFLOW.md#script-a-flow).
|
|
25
|
+
4. To re-read a window, pass `since:"latest"`: you get the changed rows, not the whole tree. To just look, use `include_accessibility_tree:false` where advertised (it keeps the current tokens valid). Do not use `max_elements:1` or a junk `query` to get a picture.
|
|
26
|
+
5. Verify at checkpoints (after a meaningful state change, before finishing), not after every action. One `verify_state` or one targeted `get_window_state` is usually enough.
|
|
17
27
|
|
|
18
28
|
## Act
|
|
19
29
|
|
|
@@ -21,12 +31,16 @@ Operate one exact target, observe its state, act once, and verify the user's pos
|
|
|
21
31
|
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
|
|
22
32
|
| Check installation and capabilities | `cua-driver --version`, `status`, `doctor`, `describe <tool>`; MCP `tools/list` | [Runtime](RUNTIME.md) |
|
|
23
33
|
| Find or open the requested app | `list_apps`, `list_windows`, `launch_app` | Current platform guide below |
|
|
24
|
-
|
|
|
34
|
+
| View a local file in the GUI | `launch_app({bundle_id, urls:["file:///…"]})` opens it in that app | Current platform guide below |
|
|
35
|
+
| Observe one window | `get_window_state({pid, window_id, query})` | [Workflow](WORKFLOW.md) |
|
|
25
36
|
| Act on a control | `click` / `type_text` with a fresh `element_token` and exact window target | [Workflow](WORKFLOW.md) |
|
|
37
|
+
| Act and see what changed in one call | `run_steps({steps:[{tool,args},...], observe:{}})`; stops at the first failure | [Workflow](WORKFLOW.md#batch-known-actions) |
|
|
38
|
+
| Loop, branch or retry in one call | `run_script({script})`: JavaScript over the `cua` API, sandboxed, time and call limits | [Workflow](WORKFLOW.md#script-a-flow) |
|
|
26
39
|
| Use pixels when semantics cannot reach it | Fresh target screenshot, then `x,y` on the same target | [Workflow](WORKFLOW.md) |
|
|
27
40
|
| Verify the outcome | `verify_state({pid, window_id, expect})` or a fresh snapshot read by the agent | [Workflow](WORKFLOW.md) |
|
|
28
41
|
| Operate the authorized desktop | `get_desktop_state` → input with `target:{kind:"desktop",display_id:"primary"}` → `get_desktop_state` | [Workflow](WORKFLOW.md), [Linux](LINUX.md) on Wayland |
|
|
29
|
-
| Drive supported browser page content | `get_browser_state` →
|
|
42
|
+
| Drive supported browser page content | `get_browser_state` → `browser_prepare` from `detail.next_call` if refused → typed browser action | [Browser](BROWSER.md) |
|
|
43
|
+
| Browser tools refuse in the background | Not blocked: fill the page through `get_window_state` + `set_value`/click; if the first read shows only browser chrome, read again. BLOCKED only after that fails | [Browser](BROWSER.md) |
|
|
30
44
|
| Record an explicitly requested run | `start_recording` → actions → `stop_recording`; verify artifacts | [Recording](RECORDING.md) |
|
|
31
45
|
| Finish | Stop after proof; `end_session` for this run, not `cua-driver stop` on a shared service | [Runtime](RUNTIME.md) |
|
|
32
46
|
|
|
@@ -39,8 +53,8 @@ Check the installed version and advertised schema before using unfamiliar parame
|
|
|
39
53
|
## Rules
|
|
40
54
|
|
|
41
55
|
1. Select the exact target on each action. A session is lifecycle metadata, not capture scope or permission authority.
|
|
42
|
-
2. Observe before input and verify after
|
|
43
|
-
3. Use returned tokens, never invented indices. A fresh snapshot replaces prior element handles and lists them in `invalidated_snapshot_ids`; act with `element_token`.
|
|
56
|
+
2. Observe before input and verify the outcome at checkpoints, not after every action. `effect:"unverifiable"` and a successful exit are not task success; never replay a partial, canceled, or unknown action blindly.
|
|
57
|
+
3. Use returned tokens, never invented indices. A fresh snapshot replaces prior element handles and lists them in `invalidated_snapshot_ids`; act with `element_token`. Reads are bounded and return one tree form by default; follow up with `since:"latest"` instead of re-reading a large window.
|
|
44
58
|
4. Keep background window actions non-interfering. Foreground delivery and desktop input require authorization for visible control; an unavailable route is not permission to escalate.
|
|
45
59
|
5. Never infer pixels from a missing image, a different window, or an unaccounted-for resized preview. Capture failure and an empty accessibility tree are different failures.
|
|
46
60
|
6. Keep one controller for a shared desktop. Distinct sessions/cursors do not isolate focus, keyboard input, application state, or snapshot caches.
|
|
@@ -48,15 +62,17 @@ Check the installed version and advertised schema before using unfamiliar parame
|
|
|
48
62
|
|
|
49
63
|
## Failure map
|
|
50
64
|
|
|
51
|
-
| Symptom | Next step
|
|
52
|
-
| --------------------------------------------------------- |
|
|
53
|
-
| Missing binary, mismatched daemon, unknown tool/field | [Runtime preflight](RUNTIME.md#preflight-and-transport)
|
|
54
|
-
| Stale token or ambiguous window | Refresh `list_windows` / `get_window_state`; choose the intended live target
|
|
55
|
-
| Large or sparse tree
|
|
56
|
-
| `surface_identity_unproven` or screenshot permission wait | [Wayland capture recovery](LINUX.md#capture-recovery)
|
|
57
|
-
| `background_unavailable` |
|
|
58
|
-
|
|
|
59
|
-
|
|
|
65
|
+
| Symptom | Next step |
|
|
66
|
+
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
67
|
+
| Missing binary, mismatched daemon, unknown tool/field | [Runtime preflight](RUNTIME.md#preflight-and-transport) |
|
|
68
|
+
| Stale token or ambiguous window | Refresh `list_windows` / `get_window_state`; choose the intended live target |
|
|
69
|
+
| Large, truncated, or sparse tree; repeated reads | [Bounded observation and `since` diffs](WORKFLOW.md#observe) |
|
|
70
|
+
| `surface_identity_unproven` or screenshot permission wait | [Wayland capture recovery](LINUX.md#capture-recovery) |
|
|
71
|
+
| `background_unavailable` | Not a stop: that input route is closed, the task is not. Read `get_window_state` and act by element (`element_token`, `invoke_menu`); foreground only if authorized |
|
|
72
|
+
| Web page in a browser | Refs from `get_browser_state` with `browser_click` / `browser_type`; pixel clicks only when no ref exists |
|
|
73
|
+
| LibreOffice, Preview and other macOS editors | [macOS recipes](MACOS.md#libreoffice-numbers-and-other-editors-in-the-background) |
|
|
74
|
+
| Text did not visibly change | Reobserve before retrying; [text and value semantics](WORKFLOW.md#act-once) |
|
|
75
|
+
| Browser setup, binding, or ref refused | [Browser recovery](BROWSER.md#recovery-rules) |
|
|
60
76
|
|
|
61
77
|
## Consult recent Cua activity only for continuation
|
|
62
78
|
|
|
@@ -376,6 +376,11 @@ When a cua-driver surprises you, diagnose cua-driver first:
|
|
|
376
376
|
click in.
|
|
377
377
|
- **`Invalid window handle (0x80070578)`?** The HWND you passed is
|
|
378
378
|
stale (window closed, recreated). Re-resolve via `list_windows`.
|
|
379
|
+
- **Large tree or repeated reads?** `get_window_state` returns one compact
|
|
380
|
+
markdown tree capped at 250 nodes (`full_output:true` restores 5 000 nodes
|
|
381
|
+
and both forms). Pass `since:<snapshot_id>` for added/changed/removed rows;
|
|
382
|
+
the focused element is not reported on Windows yet, so an unchanged read
|
|
383
|
+
says only `no change since …`.
|
|
379
384
|
- **Empty `tree_markdown` / sparse UIA tree?** Some apps populate
|
|
380
385
|
their UIA tree lazily on first call; retry `get_window_state`
|
|
381
386
|
once. If still empty, the app has no UIA provider: fall back to an
|
|
@@ -35,14 +35,17 @@ These objects are argument fragments for tools advertising `target`, not standal
|
|
|
35
35
|
|
|
36
36
|
## Observe
|
|
37
37
|
|
|
38
|
-
`get_window_state({pid, window_id})` requests the accessibility tree and a grounding screenshot by default. Check what actually came back: permission, backing-store, or surface-identity failures can leave usable tree data without an image. `screenshot_error` and `screenshot_frame_valid:false` are not empty-tree signals.
|
|
38
|
+
`get_window_state({pid, window_id})` requests the accessibility tree and a grounding screenshot by default. Start with `query` (or `max_elements`) instead of a full read, and verify at checkpoints rather than after every action. Check what actually came back: permission, backing-store, or surface-identity failures can leave usable tree data without an image. `screenshot_error` and `screenshot_frame_valid:false` are not empty-tree signals.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
By default the tree comes back **once**, as compact `tree_markdown` (`tree_format:"markdown"`). A row `[N]` is addressed with `element_token` `<snapshot_id>:N`; the `snapshot_id` is in the response header and in `structuredContent`. Use `tree_format:"elements"` for the structured `elements` array when you need explicit tokens, frames, parents, or values, or `"both"` for the old double payload (about twice the size). `full_output:true` restores the previous full response, including the platform's walk limits. In `elements`, rows may contain `element_token`, role, label, value, actions, parent, depth, enabled/selected state, `frame` (screen coordinates, the space of `scope:"desktop"` actions), and `screenshot_frame` (pixels of the screenshot in the same response, the space of window-local pointer `x`/`y`). Missing fields are unknown.
|
|
41
41
|
|
|
42
42
|
- Use `query` to project matching rows plus ancestors without renumbering their indices.
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
43
|
+
- A read walks at most 250 nodes by default. When it stops there the response says `Tree truncated at max_elements=…` (`truncated:true`, `truncation_hint`). Pass a larger `max_elements`, or narrow with `query` / `max_depth`. Truncation does not prove absence.
|
|
44
|
+
- After the first read, pass `since:"latest"` (or `since:<snapshot_id>`) to get only what changed. `latest` is this window's most recent read with the same `query`, `max_elements` and `max_depth`. You get: `+` added, `~` changed, `-` removed rows (removed ids are the old snapshot's), or `no change since …; focused element is …` (focus is reported on macOS only). The response carries a new `snapshot_id`: use it in tokens (`<new id>:N`). Rows not listed keep their `[N]` unless a `reindexed:` line says otherwise. An unknown, expired, other-window, or differently-scoped `since` returns a full read, and `since_status` says why. A diff reads the rendered tree rows only; it does not prove the screenshot is unchanged.
|
|
45
|
+
- `_note`, `background_input`, and (Linux) `frame_note` are omitted unless `verbose:true`; a degraded snapshot keeps `background_input`.
|
|
46
|
+
- `include_screenshot:false` returns the tree only. On macOS the window keeps the pixel frame of its last screenshot while its size is unchanged, so `x,y` read off that screenshot still work; elsewhere, and after a resize, take a new screenshot before a pixel action.
|
|
47
|
+
- Where advertised, `include_accessibility_tree:false` requests capture without a tree walk. It keeps the current snapshot's rows and tokens valid. `display_only:true` with it is for live previews: it also leaves your pixel frame alone, and its image cannot ground actions. Use it when you only need to look; do not use `max_elements:1` or a `query` that matches nothing for that, because those replace the snapshot with an almost empty one.
|
|
48
|
+
- Row numbers belong to one read. A narrower re-read (smaller `max_elements`, `max_depth`, another `query`) can stop before a row you saw earlier, and `<new snapshot_id>:N` for that row is then out of range. Use rows printed in the read whose `snapshot_id` you use.
|
|
46
49
|
- `capture_mode` is deprecated and ignored. Do not change configuration to repair a sparse tree.
|
|
47
50
|
- Use `screenshot_out_file` to save a PNG instead of inlining it, then actually read the image. Use an absolute, run-scoped output path.
|
|
48
51
|
|
|
@@ -50,7 +53,7 @@ The accessibility model may lag or disagree with rendered state: Electron text s
|
|
|
50
53
|
|
|
51
54
|
## Act once
|
|
52
55
|
|
|
53
|
-
Use
|
|
56
|
+
Use the `element_token` `<snapshot_id>:N` for row `[N]` of the latest snapshot of the intended window, for example `"s0000002a:11"`. A bare `"11"` is accepted only together with `window_id` and then means row 11 of that window's current snapshot. Do not mix a row number from one read with the `snapshot_id` of another. A later snapshot can invalidate a pending action, including when another agent observes the same window.
|
|
54
57
|
|
|
55
58
|
Example CLI window action, with IDs and token replaced from the preceding response:
|
|
56
59
|
|
|
@@ -66,7 +69,7 @@ cua-driver click '{"target":{"kind":"window","pid":844,"window_id":10725},"eleme
|
|
|
66
69
|
| Focus a visible field and type | `type_text` with `x,y,text`, when that form is advertised |
|
|
67
70
|
| Replace an exposed native value | `set_value` with `pid,element_token,value` (its own schema, no `target`) |
|
|
68
71
|
| Send a key or combination | `press_key` with `key`, or `hotkey` with `keys` |
|
|
69
|
-
| Scroll / drag |
|
|
72
|
+
| Scroll / drag | `scroll` takes `direction` and `amount` (wheel notches); signed `dx`/`dy` is converted (positive `dy` is down; up to 50 is notches, more is pixels at 100 px per notch). Inspect `describe drag` |
|
|
70
73
|
|
|
71
74
|
Text insertion and value replacement are different intents. Setting a field does not prove a form submission, navigation, or rename committed. Open a collapsed search/input control and reobserve before typing into it; one focus-click may not both open and focus it. Inspect the existing value/selection before replacing content.
|
|
72
75
|
|
|
@@ -74,13 +77,48 @@ If a text action returns `unverifiable`, take a fresh snapshot before retrying.
|
|
|
74
77
|
|
|
75
78
|
Keep `delivery_mode:"background"` as the default for window input. The route may use accessibility hit-testing even when addressed by pixels: pixel coordinates do not promise physical pointer delivery. Read the returned `route` instead of inferring it from the tool name.
|
|
76
79
|
|
|
80
|
+
## Batch known actions
|
|
81
|
+
|
|
82
|
+
`run_steps` is the default way to act. When the next action or actions are decided, send them as one `run_steps` call with `observe:{}` instead of one call per action followed by a read. Even a single step pays off: the action and the look at its result become one call. The batch runs the same tools in order, stops at the first failure, and returns per-step status plus at most one bounded observation. Typical fit: fill several fields, then press a button, then read the result. Do not batch across a point where the answer decides the next step, or when a step reshuffles the window and invalidates element tokens used by later steps (use pixel targets after it, or split the batch there).
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
cua-driver run_steps '{"session":"run-1","steps":[
|
|
86
|
+
{"tool":"set_value","args":{"pid":844,"element_token":"s0000002a:14","value":"Ada"}},
|
|
87
|
+
{"tool":"set_value","args":{"pid":844,"element_token":"s0000002a:15","value":"Lovelace"}},
|
|
88
|
+
{"tool":"click","args":{"target":{"kind":"window","pid":844,"window_id":10725},"element_token":"s0000002a:21"}},
|
|
89
|
+
{"tool":"press_key","args":{"pid":844,"key":"return"}}
|
|
90
|
+
],"delay_ms":100,"observe":{}}'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- `tool` is one of `click`, `double_click`, `right_click`, `set_value`, `type_text`, `press_key`, `hotkey`, `scroll`, `drag`, `move_cursor` (`press` and `type` are accepted for `press_key` and `type_text`, `triple_click` is a click with `count:3`, and a key name such as `down` as the tool is a `press_key`); `args` are exactly that tool's arguments. Observation tools do not run inside a batch: a read between actions is skipped (it could not change the later steps), a `get_window_state` as the last step is the observation (merged with `observe`), and a trailing `zoom` runs after it. Run `describe run_steps` and `describe <tool>` for schemas. Up to 64 steps. `delivery_mode` on `run_steps` is the default for steps that set none.
|
|
94
|
+
- Name the window once: `pid` and `window_id` (or `app`/`window`) on `run_steps` itself are the default for every step that names none.
|
|
95
|
+
- A step whose `element_token` went stale because an earlier step re-rendered the window is retried once on the element with the same role and label in a fresh read, when exactly one matches; the step's line says so.
|
|
96
|
+
- Every step is validated before the first runs, so a malformed step changes nothing. Each step then passes the same session, permission, capability-manifest and approval checks as a direct call; a batch grants nothing a single call lacks, and a refused step ends the batch like any other failure.
|
|
97
|
+
- A batch has one session. Set `session` on `run_steps`; a step may repeat it but not name another.
|
|
98
|
+
- `observe` is optional and reads once, after the last executed step (also after a failure). Pass `true` or `get_window_state` arguments; `pid`/`window_id` come from the last step that names both. Defaults: `since:"latest"` (only what changed since your last read of that window with the same view; a full read if there is none), `include_screenshot:false`, `max_elements:250`. Pass `include_screenshot:true` to see the window, or `since:null` for a full read. Omit `observe` to read nothing.
|
|
99
|
+
- Read `steps[].ok` and `failed_step`. Steps before a failure did run and are not rolled back; steps after it did not. Observe before repairing, as for a single `unverifiable` action. When a step fails because another window of the app holds focus (a dialog opened mid-batch), the end read is of that window, even without `observe`; when a pixel step names a window with no screenshot yet, the end read includes its screenshot. A step refused because its app ignores background input (Electron, LibreOffice) says how to re-send it; set `foreground_fallback:true` on `run_steps` to retry such steps once in the foreground (the window is activated and the pointer may move).
|
|
100
|
+
|
|
101
|
+
## Script a flow
|
|
102
|
+
|
|
103
|
+
Use `run_script` when the flow needs logic between actions: a loop over rows, a branch on what the app shows, a retry, or a value read in one window and typed into another. The script is JavaScript, the body of an async function; it runs in ONE call and only its `return` value, console output and a per-call log come back. Use `run_steps` for a fixed list of steps you have already decided, and plain calls when the next step needs your judgement.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
cua-driver run_script '{"session":"run-1","script":"const app = await cua.getApp(\"Calculator\"); for (const key of [\"7\", \"multiply\", \"6\", \"equals\"]) await app.click({role: \"button\", name: key}); const [display] = await app.query({role: \"statictext\"}); return display.value;"}'
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- The only API is `cua`: `getApp`, `launch`, `listApps`, `listWindows`, `sleep`, and on an app `getState`, `query`, `waitFor`, `verify` and the actions (`click`, `typeText`, `pressKey`, `setValue`, `scroll`, `drag`, ...). A target is `{role, name, nth?}` (found fresh, waits up to 3 s), an `element_token`, or `[x, y]` window pixels. `describe run_script` lists the full API.
|
|
110
|
+
- A failed driver call throws; catch it to recover. An uncaught error names the script line, the call and the reason.
|
|
111
|
+
- Every driver call passes the same session, permission, capability-manifest and approval checks as a direct call, so a script grants nothing the same direct calls lack. It cannot call `run_steps`, `run_script`, `set_config` or tools outside its allowlist.
|
|
112
|
+
- Sandbox: QuickJS with no filesystem, network, process, timers or environment. Limits: `timeout_ms` wall time (default 30000, max 120000), `max_calls` driver calls (default 100, max 500), a 32 MiB heap, a bounded stack, and a 64 KiB script. The script stops when the request is cancelled.
|
|
113
|
+
- `run_script` is on by default. Whoever runs the driver can turn it off with `CUA_DRIVER_DISABLE_RUN_SCRIPT=1` or `"disable_run_script": true` in `~/.cua-driver/config.json` (the older `CUA_DRIVER_EXPERIMENTAL_SCRIPT=0` and `"experimental_script": false` also work). `set_config` cannot change it. When it is off, it is not in `tools/list`.
|
|
114
|
+
|
|
77
115
|
## Pixel coordinates
|
|
78
116
|
|
|
79
117
|
Ground window actions on the PNG from that exact `get_window_state`; ground desktop actions on `get_desktop_state`. Origins are top-left, increasing downward. The driver handles its own window capture scaling; do not add window offsets to window-local input.
|
|
80
118
|
|
|
81
119
|
The harness may downsample the displayed preview independently of the returned PNG. Use the returned dimensions and the original file. If measuring on a resized preview, account for its exact scale in both axes; do not assume the preview is native resolution. Do not guess from accessibility frames or another app's geometry.
|
|
82
120
|
|
|
83
|
-
After movement, resize, navigation, or a competing desktop interaction, reobserve.
|
|
121
|
+
After movement, resize, navigation, or a competing desktop interaction, reobserve. `zoom` takes a region as corners, `x1,y1` (top-left) to `x2,y2` (bottom-right); `x,y,width,height` is converted. Preserve the `from_zoom` mapping on the supported follow-up action. A manually cropped image requires its crop offset; an untracked crop is not an action coordinate source.
|
|
84
122
|
|
|
85
123
|
For tiny targets, inspect at full resolution or annotate a copy without changing its dimensions. Keep the raw evidence unmodified. `debug_image_out`, where advertised, captures an action diagnostic; it is not a pre-action approval step.
|
|
86
124
|
|