@unotest/core 0.32.0 → 0.33.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 +39 -0
- package/dist/index.js +15 -7
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.33.0] - 2026-09-06
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8846a06: Viewer: a run started the moment the viewer came up is shown, not lost
|
|
8
|
+
until the next change.
|
|
9
|
+
|
|
10
|
+
Watching a directory becomes live a moment after the watcher reports it
|
|
11
|
+
is ready, and a run directory created inside that gap was not merely
|
|
12
|
+
late — it was invisible until something else changed in the same day,
|
|
13
|
+
which in a quiet environment is the next run. Measured at 1-3% on macOS
|
|
14
|
+
with a busy machine, and the window is exactly "open the viewer, start a
|
|
15
|
+
run". The viewer now proves the watch delivers before it declares itself
|
|
16
|
+
up: it creates a directory of its own and waits to hear about it, so
|
|
17
|
+
boot completes on evidence rather than on a promise. A tree it cannot
|
|
18
|
+
write to, or a probe that never comes back, costs a warning in the log
|
|
19
|
+
and boots as before.
|
|
20
|
+
|
|
21
|
+
A directory whose name starts with a dot is never reported as a run — an
|
|
22
|
+
editor's leftovers, or the watcher's own probe, can no longer appear in
|
|
23
|
+
the run list as a phantom.
|
|
24
|
+
|
|
25
|
+
Run queue: a waiter whose process paused is no longer mistaken for dead
|
|
26
|
+
— the queue stamps its own files with its own clock.
|
|
27
|
+
|
|
28
|
+
A run waiting for a slot proves it is alive by touching its ticket, and
|
|
29
|
+
what it is judged against was the modification time the filesystem
|
|
30
|
+
wrote: on a network share that is the server's clock, and against a
|
|
31
|
+
machine busy enough to keep a process off the CPU, a ticket written a
|
|
32
|
+
moment ago could look like it belonged to a process that died. The queue
|
|
33
|
+
now stamps every file it creates with the same clock it judges them by.
|
|
34
|
+
|
|
35
|
+
- Updated dependencies [2abfd4d]
|
|
36
|
+
- Updated dependencies [b3e1220]
|
|
37
|
+
- Updated dependencies [b3e1220]
|
|
38
|
+
- Updated dependencies [5d1bde3]
|
|
39
|
+
- @unotest/protocol@0.33.0
|
|
40
|
+
- @unotest/dsl@0.33.0
|
|
41
|
+
|
|
3
42
|
## [0.32.0] - 2026-09-05
|
|
4
43
|
|
|
5
44
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -715,7 +715,7 @@ import {
|
|
|
715
715
|
writeFile as writeFile6
|
|
716
716
|
} from "fs/promises";
|
|
717
717
|
import { dirname as dirname3, join as join8 } from "path";
|
|
718
|
-
async function createExclusive(path, contents) {
|
|
718
|
+
async function createExclusive(path, contents, now) {
|
|
719
719
|
let handle;
|
|
720
720
|
try {
|
|
721
721
|
handle = await open2(path, "wx");
|
|
@@ -725,27 +725,33 @@ async function createExclusive(path, contents) {
|
|
|
725
725
|
}
|
|
726
726
|
try {
|
|
727
727
|
await handle.writeFile(contents, "utf8");
|
|
728
|
+
await handle.utimes(...stampOf(now));
|
|
728
729
|
} finally {
|
|
729
730
|
await handle.close();
|
|
730
731
|
}
|
|
731
732
|
return true;
|
|
732
733
|
}
|
|
733
734
|
__name(createExclusive, "createExclusive");
|
|
734
|
-
async function writeFileAtomic(path, contents, tmpToken) {
|
|
735
|
+
async function writeFileAtomic(path, contents, tmpToken, now) {
|
|
735
736
|
const tmp = join8(dirname3(path), `.tmp-${tmpToken}`);
|
|
736
737
|
await writeFile6(tmp, contents, "utf8");
|
|
738
|
+
await utimes2(tmp, ...stampOf(now));
|
|
737
739
|
await rename4(tmp, path);
|
|
738
740
|
}
|
|
739
741
|
__name(writeFileAtomic, "writeFileAtomic");
|
|
740
742
|
async function touchFile(path, now) {
|
|
741
|
-
const seconds = now / 1e3;
|
|
742
743
|
try {
|
|
743
|
-
await utimes2(path,
|
|
744
|
+
await utimes2(path, ...stampOf(now));
|
|
744
745
|
} catch (e) {
|
|
745
746
|
if (!isErrno(e, "ENOENT")) throw e;
|
|
746
747
|
}
|
|
747
748
|
}
|
|
748
749
|
__name(touchFile, "touchFile");
|
|
750
|
+
function stampOf(now) {
|
|
751
|
+
const seconds = now / 1e3;
|
|
752
|
+
return [seconds, seconds];
|
|
753
|
+
}
|
|
754
|
+
__name(stampOf, "stampOf");
|
|
749
755
|
async function fileAgeMs(path, now) {
|
|
750
756
|
try {
|
|
751
757
|
const s = await stat(path);
|
|
@@ -874,7 +880,8 @@ var SlotPool = class {
|
|
|
874
880
|
for (let n = 0; n < this.opts.total && taken.length < count; n++) {
|
|
875
881
|
await keepAlive?.();
|
|
876
882
|
const name = `${SLOT_PREFIX}${n}`;
|
|
877
|
-
|
|
883
|
+
const path = join9(this.opts.dir, name);
|
|
884
|
+
if (await createExclusive(path, body, this.opts.now())) {
|
|
878
885
|
taken.push(name);
|
|
879
886
|
}
|
|
880
887
|
}
|
|
@@ -915,7 +922,7 @@ var SlotPool = class {
|
|
|
915
922
|
});
|
|
916
923
|
const token = this.opts.token();
|
|
917
924
|
for (let attempt = 0; attempt < mutex.attempts; attempt++) {
|
|
918
|
-
if (await createExclusive(mutex.path, token)) {
|
|
925
|
+
if (await createExclusive(mutex.path, token, this.opts.now())) {
|
|
919
926
|
try {
|
|
920
927
|
return await body(() => touchFile(mutex.path, this.opts.now()));
|
|
921
928
|
} finally {
|
|
@@ -1049,7 +1056,8 @@ var FsRunQueue = class {
|
|
|
1049
1056
|
await writeFileAtomic(
|
|
1050
1057
|
join10(this.ticketsDir, name),
|
|
1051
1058
|
JSON.stringify(ticket),
|
|
1052
|
-
`${name}-${this.random()}
|
|
1059
|
+
`${name}-${this.random()}`,
|
|
1060
|
+
createdAt
|
|
1053
1061
|
);
|
|
1054
1062
|
} catch (e) {
|
|
1055
1063
|
throw new QueueUnavailableError(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unotest/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.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/
|
|
33
|
-
"@unotest/
|
|
32
|
+
"@unotest/dsl": "^0.33.0",
|
|
33
|
+
"@unotest/protocol": "^0.33.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^22.10.0",
|