u2-cli 0.1.0__tar.gz

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.
@@ -0,0 +1,52 @@
1
+ # This workflow will upload a Python Package to PyPI when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ # This workflow uses actions that are not certified by GitHub.
5
+ # They are provided by a third-party and are governed by
6
+ # separate terms of service, privacy policy, and support
7
+ # documentation.
8
+
9
+ name: PyPI
10
+
11
+ on:
12
+ push:
13
+ tags: [ 'v*.*.*' ]
14
+ workflow_dispatch:
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ release-build-and-publish-pypi:
21
+ runs-on: ubuntu-latest
22
+
23
+ environment:
24
+ name: pypi
25
+
26
+ steps:
27
+ - uses: actions/checkout@v6
28
+
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@v7
31
+
32
+ - name: "Set up Python"
33
+ uses: actions/setup-python@v6
34
+ with:
35
+ python-version-file: "pyproject.toml"
36
+
37
+ - name: Install the project
38
+ run: uv sync --all-extras --dev
39
+
40
+ - name: Build release distributions
41
+ run: uv build
42
+
43
+ - name: Upload distributions
44
+ uses: actions/upload-artifact@v7
45
+ with:
46
+ name: release-dists
47
+ path: dist/
48
+
49
+ - name: Publish PyPI
50
+ env:
51
+ UV_PUBLISH_TOKEN: ${{ secrets.UV_PUBLISH_TOKEN }}
52
+ run: uv publish
@@ -0,0 +1,207 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Spyder project settings
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope project settings
152
+ .ropeproject
153
+
154
+ # mkdocs documentation
155
+ /site
156
+
157
+ # mypy
158
+ .mypy_cache/
159
+ .dmypy.json
160
+ dmypy.json
161
+
162
+ # Pyre type checker
163
+ .pyre/
164
+
165
+ # pytype static type analyzer
166
+ .pytype/
167
+
168
+ # Cython debug symbols
169
+ cython_debug/
170
+
171
+ # PyCharm
172
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
175
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
+ #.idea/
177
+
178
+ # Abstra
179
+ # Abstra is an AI-powered process automation framework.
180
+ # Ignore directories containing user credentials, local state, and settings.
181
+ # Learn more at https://abstra.io/docs
182
+ .abstra/
183
+
184
+ # Visual Studio Code
185
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
+ # you could uncomment the following to ignore the entire vscode folder
189
+ # .vscode/
190
+
191
+ # Ruff stuff:
192
+ .ruff_cache/
193
+
194
+ # PyPI configuration file
195
+ .pypirc
196
+
197
+ # Cursor
198
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
+ # refer to https://docs.cursor.com/context/ignore-files
201
+ .cursorignore
202
+ .cursorindexingignore
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
u2_cli-0.1.0/CLAUDE.md ADDED
@@ -0,0 +1,61 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Overview
6
+
7
+ `u2-cli` is a CLI tool wrapping [uiautomator2](https://github.com/openatx/uiautomator2) to control Android devices, designed for use by AI agents.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Install deps and activate env
13
+ uv sync
14
+
15
+ # Run CLI during development (no install needed)
16
+ uv run src/u2/__init__.py <cmd>
17
+
18
+ # Run after installing as a package
19
+ uv run u2 <cmd>
20
+
21
+ # Lint
22
+ uv run ruff check .
23
+ uv run ruff format .
24
+
25
+ # Build for PyPI
26
+ uv build
27
+ ```
28
+
29
+ ## Architecture
30
+
31
+ All CLI commands output JSON: `{"success": bool, "output": str, "code": str}` where `code` is the uiautomator2 Python expression that was executed, example: `d(text='Hello').click()`, `d.shell('ls')`.
32
+
33
+ The CLI is built with [Typer](https://typer.tiangolo.com/) and organized into sub-apps:
34
+
35
+ ```
36
+ src/u2/
37
+ ├── __init__.py # Root app, State dataclass, global --serial/-s flag, main()
38
+ ├── device.py # device sub-app: info, battery, wlan-ip, shell, keyevent, push, pull, screen-on, screen-off, orientation
39
+ ├── app.py # app sub-app: start, stop, install, uninstall, clear, list, current, wait-activity
40
+ ├── screen.py # screen sub-app: screenshot, dump, size, brightness
41
+ ├── interact.py # interact sub-app: tap, long-tap, swipe, drag, type, clear
42
+ ├── element.py # element sub-app: find, wait, exists, get-text, set-text, tap, long-tap (selector-based)
43
+ └── watch.py # watch sub-app: add, remove, list, run (uiautomator2 Watcher)
44
+ ```
45
+
46
+ **Sub-app responsibilities:**
47
+
48
+ - `device` — physical device state and low-level operations: device info, battery, IP, adb shell, key events (`home`, `back`, `power`, etc.), file push/pull, screen on/off, rotation
49
+ - `app` — app lifecycle: install/uninstall APK, start/stop by package, clear data, list installed apps, get current foreground app, wait for a target activity
50
+ - `screen` — visual state: screenshot (PNG to stdout or file), XML hierarchy dump, screen size, brightness
51
+ - `interact` — coordinate-based input: tap, long-tap, swipe (from/to coords), drag, send text to focused element, clear focused text
52
+ - `element` — selector-based element interaction: find elements by `text`, `resourceId`, `className`, `xpath`, `description`; check existence; get/set text; tap or long-tap matched elements
53
+ - `watch` — register/run UI watchers that auto-click or trigger actions when a matching element appears
54
+
55
+ **Global state:** The `--serial`/`-s` flag (Android device serial) is stored in a module-level `State` dataclass in `__init__.py`. Sub-command modules access it via `from u2 import state`.
56
+
57
+ **Entry point:** `u2 = "u2:main"` in `pyproject.toml`.
58
+
59
+ ## Linting
60
+
61
+ Ruff is configured with `FBT` rules enabled — boolean positional arguments in function signatures trigger warnings. Typer-style boolean CLI options require `# noqa: FBT001/FBT002` suppressions.
u2_cli-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lanbao
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
u2_cli-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: u2-cli
3
+ Version: 0.1.0
4
+ Summary: CLI tool for executing uiautomator2 commands to control Android devices from the AI Agent
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: typer>=0.24.1
8
+ Requires-Dist: uiautomator2>=3.5.0
9
+ Description-Content-Type: text/markdown
10
+
11
+ # u2-cli
12
+ CLI tool for executing uiautomator2 commands to control Android devices from the AI Agent
u2_cli-0.1.0/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # u2-cli
2
+ CLI tool for executing uiautomator2 commands to control Android devices from the AI Agent
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "u2-cli"
7
+ version = "0.1.0"
8
+ description = "CLI tool for executing uiautomator2 commands to control Android devices from the AI Agent"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ dependencies = [
12
+ "typer>=0.24.1",
13
+ "uiautomator2>=3.5.0",
14
+ ]
15
+
16
+ [project.scripts]
17
+ u2 = "u2:main"
18
+
19
+ [tool.hatch.build.targets.wheel]
20
+ packages = ["src/u2"]
21
+
22
+ [tool.ruff]
23
+ line-length = 100
24
+
25
+ [tool.ruff.lint]
26
+ select = ["E", "F", "FBT"]
27
+ ignore = ["FBT003"]
28
+
29
+ [dependency-groups]
30
+ dev = [
31
+ "ruff>=0.15.6",
32
+ ]
@@ -0,0 +1,159 @@
1
+ ---
2
+ name: u2-cli
3
+ description: Use this skill when the user wants to control an Android device using the u2-cli tool. Triggers when: controlling an Android device via CLI, automating Android UI interactions, using uiautomator2 from the command line, finding/tapping/swiping UI elements on Android, taking screenshots or dumping UI hierarchy, managing Android apps, or running adb-based device operations through u2.
4
+ ---
5
+
6
+ # u2-cli Skill
7
+
8
+ You are helping the user control an Android device using `u2-cli`, a CLI tool wrapping uiautomator2.
9
+
10
+ The complete command reference is in [references/commands.md](references/commands.md). Always consult it for exact syntax, flags, and defaults.
11
+
12
+ Install:
13
+
14
+ ```bash
15
+ uv pip install u2-cli
16
+ ```
17
+
18
+ ## Core Workflow
19
+
20
+ ### 1. Orient yourself
21
+
22
+ Before interacting with the device, understand its current state:
23
+
24
+ ```bash
25
+ u2 screen dump --simplify # Get UI hierarchy as compact JSON
26
+ u2 screen screenshot /tmp/sc.png # Take a screenshot for visual context
27
+ u2 app current # See what app is in foreground
28
+ ```
29
+
30
+ Use `screen dump --simplify` as your primary tool for understanding what's on screen — it produces a compact JSON tree with pruned noise, shortened class names, and only the relevant attributes.
31
+
32
+ ### 2. Find elements before acting on them
33
+
34
+ Verify elements exist before tapping or typing:
35
+
36
+ ```bash
37
+ u2 element exists --text "Login"
38
+ u2 element find --xpath "//android.widget.Button"
39
+ u2 element wait --resource-id com.example:id/submit --timeout 5
40
+ ```
41
+
42
+ ### 3. Prefer `element` commands over coordinate `interact` commands
43
+
44
+ Use selector-based `element tap/long-tap` when you can identify elements by text, resource-id, or xpath. Fall back to `interact tap <x> <y>` only when no selector is available.
45
+
46
+ ### 4. Parse output correctly
47
+
48
+ All commands return JSON:
49
+ ```json
50
+ {"success": true, "output": "...", "code": "d(text='Login').click()"}
51
+ ```
52
+
53
+ Check `success` before proceeding. The `output` field contains the actual data (parse as JSON if it's a list/dict). The `code` field shows what uiautomator2 expression ran.
54
+
55
+ ---
56
+
57
+ ## Common Tasks
58
+
59
+ ### Navigate the UI
60
+
61
+ ```bash
62
+ u2 device keyevent back # Press Back
63
+ u2 device keyevent home # Press Home
64
+ u2 interact swipe 540 1500 540 500 --duration 0.3 # Scroll up
65
+ u2 interact swipe 540 500 540 1500 --duration 0.3 # Scroll down
66
+ ```
67
+
68
+ ### Tap an element
69
+
70
+ ```bash
71
+ # By text
72
+ u2 element tap --text "Sign In"
73
+
74
+ # By resource ID
75
+ u2 element tap --resource-id com.example:id/btn_login
76
+
77
+ # By XPath
78
+ u2 element tap --xpath "//android.widget.Button[@text='OK']"
79
+
80
+ # By coordinates (fallback)
81
+ u2 interact tap 540 960
82
+ ```
83
+
84
+ ### Type text
85
+
86
+ ```bash
87
+ # Tap the input field first, then type
88
+ u2 element tap --resource-id com.example:id/email_input
89
+ u2 interact type "user@example.com"
90
+
91
+ # Or set text directly on an element
92
+ u2 element set-text "user@example.com" --resource-id com.example:id/email_input
93
+ ```
94
+
95
+ ### Launch an app
96
+
97
+ ```bash
98
+ # Start fresh (stop + start)
99
+ u2 app start com.example.app --stop --wait
100
+
101
+ # Wait for specific activity to load
102
+ u2 app wait-activity .MainActivity --timeout 15
103
+ ```
104
+
105
+ ### Handle popups automatically
106
+
107
+ ```bash
108
+ # Block for 30s, auto-click any "Allow" button that appears
109
+ u2 watch add allow-popup --xpath "//android.widget.Button[@text='Allow']" --timeout 30
110
+
111
+ # One-shot: trigger immediately if a dialog is currently visible
112
+ u2 watch run --xpath "//android.widget.Button[@text='OK']"
113
+ ```
114
+
115
+ ### Capture screen state
116
+
117
+ ```bash
118
+ # Screenshot to file
119
+ u2 screen screenshot /tmp/screen.png
120
+
121
+ # Screenshot to stdout (pipe to viewer/tool)
122
+ u2 screen screenshot | display
123
+
124
+ # UI hierarchy for AI analysis
125
+ u2 screen dump --simplify
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Strategy for Autonomous Tasks
131
+
132
+ When given a multi-step task (e.g., "fill in this form", "open settings and enable X"):
133
+
134
+ 1. **Dump the screen** with `screen dump --simplify` to understand current state
135
+ 2. **Plan the steps** based on what elements are visible
136
+ 3. **Act step by step**, checking success after each command
137
+ 4. **Re-dump** after navigation or significant UI changes
138
+ 5. **Use `element wait`** before acting when a screen transition is expected
139
+
140
+ If an element isn't found, try:
141
+ - `element find` with a broader selector to explore what's on screen
142
+ - `screen dump --simplify` to re-check the current UI state
143
+ - Scrolling with `interact swipe` and then retrying
144
+
145
+ ---
146
+
147
+ ## Device Selection
148
+
149
+ When multiple devices are connected, prefix all commands with `-s SERIAL`:
150
+
151
+ ```bash
152
+ u2 -s emulator-5554 screen dump --simplify
153
+ u2 -s R3CN10XXXXX element tap --text "Login"
154
+ ```
155
+
156
+ Get available devices with:
157
+ ```bash
158
+ adb devices
159
+ ```
@@ -0,0 +1,130 @@
1
+ # u2-cli Command Reference
2
+
3
+ ## Global Options
4
+
5
+ Applies to every command:
6
+
7
+ ```
8
+ u2 [-s SERIAL] <sub-app> <command> [args]
9
+ ```
10
+
11
+ | Flag | Short | Type | Description |
12
+ |------|-------|------|-------------|
13
+ | `--serial` | `-s` | `str` | Android device serial (required when multiple devices connected) |
14
+
15
+ **Output format (all commands):**
16
+ ```json
17
+ {"success": bool, "output": str, "code": str}
18
+ ```
19
+ - `success` — whether the operation succeeded
20
+ - `output` — result data or error message
21
+ - `code` — the uiautomator2 Python expression that was executed
22
+
23
+ ---
24
+
25
+ ## `device` sub-app
26
+
27
+ Physical device state and low-level operations.
28
+
29
+ | Command | Args | Description |
30
+ |---------|------|-------------|
31
+ | `device info` | — | Returns `d.device_info` dict |
32
+ | `device battery` | — | Returns battery info dict |
33
+ | `device wlan-ip` | — | Returns WLAN IP string |
34
+ | `device shell <cmd>` | `cmd: str` | Run adb shell command, returns stdout |
35
+ | `device keyevent <key>` | `key: str` | Send key event (e.g. `home`, `back`, `power`) |
36
+ | `device push <src> <dst>` | `src: str`, `dst: str` | Push local file to device |
37
+ | `device pull <src> <dst>` | `src: str`, `dst: str` | Pull file from device |
38
+ | `device screen-on` | — | Turn screen on |
39
+ | `device screen-off` | — | Turn screen off |
40
+ | `device orientation [value]` | `value?: natural\|left\|right\|upsidedown` | Get or set orientation |
41
+
42
+ ---
43
+
44
+ ## `app` sub-app
45
+
46
+ App lifecycle management.
47
+
48
+ | Command | Args / Flags | Description |
49
+ |---------|-------------|-------------|
50
+ | `app start <package>` | `--activity/-a str`, `--wait bool`, `--stop bool` | Launch app, optionally stopping first and waiting |
51
+ | `app stop <package>` | `package: str` | Stop app by package name |
52
+ | `app install <path>` | `path: str` | Install APK from path or URL |
53
+ | `app uninstall <package>` | `package: str` | Uninstall app |
54
+ | `app clear <package>` | `package: str` | Clear app data |
55
+ | `app list` | `--filter/-f str` (`-3` third-party, `-s` system, `-d` disabled, `-e` enabled) | List installed packages |
56
+ | `app current` | — | Returns current foreground app (package, activity, pid) |
57
+ | `app wait-activity <activity>` | `--timeout/-t float` (default: 10.0) | Wait for activity to appear; `success` reflects result |
58
+
59
+ ---
60
+
61
+ ## `screen` sub-app
62
+
63
+ Visual state capture.
64
+
65
+ | Command | Args / Flags | Description |
66
+ |---------|-------------|-------------|
67
+ | `screen screenshot [path]` | `path?: str` | Save PNG to file (JSON output), or omit to write raw PNG bytes to stdout |
68
+ | `screen dump` | `--compressed bool`, `--pretty bool`, `--simplify/-s bool` | Dump UI hierarchy as XML or simplified JSON |
69
+ | `screen size` | — | Returns screen size as `WxH` string (e.g. `1080x2340`) |
70
+ | `screen brightness [value]` | `value?: int (0–255)` | Get or set screen brightness |
71
+
72
+ **`screen dump --simplify`** returns compact JSON tree with pruned/collapsed nodes:
73
+ - Keys: `type`, `text`, `desc`, `id`, `bounds`, plus boolean flags (`clickable`, `scrollable`, etc.) only when `true`, plus `children`
74
+ - Class names are shortened (e.g. `TextView` → `text`)
75
+
76
+ ---
77
+
78
+ ## `interact` sub-app
79
+
80
+ Coordinate-based input actions.
81
+
82
+ | Command | Args / Flags | Description |
83
+ |---------|-------------|-------------|
84
+ | `interact tap <x> <y>` | `x: int`, `y: int` | Tap at coordinates |
85
+ | `interact long-tap <x> <y>` | `x: int`, `y: int`, `--duration/-d float` (default: 0.5) | Long press at coordinates |
86
+ | `interact swipe <fx> <fy> <tx> <ty>` | from/to coords, `--duration/-d float` (default: 0.5) | Swipe between two points |
87
+ | `interact drag <sx> <sy> <ex> <ey>` | start/end coords, `--duration/-d float` (default: 0.5) | Drag between two points |
88
+ | `interact type <text>` | `text: str` | Type text into focused element (clipboard paste, supports Unicode/Chinese) |
89
+ | `interact clear` | — | Clear text in focused element |
90
+
91
+ ---
92
+
93
+ ## `element` sub-app
94
+
95
+ Selector-based element interaction. At least one selector required per command.
96
+
97
+ **Shared selector options:**
98
+
99
+ | Flag | Short | Description |
100
+ |------|-------|-------------|
101
+ | `--text` | `-t` | Element text |
102
+ | `--resource-id` | `-r` | Resource ID |
103
+ | `--class-name` | `-c` | Class name |
104
+ | `--xpath` | `-x` | XPath expression (uses `d.xpath(...)` path) |
105
+ | `--description` | `-d` | Content description |
106
+
107
+ Multiple non-xpath selectors can be combined. XPath takes a separate code path.
108
+
109
+ | Command | Extra Flags | Description |
110
+ |---------|------------|-------------|
111
+ | `element find` | `--timeout/-T float` (default: 0.0) | Find elements, returns JSON array of element info dicts |
112
+ | `element wait` | `--timeout/-T float` (default: 10.0) | Wait for element; `success` reflects result |
113
+ | `element exists` | — | `output` is `"true"` or `"false"` |
114
+ | `element get-text` | `--timeout/-T float` (default: 10.0) | Returns element's text in `output` |
115
+ | `element set-text <value>` | `value: str`, `--timeout/-T float` (default: 10.0) | Set element text |
116
+ | `element tap` | `--timeout/-T float` (default: 10.0) | Tap matched element |
117
+ | `element long-tap` | `--duration/-D float` (default: 0.5), `--timeout/-T float` (default: 10.0) | Long-tap matched element |
118
+
119
+ ---
120
+
121
+ ## `watch` sub-app
122
+
123
+ UI watchers that auto-trigger actions when a matching element appears.
124
+
125
+ | Command | Args / Flags | Description |
126
+ |---------|-------------|-------------|
127
+ | `watch add <name>` | `--xpath/-x str` (required), `--action/-a str` (default: `click`), `--timeout/-t float` (default: 30.0) | Register watcher, start it, block for timeout, then stop. Actions: `click`, `back`, `home`, `recent` |
128
+ | `watch remove <name>` | `name: str` (use `__all__` to remove all) | Remove watcher (in-memory, same process only) |
129
+ | `watch list` | — | Returns whether watcher loop is running |
130
+ | `watch run` | `--xpath/-x str` (required), `--action/-a str` (default: `click`) | One-shot: register `__run__` watcher, fire once, remove it. `success` reflects whether it triggered |