@unotest/core 0.26.0 → 0.27.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/CHANGELOG.md +55 -0
- package/dist/index.d.ts +24 -2
- package/dist/index.js +27 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.27.0] - 2026-08-31
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- New `computeSchedulesFingerprint(entries)` — sha256 of
|
|
8
|
+
`canonicalScheduleSet` from `@unotest/protocol` (the canon lives
|
|
9
|
+
there, the crypto here). `BundleProvenance` gains optional
|
|
10
|
+
`schedulesFingerprint`, carried into the packed manifest: what lets a
|
|
11
|
+
box compare the schedule set it reads with the set the pusher saw.
|
|
12
|
+
|
|
13
|
+
- c843d21: Schedules from the viewer — for collections and single tests.
|
|
14
|
+
|
|
15
|
+
Right-click a test or a collection in the viewer → **Schedule…**: a
|
|
16
|
+
human schedule builder (frequency select — every 5/15 min, hourly,
|
|
17
|
+
every 2/4/6/12 h, daily, weekly — plus toggle badges for minutes,
|
|
18
|
+
hours and weekdays; multi-select, so `04` + `16` × `00` + `30` runs
|
|
19
|
+
four times a day). Saved to `unotest/schedules.yaml`, versioned next
|
|
20
|
+
to the tests; a box applies it after commit & sync. The Home screen
|
|
21
|
+
gains a `last run | schedule` toggle: in schedule mode tiles are
|
|
22
|
+
tinted by how often a test runs (grey = not scheduled), with an
|
|
23
|
+
upcoming list and per-tile next-run times in your browser's clock.
|
|
24
|
+
|
|
25
|
+
Under the hood:
|
|
26
|
+
|
|
27
|
+
- `unotest/schedules.yaml` is a new schedule registry; `unotest-web
|
|
28
|
+
schedules [--json]` prints it merged with the config's `schedules`
|
|
29
|
+
(the file wins on a duplicate target), so boxes pick both up
|
|
30
|
+
unchanged.
|
|
31
|
+
- A schedule entry may now target a single test: `scenario:
|
|
32
|
+
<ref>` instead of `collection: <name>`.
|
|
33
|
+
- `unotest-web e2e <name> --scheduled[=index]` runs a test the way its
|
|
34
|
+
entry says (env + prepare, exit 94 when prepare fails) — the
|
|
35
|
+
per-test mirror of `collection --scheduled`.
|
|
36
|
+
- Viewer server: `GET/PUT /api/schedules` (validated by the same
|
|
37
|
+
parser the CLI reads the file with).
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- Updated dependencies [c843d21]
|
|
42
|
+
- @unotest/protocol@0.27.0
|
|
43
|
+
- @unotest/dsl@0.27.0
|
|
44
|
+
|
|
45
|
+
## [0.26.1] - 2026-08-30
|
|
46
|
+
|
|
47
|
+
### Patch Changes
|
|
48
|
+
|
|
49
|
+
- `packBundle` accepts `declaredVariables` — the external NAMES a suite
|
|
50
|
+
declares, carried in the manifest so a box can tell a pusher which of
|
|
51
|
+
them it has no value for. Names only; the files that hold the values
|
|
52
|
+
are excluded from every bundle as before.
|
|
53
|
+
|
|
54
|
+
- Updated dependencies [9424f6b]
|
|
55
|
+
- @unotest/protocol@0.26.1
|
|
56
|
+
- @unotest/dsl@0.26.1
|
|
57
|
+
|
|
3
58
|
## [0.26.0] - 2026-08-30
|
|
4
59
|
|
|
5
60
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RunArtifact, RunManifest, RunSources, RuntimeStateFile, RuntimeState, DbgCommand, PickerMode, DbgCommandRecord, DbgCommandProbe, IRunQueue, EnqueueRunInput, RunQueueTicketHandle, QueueSnapshot, QueueTicket, RunQueueLease, BundleGitInfo, BundleManifest } from '@unotest/protocol';
|
|
1
|
+
import { RunArtifact, RunManifest, RunSources, RuntimeStateFile, RuntimeState, DbgCommand, PickerMode, DbgCommandRecord, DbgCommandProbe, IRunQueue, EnqueueRunInput, RunQueueTicketHandle, QueueSnapshot, QueueTicket, RunQueueLease, BundleGitInfo, BundleManifest, ScheduleEntry } from '@unotest/protocol';
|
|
2
2
|
export { isRecord } from '@unotest/protocol';
|
|
3
3
|
import { ExecutionEvent } from '@unotest/dsl/executor';
|
|
4
4
|
|
|
@@ -222,6 +222,13 @@ interface E2EFlags {
|
|
|
222
222
|
* Empty when --break wasn't passed — caller falls back to the
|
|
223
223
|
* `.debugger[-suffix].json` breakpoint store. */
|
|
224
224
|
breakFlag: string[];
|
|
225
|
+
/** Scheduled run (`--scheduled[=index]`): honour the scenario's
|
|
226
|
+
* schedules entry — its env and prepare. Mirrors the collection
|
|
227
|
+
* command's flag. */
|
|
228
|
+
scheduled: boolean;
|
|
229
|
+
/** WHICH schedules entry (zero-based position in the merged list),
|
|
230
|
+
* when the executor pins it. */
|
|
231
|
+
scheduleIndex?: number;
|
|
225
232
|
}
|
|
226
233
|
declare function parseE2EFlags(args: string[]): E2EFlags;
|
|
227
234
|
|
|
@@ -421,6 +428,14 @@ interface BundleProvenance {
|
|
|
421
428
|
webVersion: string;
|
|
422
429
|
author?: string;
|
|
423
430
|
git?: BundleGitInfo;
|
|
431
|
+
/** Names of the externals the suite declares. The files that hold them
|
|
432
|
+
* never travel (their values belong to an environment), so the names
|
|
433
|
+
* ride in the manifest — that is what lets a box say at upload which
|
|
434
|
+
* of them it cannot supply. */
|
|
435
|
+
declaredVariables?: readonly string[];
|
|
436
|
+
/** `computeSchedulesFingerprint` of the effective schedules at pack
|
|
437
|
+
* time — see the manifest field's doc in `@unotest/protocol`. */
|
|
438
|
+
schedulesFingerprint?: string;
|
|
424
439
|
}
|
|
425
440
|
interface PackedBundle {
|
|
426
441
|
bundleId: string;
|
|
@@ -441,6 +456,13 @@ interface UnpackOptions {
|
|
|
441
456
|
}
|
|
442
457
|
declare function unpackBundle(archive: Uint8Array, options?: UnpackOptions): UnpackedBundle;
|
|
443
458
|
|
|
459
|
+
/** sha256 of the canonical effective schedule set — what `bundle push`
|
|
460
|
+
* records in the manifest (`schedulesFingerprint`) and a box re-computes
|
|
461
|
+
* after reading `schedules --json` in its own environment. Equal hashes
|
|
462
|
+
* mean the box arms exactly the set the pusher saw; different hashes
|
|
463
|
+
* mean the project's config computed schedules from its surroundings. */
|
|
464
|
+
declare function computeSchedulesFingerprint(entries: readonly ScheduleEntry[]): string;
|
|
465
|
+
|
|
444
466
|
/** The archive is not a readable bundle: broken gzip, a truncated tar, a
|
|
445
467
|
* header whose checksum does not add up, a member that is not a plain
|
|
446
468
|
* file. Everything a box refuses BEFORE writing anything to disk. */
|
|
@@ -476,4 +498,4 @@ declare class BundleIdMismatchError extends UnotestError {
|
|
|
476
498
|
constructor(claimed: string, computed: string);
|
|
477
499
|
}
|
|
478
500
|
|
|
479
|
-
export { type ArtifactRedactor, type BundleFile, BundleFormatError, BundleIdMismatchError, BundlePathError, type BundleProvenance, BundleTooLargeError, type DebugCommandsWatcherDeps, type DebugControlTarget, type DebugWatcherLogger, type E2EFlags, FsRunQueue, type FsRunQueueOptions, type GitignoreUpdate, type GlobalPoolOptions, type IRunArtifactWriter, JsonlRunArtifactWriter, type JsonlRunArtifactWriterOptions, type PackedBundle, QueueTicketLostError, QueueUnavailableError, QueueWaitAbortedError, type RunHeartbeat, type RuntimeExecState, type RuntimeInspection, type RuntimeInspectionInput, type RuntimeStateExtra, type RuntimeStateWriter, type RuntimeStateWriterDeps, type TarEntry, UnotestError, type UnpackOptions, type UnpackedBundle, type WriteManifestInput, type WriteRunSourcesInput, appendUniqueLines, applyEnvLayers, assertSafeBundlePath, buildRuntimeInspection, computeBundleId, computeTreeSha256, createRunArtifactWriter, createRuntimeStateWriter, currentLocation, extractCallStack, globalPoolFromEnv, leaseEnv, levenshteinDistance, packBundle, parseE2EFlags, readDebuggerBreakpoints, readEnvFile, readEnvLayers, readTar, startDebugCommandsWatcher, startRunHeartbeat, suggestClosest, toProtocolRuntimeState, unpackBundle, writeRunManifest, writeRunSources, writeTar };
|
|
501
|
+
export { type ArtifactRedactor, type BundleFile, BundleFormatError, BundleIdMismatchError, BundlePathError, type BundleProvenance, BundleTooLargeError, type DebugCommandsWatcherDeps, type DebugControlTarget, type DebugWatcherLogger, type E2EFlags, FsRunQueue, type FsRunQueueOptions, type GitignoreUpdate, type GlobalPoolOptions, type IRunArtifactWriter, JsonlRunArtifactWriter, type JsonlRunArtifactWriterOptions, type PackedBundle, QueueTicketLostError, QueueUnavailableError, QueueWaitAbortedError, type RunHeartbeat, type RuntimeExecState, type RuntimeInspection, type RuntimeInspectionInput, type RuntimeStateExtra, type RuntimeStateWriter, type RuntimeStateWriterDeps, type TarEntry, UnotestError, type UnpackOptions, type UnpackedBundle, type WriteManifestInput, type WriteRunSourcesInput, appendUniqueLines, applyEnvLayers, assertSafeBundlePath, buildRuntimeInspection, computeBundleId, computeSchedulesFingerprint, computeTreeSha256, createRunArtifactWriter, createRuntimeStateWriter, currentLocation, extractCallStack, globalPoolFromEnv, leaseEnv, levenshteinDistance, packBundle, parseE2EFlags, readDebuggerBreakpoints, readEnvFile, readEnvLayers, readTar, startDebugCommandsWatcher, startRunHeartbeat, suggestClosest, toProtocolRuntimeState, unpackBundle, writeRunManifest, writeRunSources, writeTar };
|
package/dist/index.js
CHANGED
|
@@ -423,11 +423,19 @@ __name(runCapability, "runCapability");
|
|
|
423
423
|
function parseE2EFlags(args) {
|
|
424
424
|
const positional = [];
|
|
425
425
|
let debug = false;
|
|
426
|
+
let scheduled = false;
|
|
427
|
+
let scheduleIndex;
|
|
426
428
|
const breakFlag = [];
|
|
427
429
|
for (let i = 0; i < args.length; i++) {
|
|
428
430
|
const a = args[i];
|
|
429
431
|
if (a === "--debug") {
|
|
430
432
|
debug = true;
|
|
433
|
+
} else if (a === "--scheduled") {
|
|
434
|
+
scheduled = true;
|
|
435
|
+
} else if (a.startsWith("--scheduled=")) {
|
|
436
|
+
scheduled = true;
|
|
437
|
+
const n = Number(a.slice("--scheduled=".length));
|
|
438
|
+
if (Number.isInteger(n) && n >= 0) scheduleIndex = n;
|
|
431
439
|
} else if (a === "--break") {
|
|
432
440
|
const next = args[i + 1];
|
|
433
441
|
if (next === void 0 || next.startsWith("--")) {
|
|
@@ -441,7 +449,13 @@ function parseE2EFlags(args) {
|
|
|
441
449
|
positional.push(a);
|
|
442
450
|
}
|
|
443
451
|
}
|
|
444
|
-
return {
|
|
452
|
+
return {
|
|
453
|
+
positional,
|
|
454
|
+
debug,
|
|
455
|
+
breakFlag,
|
|
456
|
+
scheduled,
|
|
457
|
+
...scheduleIndex !== void 0 ? { scheduleIndex } : {}
|
|
458
|
+
};
|
|
445
459
|
}
|
|
446
460
|
__name(parseE2EFlags, "parseE2EFlags");
|
|
447
461
|
function pushBreaks(value, out) {
|
|
@@ -1483,7 +1497,9 @@ function packBundle(files, provenance) {
|
|
|
1483
1497
|
fileCount: files.length,
|
|
1484
1498
|
byteSize: files.reduce((total, file) => total + file.content.byteLength, 0),
|
|
1485
1499
|
...provenance.author !== void 0 ? { author: provenance.author } : {},
|
|
1486
|
-
...provenance.git !== void 0 ? { git: provenance.git } : {}
|
|
1500
|
+
...provenance.git !== void 0 ? { git: provenance.git } : {},
|
|
1501
|
+
...provenance.declaredVariables && provenance.declaredVariables.length > 0 ? { declaredVariables: [...provenance.declaredVariables] } : {},
|
|
1502
|
+
...provenance.schedulesFingerprint !== void 0 ? { schedulesFingerprint: provenance.schedulesFingerprint } : {}
|
|
1487
1503
|
};
|
|
1488
1504
|
const archive = writeTar([
|
|
1489
1505
|
...files,
|
|
@@ -1548,6 +1564,14 @@ function gunzip(archive, maxBytes) {
|
|
|
1548
1564
|
}
|
|
1549
1565
|
}
|
|
1550
1566
|
__name(gunzip, "gunzip");
|
|
1567
|
+
|
|
1568
|
+
// src/bundle/schedules-fingerprint.ts
|
|
1569
|
+
import { canonicalScheduleSet } from "@unotest/protocol";
|
|
1570
|
+
import { createHash as createHash2 } from "crypto";
|
|
1571
|
+
function computeSchedulesFingerprint(entries) {
|
|
1572
|
+
return createHash2("sha256").update(canonicalScheduleSet(entries)).digest("hex");
|
|
1573
|
+
}
|
|
1574
|
+
__name(computeSchedulesFingerprint, "computeSchedulesFingerprint");
|
|
1551
1575
|
export {
|
|
1552
1576
|
BundleFormatError,
|
|
1553
1577
|
BundleIdMismatchError,
|
|
@@ -1564,6 +1588,7 @@ export {
|
|
|
1564
1588
|
assertSafeBundlePath,
|
|
1565
1589
|
buildRuntimeInspection,
|
|
1566
1590
|
computeBundleId,
|
|
1591
|
+
computeSchedulesFingerprint,
|
|
1567
1592
|
computeTreeSha256,
|
|
1568
1593
|
createRunArtifactWriter,
|
|
1569
1594
|
createRuntimeStateWriter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unotest/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Shared runner-side utilities for the @unotest ecosystem: JSONL run-artifact writer (steps.jsonl + heartbeat), atomic run-manifest + run-sources writers, atomic runtime-state writer with a protocol-normalizing runtime-inspection helper, layered .env reader/applier (target + environment axes), idempotent .gitignore updater. Used by @unotest/web and @unotest/mobile; depends on @unotest/protocol plus a type-only import of @unotest/dsl/executor event types (M-20). Unlike protocol (pure data), this package owns the thin filesystem layer both runners need.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"chokidar": "^4.0.3",
|
|
32
|
-
"@unotest/dsl": "^0.
|
|
33
|
-
"@unotest/protocol": "^0.
|
|
32
|
+
"@unotest/dsl": "^0.27.0",
|
|
33
|
+
"@unotest/protocol": "^0.27.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^22.10.0",
|