@lmzhen/dsh-evolution-core 0.1.0-rc.64 → 0.1.0-rc.65
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/lib/index.js +21 -5
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -55,9 +55,10 @@ function nodeEvolutionIo() {
|
|
|
55
55
|
/**
|
|
56
56
|
* Cross-process write lock (claw `withFileLock` parity): an O_EXCL lock file
|
|
57
57
|
* guards the atomic write; a >5s-old lock is treated as stale and taken
|
|
58
|
-
* over.
|
|
59
|
-
*
|
|
60
|
-
*
|
|
58
|
+
* over. A held lock that outlasts the retry budget fails LOUD instead of
|
|
59
|
+
* proceeding unlocked — two unlocked writers overlap their RMW and lose
|
|
60
|
+
* updates, which is exactly how the rc.65 CI-only 7≠8 occurred (a slow
|
|
61
|
+
* writer held the lock past the budget and a peer entered unlocked).
|
|
61
62
|
*/
|
|
62
63
|
const withWriteLock = async (path, task) => {
|
|
63
64
|
const lock = `${path}.lock`;
|
|
@@ -83,7 +84,7 @@ function nodeEvolutionIo() {
|
|
|
83
84
|
}
|
|
84
85
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
85
86
|
}
|
|
86
|
-
|
|
87
|
+
throw new Error(`could not acquire write lock for ${path} after 10 attempts`);
|
|
87
88
|
};
|
|
88
89
|
return {
|
|
89
90
|
async readText(path) {
|
|
@@ -257,6 +258,11 @@ async function loadUsage(root, io = nodeEvolutionIo()) {
|
|
|
257
258
|
*/
|
|
258
259
|
async function mutateUsage(root, io, task) {
|
|
259
260
|
await transactIo(io, usageFile(root), async (current) => {
|
|
261
|
+
if (current !== null) try {
|
|
262
|
+
JSON.parse(current);
|
|
263
|
+
} catch {
|
|
264
|
+
return current;
|
|
265
|
+
}
|
|
260
266
|
const map = parseUsage(current);
|
|
261
267
|
await task(map);
|
|
262
268
|
return JSON.stringify(Object.fromEntries(map.entries()), null, 2);
|
|
@@ -338,6 +344,11 @@ async function saveSuppressedNames(root, names, io = nodeEvolutionIo()) {
|
|
|
338
344
|
*/
|
|
339
345
|
async function updateSuppressedNames(root, io, task) {
|
|
340
346
|
await transactIo(io, suppressedFile(root), async (current) => {
|
|
347
|
+
if (current !== null) try {
|
|
348
|
+
JSON.parse(current);
|
|
349
|
+
} catch {
|
|
350
|
+
return current;
|
|
351
|
+
}
|
|
341
352
|
const names = parseSuppressed(current);
|
|
342
353
|
await task(names);
|
|
343
354
|
return JSON.stringify({
|
|
@@ -1703,7 +1714,12 @@ async function loadMutations(root, io = nodeEvolutionIo()) {
|
|
|
1703
1714
|
}
|
|
1704
1715
|
/** Append one record, trim to `cap`, and write atomically (versioned shape). */
|
|
1705
1716
|
async function recordMutation(root, io, record, cap = 500) {
|
|
1706
|
-
await transactIo(io, mutationsFile(root), (current) => {
|
|
1717
|
+
await transactIo(io, mutationsFile(root), async (current) => {
|
|
1718
|
+
if (current !== null) try {
|
|
1719
|
+
JSON.parse(current);
|
|
1720
|
+
} catch {
|
|
1721
|
+
return current;
|
|
1722
|
+
}
|
|
1707
1723
|
const existing = parseMutationRecords(current);
|
|
1708
1724
|
existing.push(record);
|
|
1709
1725
|
const trimmed = existing.length > cap ? existing.slice(existing.length - cap) : existing;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-core",
|
|
3
3
|
"description": "Shared stores, prompts, signals and lifecycle logic for the dsh-evolution plugin family (community build)",
|
|
4
|
-
"version": "0.1.0-rc.
|
|
4
|
+
"version": "0.1.0-rc.65",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|