adb-ready 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -147,7 +147,10 @@ unambiguous paired service; it never guesses among multiple devices.
147
147
 
148
148
  Tool calls within one MCP connection are executed in submission order. This
149
149
  prevents parallel agent requests from interleaving target binding, UI snapshots,
150
- or device mutations. Separate MCP connections remain independent.
150
+ or device mutations. Separate MCP connections remain independent, while the
151
+ short Android hierarchy-capture step is additionally serialized per target
152
+ across connections and processes because the platform exposes only one active
153
+ UI Automation service per target.
151
154
 
152
155
  ## Tool surface
153
156
 
@@ -32,6 +32,12 @@ Root presentation flags may appear in either order. Adding
32
32
  `--non-interactive` does not change the result shape or fall back to human
33
33
  help.
34
34
 
35
+ Version probes follow the same rule without loading configuration or ADB:
36
+ `adb-ready version` and `adb-ready --version` print one conventional bare
37
+ version line, while `version --format plain`, `version --json`, and
38
+ `version --format ndjson` return their documented automation shapes. Output
39
+ flags may appear before or after `version` or `--version`.
40
+
35
41
  Machine data is written to `stdout`. Human progress and diagnostics are written
36
42
  to `stderr`. `--quiet` hides successful human output without hiding failures.
37
43
 
@@ -125,10 +131,25 @@ adb-ready init --dry-run --json
125
131
  adb-ready connect 192.168.1.42:37123 --dry-run --json
126
132
  adb-ready ports reverse add 8081 --dry-run --json
127
133
  adb-ready dev --port 8081 --dry-run --json
134
+ adb-ready run --avd Pixel_9_API_36 --deploy --dry-run --json -- maestro test smoke.yaml
128
135
  ```
129
136
 
130
137
  Plan steps declare their risk. A dry run performs no pairing, connection,
131
- mapping, hook, or child-process mutation.
138
+ mapping, hook, deployment, or child-process mutation. `dev` and `run` plans are
139
+ compiled offline even when `--device`, `--transport-id`, `--last`, `--select`,
140
+ or `--avd` is present: ADB Ready does not contact the ADB server, inspect a
141
+ target, start an emulator, resolve an artifact, launch the project, or execute
142
+ the verifier. Target selectors and artifact paths remain declarative inputs in
143
+ the plan and are validated only during an actual run.
144
+
145
+ Port endpoints are always named by their role. Forward mappings listen on the
146
+ host and route to the selected device; reverse mappings listen on the device
147
+ and route back to the host:
148
+
149
+ ```bash
150
+ adb-ready ports forward add 9229 3000 --dry-run # host 9229 -> device 3000
151
+ adb-ready ports reverse add 8081 3000 --dry-run # device 8081 -> host 3000
152
+ ```
132
153
 
133
154
  ## Run one bounded verification
134
155
 
@@ -163,6 +184,50 @@ Preview the complete project plan before a device is allocated:
163
184
  adb-ready run --preset expo --dry-run --json -- npm run test:e2e
164
185
  ```
165
186
 
187
+ ### Start an existing AVD and deploy the intended build
188
+
189
+ For a complete local or CI-owned emulator job, name one existing AVD and either
190
+ provide the intended artifact or let ADB Ready discover exactly one compatible
191
+ build output:
192
+
193
+ ```bash
194
+ adb-ready run \
195
+ --avd Pixel_9_API_36 \
196
+ --artifact android/app/build/outputs/apk/debug/app-debug.apk \
197
+ --package com.example.app \
198
+ --run-timeout 10m \
199
+ -- maestro '--device={target.serial}' test .maestro/smoke.yaml
200
+
201
+ adb-ready run --avd Pixel_9_API_36 --deploy --variant debug -- \
202
+ ./gradlew connectedDebugAndroidTest
203
+ ```
204
+
205
+ The AVD must already exist. ADB Ready uses the standard Android Emulator and
206
+ ADB tools as its portable baseline; it does not create, delete, or upgrade an
207
+ SDK or AVD. An already-running matching emulator is reused and never stopped.
208
+ An emulator started by this run is readiness-checked and stopped on success,
209
+ failure, cancellation, or timeout.
210
+
211
+ Artifact selection prefers Android build metadata and refuses ambiguous,
212
+ incomplete, incompatible, outside-project, or stale candidates. APK and split
213
+ APK sets install directly. APK Set and Android App Bundle deployment requires
214
+ an explicit or locally verified bundletool; ADB Ready never downloads one in
215
+ the background. The installed package, version, ABI compatibility, and launch
216
+ activity are independently verified before the project or verifier runs.
217
+
218
+ During an interactive run, the terminal shows target inspection, artifact
219
+ selection, and install verification as distinct live steps. The final summary
220
+ identifies the artifact kind, variant, file count, package, version, launch
221
+ activity, and whether a requested emulator was started or reused. Local
222
+ artifact paths remain in the redacted evidence bundle instead of being exposed
223
+ in the compact human summary. `--plain` exposes the same result as stable
224
+ line-oriented `artifact_*`, `deployment_*`, and `emulator_*` fields; `--json`
225
+ and `--ndjson` retain the complete structured automation data.
226
+
227
+ The evidence manifest also includes the verifier's bounded, redacted native
228
+ stdout and stderr. Preparation failures still publish the same result,
229
+ problems, JUnit, and evidence contract after owned-resource cleanup.
230
+
166
231
  ## CI example
167
232
 
168
233
  ```yaml
@@ -55,6 +55,25 @@ One selected transport is used for the entire session:
55
55
  Use `--device`, `--transport-id`, `--last`, or `--select` to override the normal
56
56
  selection policy.
57
57
 
58
+ ## App-scoped crash diagnostics
59
+
60
+ Set the Android application ID when project detection cannot prove it:
61
+
62
+ ```bash
63
+ adb-ready dev --package com.example.app
64
+ ```
65
+
66
+ The same value can be shared as `app.android.package` in project configuration.
67
+ ADB Ready verifies the package on the selected target and filters logcat by its
68
+ restart-stable UID when supported, with an exact PID fallback for older
69
+ targets. Expo sessions automatically switch to the package Android resolves
70
+ for the verified Expo Go or development-client launch URL.
71
+
72
+ Until that identity is verified, startup records remain explicitly
73
+ `log.unattributed`. They can help reconstruct a target timeline, but an
74
+ unrelated system or test-process crash cannot become an application problem or
75
+ outrank attributed evidence in exported AI context.
76
+
58
77
  ## Port ownership
59
78
 
60
79
  The session treats each requested mapping as one of three states:
@@ -87,6 +106,14 @@ Detection is deliberately bounded:
87
106
  - an explicit mapping for the same device port always wins; and
88
107
  - cleanup still removes only mappings created by the current session.
89
108
 
109
+ ADB's `tcp:PORT` reverse endpoint connects to host localhost, while host
110
+ toolchains may resolve `localhost` to either IPv4 or IPv6. ADB Ready probes both
111
+ loopback families. If a required service listens only on `[::1]`, it creates a
112
+ session-owned proxy on `127.0.0.1` for the same port so the selected Android
113
+ target can use the normal reverse mapping. The proxy is loopback-only, remains
114
+ owned by the session that created it, and is closed during session cleanup. ADB
115
+ Ready fails safely if that bridge cannot be created.
116
+
90
117
  Preview the resolved mappings without touching ADB:
91
118
 
92
119
  ```bash
@@ -107,8 +134,9 @@ The same switch is available to `adb-ready init`. It can also be persisted as
107
134
 
108
135
  For Expo and React Native, ADB Ready checks the local host behind the default
109
136
  device port `8081` before launching the project command. It attaches only when
110
- `/status` returns Metro's exact running-status response. An open port alone is
111
- not sufficient evidence.
137
+ `/status` returns Metro's exact running-status response and Expo identifies the
138
+ same canonical project root. An open port, an unidentified Metro server, or a
139
+ Metro server belonging to another project is not sufficient evidence.
112
140
 
113
141
  An attached Metro server remains externally owned:
114
142
 
@@ -120,10 +148,13 @@ An attached Metro server remains externally owned:
120
148
  never restarts a process ADB Ready does not own.
121
149
  - A non-Metro service on the configured host port fails with
122
150
  `DEVELOPMENT_SERVICE_CONFLICT` and an actionable explanation.
151
+ - A Metro server with a missing or different project identity fails with the
152
+ same safe conflict and remains untouched.
123
153
 
124
- Run Metro in its original terminal when you need its native reload or developer
125
- controls. A newly started Metro process continues to receive its controls
126
- directly through ADB Ready.
154
+ Run an externally owned Metro server in its original terminal when you need its
155
+ native controls. When ADB Ready starts and owns an Expo session, it activates
156
+ its own verified controls after the app and local Expo control channel are
157
+ ready.
127
158
 
128
159
  ## Expo target isolation
129
160
 
@@ -203,21 +234,23 @@ Set `dev.watch` to `false` only for a deliberately one-shot child process.
203
234
  ## Live terminal controls
204
235
 
205
236
  An interactive `adb-ready dev` session shows a compact control bar after it
206
- becomes ready. ADB Ready preserves the framework's native terminal input rather
207
- than intercepting or redefining it:
208
-
209
- - Expo shows `r` reload, `m` developer menu, `j` debugger, and `?` commands.
210
- - Flutter shows `r` hot reload, `R` hot restart, and `h` commands.
211
- - Other presets state that framework input is active without promising
212
- unsupported shortcuts.
237
+ becomes ready. The bar advertises only controls that ADB Ready has activated and
238
+ can execute itself:
239
+
240
+ - An owned Expo session supports `r` to reload the connected app, `m` to open
241
+ its developer menu, and `?` to show the exact controls again. These actions
242
+ use Expo's local message protocol only after ADB Ready verifies the loopback
243
+ Metro endpoint and an active control connection.
244
+ - An attached Metro server remains externally owned, so its controls stay in
245
+ the terminal that started it.
246
+ - Other presets show no unverified framework shortcuts.
213
247
  - `Ctrl+C` stops the owned child and performs the normal verified cleanup.
214
248
  - Health monitoring is stopped and awaited before intentional child or port
215
249
  teardown, so cancellation cannot be recorded as a device degradation or a
216
250
  recovery attempt.
217
251
 
218
252
  The control bar is never rendered by `run`, JSON/NDJSON output, redirected
219
- streams, CI, `--non-interactive`, or `--quiet`. This keeps scripts deterministic
220
- and leaves arbitrary child input untouched.
253
+ streams, CI, `--non-interactive`, or `--quiet`. This keeps scripts deterministic.
221
254
 
222
255
  ## Lifecycle hooks
223
256
 
@@ -51,7 +51,16 @@ follow boundary so records written during setup are neither lost nor repeated.
51
51
  Unparsed lines are preserved. Output arriving on `stderr` is not automatically
52
52
  classified as an error; severity comes from source semantics. Fatal Android
53
53
  exceptions, native crashes, ANRs, and React Native fatal errors become
54
- structured findings.
54
+ structured findings. Package-scoped streams first verify the installed package
55
+ identity, prefer Android's restart-stable UID filter when the selected target
56
+ supports it, and fall back to the package's current PID on older targets.
57
+
58
+ Development sessions do not infer application ownership from a broad tag such
59
+ as `AndroidRuntime`. Before an application identity is verified, matching
60
+ target-wide records are retained as low-priority `log.unattributed` evidence
61
+ and never promoted to application problems. A configured `app.android.package`
62
+ or `dev --package APP_ID` scopes the stream directly; Expo sessions retarget it
63
+ to the package that Android resolves for the verified launch URL.
55
64
 
56
65
  ## Session history
57
66
 
@@ -81,6 +90,14 @@ When the ID is omitted, the latest saved session is selected. Default retention
81
90
  keeps at most 30 finalized sessions, 14 days, and 20 MiB. Active sessions are
82
91
  not pruned as finalized history.
83
92
 
93
+ Running-session summaries are reconciled from the append-only event journal at
94
+ read time. `sessions list`, `sessions show`, and `context` therefore expose the
95
+ latest completely persisted event count, byte count, update time, and known
96
+ preset without rewriting the manifest for every log line. A trailing event
97
+ that is still being appended is ignored until its terminating newline is
98
+ durable, so concurrent inspection never treats a partial JSON record as a
99
+ corrupt session.
100
+
84
101
  Storage locations follow host conventions:
85
102
 
86
103
  | Host | Default directory |
@@ -28,6 +28,12 @@ adb-ready devices --last
28
28
  disambiguates duplicate transports. `--last` resolves the last verified target
29
29
  identity; it does not silently choose an unrelated visible device.
30
30
 
31
+ An exact serial, serial-backed alias, or transport ID also bounds target-side
32
+ identity inspection to that transport. ADB Ready does not query unrelated
33
+ visible devices before running the requested command. Stable hardware-identity
34
+ selection and remembered-target recovery inspect the inventory because those
35
+ workflows must correlate a target whose transport may have changed.
36
+
31
37
  All target-aware commands accept the same selectors.
32
38
 
33
39
  ## Pair Android 11 and newer
@@ -31,6 +31,8 @@ adb-ready context --since 5m --only problems,recovery,logs
31
31
  | `MULTIPLE_WIRELESS_ENDPOINTS` | Discovery returned ambiguous services | Pass one exact `HOST:PORT` |
32
32
  | `PORT_MAPPING_CONFLICT` | Another mapping owns the requested listen port | Inspect `ports ... list`; remove or change it explicitly |
33
33
  | `LOG_PACKAGE_NOT_RUNNING` | Package filtering could not resolve a live process | Launch the app or use another package/PID |
34
+ | `UI_HIERARCHY_BUSY` | Another process held the selected target's single UI Automation service through the UI timeout | Let that capture finish or increase the UI timeout, then retry |
35
+ | `UI_HIERARCHY_LOCK_UNAVAILABLE` | The per-user coordination directory is not writable | Restore write access to the ADB Ready state directory, then retry |
34
36
  | `UI_NOT_IDLE` | Android UI Automator could not observe a quiet accessibility window | Pause continuous UI changes or navigate to a stable screen, then retry |
35
37
  | `SESSION_RECOVERY_FAILED` | The bounded target/port recovery budget was exhausted | Inspect `problems`, network state, and saved recovery events |
36
38
  | `SESSION_PERSISTENCE_FAILED` | The private session record could not be written | Check user-state directory permissions and capacity |
@@ -23,6 +23,13 @@ UI Automator waits for a quiet accessibility window before returning data.
23
23
  quiet window; pause the changing UI or navigate to a stable screen and retry.
24
24
  ADB Ready does not silently disable device-wide animations.
25
25
 
26
+ Android permits only one active UI Automation service on a target. ADB Ready
27
+ therefore serializes the short hierarchy-capture step per target, including
28
+ across separate CLI and MCP processes. Independent targets still run in
29
+ parallel, and selector processing or input does not hold the capture lock. If
30
+ another process does not finish within the configured UI timeout, the command
31
+ returns `UI_HIERARCHY_BUSY` instead of misreporting an inaccessible screen.
32
+
26
33
  ## Audit one screen for people and agents
27
34
 
28
35
  ```bash
@@ -15,6 +15,8 @@ adb-ready dev --dry-run
15
15
  - [`flutter/adb-ready.config.json`](./flutter/adb-ready.config.json)
16
16
  - [`capacitor/adb-ready.config.json`](./capacitor/adb-ready.config.json)
17
17
  - [`custom/adb-ready.config.json`](./custom/adb-ready.config.json)
18
+ - [`automation/README.md`](./automation/README.md) — one finite AVD, deployment,
19
+ verifier, evidence, and cleanup job
18
20
 
19
21
  Prefer `adb-ready init` when starting from an existing detected project. Add
20
22
  only the ports, hooks, and retention rules that the project genuinely needs.
@@ -0,0 +1,24 @@
1
+ # Autonomous Android verification
2
+
3
+ Preview the complete workflow without starting an emulator, installing an app,
4
+ or launching a process:
5
+
6
+ ```bash
7
+ adb-ready run \
8
+ --avd Pixel_9_API_36 \
9
+ --artifact android/app/build/outputs/apk/debug/app-debug.apk \
10
+ --package com.example.app \
11
+ --dry-run \
12
+ --json \
13
+ -- maestro '--device={target.serial}' test .maestro/smoke.yaml
14
+ ```
15
+
16
+ Remove `--dry-run` to execute the verified job. Use `--deploy --variant debug`
17
+ instead of `--artifact` when the project contains exactly one compatible debug
18
+ artifact. ADB Ready refuses ambiguous outputs instead of selecting by filename
19
+ or modification time.
20
+
21
+ The verifier is invoked directly, receives the same target in `ANDROID_SERIAL`
22
+ and `ADB_READY_TARGET_SERIAL`, and retains its bounded output in the run's local
23
+ evidence bundle. A matching emulator that was already running is left running;
24
+ only an emulator started by this invocation is stopped.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adb-ready",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Agent-ready Android CLI for reliable ADB sessions, app automation, and verified evidence.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "title": "ADB Ready agent tool contract",
3
3
  "schemaVersion": 1,
4
- "packageVersion": "0.4.1",
4
+ "packageVersion": "0.5.0",
5
5
  "protocolVersion": "2025-11-25",
6
6
  "transport": "stdio",
7
7
  "tools": [