verikun 0.25.0 → 0.26.0-rc.1
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 +42 -6
- package/CHANGELOG.md +64 -0
- package/README.md +2 -2
- package/dist/agent/remote.js +7 -0
- package/dist/cli.js +658 -64
- package/dist/device/claims.js +27 -6
- package/dist/device/failover.js +21 -2
- package/dist/device/grant.js +183 -0
- package/dist/device/pool.js +116 -0
- package/dist/device/prep.js +49 -11
- package/dist/drivers/adb.js +56 -32
- package/dist/drivers/ios.js +6 -1
- package/dist/drivers/lifecycle.js +6 -1
- package/dist/exec.js +79 -0
- package/dist/output.js +24 -1
- package/dist/report.js +26 -7
- package/dist/rpc.js +10 -0
- package/dist/run.js +67 -13
- package/dist/server-pool.js +349 -0
- package/dist/server-worker.js +148 -0
- package/dist/server.js +852 -230
- package/dist/suite.js +350 -79
- package/dist/version.js +1 -1
- package/dist/wait.js +20 -0
- package/package.json +1 -1
|
@@ -141,7 +141,10 @@ banner, the retry path, dark theme, a layout that breaks at accessibility text s
|
|
|
141
141
|
you reset it, so don't leave someone's phone in airplane mode.
|
|
142
142
|
|
|
143
143
|
- `vk device prep [--dry-run] [--revert]` — set a **test** device up once, stickily:
|
|
144
|
-
`animations=off stay-awake=
|
|
144
|
+
`animations=off stay-awake=off screen-timeout=1m dnd=on doze=off`. The display then sleeps by
|
|
145
|
+
itself a minute after the last command and is woken by the next one; `--no-sleep-when-idle`
|
|
146
|
+
keeps it lit for good (`stay-awake=on screen-timeout=max`), which is what a device with a
|
|
147
|
+
PIN/pattern lock needs, since verikun can only clear a *swipe* lock.
|
|
145
148
|
|
|
146
149
|
Unlike `device set`, prep **survives the run** and is undone only by `--revert`. A physical
|
|
147
150
|
device must be named (`--device <serial>`) — that requirement is deliberate, so prep can
|
|
@@ -394,7 +397,8 @@ vk ai onboarding.md --timeout 5m # tighten the run timeout (default 15m)
|
|
|
394
397
|
(`--max-cost-usd`) or the wall-clock passes **15m** (`--timeout`), so a runaway
|
|
395
398
|
compile/repair loop can't spend or hang without limit. The ceiling is **per test, not per
|
|
396
399
|
suite** — `vk suite` gives each `*.md` its own fresh budget, so 20 tests at the default can
|
|
397
|
-
reach $60;
|
|
400
|
+
reach $60; lower the per-test figure, or set `vk suite --max-suite-cost-usd <n>` for an
|
|
401
|
+
aggregate cap (off by default; stops the suite at exit `1`). A model is only
|
|
398
402
|
ever called to **compile** (once, on a cache miss) or to **repair** (≤3 per failing step);
|
|
399
403
|
replay is always $0, and every non-`ai` command is $0 always. Full mechanism, the estimate
|
|
400
404
|
formula and the cache multipliers: <https://ddikman.github.io/verikun/reference/cost/>.
|
|
@@ -434,6 +438,28 @@ vk suite tests/ --app com.example.app # reset app data between tests
|
|
|
434
438
|
are **not** counted as failures. So `3` = fix the machine and rerun; `1` = a real
|
|
435
439
|
regression to investigate.
|
|
436
440
|
|
|
441
|
+
### Across several devices
|
|
442
|
+
|
|
443
|
+
Suite time is the **sum** of its tests on one device. Given a pool, the suite becomes a
|
|
444
|
+
work queue instead — every device takes the next test as it frees up:
|
|
445
|
+
|
|
446
|
+
```sh
|
|
447
|
+
vk suite tests/ --app com.example.app --devices emulator-5554,emulator-5556
|
|
448
|
+
vk suite tests/ --app com.example.app --server "$VERIKUN_SERVER" # a pooled server
|
|
449
|
+
vk suite tests/ --app com.example.app --servers http://a:8391,http://b:8391
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
- A `vk server --devices all` holds several devices behind one URL; a plain `--server`
|
|
453
|
+
suite reads its capacity and sizes itself. Nothing else about the command changes.
|
|
454
|
+
- **File order stops sequencing tests** — they must be independent. Ordering becomes
|
|
455
|
+
longest-first, learned from the previous run's `index.json`.
|
|
456
|
+
- Each row records **which device ran it**, and the manifest splits
|
|
457
|
+
`totals.wallClockMs` (how long the gate took) from `totals.durationMs` (device-seconds).
|
|
458
|
+
- `--concurrency N` caps how many run at once — more devices on one host can thrash it.
|
|
459
|
+
`--max-suite-cost-usd N` stops the suite once total model spend crosses it (exit `1`).
|
|
460
|
+
- A device that breaks retires; its tests move to the others. Exit `3` only when all are gone.
|
|
461
|
+
- `--ensure-device` is refused with `--devices` — start the pool with `vk devices start`.
|
|
462
|
+
|
|
437
463
|
## Drive a remote device (--server)
|
|
438
464
|
|
|
439
465
|
If the device is attached to another machine running `vk server`, point
|
|
@@ -447,11 +473,17 @@ vk install ./app-debug.apk --server "$VERIKUN_SERVER" # server needs --allow-i
|
|
|
447
473
|
vk suite tests/ --app com.example.app --server "$VERIKUN_SERVER"
|
|
448
474
|
```
|
|
449
475
|
|
|
450
|
-
A wrong URL/key fails fast with exit 3; `409` means
|
|
451
|
-
|
|
452
|
-
expose a device from THIS machine: `vk server --allow-install`
|
|
476
|
+
A wrong URL/key fails fast with exit 3; `409` means every device is already
|
|
477
|
+
leased by another run; `503` means the server has no device attached — boot one
|
|
478
|
+
(below). To expose a device from THIS machine: `vk server --allow-install`
|
|
453
479
|
(add `--bind <addr>` to leave loopback; auth key auto-generates if unset).
|
|
454
480
|
|
|
481
|
+
`vk server --devices all` (or `all-android` / `all-ios` / a serial list) serves a **pool**
|
|
482
|
+
from one address. Each run leases one device for its whole life, so a run's steps and
|
|
483
|
+
repairs always land on the same phone. `vk install --server` then installs on every device;
|
|
484
|
+
`vk devices start|restart|stop --server` is refused (`403`) — a pool has no single device
|
|
485
|
+
to act on.
|
|
486
|
+
|
|
455
487
|
**If you see `[verikun] server moved device: A → B` on stderr**, the server left a
|
|
456
488
|
device that failed and is now on another one. What that means depends on the line:
|
|
457
489
|
|
|
@@ -463,7 +495,9 @@ device that failed and is now on another one. What that means depends on the lin
|
|
|
463
495
|
flow again from the top if you want it on B.
|
|
464
496
|
|
|
465
497
|
The server rules the bad device out until it is power-cycled;
|
|
466
|
-
`vk devices --server <url>` shows why in its `NOTE` column.
|
|
498
|
+
`vk devices --server <url>` shows why in its `NOTE` column. On a pool the replacement
|
|
499
|
+
joins the pool, so capacity holds — and the last device is never shed, so its own error
|
|
500
|
+
keeps reaching you rather than a bare "no device attached".
|
|
467
501
|
|
|
468
502
|
## The device is missing or wedged
|
|
469
503
|
|
|
@@ -549,6 +583,8 @@ owns the redaction and the review-first flow.
|
|
|
549
583
|
verikun detects this, wakes the device and clears a *swipe* lock automatically; on a
|
|
550
584
|
PIN/pattern/password it exits **3** naming the lock rather than returning that dump.
|
|
551
585
|
Tell the user to remove the lock in Settings > Security — verikun never asks for a PIN.
|
|
586
|
+
Taps, swipes, typing and screenshots wake it the same way: a prepped display sleeps after a
|
|
587
|
+
minute idle, and an injected tap on a sleeping screen would otherwise do nothing and exit `0`.
|
|
552
588
|
- **Ambiguous selector → exit 2**, never a random tap. `vk` prints the candidate
|
|
553
589
|
matches; add `--index N` or use a more specific selector.
|
|
554
590
|
- **Indexes are per-snapshot.** `vk tap 3` taps `[3]` from the *latest* dump;
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,70 @@ All notable changes to this project are documented here. The format is based on
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
### Changed
|
|
10
|
+
- **`VERIKUN_CLAIM_TTL_MIN`** now also paces a parallel suite's claim heartbeat — a quarter of
|
|
11
|
+
the window, capped at 60s — so a short TTL no longer races it.
|
|
12
|
+
|
|
13
|
+
## [0.26.0] - 2026-08-24
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **`vk suite --devices a,b` / `--servers u1,u2`**: run tests across a device pool, next free
|
|
17
|
+
device takes the next test. One merged report. ([#39])
|
|
18
|
+
- **`vk suite --server`**: sizes itself automatically from a pooled server's capacity — one URL,
|
|
19
|
+
one secret, unchanged CI line. ([#39])
|
|
20
|
+
- **`vk server --devices all | all-android | all-ios | a,b`**: serve several devices from one
|
|
21
|
+
address, one lease per run. ([#39])
|
|
22
|
+
- **`vk suite --devices all | all-android | all-ios`**: same spelling as `vk server --devices`. ([#39])
|
|
23
|
+
- **`vk suite --concurrency n`**: cap how many devices run at once, below the pool's size. ([#39])
|
|
24
|
+
- **`vk suite --max-suite-cost-usd n`**: stop the suite once total model spend crosses it
|
|
25
|
+
(exit `1`). Off by default. ([#39])
|
|
26
|
+
- **`vk ai --reset-app <id>`**: clear (iOS: force-stop) the app before the first step, on the run's
|
|
27
|
+
own device.
|
|
28
|
+
- **`VERIKUN_LANE`**: moves the active run to `./.verikun/run-<lane>/` so concurrent tests in one
|
|
29
|
+
working directory don't delete each other's state.
|
|
30
|
+
- **`POST /v1/lease`** and `capacity` / `devices` on `/v1/health`: which device a run token holds,
|
|
31
|
+
and how many the server has.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- **Suite manifest**: adds `totals.wallClockMs`, `concurrency` and a per-test `device`.
|
|
35
|
+
`totals.durationMs` is unchanged but is now labelled device time. `schemaVersion` stays `1`.
|
|
36
|
+
- **`vk install --server`** installs on **every** device of a pooled server, not one.
|
|
37
|
+
- **Release workflow**: a prerelease tag takes its GitHub release notes from the version it is a candidate for (`v1.0.0-rc.1` → `## [1.0.0]`).
|
|
38
|
+
- **`vk suite --devices`**: file order no longer sequences tests, and longest-first ordering is
|
|
39
|
+
taken from the previous run's manifest. A serial suite is unchanged. ([#39])
|
|
40
|
+
- **`vk server --devices`**: `/v1/devices/{start,restart,stop}` answer `403` on a pool — there is
|
|
41
|
+
no single device to act on. `--ensure-device` is likewise refused with `--devices`.
|
|
42
|
+
- **`vk suite --devices` with `--server`** is a usage error (exit `2`): it would have tested local
|
|
43
|
+
devices and reported green.
|
|
44
|
+
- **`vk suite --servers u1,u2`**: opens one lane per device each server has, not one per URL.
|
|
45
|
+
- **`vk server`**: a lease is broken only when another run needs that device, so a paused run
|
|
46
|
+
keeps its own phone.
|
|
47
|
+
- **`--json` errors** carry `errorKind`, the error's class, so a caller need not match on message
|
|
48
|
+
text.
|
|
49
|
+
- **`vk server --devices all`** and failover prefer virtual devices, so neither enlists an attached
|
|
50
|
+
phone unasked.
|
|
51
|
+
- **`vk server` failover on a pool**: a failed device is quarantined and a healthy one takes its
|
|
52
|
+
place, so capacity holds. ([#39], [#99])
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
- **`--server` runs no longer fail with `fetch failed`** when a step follows a pause longer
|
|
56
|
+
than 5s, such as a cold compile.
|
|
57
|
+
- **`--server` screenshots and failure evidence** are no longer corrupted in the archived report.
|
|
58
|
+
|
|
59
|
+
[#39]: https://github.com/ddikman/verikun/issues/39
|
|
60
|
+
|
|
61
|
+
## [0.25.1] - 2026-08-21
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
- **`vk device prep`**: gives the display a 1-minute timeout instead of keeping it lit forever; `--no-sleep-when-idle` keeps the old behaviour. ([#101])
|
|
65
|
+
- **`vk batch|ai|suite`**: no longer switch a prepped device's display off at teardown — it now sleeps by itself.
|
|
66
|
+
- **`vk tap|type|key|swipe|screenshot`**: wake a sleeping display first; an injected tap on a dozing screen did nothing and exited `0`.
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
- **`vk device prep`**: warns when a device that will now sleep is behind a PIN/pattern lock.
|
|
70
|
+
|
|
71
|
+
[#101]: https://github.com/ddikman/verikun/issues/101
|
|
72
|
+
|
|
9
73
|
## [0.25.0] - 2026-08-21
|
|
10
74
|
|
|
11
75
|
### Added
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- **Puppeteer for native mobile** — a thin wrapper over native Android and iOS automation runners with zero runtime dependencies.
|
|
9
9
|
- **Natural-language tests** — `vk ai <file>`: runs plain-English tests, compiled once and replayed model-free (~$0), calling a model only to self-heal a drifted step. [What that costs](https://ddikman.github.io/verikun/reference/cost/), and how the `--max-cost-usd` ceiling bounds it.
|
|
10
10
|
- **Self-improving** — the agent runner will provide prescriptive improvements to existing scripts to help stabilise flakiness for future runs.
|
|
11
|
-
- **CI-ready** — `vk suite` runs a folder of tests as one gated pass/fail run; `vk server` exposes
|
|
11
|
+
- **CI-ready** — `vk suite` runs a folder of tests as one gated pass/fail run, across one device or a whole pool of them; `vk server` exposes real devices over an authenticated tunnel so a disposable CI runner (no phone attached) can still drive them, and swaps out any that goes bad.
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
$ vk ui
|
|
@@ -38,7 +38,7 @@ The package also carries the agent [`SKILL.md`](.claude/skills/verikun/SKILL.md)
|
|
|
38
38
|
|
|
39
39
|
```sh
|
|
40
40
|
vk doctor # check adb/device (read-only — never changes anything)
|
|
41
|
-
vk device prep --device <id> # set a TEST device up once: animations off,
|
|
41
|
+
vk device prep --device <id> # set a TEST device up once: animations off, sane display timeout
|
|
42
42
|
vk devices # list attached devices
|
|
43
43
|
vk ui # semantic snapshot of the current screen
|
|
44
44
|
vk tap @login_button # tap by resource-id
|
package/dist/agent/remote.js
CHANGED
|
@@ -170,6 +170,13 @@ function createRemoteBackend(opts, health) {
|
|
|
170
170
|
};
|
|
171
171
|
return {
|
|
172
172
|
exec: (command, positionals, flags) => execRaw({ command, positionals, flags }, true),
|
|
173
|
+
async lease() {
|
|
174
|
+
// Feature-detect on a FIELD, never on the version: `capacity` and /v1/lease landed
|
|
175
|
+
// together, and a client cannot otherwise tell "old server" from "new server".
|
|
176
|
+
if (health.capacity === undefined)
|
|
177
|
+
return null;
|
|
178
|
+
return t.postJson('/v1/lease', {}, HEALTH_TIMEOUT_MS);
|
|
179
|
+
},
|
|
173
180
|
async getElements() {
|
|
174
181
|
const res = await t.postJson('/v1/elements', {}, ELEMENTS_TIMEOUT_MS);
|
|
175
182
|
return res.elements;
|