@unotest/core 0.26.1 → 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 +42 -0
- package/dist/index.d.ts +19 -2
- package/dist/index.js +26 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
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
|
+
|
|
3
45
|
## [0.26.1] - 2026-08-30
|
|
4
46
|
|
|
5
47
|
### Patch 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
|
|
|
@@ -426,6 +433,9 @@ interface BundleProvenance {
|
|
|
426
433
|
* ride in the manifest — that is what lets a box say at upload which
|
|
427
434
|
* of them it cannot supply. */
|
|
428
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;
|
|
429
439
|
}
|
|
430
440
|
interface PackedBundle {
|
|
431
441
|
bundleId: string;
|
|
@@ -446,6 +456,13 @@ interface UnpackOptions {
|
|
|
446
456
|
}
|
|
447
457
|
declare function unpackBundle(archive: Uint8Array, options?: UnpackOptions): UnpackedBundle;
|
|
448
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
|
+
|
|
449
466
|
/** The archive is not a readable bundle: broken gzip, a truncated tar, a
|
|
450
467
|
* header whose checksum does not add up, a member that is not a plain
|
|
451
468
|
* file. Everything a box refuses BEFORE writing anything to disk. */
|
|
@@ -481,4 +498,4 @@ declare class BundleIdMismatchError extends UnotestError {
|
|
|
481
498
|
constructor(claimed: string, computed: string);
|
|
482
499
|
}
|
|
483
500
|
|
|
484
|
-
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) {
|
|
@@ -1484,7 +1498,8 @@ function packBundle(files, provenance) {
|
|
|
1484
1498
|
byteSize: files.reduce((total, file) => total + file.content.byteLength, 0),
|
|
1485
1499
|
...provenance.author !== void 0 ? { author: provenance.author } : {},
|
|
1486
1500
|
...provenance.git !== void 0 ? { git: provenance.git } : {},
|
|
1487
|
-
...provenance.declaredVariables && provenance.declaredVariables.length > 0 ? { declaredVariables: [...provenance.declaredVariables] } : {}
|
|
1501
|
+
...provenance.declaredVariables && provenance.declaredVariables.length > 0 ? { declaredVariables: [...provenance.declaredVariables] } : {},
|
|
1502
|
+
...provenance.schedulesFingerprint !== void 0 ? { schedulesFingerprint: provenance.schedulesFingerprint } : {}
|
|
1488
1503
|
};
|
|
1489
1504
|
const archive = writeTar([
|
|
1490
1505
|
...files,
|
|
@@ -1549,6 +1564,14 @@ function gunzip(archive, maxBytes) {
|
|
|
1549
1564
|
}
|
|
1550
1565
|
}
|
|
1551
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");
|
|
1552
1575
|
export {
|
|
1553
1576
|
BundleFormatError,
|
|
1554
1577
|
BundleIdMismatchError,
|
|
@@ -1565,6 +1588,7 @@ export {
|
|
|
1565
1588
|
assertSafeBundlePath,
|
|
1566
1589
|
buildRuntimeInspection,
|
|
1567
1590
|
computeBundleId,
|
|
1591
|
+
computeSchedulesFingerprint,
|
|
1568
1592
|
computeTreeSha256,
|
|
1569
1593
|
createRunArtifactWriter,
|
|
1570
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",
|