verikun 0.25.1 → 0.26.0-rc.2
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 -5
- package/CHANGELOG.md +56 -0
- package/README.md +1 -1
- package/dist/agent/remote.js +7 -0
- package/dist/cli.js +628 -24
- package/dist/device/claims.js +27 -0
- package/dist/device/failover.js +24 -3
- package/dist/device/grant.js +183 -0
- package/dist/device/pool.js +116 -0
- package/dist/drivers/adb.js +134 -6
- 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
|
@@ -397,7 +397,8 @@ vk ai onboarding.md --timeout 5m # tighten the run timeout (default 15m)
|
|
|
397
397
|
(`--max-cost-usd`) or the wall-clock passes **15m** (`--timeout`), so a runaway
|
|
398
398
|
compile/repair loop can't spend or hang without limit. The ceiling is **per test, not per
|
|
399
399
|
suite** — `vk suite` gives each `*.md` its own fresh budget, so 20 tests at the default can
|
|
400
|
-
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
|
|
401
402
|
ever called to **compile** (once, on a cache miss) or to **repair** (≤3 per failing step);
|
|
402
403
|
replay is always $0, and every non-`ai` command is $0 always. Full mechanism, the estimate
|
|
403
404
|
formula and the cache multipliers: <https://ddikman.github.io/verikun/reference/cost/>.
|
|
@@ -437,6 +438,28 @@ vk suite tests/ --app com.example.app # reset app data between tests
|
|
|
437
438
|
are **not** counted as failures. So `3` = fix the machine and rerun; `1` = a real
|
|
438
439
|
regression to investigate.
|
|
439
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
|
+
|
|
440
463
|
## Drive a remote device (--server)
|
|
441
464
|
|
|
442
465
|
If the device is attached to another machine running `vk server`, point
|
|
@@ -450,11 +473,23 @@ vk install ./app-debug.apk --server "$VERIKUN_SERVER" # server needs --allow-i
|
|
|
450
473
|
vk suite tests/ --app com.example.app --server "$VERIKUN_SERVER"
|
|
451
474
|
```
|
|
452
475
|
|
|
453
|
-
A wrong URL/key fails fast with exit 3; `409` means
|
|
454
|
-
|
|
455
|
-
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`
|
|
456
479
|
(add `--bind <addr>` to leave loopback; auth key auto-generates if unset).
|
|
457
480
|
|
|
481
|
+
**`vk install` on Android replaces a build signed by a different key.** Android refuses
|
|
482
|
+
to update a package across signing keys, so verikun removes the installed build and
|
|
483
|
+
installs again, warning on stderr that **that build's app data is gone**. A same-key
|
|
484
|
+
install still keeps its data. Do not treat the warning as a failure — it is how the
|
|
485
|
+
install succeeded. iOS has no equivalent recovery; the install just fails there.
|
|
486
|
+
|
|
487
|
+
`vk server --devices all` (or `all-android` / `all-ios` / a serial list) serves a **pool**
|
|
488
|
+
from one address. Each run leases one device for its whole life, so a run's steps and
|
|
489
|
+
repairs always land on the same phone. `vk install --server` then installs on every device;
|
|
490
|
+
`vk devices start|restart|stop --server` is refused (`403`) — a pool has no single device
|
|
491
|
+
to act on.
|
|
492
|
+
|
|
458
493
|
**If you see `[verikun] server moved device: A → B` on stderr**, the server left a
|
|
459
494
|
device that failed and is now on another one. What that means depends on the line:
|
|
460
495
|
|
|
@@ -466,7 +501,9 @@ device that failed and is now on another one. What that means depends on the lin
|
|
|
466
501
|
flow again from the top if you want it on B.
|
|
467
502
|
|
|
468
503
|
The server rules the bad device out until it is power-cycled;
|
|
469
|
-
`vk devices --server <url>` shows why in its `NOTE` column.
|
|
504
|
+
`vk devices --server <url>` shows why in its `NOTE` column. On a pool the replacement
|
|
505
|
+
joins the pool, so capacity holds — and the last device is never shed, so its own error
|
|
506
|
+
keeps reaching you rather than a bare "no device attached".
|
|
470
507
|
|
|
471
508
|
## The device is missing or wedged
|
|
472
509
|
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,62 @@ All notable changes to this project are documented here. The format is based on
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
### Changed
|
|
10
|
+
- **`vk install`** (Android) removes a differently-signed build of the same package and retries,
|
|
11
|
+
instead of failing. Its app data is lost; stderr says so. ([#96])
|
|
12
|
+
- **`VERIKUN_CLAIM_TTL_MIN`** now also paces a parallel suite's claim heartbeat — a quarter of
|
|
13
|
+
the window, capped at 60s — so a short TTL no longer races it.
|
|
14
|
+
|
|
15
|
+
[#96]: https://github.com/ddikman/verikun/issues/96
|
|
16
|
+
|
|
17
|
+
## [0.26.0] - 2026-08-24
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- **`vk suite --devices a,b` / `--servers u1,u2`**: run tests across a device pool, next free
|
|
21
|
+
device takes the next test. One merged report. ([#39])
|
|
22
|
+
- **`vk suite --server`**: sizes itself automatically from a pooled server's capacity — one URL,
|
|
23
|
+
one secret, unchanged CI line. ([#39])
|
|
24
|
+
- **`vk server --devices all | all-android | all-ios | a,b`**: serve several devices from one
|
|
25
|
+
address, one lease per run. ([#39])
|
|
26
|
+
- **`vk suite --devices all | all-android | all-ios`**: same spelling as `vk server --devices`. ([#39])
|
|
27
|
+
- **`vk suite --concurrency n`**: cap how many devices run at once, below the pool's size. ([#39])
|
|
28
|
+
- **`vk suite --max-suite-cost-usd n`**: stop the suite once total model spend crosses it
|
|
29
|
+
(exit `1`). Off by default. ([#39])
|
|
30
|
+
- **`vk ai --reset-app <id>`**: clear (iOS: force-stop) the app before the first step, on the run's
|
|
31
|
+
own device.
|
|
32
|
+
- **`VERIKUN_LANE`**: moves the active run to `./.verikun/run-<lane>/` so concurrent tests in one
|
|
33
|
+
working directory don't delete each other's state.
|
|
34
|
+
- **`POST /v1/lease`** and `capacity` / `devices` on `/v1/health`: which device a run token holds,
|
|
35
|
+
and how many the server has.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- **Suite manifest**: adds `totals.wallClockMs`, `concurrency` and a per-test `device`.
|
|
39
|
+
`totals.durationMs` is unchanged but is now labelled device time. `schemaVersion` stays `1`.
|
|
40
|
+
- **`vk install --server`** installs on **every** device of a pooled server, not one.
|
|
41
|
+
- **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]`).
|
|
42
|
+
- **`vk suite --devices`**: file order no longer sequences tests, and longest-first ordering is
|
|
43
|
+
taken from the previous run's manifest. A serial suite is unchanged. ([#39])
|
|
44
|
+
- **`vk server --devices`**: `/v1/devices/{start,restart,stop}` answer `403` on a pool — there is
|
|
45
|
+
no single device to act on. `--ensure-device` is likewise refused with `--devices`.
|
|
46
|
+
- **`vk suite --devices` with `--server`** is a usage error (exit `2`): it would have tested local
|
|
47
|
+
devices and reported green.
|
|
48
|
+
- **`vk suite --servers u1,u2`**: opens one lane per device each server has, not one per URL.
|
|
49
|
+
- **`vk server`**: a lease is broken only when another run needs that device, so a paused run
|
|
50
|
+
keeps its own phone.
|
|
51
|
+
- **`--json` errors** carry `errorKind`, the error's class, so a caller need not match on message
|
|
52
|
+
text.
|
|
53
|
+
- **`vk server --devices all`** and failover prefer virtual devices, so neither enlists an attached
|
|
54
|
+
phone unasked.
|
|
55
|
+
- **`vk server` failover on a pool**: a failed device is quarantined and a healthy one takes its
|
|
56
|
+
place, so capacity holds. ([#39], [#99])
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
- **`--server` runs no longer fail with `fetch failed`** when a step follows a pause longer
|
|
60
|
+
than 5s, such as a cold compile.
|
|
61
|
+
- **`--server` screenshots and failure evidence** are no longer corrupted in the archived report.
|
|
62
|
+
|
|
63
|
+
[#39]: https://github.com/ddikman/verikun/issues/39
|
|
64
|
+
|
|
9
65
|
## [0.25.1] - 2026-08-21
|
|
10
66
|
|
|
11
67
|
### Changed
|
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
|
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;
|