verikun 0.21.1 → 0.23.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/.claude/skills/verikun/SKILL.md +35 -8
- package/CHANGELOG.md +68 -16
- package/README.md +13 -3
- package/dist/agent/remote.js +44 -0
- package/dist/args.js +5 -0
- package/dist/cli.js +431 -32
- package/dist/companion/dump-match.js +100 -0
- package/dist/companion/manager.js +7 -2
- package/dist/companion/protocol.js +10 -4
- package/dist/device/claims.js +594 -0
- package/dist/drivers/adb.js +303 -32
- package/dist/drivers/index.js +4 -1
- package/dist/drivers/ios.js +162 -32
- package/dist/drivers/lifecycle.js +188 -0
- package/dist/errors.js +2 -2
- package/dist/exec.js +48 -0
- package/dist/run.js +10 -0
- package/dist/server.js +310 -18
- package/dist/version.js +1 -1
- package/dist/wait.js +61 -0
- package/package.json +4 -1
- package/tools/verikun-companion/prebuilt/verikun-companion.jar +0 -0
|
@@ -17,7 +17,9 @@ description: >-
|
|
|
17
17
|
directory of natural-language tests as a gated suite with `vk suite <dir>`
|
|
18
18
|
(overview report + non-zero exit on failure — the CI gate). A remote device is
|
|
19
19
|
reachable via `--server <url>` (ai/suite/install) against a `vk server` running
|
|
20
|
-
next to it.
|
|
20
|
+
next to it. If no device is available, or one has gone flaky, start or restart it
|
|
21
|
+
with `vk devices start|stop|restart <name>` (`vk devices --all` lists what is
|
|
22
|
+
startable). iOS (--ios): full parity via idb (tap/type/swipe/`ui` +
|
|
21
23
|
screenshot/launch/stop), on simulators and devices; install idb and see
|
|
22
24
|
`vk doctor --ios`.
|
|
23
25
|
---
|
|
@@ -427,9 +429,29 @@ vk suite tests/ --app com.example.app --server "$VERIKUN_SERVER"
|
|
|
427
429
|
```
|
|
428
430
|
|
|
429
431
|
A wrong URL/key fails fast with exit 3; `409` means another run holds the
|
|
430
|
-
device
|
|
432
|
+
device; `503` means the server has no device attached — boot one (below). To
|
|
433
|
+
expose a device from THIS machine: `vk server --allow-install`
|
|
431
434
|
(add `--bind <addr>` to leave loopback; auth key auto-generates if unset).
|
|
432
435
|
|
|
436
|
+
## The device is missing or wedged
|
|
437
|
+
|
|
438
|
+
```sh
|
|
439
|
+
vk devices --all # what's attached AND what could be started
|
|
440
|
+
vk devices start Pixel_6_API_34 # boot it; prints the serial when drivable
|
|
441
|
+
vk devices restart Pixel_6_API_34 # a live device gone flaky
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Exit codes tell you whether to retry: **1** = unknown name, or the boot timed out
|
|
445
|
+
(the device is still starting — retrying often works, and it is left running).
|
|
446
|
+
**2** = ambiguous name (simulator names repeat across iOS runtimes — pass the UDID
|
|
447
|
+
from `vk devices --all`), or the target is a physical device (never power-cycled).
|
|
448
|
+
**3** = the toolchain is missing (set `VERIKUN_EMULATOR` to the SDK's `emulator`
|
|
449
|
+
binary) — retrying will not help.
|
|
450
|
+
|
|
451
|
+
`start` is idempotent, so it is safe to call when unsure. Add `--ensure-device` to
|
|
452
|
+
`vk ai` / `vk suite` / `vk install` to boot once before the first step instead. Both
|
|
453
|
+
work against a remote server (`--server <url>`) when it runs `--allow-device-control`.
|
|
454
|
+
|
|
433
455
|
## Test runs & reports
|
|
434
456
|
|
|
435
457
|
Every action is **recorded into a test run** — one auto-starts on your first
|
|
@@ -471,18 +493,18 @@ identifier memory described above. Set `VERIKUN_NO_RUN=1` to disable recording.
|
|
|
471
493
|
When **verikun itself** — not the app, not your selector — is the friction (a model heal on
|
|
472
494
|
a *cached* replay: `[ai] plan cache hit` + a repair, or `"cached": true` with
|
|
473
495
|
`modelRepairs > 0` in `--json`; a `drifted, not repaired` give-up; or a recurring gotcha in
|
|
474
|
-
vk's own operation), use the **`suggest-verikun-improvement`** skill. It
|
|
496
|
+
vk's own operation), use the **`suggest-verikun-improvement`** skill. It writes a light,
|
|
475
497
|
TL;DR-first suggestion — **redacted** of every app-under-test specific (package, on-screen
|
|
476
|
-
text, selector values, test prose, logs) — for you to
|
|
477
|
-
`ddikman/verikun
|
|
478
|
-
|
|
498
|
+
text, selector values, test prose, logs) — to a **local file for you to read and edit**, and
|
|
499
|
+
files nothing to `ddikman/verikun` until you say so. Don't hand-roll the issue: that skill
|
|
500
|
+
owns the redaction and the review-first flow.
|
|
479
501
|
|
|
480
502
|
## Exit codes — rely on these for control flow
|
|
481
503
|
|
|
482
504
|
- `0` success / found / assertion passed
|
|
483
505
|
- `1` not found / assertion failed / wait timeout
|
|
484
506
|
- `2` usage error **or ambiguous selector** (refine it or add `--index N`)
|
|
485
|
-
- `3` environment error (no device, adb/idb missing, hierarchy dump failed) — for
|
|
507
|
+
- `3` environment error (no usable device, adb/idb missing, hierarchy dump failed) — for
|
|
486
508
|
`ai`/`suite`/`install`/`server` the toolchain is verified up front, so this arrives
|
|
487
509
|
immediately with an install hint rather than mid-flow
|
|
488
510
|
|
|
@@ -498,7 +520,12 @@ draft-first flow.
|
|
|
498
520
|
- **`vk device set` from a plain shell stays applied.** Inside `batch`/`ai`/`suite` it is
|
|
499
521
|
restored automatically even if the flow dies, but a one-off `vk device set airplane=on`
|
|
500
522
|
is yours to `vk device reset` — don't strand someone's phone offline.
|
|
501
|
-
- **
|
|
523
|
+
- **The device picks itself, and won't collide with another agent.** With several attached,
|
|
524
|
+
`vk` takes one no other job is driving and notes it on stderr. Exit `2` means every device
|
|
525
|
+
is genuinely busy (the message names each holder) — pass `-d <serial>`, wait, or
|
|
526
|
+
`vk device release <serial>` if that job is gone. `vk devices` shows who holds what.
|
|
527
|
+
Naming a busy device with `-d` is refused, on purpose: two jobs on one phone corrupt both
|
|
528
|
+
runs, and it surfaces as a bogus assertion failure. `VERIKUN_NO_CLAIM=1` opts out entirely.
|
|
502
529
|
- **`vk text` opens the keyboard.** Use `--enter` to submit, or `vk back` to
|
|
503
530
|
dismiss it before re-inspecting (it can cover elements).
|
|
504
531
|
- **Unicode/emoji** may not type via `adb input text` (an Android limitation);
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,74 @@ All notable changes to this project are documented here. The format is based on
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.23.0] - 2026-08-17
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **`npm run docs` / `docs:install` / `docs:build`**: run the documentation site from the repo
|
|
13
|
+
root; README covers the local setup.
|
|
14
|
+
- **`vk devices start|stop|restart <name>`**: boot, shut down or power-cycle an Android AVD or iOS
|
|
15
|
+
simulator. `start` is idempotent and waits until the device is actually drivable.
|
|
16
|
+
- **`vk devices --all`**: also lists startable (not-yet-booted) AVDs and simulators.
|
|
17
|
+
- **`vk devices start|restart --wipe`**: erase the device's data first (`-wipe-data` / `simctl erase`).
|
|
18
|
+
- **`vk server --allow-device-control[=names]`**: let a client restart/stop the server's device;
|
|
19
|
+
`=names` also permits starting those targets. The server may then listen with no device bound.
|
|
20
|
+
- **`--ensure-device[=name]`** on `ai`/`suite`/`install`: boot a device once before the first step.
|
|
21
|
+
- **`VERIKUN_EMULATOR`**: path to the SDK `emulator` binary when it is not on `PATH`.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- **`vk devices`**: gains `KIND` and `NAME` columns, so an emulator shows the AVD name you pass to
|
|
25
|
+
`stop`/`restart`.
|
|
26
|
+
- **`/v1/health`**: `serial` may now be `null`; adds `deviceControlEnabled`, `deviceNamingEnabled`
|
|
27
|
+
and `deviceState` for feature detection.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- **`vk devices start --server`**: releases the device lock when it finishes, instead of `409`ing
|
|
31
|
+
the run it just booted the device for.
|
|
32
|
+
|
|
33
|
+
## [0.22.2] - 2026-08-17
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
- **`suggest-verikun-improvement`**: the draft is written to `.context/` for review; nothing is
|
|
37
|
+
filed until you say so. ([#66])
|
|
38
|
+
- **Improvement reports**: `Shape of the fix` becomes a short `Proposed fix` — a few bullets,
|
|
39
|
+
not a spec. ([#66])
|
|
40
|
+
|
|
41
|
+
[#66]: https://github.com/ddikman/verikun/issues/66
|
|
42
|
+
|
|
43
|
+
## [0.22.1] - 2026-08-15
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
- **The Flutter fixture raises a real system permission dialog** (`@vk_permission`, Android
|
|
47
|
+
only), so [#79] reproduces on demand.
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
- **Hierarchy reads now see a window another app opens on top** — a runtime-permission dialog is
|
|
51
|
+
no longer invisible to the companion. ([#79])
|
|
52
|
+
|
|
53
|
+
[#79]: https://github.com/ddikman/verikun/issues/79
|
|
54
|
+
|
|
55
|
+
## [0.22.0] - 2026-08-15
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
- **Device claims**: `vk` now picks a device no other job is driving; a busy one is refused
|
|
59
|
+
with exit `2`. Writes `~/.verikun/devices/`; `VERIKUN_NO_CLAIM=1` opts out. ([#49])
|
|
60
|
+
- **`vk devices`**: a `USED BY` column names the job holding each device; `--json` gains
|
|
61
|
+
`claim`. ([#49])
|
|
62
|
+
- **`vk device release [serial]`**: hands a device back without waiting for its claim to go
|
|
63
|
+
stale. ([#49])
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
- **Several attached devices no longer exits `2`** — a free one is auto-selected. Pass
|
|
67
|
+
`--device` to pin it, as before. ([#49])
|
|
68
|
+
- **Changelog entries are now one line each**, per the new `changelog-entry` skill — root cause,
|
|
69
|
+
benchmarks and rationale move to the PR body and `docs/`.
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
- **Failure evidence**: a step that could not resolve a device printed its error three times;
|
|
73
|
+
capture is now skipped when there is no screen to photograph.
|
|
74
|
+
|
|
75
|
+
[#49]: https://github.com/ddikman/verikun/issues/49
|
|
76
|
+
|
|
9
77
|
## [0.21.1] - 2026-08-13
|
|
10
78
|
|
|
11
79
|
### Fixed
|
|
@@ -403,22 +471,6 @@ All notable changes to this project are documented here. The format is based on
|
|
|
403
471
|
e2e fixture app, 74 files of Gradle/Xcode/PNG that no end user installing the CLI should download.
|
|
404
472
|
- `publish.yml` also verifies `package-lock.json` is in sync with `package.json`'s version. `npm ci`
|
|
405
473
|
does not catch this — it errors only on dependency drift, never on the root `version` field.
|
|
406
|
-
|
|
407
|
-
### Fixed
|
|
408
|
-
- **The Claude Code plugin no longer ships the contributor-only `create-pr` skill.** The manifest
|
|
409
|
-
pointed `skills` at the container `.claude/skills/`, and that field only ever *adds* to the scan,
|
|
410
|
-
so every skill in it reached end users — costing roughly 260 always-on tokens per session for one
|
|
411
|
-
they cannot use. It now lists the two user-facing skills explicitly. Naming a single skill would
|
|
412
|
-
not do: that drops `suggest-verikun-improvement`, which the main skill hands off to.
|
|
413
|
-
|
|
414
|
-
- **`CHANGELOG.md` is now included in the published npm package.** `package.json`'s `"files"` is an
|
|
415
|
-
allowlist, and npm force-includes only `package.json`, `README`, `LICENSE`, the `main` file and the
|
|
416
|
-
`bin` file(s) — a changelog is *not* on that list (npm 5/6 included one; modern npm does not).
|
|
417
|
-
Every release up to 0.19.0 therefore published without a changelog, and did so silently: the
|
|
418
|
-
publish succeeded, CI was green, and nothing anywhere reported the omission.
|
|
419
|
-
`tests/package-files.test.ts` now guards the allowlist, including against an entry whose path no
|
|
420
|
-
longer exists.
|
|
421
|
-
|
|
422
474
|
## [0.19.0] - 2026-08-08
|
|
423
475
|
|
|
424
476
|
### Added
|
package/README.md
CHANGED
|
@@ -62,16 +62,16 @@ There is also no need for an MCP here: verikun runs locally with all its depende
|
|
|
62
62
|
|---|---|
|
|
63
63
|
| **Getting started** | [Installation](https://ddikman.github.io/verikun/getting-started/installation/) · [Your first test](https://ddikman.github.io/verikun/getting-started/your-first-test/) · [Using it from an AI agent](https://ddikman.github.io/verikun/getting-started/using-from-an-agent/) |
|
|
64
64
|
| **Guides** | [Writing test cases](https://ddikman.github.io/verikun/guides/writing-test-cases/) · [Natural-language tests](https://ddikman.github.io/verikun/guides/natural-language-tests/) · [Suites](https://ddikman.github.io/verikun/guides/suites/) · [Remote devices & CI](https://ddikman.github.io/verikun/guides/remote-devices-and-ci/) · [iOS setup](https://ddikman.github.io/verikun/guides/ios-setup/) · [Platform support](https://ddikman.github.io/verikun/guides/platform-support/) · [Troubleshooting](https://ddikman.github.io/verikun/guides/troubleshooting/) |
|
|
65
|
-
| **Reference** | [Commands](https://ddikman.github.io/verikun/reference/commands/) · [Selectors](https://ddikman.github.io/verikun/reference/selectors/) · [Auto-wait](https://ddikman.github.io/verikun/reference/auto-wait/) · [Global flags](https://ddikman.github.io/verikun/reference/global-flags/) · [Exit codes](https://ddikman.github.io/verikun/reference/exit-codes/) · [Environment variables](https://ddikman.github.io/verikun/reference/environment-variables/) · [Reports & test runs](https://ddikman.github.io/verikun/reference/reports-and-test-runs/) · [Device state](https://ddikman.github.io/verikun/reference/device-state/) · [Screenshots](https://ddikman.github.io/verikun/reference/screenshots/) · [AI plans & models](https://ddikman.github.io/verikun/reference/ai-plans/) |
|
|
65
|
+
| **Reference** | [Commands](https://ddikman.github.io/verikun/reference/commands/) · [Selectors](https://ddikman.github.io/verikun/reference/selectors/) · [Auto-wait](https://ddikman.github.io/verikun/reference/auto-wait/) · [Global flags](https://ddikman.github.io/verikun/reference/global-flags/) · [Exit codes](https://ddikman.github.io/verikun/reference/exit-codes/) · [Environment variables](https://ddikman.github.io/verikun/reference/environment-variables/) · [Reports & test runs](https://ddikman.github.io/verikun/reference/reports-and-test-runs/) · [Device state](https://ddikman.github.io/verikun/reference/device-state/) · [Device claims](https://ddikman.github.io/verikun/reference/device-claims/) · [Screenshots](https://ddikman.github.io/verikun/reference/screenshots/) · [AI plans & models](https://ddikman.github.io/verikun/reference/ai-plans/) |
|
|
66
66
|
| **Internals** | [Architecture](https://ddikman.github.io/verikun/internals/architecture/) · [Core principles](https://ddikman.github.io/verikun/internals/core-principles/) · [Plan IR & the replay engine](https://ddikman.github.io/verikun/internals/plan-ir-and-engine/) · [Contracts](https://ddikman.github.io/verikun/internals/contracts/) · [Contributing](https://ddikman.github.io/verikun/internals/contributing/) |
|
|
67
67
|
|
|
68
|
-
**Exit codes**, since they are the machine contract everything else rests on: `0` success · `1` not found / assertion failed / timeout · `2` usage error
|
|
68
|
+
**Exit codes**, since they are the machine contract everything else rests on: `0` success · `1` not found / assertion failed / timeout · `2` usage error, ambiguous selector, or a device another job is driving · `3` environment error. Data goes to stdout; diagnostics to stderr. [Full contract](https://ddikman.github.io/verikun/reference/exit-codes/). Parallel agents share a host-level [device claim](https://ddikman.github.io/verikun/reference/device-claims/) so two jobs do not silently land on the same phone.
|
|
69
69
|
|
|
70
70
|
## Feedback — help improve verikun
|
|
71
71
|
|
|
72
72
|
verikun improves from the rough edges people hit while driving it. When verikun *itself* is the friction — a step that heals on every cached replay (an unstable compiled selector, often a label-only control with no resource-id), a repair "give-up", or a gotcha in its own operation — that's worth an issue at [github.com/ddikman/verikun/issues](https://github.com/ddikman/verikun/issues).
|
|
73
73
|
|
|
74
|
-
Driving verikun with an AI agent + the [skill](.claude/skills/verikun/SKILL.md)? It hands off to the **`suggest-verikun-improvement`** skill, which
|
|
74
|
+
Driving verikun with an AI agent + the [skill](.claude/skills/verikun/SKILL.md)? It hands off to the **`suggest-verikun-improvement`** skill, which writes a short, TL;DR-first suggestion **to a local file for you to read and edit**, **files nothing until you say so**, and **redacts every app-under-test specific** (package, on-screen text, selector values, test prose, logs) so no client code or logic can leak.
|
|
75
75
|
|
|
76
76
|
## Contributing
|
|
77
77
|
|
|
@@ -84,6 +84,16 @@ npm link # optional: put `verikun` and `vk` on your PATH
|
|
|
84
84
|
|
|
85
85
|
Zero runtime dependencies; the only dev dependencies are `typescript` and `@types/node`. The full contributor guide — the test loop, the Flutter device fixture, versioning and releasing — is in [Contributing](https://ddikman.github.io/verikun/internals/contributing/).
|
|
86
86
|
|
|
87
|
+
To work on the [documentation site](https://ddikman.github.io/verikun/), which is an Astro Starlight project in `docs/` with its own dependencies (so `npm install` above does not cover it):
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
npm run docs:install # once — installs the site's dependencies (needs Node >= 22.12)
|
|
91
|
+
npm run docs # dev server with live reload at http://localhost:4321/verikun/
|
|
92
|
+
npm run docs:build # production build; fails on a dead internal link
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Open **http://localhost:4321/verikun/** — the site is served under a base path, so bare `localhost:4321` is a 404. Astro needs **Node ≥ 22.12** while the CLI supports Node ≥ 18, so `nvm use 22` first if your shell's Node is older.
|
|
96
|
+
|
|
87
97
|
## License
|
|
88
98
|
|
|
89
99
|
[MIT](LICENSE)
|
package/dist/agent/remote.js
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
// local one. Recording stays a caller concern: this module never touches ./.verikun.
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.pingServer = pingServer;
|
|
13
|
+
exports.remoteDeviceOp = remoteDeviceOp;
|
|
14
|
+
exports.remoteDeviceList = remoteDeviceList;
|
|
13
15
|
exports.createRemoteBackend = createRemoteBackend;
|
|
14
16
|
const node_fs_1 = require("node:fs");
|
|
15
17
|
const node_crypto_1 = require("node:crypto");
|
|
@@ -22,6 +24,11 @@ const HEALTH_TIMEOUT_MS = 10_000;
|
|
|
22
24
|
const ELEMENTS_TIMEOUT_MS = 60_000;
|
|
23
25
|
const EXEC_TIMEOUT_MS = 10 * 60_000;
|
|
24
26
|
const INSTALL_TIMEOUT_MS = 15 * 60_000;
|
|
27
|
+
const DEVICE_LIST_TIMEOUT_MS = 30_000;
|
|
28
|
+
// Above the server's own 4-minute boot ceiling, so the SERVER reports why a boot
|
|
29
|
+
// timed out rather than the client aborting into a generic "timed out after 300s".
|
|
30
|
+
const DEVICE_START_TIMEOUT_MS = 5 * 60_000;
|
|
31
|
+
const DEVICE_STOP_TIMEOUT_MS = 60_000;
|
|
25
32
|
const trimUrl = (url) => url.replace(/\/+$/, '');
|
|
26
33
|
function describeStatus(status, body, url) {
|
|
27
34
|
const detail = body?.error ? `: ${body.error}` : '';
|
|
@@ -31,6 +38,9 @@ function describeStatus(status, body, url) {
|
|
|
31
38
|
if (status === 409) {
|
|
32
39
|
return new errors_1.CliError(`verikun server device is busy (409)${detail || ' — another run holds the device; retry when it finishes'}.`, 3);
|
|
33
40
|
}
|
|
41
|
+
if (status === 503) {
|
|
42
|
+
return new errors_1.CliError(`verikun server has no device attached (503)${detail}.`, 3);
|
|
43
|
+
}
|
|
34
44
|
// The server sends the intended exit code (usage 2 / env 3) in the body; fall
|
|
35
45
|
// back on the HTTP class when it didn't.
|
|
36
46
|
const exitCode = body?.exitCode ?? (status === 400 || status === 404 || status === 413 ? 2 : 3);
|
|
@@ -89,6 +99,15 @@ class RemoteTransport {
|
|
|
89
99
|
postJson(path, payload, timeoutMs) {
|
|
90
100
|
return this.request('POST', path, JSON.stringify(payload), timeoutMs, { 'content-type': 'application/json' });
|
|
91
101
|
}
|
|
102
|
+
/** Best-effort: give the device lock back. A lock we fail to release ages out. */
|
|
103
|
+
async release() {
|
|
104
|
+
try {
|
|
105
|
+
await this.postJson('/v1/release', {}, HEALTH_TIMEOUT_MS);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
/* the idle takeover covers it */
|
|
109
|
+
}
|
|
110
|
+
}
|
|
92
111
|
}
|
|
93
112
|
/** GET /v1/health — the `--server` preflight. Reachability, the server's platform +
|
|
94
113
|
* serial (which become the run's context), and — when a key is supplied — an auth
|
|
@@ -101,6 +120,31 @@ async function pingServer(opts) {
|
|
|
101
120
|
}
|
|
102
121
|
return health;
|
|
103
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* POST /v1/devices/{start,restart,stop}. Standalone beside pingServer rather than on
|
|
125
|
+
* the ExecBackend seam: that seam is the engine's DEVICE WORK (exec/getElements/
|
|
126
|
+
* install/reset), and adding administration to it would oblige the local backend to
|
|
127
|
+
* implement a verb nothing in the engine ever calls.
|
|
128
|
+
*/
|
|
129
|
+
async function remoteDeviceOp(opts, op, body = {}) {
|
|
130
|
+
const t = new RemoteTransport(opts);
|
|
131
|
+
const timeout = op === 'stop' ? DEVICE_STOP_TIMEOUT_MS : DEVICE_START_TIMEOUT_MS;
|
|
132
|
+
try {
|
|
133
|
+
return await t.postJson(`/v1/devices/${op}`, body, timeout);
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
// This is a one-shot administrative call under its own run token, not a run —
|
|
137
|
+
// so hand the device lock straight back. Without this, `vk devices start
|
|
138
|
+
// --server` (and the --ensure-device preflight, which uses its own token) would
|
|
139
|
+
// 409 the very run it just booted the device for, until the 5-minute idle takeover.
|
|
140
|
+
await t.release();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** GET /v1/devices — what the server can see and what it will boot on request. */
|
|
144
|
+
async function remoteDeviceList(opts) {
|
|
145
|
+
const t = new RemoteTransport(opts);
|
|
146
|
+
return t.request('GET', '/v1/devices', undefined, DEVICE_LIST_TIMEOUT_MS);
|
|
147
|
+
}
|
|
104
148
|
function decodeArtifacts(encoded) {
|
|
105
149
|
const out = {};
|
|
106
150
|
for (const [rel, b64] of Object.entries(encoded ?? {}))
|
package/dist/args.js
CHANGED
|
@@ -43,8 +43,13 @@ const BOOLEAN = new Set([
|
|
|
43
43
|
'no-cache',
|
|
44
44
|
'no-restart',
|
|
45
45
|
'no-logs',
|
|
46
|
+
'wipe',
|
|
46
47
|
'allow-install',
|
|
47
48
|
'allow-unsafe-anonymous',
|
|
49
|
+
// NOT here on purpose: 'allow-device-control' and 'ensure-device' are tri-state
|
|
50
|
+
// (absent / on / on-with-a-value), and the inline `--flag=value` branch is checked
|
|
51
|
+
// BEFORE this set — listing them would make `--allow-device-control=Pixel_6` parse
|
|
52
|
+
// fine but `--ensure-device Pixel_6` silently become a boolean plus a positional.
|
|
48
53
|
// Selector state modifiers (STATE_ATTRS in ui/selector.ts) and their negations.
|
|
49
54
|
// `enabled` was missing here until 0.15.0, and the omission was not cosmetic: a
|
|
50
55
|
// non-BOOLEAN flag swallows the next token, so `vk tap --enabled @submit` bound
|