@yemi33/minions 0.1.291 → 0.1.292
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 +4 -1
- package/engine/shared.js +37 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.292 (2026-04-03)
|
|
4
4
|
|
|
5
5
|
### Features
|
|
6
|
+
- harden shared.js — backup verification, lock TOCTOU, docs
|
|
6
7
|
- all doc-chats use Sonnet with full tools (agent change)
|
|
7
8
|
|
|
8
9
|
### Fixes
|
|
10
|
+
- add behavioral tests for CRITICAL propagation and stale lock ENOENT
|
|
11
|
+
- CRITICAL errors in safeJson now propagate to callers
|
|
9
12
|
- defer plan archiving until verify completes, add 20 verify tests
|
|
10
13
|
- enforce worktree isolation — 4 code paths fixed
|
|
11
14
|
- ' not 'Evaluate:'
|
package/engine/shared.js
CHANGED
|
@@ -52,14 +52,37 @@ function safeJson(p) {
|
|
|
52
52
|
const backupData = JSON.parse(fs.readFileSync(backupPath, 'utf8'));
|
|
53
53
|
// Backup is valid — restore it to the primary file (atomic via safeWrite)
|
|
54
54
|
console.log(`[safeJson] restored ${path.basename(p)} from .backup sidecar`);
|
|
55
|
-
try {
|
|
55
|
+
try {
|
|
56
|
+
safeWrite(p, backupData);
|
|
57
|
+
// Verify the restored file matches expected content
|
|
58
|
+
const verifyData = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
59
|
+
if (JSON.stringify(verifyData) !== JSON.stringify(backupData)) {
|
|
60
|
+
const errMsg = `[safeJson] CRITICAL: backup restore verification failed for ${p} — written data does not match backup`;
|
|
61
|
+
console.error(errMsg);
|
|
62
|
+
throw new Error(errMsg);
|
|
63
|
+
}
|
|
64
|
+
} catch (restoreErr) {
|
|
65
|
+
// Re-throw CRITICAL errors so they propagate to callers
|
|
66
|
+
if (restoreErr.message && restoreErr.message.includes('CRITICAL')) throw restoreErr;
|
|
67
|
+
const errMsg = `[safeJson] CRITICAL: backup restore failed for ${p}: ${restoreErr.message}`;
|
|
68
|
+
console.error(errMsg);
|
|
69
|
+
throw new Error(errMsg);
|
|
70
|
+
}
|
|
56
71
|
return backupData;
|
|
57
|
-
} catch {
|
|
72
|
+
} catch (outerErr) {
|
|
73
|
+
// Let CRITICAL errors propagate — callers must know about data integrity failures
|
|
74
|
+
if (outerErr.message && outerErr.message.includes('CRITICAL')) throw outerErr;
|
|
58
75
|
return null;
|
|
59
76
|
}
|
|
60
77
|
}
|
|
61
78
|
}
|
|
62
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Monotonic counter for generating unique temp file names within this process.
|
|
82
|
+
* Assumes single-thread execution (no worker_threads). If worker_threads are
|
|
83
|
+
* introduced, this must be replaced with an atomic or thread-safe counter to
|
|
84
|
+
* avoid temp file name collisions.
|
|
85
|
+
*/
|
|
63
86
|
let _tmpCounter = 0;
|
|
64
87
|
|
|
65
88
|
function safeWrite(p, data) {
|
|
@@ -129,10 +152,19 @@ function withFileLock(lockPath, fn, {
|
|
|
129
152
|
try {
|
|
130
153
|
const stat = fs.statSync(lockPath);
|
|
131
154
|
if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {
|
|
132
|
-
try {
|
|
133
|
-
|
|
155
|
+
try {
|
|
156
|
+
fs.unlinkSync(lockPath);
|
|
157
|
+
} catch (unlinkErr) {
|
|
158
|
+
// ENOENT: another process deleted the lock between stat and unlink — safe to retry
|
|
159
|
+
if (unlinkErr.code !== 'ENOENT') throw unlinkErr;
|
|
160
|
+
}
|
|
161
|
+
sleepMs(retryDelayMs); // avoid busy-loop on contention
|
|
162
|
+
continue;
|
|
134
163
|
}
|
|
135
|
-
} catch {
|
|
164
|
+
} catch (staleErr) {
|
|
165
|
+
// ENOENT from statSync: lock file disappeared between EEXIST and stat — retry will succeed
|
|
166
|
+
if (staleErr.code !== 'ENOENT') throw staleErr;
|
|
167
|
+
}
|
|
136
168
|
sleepMs(retryDelayMs);
|
|
137
169
|
}
|
|
138
170
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.292",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|