pi-cohort 7.4.3 → 7.4.4
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 +6 -0
- package/package.json +1 -1
- package/src/shared/utils.ts +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [7.4.4] - 2026-10-22
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Async run status reads no longer serve a stale `running` state after an atomic `status.json` replacement that lands on the same mtime; the read cache now also compares inode and size.
|
|
7
|
+
- The Tests workflow passes on Windows again: CRLF, POSIX file-mode, ENOTDIR, and SIGUSR2 assumptions in tests are normalized or skipped on win32, and run-dir cleanup retries while detached runners finish writing.
|
|
8
|
+
|
|
3
9
|
## [7.4.3] - 2026-10-20
|
|
4
10
|
|
|
5
11
|
### Changed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cohort",
|
|
3
|
-
"version": "7.4.
|
|
3
|
+
"version": "7.4.4",
|
|
4
4
|
"description": "Delegate Pi work to focused child agents: code review, scouting, implementation, parallel audits, saved chains, and background jobs.",
|
|
5
5
|
"author": "Jacek Juraszek",
|
|
6
6
|
"license": "MIT",
|
package/src/shared/utils.ts
CHANGED
|
@@ -16,7 +16,9 @@ import type { AgentProgress, AsyncStatus, Details, DisplayItem, ErrorInfo, Singl
|
|
|
16
16
|
|
|
17
17
|
export { getAgentDir } from "./agent-dir.ts";
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// Keyed on inode too: writeAtomicJson renames a fresh file in, and a coarse
|
|
20
|
+
// filesystem clock can give the replacement the same mtime as the original.
|
|
21
|
+
const statusCache = new Map<string, { mtime: number; ino: number; size: number; status: AsyncStatus }>();
|
|
20
22
|
|
|
21
23
|
function getErrorMessage(error: unknown): string {
|
|
22
24
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -35,7 +37,7 @@ function isNotFoundError(error: unknown): boolean {
|
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
/**
|
|
38
|
-
* Read async job status from disk (with
|
|
40
|
+
* Read async job status from disk (with stat-based caching)
|
|
39
41
|
*/
|
|
40
42
|
export function readStatus(asyncDir: string): AsyncStatus | null {
|
|
41
43
|
const statusPath = path.join(asyncDir, "status.json");
|
|
@@ -51,7 +53,7 @@ export function readStatus(asyncDir: string): AsyncStatus | null {
|
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
const cached = statusCache.get(statusPath);
|
|
54
|
-
if (cached && cached.mtime === stat.mtimeMs) {
|
|
56
|
+
if (cached && cached.mtime === stat.mtimeMs && cached.ino === stat.ino && cached.size === stat.size) {
|
|
55
57
|
return cached.status;
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -74,7 +76,7 @@ export function readStatus(asyncDir: string): AsyncStatus | null {
|
|
|
74
76
|
});
|
|
75
77
|
}
|
|
76
78
|
|
|
77
|
-
statusCache.set(statusPath, { mtime: stat.mtimeMs, status });
|
|
79
|
+
statusCache.set(statusPath, { mtime: stat.mtimeMs, ino: stat.ino, size: stat.size, status });
|
|
78
80
|
if (statusCache.size > 50) {
|
|
79
81
|
const firstKey = statusCache.keys().next().value;
|
|
80
82
|
if (firstKey) statusCache.delete(firstKey);
|