pi-fabric 0.82.4 → 0.82.5
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/dist/chunks/{chunk-P2DSRJQX.js → chunk-65QIOGTE.js} +2 -2
- package/dist/chunks/chunk-7363CD5A.js +38 -0
- package/dist/chunks/chunk-7363CD5A.js.map +7 -0
- package/dist/chunks/{chunk-2YCOXT4W.js → chunk-77FQHHZD.js} +2 -2
- package/dist/chunks/{chunk-FRHBI5QB.js → chunk-AIVWFEAN.js} +2 -2
- package/dist/chunks/{chunk-WASXKJAD.js → chunk-D6BNJP5M.js} +3 -3
- package/dist/chunks/{chunk-QJF6UH3U.js → chunk-IFBBLV7Y.js} +157 -5
- package/dist/chunks/chunk-IFBBLV7Y.js.map +7 -0
- package/dist/chunks/{chunk-3SGRTVFP.js → chunk-KAD7UWT2.js} +41 -2
- package/dist/chunks/{chunk-3SGRTVFP.js.map → chunk-KAD7UWT2.js.map} +2 -2
- package/dist/chunks/{chunk-XE54YPXQ.js → chunk-ODO6COKA.js} +778 -175
- package/dist/chunks/chunk-ODO6COKA.js.map +7 -0
- package/dist/chunks/{chunk-V3YMC3QH.js → chunk-QPS3X45K.js} +3 -3
- package/dist/chunks/{chunk-QP6VA6AF.js → chunk-ROIKKEUN.js} +2 -2
- package/dist/chunks/{chunk-JNACUKKJ.js → chunk-SL5QT2BU.js} +80 -3
- package/dist/chunks/chunk-SL5QT2BU.js.map +7 -0
- package/dist/chunks/{chunk-J5YYORXB.js → chunk-XWBQGXWG.js} +4 -4
- package/dist/commands/fabric.d.ts.map +1 -1
- package/dist/core/action-registry.js +4 -4
- package/dist/core/atomic-write.d.ts +1 -0
- package/dist/core/atomic-write.d.ts.map +1 -1
- package/dist/core/file-lock.d.ts +1 -0
- package/dist/core/file-lock.d.ts.map +1 -1
- package/dist/core/stable-hash.d.ts +1 -0
- package/dist/core/stable-hash.d.ts.map +1 -1
- package/dist/entropy/compiled-store.d.ts +2 -0
- package/dist/entropy/compiled-store.d.ts.map +1 -1
- package/dist/entropy/compiled-surface.d.ts +2 -0
- package/dist/entropy/compiled-surface.d.ts.map +1 -1
- package/dist/entropy/compiler.d.ts +1 -0
- package/dist/entropy/compiler.d.ts.map +1 -1
- package/dist/entropy/corpus.d.ts +6 -0
- package/dist/entropy/corpus.d.ts.map +1 -1
- package/dist/entropy/index.d.ts +1 -0
- package/dist/entropy/index.d.ts.map +1 -1
- package/dist/entropy/index.js +44 -6
- package/dist/entropy/meter.d.ts +1 -0
- package/dist/entropy/meter.d.ts.map +1 -1
- package/dist/entropy/pool-store.d.ts +2 -0
- package/dist/entropy/pool-store.d.ts.map +1 -1
- package/dist/entropy/pool.d.ts +1 -0
- package/dist/entropy/pool.d.ts.map +1 -1
- package/dist/entropy/presentation.d.ts +12 -0
- package/dist/entropy/presentation.d.ts.map +1 -0
- package/dist/entropy/sessions.d.ts +8 -0
- package/dist/entropy/sessions.d.ts.map +1 -1
- package/dist/fabric-runtime-state.d.ts.map +1 -1
- package/dist/fabric-runtime-state.js +83 -35
- package/dist/fabric-runtime-state.js.map +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +165 -104
- package/dist/index.js.map +2 -2
- package/dist/protocol.js +2 -2
- package/dist/repairs/compiler.d.ts +1 -0
- package/dist/repairs/compiler.d.ts.map +1 -1
- package/dist/repairs/store.d.ts +1 -0
- package/dist/repairs/store.d.ts.map +1 -1
- package/dist/residency/actor-client.js +2 -2
- package/dist/residency/host.js +6 -6
- package/dist/residency/pi-entry.js +6 -6
- package/dist/speculation/scanner.js +1 -1
- package/dist/ui/settings.js +2 -2
- package/docs/entropy.md +49 -25
- package/docs/repairs.md +11 -1
- package/package.json +1 -1
- package/dist/chunks/chunk-CIJPRYAP.js +0 -16
- package/dist/chunks/chunk-CIJPRYAP.js.map +0 -7
- package/dist/chunks/chunk-JNACUKKJ.js.map +0 -7
- package/dist/chunks/chunk-QJF6UH3U.js.map +0 -7
- package/dist/chunks/chunk-XE54YPXQ.js.map +0 -7
- /package/dist/chunks/{chunk-P2DSRJQX.js.map → chunk-65QIOGTE.js.map} +0 -0
- /package/dist/chunks/{chunk-2YCOXT4W.js.map → chunk-77FQHHZD.js.map} +0 -0
- /package/dist/chunks/{chunk-FRHBI5QB.js.map → chunk-AIVWFEAN.js.map} +0 -0
- /package/dist/chunks/{chunk-WASXKJAD.js.map → chunk-D6BNJP5M.js.map} +0 -0
- /package/dist/chunks/{chunk-V3YMC3QH.js.map → chunk-QPS3X45K.js.map} +0 -0
- /package/dist/chunks/{chunk-QP6VA6AF.js.map → chunk-ROIKKEUN.js.map} +0 -0
- /package/dist/chunks/{chunk-J5YYORXB.js.map → chunk-XWBQGXWG.js.map} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-VMSGYKJS.js";
|
|
7
7
|
import {
|
|
8
8
|
renameAtomic
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KAD7UWT2.js";
|
|
10
10
|
import {
|
|
11
11
|
PI_CORE_TOOL_NAME_SET
|
|
12
12
|
} from "./chunk-YU62DDKK.js";
|
|
@@ -1206,4 +1206,4 @@ export {
|
|
|
1206
1206
|
loadFabricConfig,
|
|
1207
1207
|
saveFabricConfig
|
|
1208
1208
|
};
|
|
1209
|
-
//# sourceMappingURL=chunk-
|
|
1209
|
+
//# sourceMappingURL=chunk-65QIOGTE.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/core/stable-hash.ts
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
var stableJsonValue = (value) => {
|
|
4
|
+
if (Array.isArray(value)) return value.map(stableJsonValue);
|
|
5
|
+
if (value instanceof URL) return value.href;
|
|
6
|
+
if (value === null || typeof value !== "object") return value;
|
|
7
|
+
return Object.fromEntries(
|
|
8
|
+
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, stableJsonValue(nested)])
|
|
9
|
+
);
|
|
10
|
+
};
|
|
11
|
+
var stableJsonHash = (value) => createHash("sha256").update(JSON.stringify(stableJsonValue(value))).digest("hex");
|
|
12
|
+
var STABLE_HASH_ARRAY_CHUNK = 64;
|
|
13
|
+
var stableJsonHashArrayAsync = async (values) => {
|
|
14
|
+
const hash = createHash("sha256");
|
|
15
|
+
hash.update("[");
|
|
16
|
+
let first = true;
|
|
17
|
+
let batch = [];
|
|
18
|
+
const flush = async () => {
|
|
19
|
+
if (batch.length === 0) return;
|
|
20
|
+
hash.update(`${first ? "" : ","}${batch.join(",")}`);
|
|
21
|
+
first = false;
|
|
22
|
+
batch = [];
|
|
23
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
24
|
+
};
|
|
25
|
+
for (const value of values) {
|
|
26
|
+
batch.push(JSON.stringify(stableJsonValue(value)) ?? "null");
|
|
27
|
+
if (batch.length >= STABLE_HASH_ARRAY_CHUNK) await flush();
|
|
28
|
+
}
|
|
29
|
+
if (batch.length > 0) hash.update(`${first ? "" : ","}${batch.join(",")}`);
|
|
30
|
+
hash.update("]");
|
|
31
|
+
return hash.digest("hex");
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
stableJsonHash,
|
|
36
|
+
stableJsonHashArrayAsync
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=chunk-7363CD5A.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/core/stable-hash.ts"],
|
|
4
|
+
"sourcesContent": ["import { createHash } from \"node:crypto\";\n\n// Deterministic JSON shaping for hashing: object keys sort recursively so\n// equivalent values hash identically regardless of key insertion order. URL\n// instances hash by href \u2014 they expose no enumerable own properties, so\n// untreated they would all collapse to \"{}\" (MCP server definitions carry\n// `URL` instances for HTTP transports).\nconst stableJsonValue = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(stableJsonValue);\n if (value instanceof URL) return value.href;\n if (value === null || typeof value !== \"object\") return value;\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, stableJsonValue(nested)]),\n );\n};\n\nexport const stableJsonHash = (value: unknown): string =>\n createHash(\"sha256\").update(JSON.stringify(stableJsonValue(value))).digest(\"hex\");\nconst STABLE_HASH_ARRAY_CHUNK = 64;\n\n// Cooperative canonical hashing for large evidence arrays. Each element is\n// normalized by the same pure shaper as stableJsonHash; fixed 64-record chunks\n// keep extension hooks responsive without changing a byte of hash input.\nexport const stableJsonHashArrayAsync = async (\n values: readonly unknown[],\n): Promise<string> => {\n const hash = createHash(\"sha256\");\n hash.update(\"[\");\n let first = true;\n let batch: string[] = [];\n const flush = async (): Promise<void> => {\n if (batch.length === 0) return;\n hash.update(`${first ? \"\" : \",\"}${batch.join(\",\")}`);\n first = false;\n batch = [];\n await new Promise((resolve) => setImmediate(resolve));\n };\n for (const value of values) {\n // JSON.stringify renders undefined array entries as null.\n batch.push(JSON.stringify(stableJsonValue(value)) ?? \"null\");\n if (batch.length >= STABLE_HASH_ARRAY_CHUNK) await flush();\n }\n if (batch.length > 0) hash.update(`${first ? \"\" : \",\"}${batch.join(\",\")}`);\n hash.update(\"]\");\n return hash.digest(\"hex\");\n};\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,kBAAkB;AAO3B,IAAM,kBAAkB,CAAC,UAA4B;AACnD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,eAAe;AAC1D,MAAI,iBAAiB,IAAK,QAAO,MAAM;AACvC,MAAI,UAAU,QAAQ,OAAO,UAAU,SAAU,QAAO;AACxD,SAAO,OAAO;AAAA,IACZ,OAAO,QAAQ,KAAgC,EAC5C,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,MAAM,KAAK,cAAc,KAAK,CAAC,EACnD,IAAI,CAAC,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK,gBAAgB,MAAM,CAAC,CAAC;AAAA,EAC1D;AACF;AAEO,IAAM,iBAAiB,CAAC,UAC7B,WAAW,QAAQ,EAAE,OAAO,KAAK,UAAU,gBAAgB,KAAK,CAAC,CAAC,EAAE,OAAO,KAAK;AAClF,IAAM,0BAA0B;AAKzB,IAAM,2BAA2B,OACtC,WACoB;AACpB,QAAM,OAAO,WAAW,QAAQ;AAChC,OAAK,OAAO,GAAG;AACf,MAAI,QAAQ;AACZ,MAAI,QAAkB,CAAC;AACvB,QAAM,QAAQ,YAA2B;AACvC,QAAI,MAAM,WAAW,EAAG;AACxB,SAAK,OAAO,GAAG,QAAQ,KAAK,GAAG,GAAG,MAAM,KAAK,GAAG,CAAC,EAAE;AACnD,YAAQ;AACR,YAAQ,CAAC;AACT,UAAM,IAAI,QAAQ,CAAC,YAAY,aAAa,OAAO,CAAC;AAAA,EACtD;AACA,aAAW,SAAS,QAAQ;AAE1B,UAAM,KAAK,KAAK,UAAU,gBAAgB,KAAK,CAAC,KAAK,MAAM;AAC3D,QAAI,MAAM,UAAU,wBAAyB,OAAM,MAAM;AAAA,EAC3D;AACA,MAAI,MAAM,SAAS,EAAG,MAAK,OAAO,GAAG,QAAQ,KAAK,GAAG,GAAG,MAAM,KAAK,GAAG,CAAC,EAAE;AACzE,OAAK,OAAO,GAAG;AACf,SAAO,KAAK,OAAO,KAAK;AAC1B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
stableJsonHash
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7363CD5A.js";
|
|
4
4
|
|
|
5
5
|
// src/components/model-guidance.ts
|
|
6
6
|
var FABRIC_EXECUTION_GUIDANCE_SLOT = "fabric.execution";
|
|
@@ -228,4 +228,4 @@ export {
|
|
|
228
228
|
fabricModelGuidanceInfo,
|
|
229
229
|
resolveFabricModelGuidance
|
|
230
230
|
};
|
|
231
|
-
//# sourceMappingURL=chunk-
|
|
231
|
+
//# sourceMappingURL=chunk-77FQHHZD.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-X2MKXKDA.js";
|
|
5
5
|
import {
|
|
6
6
|
writeJsonAtomic
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KAD7UWT2.js";
|
|
8
8
|
|
|
9
9
|
// src/residency/actor-client.ts
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
@@ -84,4 +84,4 @@ var ResidentActorClient = class _ResidentActorClient {
|
|
|
84
84
|
export {
|
|
85
85
|
ResidentActorClient
|
|
86
86
|
};
|
|
87
|
-
//# sourceMappingURL=chunk-
|
|
87
|
+
//# sourceMappingURL=chunk-AIVWFEAN.js.map
|
|
@@ -9,13 +9,13 @@ import {
|
|
|
9
9
|
effectiveSchemaFor,
|
|
10
10
|
isQuarantinedRef,
|
|
11
11
|
quarantinedRefNames
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SL5QT2BU.js";
|
|
13
13
|
import {
|
|
14
14
|
FABRIC_NESTED_TOOL_CALL_ID_PREFIX
|
|
15
15
|
} from "./chunk-HDKEA77S.js";
|
|
16
16
|
import {
|
|
17
17
|
stableJsonHash
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-7363CD5A.js";
|
|
19
19
|
import {
|
|
20
20
|
FabricResolutionError,
|
|
21
21
|
FabricTraceSafeError,
|
|
@@ -1590,4 +1590,4 @@ export {
|
|
|
1590
1590
|
NESTED_TOOL_CALL_ID_PREFIX,
|
|
1591
1591
|
ActionRegistry
|
|
1592
1592
|
};
|
|
1593
|
-
//# sourceMappingURL=chunk-
|
|
1593
|
+
//# sourceMappingURL=chunk-D6BNJP5M.js.map
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
COMPILED_SURFACE_VERSION,
|
|
3
3
|
MAX_COMPILED_SURFACE_PROPOSALS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SL5QT2BU.js";
|
|
5
5
|
import {
|
|
6
|
-
writeJsonAtomic
|
|
7
|
-
|
|
6
|
+
writeJsonAtomic,
|
|
7
|
+
writeJsonAtomicAsync
|
|
8
|
+
} from "./chunk-KAD7UWT2.js";
|
|
8
9
|
|
|
9
10
|
// src/entropy/compiled-store.ts
|
|
10
11
|
import fs2 from "node:fs";
|
|
@@ -37,6 +38,106 @@ var processAlive = (pid) => {
|
|
|
37
38
|
return false;
|
|
38
39
|
}
|
|
39
40
|
};
|
|
41
|
+
var sleepAsync = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
42
|
+
var reapStaleLockAsync = async (lock, verify) => {
|
|
43
|
+
const claim = `${lock}.reap-${process.pid}-${randomUUID()}`;
|
|
44
|
+
try {
|
|
45
|
+
await fs.promises.rename(lock, claim);
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (!await verify(claim)) {
|
|
50
|
+
try {
|
|
51
|
+
await fs.promises.rename(claim, lock);
|
|
52
|
+
} catch {
|
|
53
|
+
if (await verify(claim)) {
|
|
54
|
+
await fs.promises.rm(claim, { recursive: true, force: true });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
await fs.promises.rm(claim, { recursive: true, force: true });
|
|
60
|
+
return true;
|
|
61
|
+
};
|
|
62
|
+
var withExclusiveFileLockAsync = async (options, operation) => {
|
|
63
|
+
const attempts = options.attempts ?? DEFAULT_LOCK_ATTEMPTS;
|
|
64
|
+
const delayMs = options.delayMs ?? DEFAULT_LOCK_DELAY_MS;
|
|
65
|
+
const staleMs = options.staleMs ?? DEFAULT_STALE_LOCK_MS;
|
|
66
|
+
await fs.promises.mkdir(options.directory, { recursive: true, mode: 448 });
|
|
67
|
+
const lock = path.join(options.directory, options.lockName);
|
|
68
|
+
const ownerPath = path.join(lock, "owner");
|
|
69
|
+
const token = randomUUID();
|
|
70
|
+
let acquired = false;
|
|
71
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
72
|
+
try {
|
|
73
|
+
await fs.promises.mkdir(lock, { mode: 448 });
|
|
74
|
+
try {
|
|
75
|
+
await fs.promises.writeFile(ownerPath, `${token}
|
|
76
|
+
${process.pid}
|
|
77
|
+
${Date.now()}
|
|
78
|
+
`, {
|
|
79
|
+
encoding: "utf-8",
|
|
80
|
+
mode: 384
|
|
81
|
+
});
|
|
82
|
+
} catch (error) {
|
|
83
|
+
await fs.promises.rm(lock, { recursive: true, force: true });
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
acquired = true;
|
|
87
|
+
break;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (errorCode(error) !== "EEXIST") throw error;
|
|
90
|
+
try {
|
|
91
|
+
const firstOwner = await fs.promises.readFile(ownerPath, "utf8");
|
|
92
|
+
const [, pidText, createdText] = firstOwner.trim().split("\n");
|
|
93
|
+
const stale = Date.now() - Number(createdText) > staleMs;
|
|
94
|
+
if (stale && !processAlive(Number(pidText))) {
|
|
95
|
+
const secondOwner = await fs.promises.readFile(ownerPath, "utf8");
|
|
96
|
+
if (secondOwner === firstOwner && await reapStaleLockAsync(lock, async (claimed) => {
|
|
97
|
+
try {
|
|
98
|
+
const owner = await fs.promises.readFile(path.join(claimed, "owner"), "utf8");
|
|
99
|
+
const [, pid, created] = owner.trim().split("\n");
|
|
100
|
+
return Date.now() - Number(created) > staleMs && !processAlive(Number(pid));
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
})) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
try {
|
|
110
|
+
const first = await fs.promises.stat(lock);
|
|
111
|
+
if (Date.now() - first.mtimeMs > staleMs && await reapStaleLockAsync(lock, async (claimed) => {
|
|
112
|
+
try {
|
|
113
|
+
return Date.now() - (await fs.promises.stat(claimed)).mtimeMs > staleMs;
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
})) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (attempt === attempts - 1) break;
|
|
124
|
+
await sleepAsync(delayMs);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (!acquired) throw new Error(options.timeoutMessage);
|
|
128
|
+
try {
|
|
129
|
+
return await operation();
|
|
130
|
+
} finally {
|
|
131
|
+
try {
|
|
132
|
+
const owner = await fs.promises.readFile(ownerPath, "utf8");
|
|
133
|
+
if (owner.startsWith(`${token}
|
|
134
|
+
`)) {
|
|
135
|
+
await fs.promises.rm(lock, { recursive: true, force: true });
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
40
141
|
var reapStaleLock = (lock, verify) => {
|
|
41
142
|
const claim = `${lock}.reap-${process.pid}-${randomUUID()}`;
|
|
42
143
|
try {
|
|
@@ -241,6 +342,24 @@ var loadCompiledSurface = (agentDir) => {
|
|
|
241
342
|
if (!parsedFile) return { error: "compiled surface is invalid" };
|
|
242
343
|
return { file: parsedFile };
|
|
243
344
|
};
|
|
345
|
+
var loadCompiledSurfaceAsync = async (agentDir) => {
|
|
346
|
+
const file = compiledPath(compiledSurfaceDirectory(agentDir));
|
|
347
|
+
let raw;
|
|
348
|
+
try {
|
|
349
|
+
raw = await fs2.promises.readFile(file, "utf8");
|
|
350
|
+
} catch (error) {
|
|
351
|
+
if (errorCode2(error) === "ENOENT") return {};
|
|
352
|
+
return { error: `compiled surface is unreadable: ${errorText(error)}` };
|
|
353
|
+
}
|
|
354
|
+
let parsed;
|
|
355
|
+
try {
|
|
356
|
+
parsed = JSON.parse(raw);
|
|
357
|
+
} catch {
|
|
358
|
+
return { error: "compiled surface is malformed JSON" };
|
|
359
|
+
}
|
|
360
|
+
const parsedFile = parseCompiledSurfaceFile(parsed);
|
|
361
|
+
return parsedFile ? { file: parsedFile } : { error: "compiled surface is invalid" };
|
|
362
|
+
};
|
|
244
363
|
var saveCompiledSurface = (agentDir, file) => withExclusiveFileLock(
|
|
245
364
|
{
|
|
246
365
|
directory: compiledSurfaceDirectory(agentDir),
|
|
@@ -264,12 +383,45 @@ var saveCompiledSurface = (agentDir, file) => withExclusiveFileLock(
|
|
|
264
383
|
return { file, written: true };
|
|
265
384
|
}
|
|
266
385
|
);
|
|
386
|
+
var saveCompiledSurfaceAsync = async (agentDir, file) => withExclusiveFileLockAsync(
|
|
387
|
+
{
|
|
388
|
+
directory: compiledSurfaceDirectory(agentDir),
|
|
389
|
+
lockName: "compiled.lock",
|
|
390
|
+
timeoutMessage: "Timed out waiting for the compiled entropy surface lock",
|
|
391
|
+
attempts: COMPILED_LOCK_ATTEMPTS,
|
|
392
|
+
delayMs: COMPILED_LOCK_DELAY_MS,
|
|
393
|
+
staleMs: COMPILED_STALE_LOCK_MS
|
|
394
|
+
},
|
|
395
|
+
async () => {
|
|
396
|
+
const loaded = await loadCompiledSurfaceAsync(agentDir);
|
|
397
|
+
if (loaded.error) throw new Error(loaded.error);
|
|
398
|
+
const target = compiledPath(compiledSurfaceDirectory(agentDir));
|
|
399
|
+
const serialized = `${JSON.stringify(file, null, 2)}
|
|
400
|
+
`;
|
|
401
|
+
try {
|
|
402
|
+
if (await fs2.promises.readFile(target, "utf8") === serialized) {
|
|
403
|
+
return { file, written: false };
|
|
404
|
+
}
|
|
405
|
+
} catch {
|
|
406
|
+
}
|
|
407
|
+
await writeJsonAtomicAsync(target, file, {
|
|
408
|
+
space: 2,
|
|
409
|
+
newline: true,
|
|
410
|
+
mode: 384,
|
|
411
|
+
dirMode: 448
|
|
412
|
+
});
|
|
413
|
+
return { file, written: true };
|
|
414
|
+
}
|
|
415
|
+
);
|
|
267
416
|
|
|
268
417
|
export {
|
|
418
|
+
withExclusiveFileLockAsync,
|
|
269
419
|
withExclusiveFileLock,
|
|
270
420
|
compiledSurfaceDirectory,
|
|
271
421
|
parseCompiledSurfaceArtifact,
|
|
272
422
|
loadCompiledSurface,
|
|
273
|
-
|
|
423
|
+
loadCompiledSurfaceAsync,
|
|
424
|
+
saveCompiledSurface,
|
|
425
|
+
saveCompiledSurfaceAsync
|
|
274
426
|
};
|
|
275
|
-
//# sourceMappingURL=chunk-
|
|
427
|
+
//# sourceMappingURL=chunk-IFBBLV7Y.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/entropy/compiled-store.ts", "../../src/core/file-lock.ts"],
|
|
4
|
+
"sourcesContent": ["// Persistence for the compiled entropy surface: <agent dir>/fabric/entropy/\n// compiled.json, locked across Pi processes sharing the agent directory.\n// A damaged artifact surfaces as an error and blocks compiles from\n// overwriting it \u2014 the same discipline as the repair table. The artifact is\n// clock-free, so saving byte-identical content is a no-op.\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { writeJsonAtomic, writeJsonAtomicAsync } from \"../core/atomic-write.js\";\nimport { withExclusiveFileLock, withExclusiveFileLockAsync } from \"../core/file-lock.js\";\nimport {\n COMPILED_SURFACE_VERSION,\n MAX_COMPILED_SURFACE_PROPOSALS,\n type CompiledSurfaceAppliedProposal,\n type CompiledSurfaceFile,\n type CompiledSurfaceGateRecord,\n type CompiledSurfaceOverlayEntry,\n type CompiledSurfaceQuarantineEntry,\n} from \"./compiled-surface.js\";\n\nconst COMPILED_LOCK_ATTEMPTS = 50;\nconst COMPILED_LOCK_DELAY_MS = 5;\nconst COMPILED_STALE_LOCK_MS = 30_000;\n\nexport const compiledSurfaceDirectory = (agentDir: string): string =>\n path.join(agentDir, \"fabric\", \"entropy\");\n\nconst compiledPath = (directory: string): string => path.join(directory, \"compiled.json\");\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst errorCode = (error: unknown): string | undefined =>\n isRecord(error) && typeof error.code === \"string\" ? error.code : undefined;\n\nconst errorText = (error: unknown): string =>\n (error instanceof Error ? error.message : String(error)).slice(0, 200);\n\nconst parseOverlayEntry = (value: unknown): CompiledSurfaceOverlayEntry | undefined => {\n if (!isRecord(value) || typeof value.ref !== \"string\" || !value.ref.trim()) return undefined;\n if (!isRecord(value.inputSchema)) return undefined;\n if (typeof value.baseSchemaDigest !== \"string\" || !value.baseSchemaDigest.trim()) {\n return undefined;\n }\n return {\n ref: value.ref.trim(),\n inputSchema: value.inputSchema,\n baseSchemaDigest: value.baseSchemaDigest.trim(),\n };\n};\n\nconst parseQuarantineEntry = (value: unknown): CompiledSurfaceQuarantineEntry | undefined => {\n if (!isRecord(value) || typeof value.ref !== \"string\" || !value.ref.trim()) return undefined;\n if (typeof value.baseSchemaDigest !== \"string\" || !value.baseSchemaDigest.trim()) {\n return undefined;\n }\n return { ref: value.ref.trim(), baseSchemaDigest: value.baseSchemaDigest.trim() };\n};\n\nconst parseAppliedProposal = (value: unknown): CompiledSurfaceAppliedProposal | undefined => {\n if (!isRecord(value)) return undefined;\n if (typeof value.kind !== \"string\" || !value.kind.trim()) return undefined;\n if (typeof value.ref !== \"string\" || !value.ref.trim()) return undefined;\n if (typeof value.detail !== \"string\" || !value.detail.trim()) return undefined;\n return {\n kind: value.kind.trim() as CompiledSurfaceAppliedProposal[\"kind\"],\n ref: value.ref.trim(),\n detail: value.detail.trim(),\n };\n};\n\nconst parseGateRecord = (value: unknown): CompiledSurfaceGateRecord | undefined => {\n if (!isRecord(value) || typeof value.passed !== \"boolean\") return undefined;\n if (typeof value.beforeScore !== \"number\" || typeof value.afterScore !== \"number\") {\n return undefined;\n }\n if (!Array.isArray(value.reasons) || !value.reasons.every((r) => typeof r === \"string\")) {\n return undefined;\n }\n return {\n passed: value.passed,\n beforeScore: value.beforeScore,\n afterScore: value.afterScore,\n reasons: value.reasons,\n };\n};\n\n// Guarded parse of the whole artifact. Any metric version is accepted: the\n// overlay schemas are data gated against recorded calls, so a metric bump\n// does not invalidate them; the version rides along as provenance.\nconst parseCompiledSurfaceFile = (value: unknown): CompiledSurfaceFile | undefined => {\n if (!isRecord(value) || value.version !== COMPILED_SURFACE_VERSION) return undefined;\n if (!Number.isSafeInteger(value.metricVersion) || (value.metricVersion as number) < 1) {\n return undefined;\n }\n if (!Array.isArray(value.actions) || !value.actions.every((entry) => parseOverlayEntry(entry))) {\n return undefined;\n }\n if (\n !Array.isArray(value.quarantined) ||\n !value.quarantined.every((entry) => parseQuarantineEntry(entry))\n ) {\n return undefined;\n }\n if (\n !Array.isArray(value.applied) ||\n value.applied.length > MAX_COMPILED_SURFACE_PROPOSALS ||\n !value.applied.every((entry) => parseAppliedProposal(entry))\n ) {\n return undefined;\n }\n if (!parseGateRecord(value.gate)) return undefined;\n if (typeof value.evidenceDigest !== \"string\" || !value.evidenceDigest.trim()) return undefined;\n const overlaySeen = new Set<string>();\n for (const entry of value.actions) {\n const parsed = parseOverlayEntry(entry)!;\n if (overlaySeen.has(parsed.ref)) return undefined;\n overlaySeen.add(parsed.ref);\n }\n return {\n version: COMPILED_SURFACE_VERSION,\n metricVersion: value.metricVersion as number,\n actions: value.actions.map((entry) => parseOverlayEntry(entry)!),\n quarantined: value.quarantined.map((entry) => parseQuarantineEntry(entry)!),\n applied: value.applied.map((entry) => parseAppliedProposal(entry)!),\n gate: parseGateRecord(value.gate)!,\n evidenceDigest: value.evidenceDigest.trim(),\n };\n};\n\n// Public guarded parse for artifact files that did not come from this\n// agent dir: exported artifacts being imported, or certification fixtures.\n// The same validation the store applies to its own file, so nothing trusts\n// an artifact shape the store would refuse to load.\nexport const parseCompiledSurfaceArtifact = (\n value: unknown,\n): CompiledSurfaceFile | undefined => parseCompiledSurfaceFile(value);\n\nexport interface LoadedCompiledSurface {\n file?: CompiledSurfaceFile;\n error?: string;\n}\n\nexport const loadCompiledSurface = (agentDir: string): LoadedCompiledSurface => {\n const file = compiledPath(compiledSurfaceDirectory(agentDir));\n let raw: string;\n try {\n raw = fs.readFileSync(file, \"utf8\");\n } catch (error) {\n // A missing artifact means the surface was never compiled; anything\n // else is damage that callers must surface, not silently rebuild.\n if (errorCode(error) === \"ENOENT\") return {};\n return { error: `compiled surface is unreadable: ${errorText(error)}` };\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { error: \"compiled surface is malformed JSON\" };\n }\n const parsedFile = parseCompiledSurfaceFile(parsed);\n if (!parsedFile) return { error: \"compiled surface is invalid\" };\n return { file: parsedFile };\n};\n\nexport const loadCompiledSurfaceAsync = async (\n agentDir: string,\n): Promise<LoadedCompiledSurface> => {\n const file = compiledPath(compiledSurfaceDirectory(agentDir));\n let raw: string;\n try {\n raw = await fs.promises.readFile(file, \"utf8\");\n } catch (error) {\n if (errorCode(error) === \"ENOENT\") return {};\n return { error: `compiled surface is unreadable: ${errorText(error)}` };\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { error: \"compiled surface is malformed JSON\" };\n }\n const parsedFile = parseCompiledSurfaceFile(parsed);\n return parsedFile ? { file: parsedFile } : { error: \"compiled surface is invalid\" };\n};\n\nexport interface SavedCompiledSurface {\n file: CompiledSurfaceFile;\n written: boolean;\n}\n\nexport const saveCompiledSurface = (\n agentDir: string,\n file: CompiledSurfaceFile,\n): SavedCompiledSurface =>\n withExclusiveFileLock(\n {\n directory: compiledSurfaceDirectory(agentDir),\n lockName: \"compiled.lock\",\n timeoutMessage: \"Timed out waiting for the compiled entropy surface lock\",\n attempts: COMPILED_LOCK_ATTEMPTS,\n delayMs: COMPILED_LOCK_DELAY_MS,\n staleMs: COMPILED_STALE_LOCK_MS,\n },\n () => {\n // A damaged artifact must never be silently rebuilt; fail so the\n // compile records the rejection and leaves the file for recovery.\n const loaded = loadCompiledSurface(agentDir);\n if (loaded.error) throw new Error(loaded.error);\n const target = compiledPath(compiledSurfaceDirectory(agentDir));\n const serialized = `${JSON.stringify(file, null, 2)}\\n`;\n try {\n if (fs.readFileSync(target, \"utf8\") === serialized) return { file, written: false };\n } catch {\n // Missing file: proceed to write.\n }\n writeJsonAtomic(target, file, { space: 2, newline: true, mode: 0o600, dirMode: 0o700 });\n return { file, written: true };\n },\n );\n\nexport const saveCompiledSurfaceAsync = async (\n agentDir: string,\n file: CompiledSurfaceFile,\n): Promise<SavedCompiledSurface> =>\n withExclusiveFileLockAsync(\n {\n directory: compiledSurfaceDirectory(agentDir),\n lockName: \"compiled.lock\",\n timeoutMessage: \"Timed out waiting for the compiled entropy surface lock\",\n attempts: COMPILED_LOCK_ATTEMPTS,\n delayMs: COMPILED_LOCK_DELAY_MS,\n staleMs: COMPILED_STALE_LOCK_MS,\n },\n async () => {\n const loaded = await loadCompiledSurfaceAsync(agentDir);\n if (loaded.error) throw new Error(loaded.error);\n const target = compiledPath(compiledSurfaceDirectory(agentDir));\n const serialized = `${JSON.stringify(file, null, 2)}\\n`;\n try {\n if (await fs.promises.readFile(target, \"utf8\") === serialized) {\n return { file, written: false };\n }\n } catch {\n // Missing file: proceed to write.\n }\n await writeJsonAtomicAsync(target, file, {\n space: 2,\n newline: true,\n mode: 0o600,\n dirMode: 0o700,\n });\n return { file, written: true };\n },\n );\n", "// Cross-process exclusive lock for Fabric's durable stores (the repair\n// table, the compiled entropy surface). Acquisition is a bounded retry over\n// mkdir; stale-lock recovery is an exclusive rename claim, so racing\n// reapers can never delete a lock a fresh writer owns.\n\nimport { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nconst DEFAULT_LOCK_ATTEMPTS = 50;\nconst DEFAULT_LOCK_DELAY_MS = 5;\nconst DEFAULT_STALE_LOCK_MS = 30_000;\n\nexport interface ExclusiveLockOptions {\n directory: string;\n lockName: string;\n /** Error message when acquisition times out. */\n timeoutMessage: string;\n staleMs?: number;\n attempts?: number;\n delayMs?: number;\n}\n\nconst errorCode = (error: unknown): string | undefined =>\n typeof error === \"object\" && error !== null && \"code\" in error\n ? String((error as { code?: unknown }).code)\n : undefined;\n\nconst sleepSync = (() => {\n try {\n const buffer = new Int32Array(new SharedArrayBuffer(4));\n return (ms: number): void => {\n Atomics.wait(buffer, 0, 0, ms);\n };\n } catch {\n return (): void => undefined;\n }\n})();\n\nconst processAlive = (pid: number): boolean => {\n if (!Number.isSafeInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n};\n\nconst sleepAsync = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nconst reapStaleLockAsync = async (\n lock: string,\n verify: (claimed: string) => Promise<boolean>,\n): Promise<boolean> => {\n const claim = `${lock}.reap-${process.pid}-${randomUUID()}`;\n try {\n await fs.promises.rename(lock, claim);\n } catch {\n return false;\n }\n if (!(await verify(claim))) {\n try {\n await fs.promises.rename(claim, lock);\n } catch {\n if (await verify(claim)) {\n await fs.promises.rm(claim, { recursive: true, force: true });\n }\n }\n return false;\n }\n await fs.promises.rm(claim, { recursive: true, force: true });\n return true;\n};\n\nexport const withExclusiveFileLockAsync = async <T>(\n options: ExclusiveLockOptions,\n operation: () => T | Promise<T>,\n): Promise<T> => {\n const attempts = options.attempts ?? DEFAULT_LOCK_ATTEMPTS;\n const delayMs = options.delayMs ?? DEFAULT_LOCK_DELAY_MS;\n const staleMs = options.staleMs ?? DEFAULT_STALE_LOCK_MS;\n await fs.promises.mkdir(options.directory, { recursive: true, mode: 0o700 });\n const lock = path.join(options.directory, options.lockName);\n const ownerPath = path.join(lock, \"owner\");\n const token = randomUUID();\n let acquired = false;\n for (let attempt = 0; attempt < attempts; attempt++) {\n try {\n await fs.promises.mkdir(lock, { mode: 0o700 });\n try {\n await fs.promises.writeFile(ownerPath, `${token}\\n${process.pid}\\n${Date.now()}\\n`, {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n } catch (error) {\n await fs.promises.rm(lock, { recursive: true, force: true });\n throw error;\n }\n acquired = true;\n break;\n } catch (error) {\n if (errorCode(error) !== \"EEXIST\") throw error;\n try {\n const firstOwner = await fs.promises.readFile(ownerPath, \"utf8\");\n const [, pidText, createdText] = firstOwner.trim().split(\"\\n\");\n const stale = Date.now() - Number(createdText) > staleMs;\n if (stale && !processAlive(Number(pidText))) {\n const secondOwner = await fs.promises.readFile(ownerPath, \"utf8\");\n if (\n secondOwner === firstOwner &&\n await reapStaleLockAsync(lock, async (claimed) => {\n try {\n const owner = await fs.promises.readFile(path.join(claimed, \"owner\"), \"utf8\");\n const [, pid, created] = owner.trim().split(\"\\n\");\n return Date.now() - Number(created) > staleMs && !processAlive(Number(pid));\n } catch {\n return false;\n }\n })\n ) {\n continue;\n }\n }\n } catch {\n try {\n const first = await fs.promises.stat(lock);\n if (\n Date.now() - first.mtimeMs > staleMs &&\n await reapStaleLockAsync(lock, async (claimed) => {\n try {\n return Date.now() - (await fs.promises.stat(claimed)).mtimeMs > staleMs;\n } catch {\n return false;\n }\n })\n ) {\n continue;\n }\n } catch {\n // Lock creation or stale recovery raced; retry the bounded acquisition.\n }\n }\n if (attempt === attempts - 1) break;\n await sleepAsync(delayMs);\n }\n }\n if (!acquired) throw new Error(options.timeoutMessage);\n try {\n return await operation();\n } finally {\n try {\n const owner = await fs.promises.readFile(ownerPath, \"utf8\");\n if (owner.startsWith(`${token}\\n`)) {\n await fs.promises.rm(lock, { recursive: true, force: true });\n }\n } catch {\n // A recovering process already removed this lock.\n }\n }\n};\n\n// Stale-lock recovery must be an exclusive claim. Stat-then-delete is\n// TOCTOU: two reapers (or a reaper and a fresh writer that recreated the\n// lock in between) can both pass their checks, and the slower rm then\n// deletes a lock the faster one already replaced. rename() is the claim \u2014\n// only one process can move the directory, and removal targets the claimed\n// path, never the live lock path. A claim that turns out to hold a live\n// lock is renamed back before any destructive step; a live lock is never\n// deleted, even if the rename-back races a fresh writer.\nconst reapStaleLock = (lock: string, verify: (claimed: string) => boolean): boolean => {\n const claim = `${lock}.reap-${process.pid}-${randomUUID()}`;\n try {\n fs.renameSync(lock, claim);\n } catch {\n return false;\n }\n if (!verify(claim)) {\n try {\n fs.renameSync(claim, lock);\n } catch {\n // `lock` was recreated after the claim. Re-verify before any\n // destructive step so a claimed live lock is only ever abandoned as\n // garbage, never deleted.\n if (verify(claim)) fs.rmSync(claim, { recursive: true, force: true });\n }\n return false;\n }\n fs.rmSync(claim, { recursive: true, force: true });\n return true;\n};\n\nexport const withExclusiveFileLock = <T>(\n options: ExclusiveLockOptions,\n operation: () => T,\n): T => {\n const attempts = options.attempts ?? DEFAULT_LOCK_ATTEMPTS;\n const delayMs = options.delayMs ?? DEFAULT_LOCK_DELAY_MS;\n const staleMs = options.staleMs ?? DEFAULT_STALE_LOCK_MS;\n fs.mkdirSync(options.directory, { recursive: true, mode: 0o700 });\n const lock = path.join(options.directory, options.lockName);\n const ownerPath = path.join(lock, \"owner\");\n const token = randomUUID();\n let acquired = false;\n for (let attempt = 0; attempt < attempts; attempt++) {\n try {\n fs.mkdirSync(lock, { mode: 0o700 });\n try {\n fs.writeFileSync(ownerPath, `${token}\\n${process.pid}\\n${Date.now()}\\n`, {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n } catch (error) {\n fs.rmSync(lock, { recursive: true, force: true });\n throw error;\n }\n acquired = true;\n break;\n } catch (error) {\n if (errorCode(error) !== \"EEXIST\") throw error;\n try {\n const firstOwner = fs.readFileSync(ownerPath, \"utf8\");\n const [, pidText, createdText] = firstOwner.trim().split(\"\\n\");\n const stale = Date.now() - Number(createdText) > staleMs;\n if (stale && !processAlive(Number(pidText))) {\n const secondOwner = fs.readFileSync(ownerPath, \"utf8\");\n if (\n secondOwner === firstOwner &&\n reapStaleLock(lock, (claimed) => {\n try {\n const owner = fs.readFileSync(path.join(claimed, \"owner\"), \"utf8\");\n const [, pid, created] = owner.trim().split(\"\\n\");\n return Date.now() - Number(created) > staleMs && !processAlive(Number(pid));\n } catch {\n return false;\n }\n })\n ) {\n continue;\n }\n }\n } catch {\n try {\n // Ownerless lock (crash between mkdir and the owner write): age is\n // the only signal, and the claim re-verifies it after the rename.\n const first = fs.statSync(lock);\n if (\n Date.now() - first.mtimeMs > staleMs &&\n reapStaleLock(lock, (claimed) => {\n try {\n return Date.now() - fs.statSync(claimed).mtimeMs > staleMs;\n } catch {\n return false;\n }\n })\n ) {\n continue;\n }\n } catch {\n // Lock creation or stale recovery raced; retry the bounded acquisition.\n }\n }\n if (attempt === attempts - 1) break;\n sleepSync(delayMs);\n }\n }\n if (!acquired) throw new Error(options.timeoutMessage);\n try {\n return operation();\n } finally {\n try {\n const owner = fs.readFileSync(ownerPath, \"utf8\");\n if (owner.startsWith(`${token}\\n`)) {\n fs.rmSync(lock, { recursive: true, force: true });\n }\n } catch {\n // A recovering process already removed this lock.\n }\n }\n};"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["fs", "path", "path", "errorCode", "fs"]
|
|
7
|
+
}
|
|
@@ -51,10 +51,49 @@ var writeJsonAtomic = (filePath, value, options) => {
|
|
|
51
51
|
const serialized = JSON.stringify(value, null, space) + (options?.newline === true ? "\n" : "");
|
|
52
52
|
writeFileAtomic(filePath, serialized, options);
|
|
53
53
|
};
|
|
54
|
+
var asyncSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
55
|
+
var renameAtomicAsync = async (source, target, options) => {
|
|
56
|
+
const attempts = Math.max(1, options?.renameRetries ?? 8);
|
|
57
|
+
const delay = options?.renameRetryDelayMs ?? 25;
|
|
58
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
59
|
+
try {
|
|
60
|
+
await fs.promises.rename(source, target);
|
|
61
|
+
return;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
const code = errorCode(error);
|
|
64
|
+
if (attempt === attempts || code === void 0 || !RETRYABLE_RENAME_CODES.has(code)) {
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
await asyncSleep(delay * attempt);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var writeFileAtomicAsync = async (filePath, contents, options) => {
|
|
72
|
+
await fs.promises.mkdir(path.dirname(filePath), {
|
|
73
|
+
recursive: true,
|
|
74
|
+
mode: options?.dirMode ?? 448
|
|
75
|
+
});
|
|
76
|
+
const temporary = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
77
|
+
try {
|
|
78
|
+
await fs.promises.writeFile(temporary, contents, {
|
|
79
|
+
encoding: "utf8",
|
|
80
|
+
mode: options?.mode ?? 384
|
|
81
|
+
});
|
|
82
|
+
await renameAtomicAsync(temporary, filePath, options);
|
|
83
|
+
} finally {
|
|
84
|
+
await fs.promises.rm(temporary, { force: true });
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var writeJsonAtomicAsync = async (filePath, value, options) => {
|
|
88
|
+
const space = options?.space;
|
|
89
|
+
const serialized = JSON.stringify(value, null, space) + (options?.newline === true ? "\n" : "");
|
|
90
|
+
await writeFileAtomicAsync(filePath, serialized, options);
|
|
91
|
+
};
|
|
54
92
|
|
|
55
93
|
export {
|
|
56
94
|
renameAtomic,
|
|
57
95
|
writeFileAtomic,
|
|
58
|
-
writeJsonAtomic
|
|
96
|
+
writeJsonAtomic,
|
|
97
|
+
writeJsonAtomicAsync
|
|
59
98
|
};
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
99
|
+
//# sourceMappingURL=chunk-KAD7UWT2.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/core/atomic-write.ts"],
|
|
4
|
-
"sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport interface AtomicWriteOptions {\n // File mode for the committed file (default 0o600) and for mkdir -p of its\n // parent directory (default 0o700).\n mode?: number;\n dirMode?: number;\n // Windows transiently rejects rename() with EPERM/EACCES/EEXIST/EBUSY while\n // an antivirus scan, indexer, or sibling reader probes the destination \u2014\n // milliseconds of contention, not a policy failure. Retry a bounded number\n // of times with linear backoff before surfacing the error.\n renameRetries?: number;\n renameRetryDelayMs?: number;\n}\n\nconst RETRYABLE_RENAME_CODES = new Set([\"EPERM\", \"EACCES\", \"EEXIST\", \"EBUSY\"]);\n\nconst errorCode = (error: unknown): string | undefined =>\n typeof error === \"object\" && error !== null && \"code\" in error\n ? String((error as { code?: unknown }).code)\n : undefined;\n\n// Portable synchronous sleep for the retry window (Atomics.wait is legal on\n// the Node main thread). If unavailable, retries proceed immediately \u2014 still\n// correct, just less cooperative under contention.\nconst syncSleep = (() => {\n try {\n const buffer = new Int32Array(new SharedArrayBuffer(4));\n return (ms: number): void => {\n Atomics.wait(buffer, 0, 0, ms);\n };\n } catch {\n return (): void => undefined;\n }\n})();\n\nexport const renameAtomic = (\n source: string,\n target: string,\n options?: AtomicWriteOptions,\n): void => {\n const attempts = Math.max(1, options?.renameRetries ?? 8);\n const delay = options?.renameRetryDelayMs ?? 25;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n fs.renameSync(source, target);\n return;\n } catch (error) {\n const code = errorCode(error);\n if (attempt === attempts || code === undefined || !RETRYABLE_RENAME_CODES.has(code)) {\n throw error;\n }\n syncSleep(delay * attempt);\n }\n }\n};\n\nexport const writeFileAtomic = (\n filePath: string,\n contents: string,\n options?: AtomicWriteOptions,\n): void => {\n fs.mkdirSync(path.dirname(filePath), {\n recursive: true,\n mode: options?.dirMode ?? 0o700,\n });\n const temporary = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n try {\n fs.writeFileSync(temporary, contents, {\n encoding: \"utf8\",\n mode: options?.mode ?? 0o600,\n });\n renameAtomic(temporary, filePath, options);\n } finally {\n // No-op right after a successful rename; removes the temp on failure.\n fs.rmSync(temporary, { force: true });\n }\n};\n\nexport interface AtomicJsonOptions extends AtomicWriteOptions {\n // Pretty-print indent for JSON.stringify (default: compact).\n space?: number;\n // Some on-disk formats expect a trailing newline (schema state files).\n newline?: boolean;\n}\n\nexport const writeJsonAtomic = (\n filePath: string,\n value: unknown,\n options?: AtomicJsonOptions,\n): void => {\n const space = options?.space;\n const serialized =\n JSON.stringify(value, null, space) + (options?.newline === true ? \"\\n\" : \"\");\n writeFileAtomic(filePath, serialized, options);\n};\n"],
|
|
5
|
-
"mappings": ";AAAA,SAAS,kBAAkB;AAC3B,OAAO,QAAQ;AACf,OAAO,UAAU;AAejB,IAAM,yBAAyB,oBAAI,IAAI,CAAC,SAAS,UAAU,UAAU,OAAO,CAAC;AAE7E,IAAM,YAAY,CAAC,UACjB,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,QACrD,OAAQ,MAA6B,IAAI,IACzC;AAKN,IAAM,aAAa,MAAM;AACvB,MAAI;AACF,UAAM,SAAS,IAAI,WAAW,IAAI,kBAAkB,CAAC,CAAC;AACtD,WAAO,CAAC,OAAqB;AAC3B,cAAQ,KAAK,QAAQ,GAAG,GAAG,EAAE;AAAA,IAC/B;AAAA,EACF,QAAQ;AACN,WAAO,MAAY;AAAA,EACrB;AACF,GAAG;AAEI,IAAM,eAAe,CAC1B,QACA,QACA,YACS;AACT,QAAM,WAAW,KAAK,IAAI,GAAG,SAAS,iBAAiB,CAAC;AACxD,QAAM,QAAQ,SAAS,sBAAsB;AAC7C,WAAS,UAAU,GAAG,WAAW,UAAU,WAAW;AACpD,QAAI;AACF,SAAG,WAAW,QAAQ,MAAM;AAC5B;AAAA,IACF,SAAS,OAAO;AACd,YAAM,OAAO,UAAU,KAAK;AAC5B,UAAI,YAAY,YAAY,SAAS,UAAa,CAAC,uBAAuB,IAAI,IAAI,GAAG;AACnF,cAAM;AAAA,MACR;AACA,gBAAU,QAAQ,OAAO;AAAA,IAC3B;AAAA,EACF;AACF;AAEO,IAAM,kBAAkB,CAC7B,UACA,UACA,YACS;AACT,KAAG,UAAU,KAAK,QAAQ,QAAQ,GAAG;AAAA,IACnC,WAAW;AAAA,IACX,MAAM,SAAS,WAAW;AAAA,EAC5B,CAAC;AACD,QAAM,YAAY,GAAG,QAAQ,IAAI,QAAQ,GAAG,IAAI,WAAW,CAAC;AAC5D,MAAI;AACF,OAAG,cAAc,WAAW,UAAU;AAAA,MACpC,UAAU;AAAA,MACV,MAAM,SAAS,QAAQ;AAAA,IACzB,CAAC;AACD,iBAAa,WAAW,UAAU,OAAO;AAAA,EAC3C,UAAE;AAEA,OAAG,OAAO,WAAW,EAAE,OAAO,KAAK,CAAC;AAAA,EACtC;AACF;AASO,IAAM,kBAAkB,CAC7B,UACA,OACA,YACS;AACT,QAAM,QAAQ,SAAS;AACvB,QAAM,aACJ,KAAK,UAAU,OAAO,MAAM,KAAK,KAAK,SAAS,YAAY,OAAO,OAAO;AAC3E,kBAAgB,UAAU,YAAY,OAAO;AAC/C;",
|
|
4
|
+
"sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport interface AtomicWriteOptions {\n // File mode for the committed file (default 0o600) and for mkdir -p of its\n // parent directory (default 0o700).\n mode?: number;\n dirMode?: number;\n // Windows transiently rejects rename() with EPERM/EACCES/EEXIST/EBUSY while\n // an antivirus scan, indexer, or sibling reader probes the destination \u2014\n // milliseconds of contention, not a policy failure. Retry a bounded number\n // of times with linear backoff before surfacing the error.\n renameRetries?: number;\n renameRetryDelayMs?: number;\n}\n\nconst RETRYABLE_RENAME_CODES = new Set([\"EPERM\", \"EACCES\", \"EEXIST\", \"EBUSY\"]);\n\nconst errorCode = (error: unknown): string | undefined =>\n typeof error === \"object\" && error !== null && \"code\" in error\n ? String((error as { code?: unknown }).code)\n : undefined;\n\n// Portable synchronous sleep for the retry window (Atomics.wait is legal on\n// the Node main thread). If unavailable, retries proceed immediately \u2014 still\n// correct, just less cooperative under contention.\nconst syncSleep = (() => {\n try {\n const buffer = new Int32Array(new SharedArrayBuffer(4));\n return (ms: number): void => {\n Atomics.wait(buffer, 0, 0, ms);\n };\n } catch {\n return (): void => undefined;\n }\n})();\n\nexport const renameAtomic = (\n source: string,\n target: string,\n options?: AtomicWriteOptions,\n): void => {\n const attempts = Math.max(1, options?.renameRetries ?? 8);\n const delay = options?.renameRetryDelayMs ?? 25;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n fs.renameSync(source, target);\n return;\n } catch (error) {\n const code = errorCode(error);\n if (attempt === attempts || code === undefined || !RETRYABLE_RENAME_CODES.has(code)) {\n throw error;\n }\n syncSleep(delay * attempt);\n }\n }\n};\n\nexport const writeFileAtomic = (\n filePath: string,\n contents: string,\n options?: AtomicWriteOptions,\n): void => {\n fs.mkdirSync(path.dirname(filePath), {\n recursive: true,\n mode: options?.dirMode ?? 0o700,\n });\n const temporary = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n try {\n fs.writeFileSync(temporary, contents, {\n encoding: \"utf8\",\n mode: options?.mode ?? 0o600,\n });\n renameAtomic(temporary, filePath, options);\n } finally {\n // No-op right after a successful rename; removes the temp on failure.\n fs.rmSync(temporary, { force: true });\n }\n};\n\nexport interface AtomicJsonOptions extends AtomicWriteOptions {\n // Pretty-print indent for JSON.stringify (default: compact).\n space?: number;\n // Some on-disk formats expect a trailing newline (schema state files).\n newline?: boolean;\n}\n\nexport const writeJsonAtomic = (\n filePath: string,\n value: unknown,\n options?: AtomicJsonOptions,\n): void => {\n const space = options?.space;\n const serialized =\n JSON.stringify(value, null, space) + (options?.newline === true ? \"\\n\" : \"\");\n writeFileAtomic(filePath, serialized, options);\n};\n\nconst asyncSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nconst renameAtomicAsync = async (\n source: string,\n target: string,\n options?: AtomicWriteOptions,\n): Promise<void> => {\n const attempts = Math.max(1, options?.renameRetries ?? 8);\n const delay = options?.renameRetryDelayMs ?? 25;\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n await fs.promises.rename(source, target);\n return;\n } catch (error) {\n const code = errorCode(error);\n if (attempt === attempts || code === undefined || !RETRYABLE_RENAME_CODES.has(code)) {\n throw error;\n }\n await asyncSleep(delay * attempt);\n }\n }\n};\n\nconst writeFileAtomicAsync = async (\n filePath: string,\n contents: string,\n options?: AtomicWriteOptions,\n): Promise<void> => {\n await fs.promises.mkdir(path.dirname(filePath), {\n recursive: true,\n mode: options?.dirMode ?? 0o700,\n });\n const temporary = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await fs.promises.writeFile(temporary, contents, {\n encoding: \"utf8\",\n mode: options?.mode ?? 0o600,\n });\n await renameAtomicAsync(temporary, filePath, options);\n } finally {\n await fs.promises.rm(temporary, { force: true });\n }\n};\n\nexport const writeJsonAtomicAsync = async (\n filePath: string,\n value: unknown,\n options?: AtomicJsonOptions,\n): Promise<void> => {\n const space = options?.space;\n const serialized =\n JSON.stringify(value, null, space) + (options?.newline === true ? \"\\n\" : \"\");\n await writeFileAtomicAsync(filePath, serialized, options);\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|