dsh-apk-vm 0.0.0-stage → 0.3.13

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 ADDED
@@ -0,0 +1,345 @@
1
+ # Changelog
2
+
3
+ ## 0.3.13
4
+
5
+ Open-source package identity.
6
+
7
+ ### Changed
8
+
9
+ - Package name changed from `@local/dsh-apk-vm` to **`dsh-apk-vm`**, following the DSH plugin
10
+ naming convention (`dsh-*`). The Host export, client bundle id, Cordis patch row, smoke tests
11
+ and docs were updated to match.
12
+ - `author` is now `yuxiaole-bili <https://github.com/yuxiaole-bili/>`.
13
+ - Removed `private: true` and added `publishConfig` for the public npm package
14
+ **`dsh-apk-vm`**; the primary install command is now
15
+ `dsh plugin --profile web add dsh-apk-vm` (source/GitHub install remains a fallback).
16
+ - Wrote the package/plugin descriptions (English + Chinese `meta.description`), expanded
17
+ keywords, and added a suggested GitHub repository description/topics list to
18
+ `docs/RELEASING.md`.
19
+ - Configured repository metadata for
20
+ <https://github.com/yuxiaole-bili/dsh-apk-vm>: `repository`, `homepage`, `bugs`, README
21
+ badges/repository link, issue-template security/repository links, and the local `origin`
22
+ remote.
23
+ - Added the community-market submission package: one-line value, copyable source install
24
+ command, capability category, risk/permissions/compatibility section, real screenshots
25
+ (main panel + right sidebar), and `docs/SUBMISSION.md` with the filled `dsh-plugin.org` issue
26
+ template.
27
+
28
+ ## 0.3.12
29
+
30
+ Clipboard fix + open-source release preparation.
31
+
32
+ ### Fixed
33
+
34
+ - `SET_CLIPBOARD` returned a BigInt sequence that could not be JSON-serialized; it is now a
35
+ decimal string.
36
+ - `GET_CLIPBOARD` now sends the required single `copyKey` payload byte instead of an empty
37
+ message, which previously stalled the control stream and timed out.
38
+ - Live-verified: set `dsh-clipboard-test-42`, then read it back successfully.
39
+
40
+ ### Open-source preparation
41
+
42
+ - Added `CODE_OF_CONDUCT.md`, `.editorconfig` and `docs/RELEASING.md`.
43
+ - Removed personal/local paths from DEMO/DESIGN/spike docs and scripts; removed the stale
44
+ hard-coded DSH WebSocket port fallback from `client.js`.
45
+ - Updated `NOTICE` (only the bundled scrcpy JAR is redistributed; test-only upstream sources are
46
+ not in the repo), `SECURITY.md` supported versions and loopback threat model.
47
+ - Package metadata: author; contributor/security/CoC/docs included in the npm pack file list.
48
+ - README: open-source distribution note, CoC/release links, lifecycle test in the contributor
49
+ quick reference.
50
+ - Added `docs/PRIVACY.md` and `scripts/privacy-scan.mjs`; CI scans the tracked tree for personal
51
+ paths, private IPs, agent instance IDs, credential patterns and emails. The clean single-commit
52
+ `open-source` branch is the recommended public history; the local dev history contains older
53
+ workspace paths.
54
+
55
+ ## 0.3.11
56
+
57
+ Clipboard sync over scrcpy control.
58
+
59
+ ### Added
60
+
61
+ - `buildSetClipboardMessage()` (u8 type=9, u64 sequence, u8 paste, i32 length, UTF-8) and
62
+ `ScrcpySession.setClipboard()` / `requestClipboard()` (`GET_CLIPBOARD`, awaited device reply).
63
+ - `GET/POST /apk-vm/clipboard` plus per-instance `/apk-vm/instances/<id>/clipboard`.
64
+ - Panel debug card: **Copy field to device** / **Get device clipboard** buttons (the latter also
65
+ writes to the host clipboard when permitted).
66
+ - `apk_vm` actions `clipboard_set` / `clipboard_get`.
67
+
68
+ ## 0.3.10
69
+
70
+ Two-finger pinch/zoom over the scrcpy control socket.
71
+
72
+ ### Added
73
+
74
+ - `POST /apk-vm/touch` (and per-instance `/apk-vm/instances/<id>/touch`) forwards multi-pointer
75
+ touch down/move/up/cancel to the active scrcpy session. Coordinates are video-frame pixels.
76
+ - The screen promotes a two-finger gesture from the adb single-pointer path to a scrcpy
77
+ multi-touch pinch, with pointer capture and 60 Hz move throttling.
78
+ - `ScrcpyStream.sendTouch()` / `ExtraVmInstance.sendTouch()` for per-instance control.
79
+
80
+ ## 0.3.9
81
+
82
+ Agent UI automation.
83
+
84
+ ### Added
85
+
86
+ - `apk_vm` actions `find_ui` / `assert_text` / `tap_text`: dump UIAutomator XML, filter nodes by
87
+ text / resource-id / content-desc / class, return matching bounds/centers, assert presence, or
88
+ tap the matching node's center. `assert_text` returns `ok:false` on a missing node instead of
89
+ throwing, so Agents can branch on assertions.
90
+
91
+ ### Verified
92
+
93
+ - Live multi-instance VM: `find_ui {"text":"Phone"}` → `Phone @ 102,1121`;
94
+ `assert_text` found 1 node; `tap_text` opened Phone; `key HOME` returned to the launcher.
95
+
96
+ ## 0.3.8
97
+
98
+ Bootstrap a completely empty Android SDK.
99
+
100
+ ### Added
101
+
102
+ - `bootstrapSdk()`: downloads the official command-line tools ZIP for Windows/macOS/Linux,
103
+ extracts it into `<sdkRoot>/cmdline-tools/latest`, runs `sdkmanager --licenses`, then installs
104
+ platform-tools/emulator/build-tools/platform. HTTPS only, 512 MiB cap, temp archive cleanup,
105
+ JDK pre-check, no shell interpolation.
106
+ - `POST /apk-vm/setup {"action":"bootstrap-sdk"}`, gated by `allowSetupDownloads`;
107
+ Environment card shows **Bootstrap SDK** when sdkmanager is missing.
108
+ - Setup report action list + 2 hermetic bootstrap tests (injected download/extract/exec).
109
+
110
+ ### Verified
111
+
112
+ - `spike/setup-smoke.mjs`: **32/32** (bootstrap argv, extracted sdkmanager, license/install
113
+ calls, invalid-package rejection).
114
+ - Live host: setup actions include `bootstrap-sdk` (unavailable because sdkmanager exists).
115
+
116
+ ## 0.3.7
117
+
118
+ Hardware keyboard forwarding in the H.264/PNG screen.
119
+
120
+ ### Added
121
+
122
+ - Clicking the guest screen focuses it; common hardware keys (arrows, Enter, Escape, Tab,
123
+ Backspace, Delete, Home) become Android key events, and printable characters are forwarded as
124
+ text input. Input fields are excluded so typing in the panel is unaffected.
125
+ - Screen hint documents the keyboard behavior.
126
+
127
+ ## 0.3.6
128
+
129
+ SDK component installation from the Environment card.
130
+
131
+ ### Added
132
+
133
+ - `installSdkPackages({ packages })` in `lib/setup.js`: validated, bounded
134
+ `sdkmanager --install <pkg…>` with optional license stdin.
135
+ - `POST /apk-vm/setup {"action":"install-tools"}` installs missing
136
+ platform-tools/emulator/build-tools/platform (or caller-supplied `packages`), gated by
137
+ `allowSetupDownloads: true`.
138
+ - Environment card exposes the **Install SDK tools** action when adb/emulator are missing.
139
+ - Setup report action list and hermetic setup test updated (30/30).
140
+
141
+ ## 0.3.5
142
+
143
+ Static APK preview.
144
+
145
+ ### Added
146
+
147
+ - `aapt2` badging parser now returns versionName/versionCode, min/target SDK, permissions,
148
+ features, native ABIs and the launcher icon path in addition to package/label/activity.
149
+ - `GET /apk-vm/apk-info?path=…` static metadata (no VM boot).
150
+ - `GET /apk-vm/apk-icon?path=…` extracts a raster launcher icon directly from the APK ZIP with
151
+ a dependency-free ZIP reader (adaptive XML icons are reported but not rasterized).
152
+ - APK list shows icons for raster APKs; `apk_vm` action `apk_info`.
153
+
154
+ ### Verified
155
+
156
+ - `anim60.apk`: targetSdk 34, zero permissions, activity resolved.
157
+ - `DSH-1.12-vc13.apk`: icon extracted as a 631-byte PNG (`89 50 4e 47` signature).
158
+ - `yuagent-final.apk`: versionName 0.4.4, 5 permissions, adaptive XML icon reported.
159
+
160
+ ## 0.3.4
161
+
162
+ Live logcat and crash observability.
163
+
164
+ ### Added
165
+
166
+ - Debug card: **Live logcat** toggle (2 s polling), **Crash log** button (`logcat -b crash`).
167
+ - `AndroidVm.logcat({ buffer })` supports `main|system|crash|events|all|radio|kernel`;
168
+ HTTP routes accept `?buffer=`, and the `apk_vm` tool accepts `buffer`.
169
+ - Verified `npm test` and the client smoke suite with the new debug controls.
170
+
171
+ ## 0.3.3
172
+
173
+ Physical/remote adb device switching.
174
+
175
+ ### Added
176
+
177
+ - `AndroidVm.listDevices()` reports emulator, USB/physical and network adb devices with
178
+ state/model/product/transport metadata.
179
+ - `GET /apk-vm/devices` and `POST /apk-vm/device` (`{"serial":…}` / `{"serial":""}`) attach an
180
+ online device or restore the managed AVD identity; the Environment card has a device picker
181
+ with Attach/Detach.
182
+ - `apk_vm` actions `devices`, `attach_device`, `detach_device`.
183
+ - Stop/dispose never sends `emu kill` or disconnects an external physical device.
184
+
185
+ ### Verified
186
+
187
+ - Attached the running emulator as an external device and detached back to `dsh_apk` while
188
+ retaining `ready`; `/apk-vm/devices` returns serial/state/kind/model.
189
+
190
+ ## 0.3.2
191
+
192
+ Artifact download for screenshots/recordings.
193
+
194
+ ### Added
195
+
196
+ - `GET /apk-vm/artifacts?name=…` streams a plugin-created screenshot/recording from the OS temp
197
+ dir with a strict basename whitelist (no arbitrary paths).
198
+ - The panel's Record action now auto-downloads the MP4 after `screenrecord` completes.
199
+
200
+ ## 0.3.1
201
+
202
+ Loopback-only VM API by default.
203
+
204
+ ### Security
205
+
206
+ - Every `/apk-vm/*` HTTP route and the WebSocket upgrade now reject clients whose TCP peer is
207
+ not loopback unless `allowRemote: true` is explicitly configured. Exposing the DSH Web UI on
208
+ the LAN no longer automatically exposes the rooted debug API.
209
+ - Documented the reverse-proxy/LAN threat model and `allowRemote` opt-in.
210
+
211
+ ## 0.3.0
212
+
213
+ Production lifecycle + management layer.
214
+
215
+ ### Added
216
+
217
+ - **Instance lifecycle:** extra VMs expose `owner` / `lastUsedAt` / `idleMs`; an idle reaper stops
218
+ extras after `instanceIdleMs` (default 15 min) when no panel frames, H.264 clients or Agent
219
+ commands are active. AVDs are kept for quick reuse. New **VM instances** panel card with
220
+ owner/idle and Stop/Destroy actions.
221
+ - **Installed-app management:** panel card lists third-party packages for the active instance and
222
+ exposes force-stop / clear-data / uninstall (backed by the existing rooted debug routes).
223
+ - **Agent high-level input:** `apk_vm` actions `tap`, `swipe`, `long_press`, `key`, `text` with
224
+ device-coordinate validation and the same per-instance routing as shell/debug actions.
225
+ - Hermetic `spike/instances-smoke.mjs` lifecycle test + CI step.
226
+
227
+ ### Verified
228
+
229
+ - `apk_vm key HOME`, `tap 360,1180`, `long_press 360,1180,600ms`, `text "dsh"` all succeeded on the
230
+ default VM via an isolated subagent.
231
+ - `/apk-vm/instances` returns owner/idle metadata; lifecycle unit test passes.
232
+
233
+ ## 0.2.4
234
+
235
+ Fix H.264 input coordinate mapping.
236
+
237
+ ### Fixed
238
+
239
+ - H.264 frames are downscaled (540×960) but `input tap` expects the guest display
240
+ coordinate space (720×1280). The client previously sent video coordinates directly, so a tap
241
+ at YuAgent (device ~446,1014 → video ~334,760) landed in the Phone icon. Input mapping now
242
+ always uses `wm size` (swapped when rotated) while video dimensions only control the canvas
243
+ aspect.
244
+ - Clicking icons in the H.264 view now hits the intended app.
245
+
246
+ ## 0.2.3
247
+
248
+ Fix H.264 WebSocket target in the DSH desktop shell.
249
+
250
+ ### Fixed
251
+
252
+ - The desktop shell can load the panel from a custom scheme where `location.host` is empty or
253
+ meaningless; the client previously fell back to a hard-coded stale localhost port, so the
254
+ H.264 WebSocket never connected and the panel stayed on the 1–2 fps PNG path.
255
+ - `/apk-vm/state` now returns the server's real origin; the client derives `ws://`/`wss://` from
256
+ it. WebSocket close/decoder errors are also included in the client capability report.
257
+ - Header continues to show the active transport (`H.264` vs `PNG`).
258
+
259
+ ## 0.2.2
260
+
261
+ Stream-mode visibility / diagnostics.
262
+
263
+ ### Added
264
+
265
+ - The header frame-rate badge now shows the transport: `FPS 59.0 · H.264` or `FPS 1.5 · PNG`,
266
+ so a low FPS is no longer ambiguous.
267
+ - Client capability report (`POST /apk-vm/client-report`) records the client build, WebCodecs
268
+ availability and `avc1` support in `/apk-vm/state.client`; the panel shows a fallback hint
269
+ when H.264 is unsupported in the current WebView.
270
+
271
+ ## 0.2.1
272
+
273
+ Per-instance H.264 for multi-agent VMs.
274
+
275
+ ### Added
276
+
277
+ - **Every extra instance now has its own H.264/WebCodecs stream** (`lib/video-stream.js`,
278
+ `ScrcpyStream`): independent scrcpy server, free local port, init/AVCC/keyframe handling,
279
+ rotation re-init and idle stop. Extra instances are created with a 720×1280 display
280
+ (instead of the pixel_5 1080×2340 profile) so several GPU encoders stay stable.
281
+ - Extra instance WebSocket endpoint: `/apk-vm/instances/<id>/ws`; panel instance selector now
282
+ shows H.264 canvas for extras too, with PNG fallback.
283
+
284
+ ### Fixed
285
+
286
+ - Earlier 0.2.0 extra instances used PNG preview; larger AVD resolutions could stall the
287
+ emulator GPU when combined with a second scrcpy encoder. 720×1280 + per-instance stream is
288
+ stable.
289
+
290
+ ### Verified
291
+
292
+ - Extra instance (emulator-5560, 720×1280): H.264 init `540×960`, **412 packets/10 s** with the
293
+ 60Hz animation app; extra frame PNG and default VM remained responsive; destroy returns to
294
+ default only.
295
+
296
+ ## 0.2.0
297
+
298
+ Multi-agent / multi-instance support.
299
+
300
+ ### Added
301
+
302
+ - **Multiple concurrent VMs.** `InstanceManager` (`lib/instances.js`) creates isolated instances
303
+ with their own AVD, emulator console port, snapshot and AndroidVm state. The first Agent gets
304
+ the default VM; later Agents are assigned isolated instances automatically (up to
305
+ `maxInstances`, default 3 extra).
306
+ - HTTP instance API: `GET/POST /apk-vm/instances`, `DELETE /apk-vm/instances/:id`, and a
307
+ per-instance namespace `/apk-vm/instances/:id/{state,frame,vm,input,install,upload,debug/*}`.
308
+ - Panel instance selector + **New VM / Destroy VM** actions; extra instances use PNG preview
309
+ (H.264 remains on the default VM).
310
+ - `apk_vm` Agent tool: `instance` parameter, per-Agent assignment, and
311
+ `list_instances` / `create_instance` / `destroy_instance` / `start` / `stop` actions.
312
+ - `multiInstance` + `maxInstances` config; release version 0.2.0.
313
+
314
+ ### Verified
315
+
316
+ - Two VMs run concurrently: default `emulator-5558` and extra `emulator-5560`
317
+ (`dsh_apk_test1`), both ready/root, extra frame PNG and root shell verified while default
318
+ remained ready. Extra instance cold boot ~27.5 s, later quick boot from its own snapshot.
319
+
320
+ ## 0.1.0
321
+
322
+ First open-source release.
323
+
324
+ ### Added
325
+
326
+ - Sidebar `apk-vm` entry + main panel, optional `dsh-better-sidebar` tab.
327
+ - AOSP Android Emulator lifecycle with quick-boot snapshot, host GPU, hypervisor detection.
328
+ - H.264/WebCodecs stream up to 60 fps over `/apk-vm/ws`; PNG screencap fallback.
329
+ - Rooted guest debug surface: auto `adb root`, on-device toolkit, `/apk-vm/debug/*` HTTP API,
330
+ `apk_vm` Agent tool (shell/logcat/props/packages/install/push/pull/reboot/root/rotate/
331
+ ui_dump/record/perf/screenshot/actions).
332
+ - One-glance Environment card + `/apk-vm/setup`: cross-platform SDK/adb/emulator/system image/
333
+ AVD/acceleration detection, AVD creation, opt-in system-image download.
334
+ - APK upload by button or drag-and-drop (`/apk-vm/upload`, 500 MiB limit, ZIP magic check).
335
+ - Multi-AVD list/switch (`/apk-vm/avds`, `/apk-vm/avd`).
336
+ - Same-origin guard for HTTP routes and WebSocket upgrades; bounded bodies/outputs; argv-only
337
+ child processes.
338
+ - Apache-2.0 LICENSE/NOTICE, CONTRIBUTING, SECURITY, GitHub Actions CI, issue/PR templates,
339
+ README/demo script.
340
+
341
+ ### Known limitations
342
+
343
+ - Windows x64 is the only end-to-end verified host; macOS/Linux discovery is tested hermetically.
344
+ - Static screens naturally show a low FPS (encoder emits on change); audio and physical-device
345
+ switching are roadmap items.
@@ -0,0 +1,130 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported privately to the project maintainers through the repository's
63
+ **Security → Report a vulnerability** channel, or by contacting a maintainer
64
+ through the repository's listed contact channel. All complaints will be reviewed
65
+ and investigated promptly and fairly.
66
+
67
+ All community leaders are obligated to respect the privacy and security of the
68
+ reporter of any incident.
69
+
70
+ ## Enforcement Guidelines
71
+
72
+ Community leaders will follow these Community Impact Guidelines in determining
73
+ the consequences for any action they deem in violation of this Code of Conduct:
74
+
75
+ ### 1. Correction
76
+
77
+ **Community Impact**: Use of inappropriate language or other behavior deemed
78
+ unprofessional or unwelcome in the community.
79
+
80
+ **Consequence**: A private, written warning from community leaders, providing
81
+ clarity around the nature of the violation and an explanation of why the
82
+ behavior was inappropriate. A public apology may be requested.
83
+
84
+ ### 2. Warning
85
+
86
+ **Community Impact**: A violation through a single incident or series of
87
+ actions.
88
+
89
+ **Consequence**: A warning with consequences for continued behavior. No
90
+ interaction with the people involved, including unsolicited interaction with
91
+ those enforcing the Code of Conduct, for a specified period of time. This
92
+ includes avoiding interactions in community spaces as well as external channels
93
+ like social media. Violating these terms may lead to a temporary or permanent
94
+ ban.
95
+
96
+ ### 3. Temporary Ban
97
+
98
+ **Community Impact**: A serious violation of community standards, including
99
+ sustained inappropriate behavior.
100
+
101
+ **Consequence**: A temporary ban from any sort of interaction or public
102
+ communication with the community for a specified period of time. No public or
103
+ private interaction with the people involved, including unsolicited interaction
104
+ with those enforcing the Code of Conduct, is allowed during this period.
105
+ Violating these terms may lead to a permanent ban.
106
+
107
+ ### 4. Permanent Ban
108
+
109
+ **Community Impact**: Demonstrating a pattern of violation of community
110
+ standards, including sustained inappropriate behavior, harassment of an
111
+ individual, or aggression toward or disparagement of classes of individuals.
112
+
113
+ **Consequence**: A permanent ban from any sort of public interaction within the
114
+ community.
115
+
116
+ ## Attribution
117
+
118
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
119
+ version 2.1, available at
120
+ https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
121
+
122
+ Community Impact Guidelines were inspired by
123
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
124
+
125
+ For answers to common questions about this code of conduct, see the FAQ at
126
+ https://www.contributor-covenant.org/faq. Translations are available at
127
+ https://www.contributor-covenant.org/translations.
128
+
129
+ [homepage]: https://www.contributor-covenant.org
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
@@ -0,0 +1,177 @@
1
+ # Contributing to dsh-apk-vm
2
+
3
+ Thanks for improving the APK Virtual Machine plugin. This document covers the repository
4
+ layout, the development workflow, the checks a change must pass, and the conventions this
5
+ project follows.
6
+
7
+ By participating you agree to keep discussion respectful and to license your contributions
8
+ under the repository's [Apache-2.0](LICENSE) terms.
9
+
10
+ - Bugs / feature requests: use the [issue templates](.github/ISSUE_TEMPLATE/).
11
+ - Community behavior: follow [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
12
+ - Security issues: **do not** open a public issue — follow [SECURITY.md](SECURITY.md).
13
+ - Larger design changes: open an issue first; the architecture notes live in
14
+ [DESIGN.md](DESIGN.md).
15
+
16
+ ---
17
+
18
+ ## Repository layout
19
+
20
+ | Path | What it is |
21
+ | --- | --- |
22
+ | [index.js](index.js) | Host half (`apply(ctx, config)`): HTTP routes, WebSocket relay, rooted debug API, `apk_vm` Agent tool. |
23
+ | [client.js](client.js) | Client half: a pre-built browser bundle exposing the sidebar entry, main panel, better-sidebar tab, environment card, APK upload/drop and WebCodecs canvas. |
24
+ | [lib/android.js](lib/android.js) | `AndroidVm`: AVD lifecycle, adb commands, APK discovery/install, screenshots, input, rooted debug helpers and the extra device actions (rotate / UI dump / record / perf). |
25
+ | [lib/scrcpy.js](lib/scrcpy.js) | `ScrcpySession`: pushes the vendored scrcpy server, H.264 demux, Annex-B→AVCC, control messages. |
26
+ | [lib/setup.js](lib/setup.js) | Dependency-free environment detection (SDK, adb, emulator, command-line tools, system image, AVD, acceleration) plus `createAvd()` / `installSystemImage()`. |
27
+ | [lib/ws.js](lib/ws.js) | Dependency-free RFC 6455 WebSocket server used by `/apk-vm/ws`. |
28
+ | [lib/vendor/scrcpy-server-v5.0.1.jar](lib/vendor/scrcpy-server-v5.0.1.jar) | Vendored scrcpy 5.0.1 server JAR (Apache-2.0, unmodified — see [NOTICE](NOTICE)). |
29
+ | [cordis.patch.yml](cordis.patch.yml) | Bundle patch that inserts the plugin row and its default config. |
30
+ | [locale/](locale) | `en.json` / `zh.json` display metadata (`meta.title`, `meta.description`). |
31
+ | [spike/](spike) | Test harnesses and protocol notes. Not loaded by the plugin at runtime. |
32
+ | [DESIGN.md](DESIGN.md) | Design rationale, architecture, verified measurements and evolution notes (Chinese). |
33
+
34
+ There is **no build step and no npm dependency graph**: `index.js` and `lib/**` import Node
35
+ built-ins only, and `client.js` is plain JavaScript evaluated by the DSH Web module loader.
36
+ Do not introduce a bundler or npm packages for the Host half; keep `client.js` dependency-free
37
+ apart from the `react` provided by the DSH client runtime.
38
+
39
+ ---
40
+
41
+ ## Development environment
42
+
43
+ - **Node.js 24+** for running the checks (`node --check`, spike suites) — matches CI.
44
+ - A **Windows host** for end-to-end work: Android SDK (`platform-tools`, `emulator`,
45
+ `build-tools`), one AOSP system image (the reference image is
46
+ `system-images;android-34;default;x86_64`), hardware acceleration (AEHD/WHPX on Windows) and
47
+ an AVD created for the plugin. The panel's **Environment** card reports what is missing.
48
+ - **No `npm install` is required.** If you add files that should ship, update `files` in
49
+ [package.json](package.json) — do not add runtime dependencies.
50
+
51
+ A quick manual smoke test on a development machine:
52
+
53
+ ```bash
54
+ # 1. install this folder as a local bundle in DSH (Plugins UI or plugin_manager tool)
55
+ # 2. reload the DSH Web UI
56
+ # 3. open the APK Virtual Machine sidebar entry and check the Environment card
57
+ # 4. start the VM, install an APK (upload or path), interact, exercise the Rooted debug card
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Testing
63
+
64
+ ### Headless suites (run in CI, no emulator needed)
65
+
66
+ ```bash
67
+ node --check index.js
68
+ node --check client.js
69
+ for f in lib/*.js; do node --check "$f"; done
70
+
71
+ node spike/ui-smoke.cjs # 136 sandbox assertions on the real client bundle
72
+ node spike/ui-better-sidebar-smoke.cjs # optional better-sidebar integration
73
+ node spike/setup-smoke.mjs # 30 hermetic environment/setup checks (no SDK needed)
74
+ node spike/android/mock-device.mjs # device critical path against a mock adb (24 checks)
75
+ node spike/android/launch-plan.mjs # fast-boot argv plan assertions
76
+ ```
77
+
78
+ `spike/android/mock-device.mjs` parses a real APK with `aapt2`, so it needs Android SDK
79
+ build-tools (`ANDROID_HOME` / `ANDROID_SDK_ROOT` or an SDK found on the host). The CI workflow
80
+ uses the Android SDK preinstalled on GitHub's `ubuntu-latest` runner. `spike/setup-smoke.mjs` is
81
+ fully hermetic: it mocks OS layouts and the `exec` boundary, so it needs neither an SDK nor an
82
+ emulator and runs on any OS.
83
+
84
+ The Host HTTP/WebSocket surface (`/apk-vm/*`, including `/apk-vm/upload` and `/apk-vm/setup`)
85
+ is exercised in parts by the client sandbox (request shape) and the setup suite; end-to-end
86
+ route-level tests belong to the Windows-local integration pass. When changing routes, keep the
87
+ same-origin guard, body bounds and lifecycle cleanup intact.
88
+
89
+ A few more harnesses are useful but not part of CI:
90
+
91
+ ```bash
92
+ node spike/scrcpy/test-fake-device.js # 160 assertions against a fake scrcpy-server
93
+ node spike/android/smoke.mjs # device methods with an injected empty adb
94
+ ```
95
+
96
+ Running `spike/scrcpy/test-fake-device.js` regenerates
97
+ `spike/scrcpy/capture-fake.h264` and `spike/scrcpy/report.json`; treat those as generated
98
+ artifacts, not hand-edited sources.
99
+
100
+ ### Emulator integration tests are Windows-local only
101
+
102
+ The end-to-end paths (real emulator boot, snapshot save/restore, actual H.264 stream, rooted
103
+ debug actions, APK upload) require hardware virtualization and an AVD. GitHub-hosted runners do
104
+ not provide nested virtualization, so these tests are **not** part of hosted CI. When a change
105
+ touches VM lifecycle, boot plans, streaming, upload or the rooted debug surface, run the
106
+ relevant scenario on a Windows host and state in the PR what you ran and what you observed
107
+ (boot kind/time, FPS, logs).
108
+
109
+ Do not report unmeasured numbers as results. If a benchmark could not be reproduced, say so
110
+ instead of copying a figure from an earlier run.
111
+
112
+ ### UI changes
113
+
114
+ - `client.js` is loaded via `window.__ModuleLoader__.load(...)` and may only require `react`;
115
+ keep it a single self-contained browser file.
116
+ - Style with `--dsw-alias-*` theme tokens (no hard-coded panel/button colors); content inside the
117
+ phone frame (the simulated Android screen) is the intended exception.
118
+ - Add strings to both `en` and `zh` maps in `client.js`; keep locale files for metadata in sync.
119
+ - The DSH Web GUI is authenticated. The headless verification flow used for decoding tests may
120
+ not be able to load the panel itself, so validate UI behavior with `spike/ui-smoke.cjs`
121
+ (which renders the real component tree in a sandbox) and, when possible, a signed-in manual
122
+ pass. Never commit screenshots or numbers that were not actually captured.
123
+
124
+ ---
125
+
126
+ ## Coding conventions
127
+
128
+ - **Never build shell command strings for host processes.** Spawn `adb`/`emulator`/`sdkmanager`/
129
+ `avdmanager` with `child_process.spawn(exe, argv)` and pass user data as argv entries.
130
+ - **Bound everything.** Request bodies, APK uploads, stdout/stderr, log lines, APK scan
131
+ depth/results and screenshots already have limits; keep new code within them.
132
+ - **Fail visibly.** Return structured `{ ok: false, error }` (or throw inside route handlers,
133
+ which the shared wrapper converts) and surface problems in the panel/log tail instead of
134
+ swallowing them.
135
+ - **Same-origin only.** All HTTP/WebSocket routes live behind the DSH Web server and keep the
136
+ `isSameOrigin` check; do not bind additional listeners.
137
+ - **Clean up.** Register routes/timers/tools inside `ctx.effect(...)` and return disposers;
138
+ stopping/restarting/unloading must stop the emulator, the scrcpy session, WebSocket clients
139
+ and the upload temp directory.
140
+ - **Bounded surface.** Keep the scrcpy session shared across clients and stop it when the last
141
+ client disconnects (the VM keeps running).
142
+ - **Verified claims only.** README/verification tables must match what was measured on a named
143
+ host. Mark unshipped features under *Roadmap* — never as available.
144
+
145
+ ---
146
+
147
+ ## Commit and pull requests
148
+
149
+ - Keep PRs focused; a bug fix or a feature plus its docs/tests is the right size.
150
+ - Write commit messages that explain the *why*; reference issues when applicable.
151
+ - Fill out [.github/PULL_REQUEST_TEMPLATE.md](.github/PULL_REQUEST_TEMPLATE.md), including the
152
+ checks you ran and any platform-specific verification.
153
+ - Do not commit build outputs, `node_modules`, emulator logs, recordings, API keys, or paths
154
+ from your machine that are not needed for the feature.
155
+ - If you change configuration keys, routes, or the `apk_vm` tool schema, update
156
+ [README.md](README.md) (Configuration / HTTP control plane / tool sections) in the same PR.
157
+ - If you add a new file that must ship with the package, update `files` in `package.json`.
158
+
159
+ ---
160
+
161
+ ## Release hygiene (maintainers)
162
+
163
+ 1. Run the headless suites above (they mirror CI).
164
+ 2. Run the Windows-local emulator scenarios for anything touching boot/stream/upload/debug.
165
+ 3. Re-read the README "Verification" and "Performance" tables; delete or update anything that no
166
+ longer holds, and never fill in a number that was not measured on the stated host.
167
+ 4. Confirm [NOTICE](NOTICE) still matches the vendored third-party content.
168
+ 5. Confirm the demo placeholders in README are either replaced by real assets or still clearly
169
+ marked as not recorded.
170
+
171
+ ---
172
+
173
+ ## License
174
+
175
+ By contributing you agree that your contributions are licensed under the Apache License,
176
+ Version 2.0, and that you have the right to submit them. See [LICENSE](LICENSE) and
177
+ [NOTICE](NOTICE) for the project license and third-party attribution.