@lmzhen/dsh-evolution-state-json 0.3.16 → 0.3.18
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 +58 -17
- package/package.json +5 -5
package/lib/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import z from "@deepseek-ai/schemastery";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
|
+
import { CLAIM_EXPIRY_MS, canClaimPending, canResolvePending, releasedStatus } from "@lmzhen/dsh-evolution-state-storage";
|
|
5
6
|
//#region ../evolution-core/src/io.ts
|
|
6
7
|
/**
|
|
7
8
|
* Run `task` inside `io.transact` when the backend provides it; otherwise fall
|
|
@@ -301,6 +302,24 @@ createPromptBundle({
|
|
|
301
302
|
const FILLER = String.raw`(?:\w+\s+){0,8}`;
|
|
302
303
|
new RegExp(String.raw`ignore\s+${FILLER}(?:previous|above|prior|all)\s+${FILLER}instructions`, "i"), new RegExp(String.raw`new\s+${FILLER}system\s+${FILLER}prompt`, "i"), new RegExp(String.raw`forget\s+${FILLER}(?:everything|all)\s+${FILLER}(?:discussed|you\s+know)`, "i"), new RegExp(String.raw`you\s+have\s+been\s+${FILLER}(?:updated|upgraded|patched)\s+to`, "i"), new RegExp(String.raw`do\s+not\s+${FILLER}tell\s+${FILLER}the\s+user`, "i"), new RegExp(String.raw`output\s+${FILLER}(?:system|initial)\s+prompt`, "i");
|
|
303
304
|
//#endregion
|
|
305
|
+
//#region ../evolution-core/src/serial.ts
|
|
306
|
+
/**
|
|
307
|
+
* A process-local serial task queue: each task starts only after the previous
|
|
308
|
+
* one settles (success or failure), so read-modify-write sequences that share
|
|
309
|
+
* one file never interleave inside this process. The durable cross-process
|
|
310
|
+
* serialization layer is the IO backend's transact lock; this chain is the
|
|
311
|
+
* second layer (0.3.17 S2.8, T-1: the shape was duplicated in state-json and
|
|
312
|
+
* memory-files — one factory now).
|
|
313
|
+
*/
|
|
314
|
+
function makeSerialQueue() {
|
|
315
|
+
let chain = Promise.resolve();
|
|
316
|
+
return (task) => {
|
|
317
|
+
const run = chain.then(task, task);
|
|
318
|
+
chain = run.then(() => void 0, () => void 0);
|
|
319
|
+
return run;
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
304
323
|
//#region ../../../node_modules/.pnpm/js-yaml@4.2.0/node_modules/js-yaml/dist/js-yaml.mjs
|
|
305
324
|
/*! js-yaml 4.2.0 https://github.com/nodeca/js-yaml @license MIT */
|
|
306
325
|
var __create = Object.create;
|
|
@@ -2648,13 +2667,24 @@ function apply(ctx, rawConfig) {
|
|
|
2648
2667
|
const root = rawConfig.root || defaultRoot();
|
|
2649
2668
|
const io = () => ctx.evolutionIo.provider();
|
|
2650
2669
|
const pathOf = (file) => join(root, file);
|
|
2670
|
+
/** 0.3.17 (E-9): a malformed state file used to parse to `null` and was then
|
|
2671
|
+
* OVERWRITTEN by the next save — every other session's review state / the
|
|
2672
|
+
* whole pending table vanished silently. Fail loud instead: preserve the
|
|
2673
|
+
* original bytes beside it and throw, so the operator can rescue and the
|
|
2674
|
+
* corruption is never accepted as "empty". */
|
|
2675
|
+
async function quarantine(file, raw, reason) {
|
|
2676
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2677
|
+
const dest = `${pathOf(file)}.corrupt-${stamp}-${Math.random().toString(36).slice(2, 6)}`;
|
|
2678
|
+
await io().writeText(dest, raw).catch(() => {});
|
|
2679
|
+
throw new Error(`evolution state file "${file}" is not valid JSON (${reason}); original preserved at ${dest} — inspect and fix it, then retry.`);
|
|
2680
|
+
}
|
|
2651
2681
|
async function readJson(file) {
|
|
2652
2682
|
const raw = await io().readText(pathOf(file));
|
|
2653
2683
|
if (raw === null) return null;
|
|
2654
2684
|
try {
|
|
2655
2685
|
return JSON.parse(raw);
|
|
2656
|
-
} catch {
|
|
2657
|
-
return
|
|
2686
|
+
} catch (error) {
|
|
2687
|
+
return await quarantine(file, raw, error instanceof Error ? error.message : String(error));
|
|
2658
2688
|
}
|
|
2659
2689
|
}
|
|
2660
2690
|
/**
|
|
@@ -2669,19 +2699,14 @@ function apply(ctx, rawConfig) {
|
|
|
2669
2699
|
let parsed = null;
|
|
2670
2700
|
if (current !== null) try {
|
|
2671
2701
|
parsed = JSON.parse(current);
|
|
2672
|
-
} catch {
|
|
2673
|
-
|
|
2702
|
+
} catch (error) {
|
|
2703
|
+
return await quarantine(file, current, error instanceof Error ? error.message : String(error));
|
|
2674
2704
|
}
|
|
2675
2705
|
const next = await task(parsed);
|
|
2676
2706
|
return next === null ? null : JSON.stringify(next, null, 2);
|
|
2677
2707
|
});
|
|
2678
2708
|
}
|
|
2679
|
-
|
|
2680
|
-
function mutate(task) {
|
|
2681
|
-
const run = chain.then(task, task);
|
|
2682
|
-
chain = run.then(() => void 0, () => void 0);
|
|
2683
|
-
return run;
|
|
2684
|
-
}
|
|
2709
|
+
const mutate = makeSerialQueue();
|
|
2685
2710
|
async function loadPendingMap() {
|
|
2686
2711
|
const [current, legacy] = await Promise.all([readJson("pending-state.json"), readJson("pending.json")]);
|
|
2687
2712
|
return {
|
|
@@ -2717,6 +2742,21 @@ function apply(ctx, rawConfig) {
|
|
|
2717
2742
|
}));
|
|
2718
2743
|
});
|
|
2719
2744
|
},
|
|
2745
|
+
async transactCuratorState(task) {
|
|
2746
|
+
await mutate(async () => {
|
|
2747
|
+
await jsonTransact("curator-state.json", (current) => {
|
|
2748
|
+
const next = task(current?.primary ?? null);
|
|
2749
|
+
if (next === null) {
|
|
2750
|
+
if (current !== null) delete current.primary;
|
|
2751
|
+
return current ?? {};
|
|
2752
|
+
}
|
|
2753
|
+
return {
|
|
2754
|
+
...current ?? {},
|
|
2755
|
+
primary: next
|
|
2756
|
+
};
|
|
2757
|
+
});
|
|
2758
|
+
});
|
|
2759
|
+
},
|
|
2720
2760
|
async listPending(status = "pending") {
|
|
2721
2761
|
return await mutate(async () => {
|
|
2722
2762
|
const map = await loadPendingMap();
|
|
@@ -2743,12 +2783,13 @@ function apply(ctx, rawConfig) {
|
|
|
2743
2783
|
...current ?? {}
|
|
2744
2784
|
};
|
|
2745
2785
|
const record = map[id] ?? null;
|
|
2746
|
-
if (record === null || record.status
|
|
2786
|
+
if (record === null || !canClaimPending(record.status)) return map;
|
|
2747
2787
|
const now = Date.now();
|
|
2748
2788
|
const claimedAt = typeof record.claimedAt === "string" ? Date.parse(record.claimedAt) : 0;
|
|
2749
|
-
if (record.claimedBy !== void 0 && Number.isFinite(claimedAt) && now - claimedAt <
|
|
2789
|
+
if (record.claimedBy !== void 0 && Number.isFinite(claimedAt) && now - claimedAt < CLAIM_EXPIRY_MS) return map;
|
|
2750
2790
|
slot.claimed = {
|
|
2751
2791
|
...record,
|
|
2792
|
+
status: "executing",
|
|
2752
2793
|
claimedBy: claimId,
|
|
2753
2794
|
claimedAt: new Date(now).toISOString()
|
|
2754
2795
|
};
|
|
@@ -2766,10 +2807,10 @@ function apply(ctx, rawConfig) {
|
|
|
2766
2807
|
...current ?? {}
|
|
2767
2808
|
};
|
|
2768
2809
|
const record = map[id];
|
|
2769
|
-
if (record
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2810
|
+
if (!record || record.claimedBy !== claimId) return map;
|
|
2811
|
+
record.status = releasedStatus(record.status);
|
|
2812
|
+
delete record.claimedBy;
|
|
2813
|
+
delete record.claimedAt;
|
|
2773
2814
|
return map;
|
|
2774
2815
|
});
|
|
2775
2816
|
});
|
|
@@ -2786,7 +2827,7 @@ function apply(ctx, rawConfig) {
|
|
|
2786
2827
|
...current ?? {}
|
|
2787
2828
|
};
|
|
2788
2829
|
const record = map[id] ?? null;
|
|
2789
|
-
if (record === null || record.status
|
|
2830
|
+
if (record === null || !canResolvePending(record.status)) {
|
|
2790
2831
|
result = {
|
|
2791
2832
|
record,
|
|
2792
2833
|
applied: false
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-state-json",
|
|
3
3
|
"description": "JSON-file evolution state provider over the IO seam (community build)",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.18",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
39
39
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
40
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
41
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.3.
|
|
40
|
+
"@lmzhen/dsh-evolution-io": "^0.3.18",
|
|
41
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.3.18"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
45
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
46
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.3.
|
|
45
|
+
"@lmzhen/dsh-evolution-io": "^0.3.18",
|
|
46
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.3.18"
|
|
47
47
|
}
|
|
48
48
|
}
|