dsh-mobilecode 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -1
- package/lib/android-stream.js +3 -4
- package/lib/client.js +1054 -961
- package/lib/device-build.js +255 -18
- package/lib/index.js +559 -18
- package/lib/uitree.js +4 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -87,6 +87,11 @@ drawer:
|
|
|
87
87
|
- `device_apps` / `device_launch_app` — list installed packages (third-party by
|
|
88
88
|
default) so a package name is never guessed / launch one by package or a
|
|
89
89
|
unique substring, with `relaunch` for a cold start.
|
|
90
|
+
- `device_intent` — open anything by Android intent: an `action` (e.g.
|
|
91
|
+
`android.settings.WIFI_SETTINGS`), a deep-link `uri` (`geo:`, `https://`,
|
|
92
|
+
`file://`), or an explicit `component` (`pkg/.Activity`). Reaches screens no
|
|
93
|
+
tap can address. Values are single-quoted for the device shell (apostrophes
|
|
94
|
+
escaped, control characters refused), so metacharacters stay inert.
|
|
90
95
|
- `device_stream` — drive the live screen stream the panel shows: `start` an
|
|
91
96
|
online device (returns a signed `streamUrl`), `status`, or `stop`. Agents that
|
|
92
97
|
just need to see the screen should prefer `device_screen` / `device_ui_tree`.
|
|
@@ -133,6 +138,34 @@ the plain JSON summary (path + UI tree + OCR) with no new error.
|
|
|
133
138
|
emulator binary, and what the plugin currently runs (preview servers, Metro,
|
|
134
139
|
builds per directory).
|
|
135
140
|
|
|
141
|
+
**Device-ultimate port (v0.6.0)** — tools ported from
|
|
142
|
+
[dsh-adb-ultimate](https://github.com/newborne/dsh-adb-ultimate), rebuilt on the
|
|
143
|
+
classified adb boundary (argv-based, quoted, replay-safe):
|
|
144
|
+
|
|
145
|
+
- `device_scroll_to` — scroll until an element (`resource_id` or `text`/
|
|
146
|
+
content-desc, exact then substring) comes into view, then report it with its
|
|
147
|
+
center tap point. Completes the control loop for long lists: `device_wait_for`
|
|
148
|
+
waits without scrolling, this brings the element on-screen so a follow-up
|
|
149
|
+
`device_tap_element` can hit it. Defaults to 8 swipes, swipe direction
|
|
150
|
+
`up`/`left`.
|
|
151
|
+
- `device_connect` — attach a Wi-Fi device: `adb connect <host>:<port>`
|
|
152
|
+
(default port 5555); pass `pairing_code` + `pairing_port` (default 37000) for
|
|
153
|
+
the first-time Android 11+ "Pair device" flow. Reattaching a known device
|
|
154
|
+
needs no code.
|
|
155
|
+
- `device_pair_qr` — the full pairing journey in one call: generates a
|
|
156
|
+
`WIFI:T:ADB;S:...;P:...;;` QR string (render it with any QR generator and scan
|
|
157
|
+
with Settings → Connected devices → Pair by QR), polls `adb mdns services`
|
|
158
|
+
(adb ≥ 31) for `_adb-tls-pairing._tcp`, then auto-pairs and connects.
|
|
159
|
+
- `device_perf` — one-shot RAM / battery / CPU snapshot (meminfo +
|
|
160
|
+
`dumpsys battery` + cpuinfo → used %, level/temp/status/health, cores).
|
|
161
|
+
- `device_app_info` — per-app detail from `dumpsys package`: versionName/
|
|
162
|
+
versionCode, minSdk/targetSdk, requested permissions, exported activities.
|
|
163
|
+
- `device_install` / `device_uninstall` — sideload a local APK
|
|
164
|
+
(`-r -g`: replace + grant runtime permissions) / remove an app (optionally
|
|
165
|
+
`-k` keep data). Uninstall is destructive.
|
|
166
|
+
- `device_reboot` — reboot into `normal` / `recovery` / `bootloader`
|
|
167
|
+
(the device drops offline and comes back in a minute or two).
|
|
168
|
+
|
|
136
169
|
**First-run experience & settings**
|
|
137
170
|
|
|
138
171
|
- On first start after installation, a **welcome window** explains how to use the
|
|
@@ -148,6 +181,13 @@ the plain JSON summary (path + UI tree + OCR) with no new error.
|
|
|
148
181
|
Fix button for auto-fixable checks (PaddleOCR install).
|
|
149
182
|
- **PaddleOCR** — install status, progress log, and the install button.
|
|
150
183
|
- **AI Prompt** — the copyable agent prompt.
|
|
184
|
+
- **Connection** — the resolved adb binary path and every device `adb` sees
|
|
185
|
+
(serial, state dot, model, USB / Wi-Fi badge), straight from
|
|
186
|
+
`GET /connection`. A **connect form** (device IP + port, optional pairing
|
|
187
|
+
code + pair port → `POST /connect`) and a **Pair by QR** button
|
|
188
|
+
(`POST /pair-qr`, one blocking call that generates the `WIFI:T:ADB` QR,
|
|
189
|
+
waits for the mDNS scan and auto-pairs + connects) plus an in-line refresh.
|
|
190
|
+
Explains the Wi-Fi reconnect policy.
|
|
151
191
|
- The same settings appear as a **`MobileCode` page in the DSH Settings**
|
|
152
192
|
(registered as a `settings.section` slot, like the other installed plugins),
|
|
153
193
|
so they are reachable from Settings even when the Devices pane is closed.
|
|
@@ -159,7 +199,23 @@ the plain JSON summary (path + UI tree + OCR) with no new error.
|
|
|
159
199
|
`directory` + `platform` body, mirroring mobilecode's `server.devicePreview`
|
|
160
200
|
group — plus setup endpoints: `GET /welcome`, `POST /welcome/dismiss`,
|
|
161
201
|
`GET /doctor`, `POST /doctor/fix {id}`, `GET /ocr`, `POST /ocr/install`,
|
|
162
|
-
`GET/POST /settings
|
|
202
|
+
`GET/POST /settings`, `GET /connection` — plus the Wi-Fi actions
|
|
203
|
+
`POST /connect` (host/port/pairing code) and `POST /pair-qr` (mDNS QR flow).
|
|
204
|
+
|
|
205
|
+
**One classified adb boundary** — every serial-targeted adb command runs through
|
|
206
|
+
`adbRun()` in `lib/device-build.js`:
|
|
207
|
+
|
|
208
|
+
- A transport failure (`device not found` / `offline` / `unauthorized` /
|
|
209
|
+
`closed` / `no devices`) on a **Wi-Fi serial** (`ip:port`) gets exactly ONE
|
|
210
|
+
`adb connect` retry. Read-only commands (the `replaySafeAdb` allowlist:
|
|
211
|
+
`exec-out`/`screencap`/`uiautomator`/`dumpsys`/`getprop`/`logcat`/`cat`/…)
|
|
212
|
+
then replay automatically; **side-effectful ones never do** — a replayed tap
|
|
213
|
+
could double-tap — they raise "reconnected — call again" instead.
|
|
214
|
+
- USB serials and non-transport failures (a real `am start` error, a
|
|
215
|
+
`SecurityException`) surface as classified, actionable errors — the old
|
|
216
|
+
silent `capture()` → `""` swallowing is gone on agent-facing paths.
|
|
217
|
+
- Tolerant internal callers (boot polling, IME checks) opt back into
|
|
218
|
+
best-effort with an explicit `.catch(() => "")`.
|
|
163
219
|
|
|
164
220
|
## How it works
|
|
165
221
|
|
package/lib/android-stream.js
CHANGED
|
@@ -247,7 +247,7 @@ export class AndroidStreamHost {
|
|
|
247
247
|
|
|
248
248
|
async getRotation(serial) {
|
|
249
249
|
try {
|
|
250
|
-
const value = Number((await DeviceBuild.
|
|
250
|
+
const value = Number((await DeviceBuild.adbRun(serial, ['shell', 'settings', 'get', 'system', 'user_rotation'])).trim())
|
|
251
251
|
return ROTATION_CYCLE.includes(value) ? value : 0
|
|
252
252
|
} catch {
|
|
253
253
|
return 0
|
|
@@ -263,8 +263,7 @@ export class AndroidStreamHost {
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
async #shell(serial, shell) {
|
|
266
|
-
|
|
267
|
-
if (code !== 0) throw new Error(`adb shell ${shell.join(' ')} failed (exit ${code})`)
|
|
266
|
+
await DeviceBuild.adbRun(serial, ['shell', ...shell], { timeoutMs: CONTROL_TIMEOUT_MS })
|
|
268
267
|
}
|
|
269
268
|
|
|
270
269
|
async #keepAliveTick() {
|
|
@@ -371,7 +370,7 @@ export class AndroidStreamHost {
|
|
|
371
370
|
|
|
372
371
|
/** Override-aware physical screen size for the non-streaming control fallback. */
|
|
373
372
|
async function screenSize(serial) {
|
|
374
|
-
const output = await DeviceBuild.
|
|
373
|
+
const output = await DeviceBuild.adbRun(serial, ['shell', 'wm', 'size'])
|
|
375
374
|
const match = /Override size:\s*(\d+)x(\d+)/.exec(output) ?? /Physical size:\s*(\d+)x(\d+)/.exec(output)
|
|
376
375
|
if (!match) throw new Error(`cannot read the screen size of ${serial}`)
|
|
377
376
|
return { width: Number(match[1]), height: Number(match[2]) }
|