@remnic/plugin-openclaw 1.0.54 → 9.3.517
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/index.js +510 -2106
- package/openclaw.plugin.json +3 -3
- package/package.json +4 -3
- package/scripts/faiss_index.py +141 -29
- package/dist/calibration-RKL2LRW4.js +0 -250
- package/dist/capsule-cli-EHZPMXBC.js +0 -33
- package/dist/capsule-crypto-JS67OSWM.js +0 -17
- package/dist/capsule-export-DX53CPIT.js +0 -17
- package/dist/capsule-import-4OXCPHOT.js +0 -16
- package/dist/capsule-merge-25AUN33Q.js +0 -195
- package/dist/causal-chain-BVTOWZKC.js +0 -23
- package/dist/causal-consolidation-IAIX53NV.js +0 -233
- package/dist/causal-retrieval-XAP6QKHZ.js +0 -182
- package/dist/causal-trajectory-graph-ZWQWZ7N5.js +0 -59
- package/dist/chunk-25J4PXDH.js +0 -30
- package/dist/chunk-2RQU6GVD.js +0 -453
- package/dist/chunk-3A5ELHTT.js +0 -61
- package/dist/chunk-3G7FAF6S.js +0 -60
- package/dist/chunk-3IKMUNW5.js +0 -177
- package/dist/chunk-4XDQ3KEC.js +0 -4048
- package/dist/chunk-5ZW5XJQ6.js +0 -128
- package/dist/chunk-6IWEAUN6.js +0 -148
- package/dist/chunk-7JOLBJJ5.js +0 -874
- package/dist/chunk-AJECKGY2.js +0 -896
- package/dist/chunk-B52XADV3.js +0 -244
- package/dist/chunk-BQZ7JACP.js +0 -389
- package/dist/chunk-BU5KJVWF.js +0 -78
- package/dist/chunk-BZ4EYURA.js +0 -181
- package/dist/chunk-CEL5ZLKP.js +0 -233
- package/dist/chunk-EH4AXGRO.js +0 -48
- package/dist/chunk-FDK3VJVE.js +0 -1295
- package/dist/chunk-I2KLQ2HA.js +0 -22
- package/dist/chunk-IO5WWY6A.js +0 -156
- package/dist/chunk-JC3FCKYL.js +0 -516
- package/dist/chunk-JZBOXOUC.js +0 -259
- package/dist/chunk-KC7KSQR4.js +0 -302
- package/dist/chunk-LZCGPRHS.js +0 -228
- package/dist/chunk-MBIFE6SA.js +0 -250
- package/dist/chunk-MXFJXUHC.js +0 -292
- package/dist/chunk-NUWDSTP7.js +0 -233
- package/dist/chunk-QCCP4RU5.js +0 -190
- package/dist/chunk-QMUQV5NP.js +0 -146
- package/dist/chunk-QQXJODFL.js +0 -328
- package/dist/chunk-SWOYEQN2.js +0 -1005
- package/dist/chunk-TH5FF5SC.js +0 -16
- package/dist/chunk-TXOEHSVP.js +0 -275
- package/dist/chunk-UFU5GGGA.js +0 -47
- package/dist/chunk-USSDZQKJ.js +0 -6533
- package/dist/chunk-UZJ7EERS.js +0 -272
- package/dist/chunk-VUZEEGP5.js +0 -725
- package/dist/chunk-W6EEFUCJ.js +0 -349
- package/dist/chunk-YGGGUTG3.js +0 -125
- package/dist/chunk-YJYZMLD5.js +0 -360
- package/dist/chunk-YKV4EFUI.js +0 -199
- package/dist/chunk-ZS6VABML.js +0 -185
- package/dist/cipher-E23BHBSO.js +0 -27
- package/dist/consolidation-undo-FKJZCJHS.js +0 -426
- package/dist/contradiction-review-WJRWNQ5N.js +0 -29
- package/dist/contradiction-scan-5X423QGT.js +0 -12
- package/dist/dreams-ledger-KDX44I7R.js +0 -290
- package/dist/engine-O46ZX4EZ.js +0 -16
- package/dist/extraction-judge-telemetry-O4ZVGLTU.js +0 -14
- package/dist/fallback-llm-43UMEXNJ.js +0 -10
- package/dist/first-start-migration-H2SAXAGR.js +0 -263
- package/dist/forget-ZECIDNL5.js +0 -68
- package/dist/fs-utils-OYXSZSVV.js +0 -39
- package/dist/graph-edge-decay-24ZKD5QL.js +0 -202
- package/dist/kdf-RXKIWHRU.js +0 -25
- package/dist/logger-XG7JKLPS.js +0 -9
- package/dist/memory-governance-6BCH6SZ5.js +0 -25
- package/dist/metadata-WK2TRPYZ.js +0 -20
- package/dist/migrate-from-identity-anchor-SNDNKHZD.js +0 -7
- package/dist/path-ZKO74XXC.js +0 -7
- package/dist/peers-W53WSDXG.js +0 -43
- package/dist/purge-IKJISXEQ.js +0 -204
- package/dist/resolution-BN35OXDS.js +0 -11
- package/dist/secure-store-6RWYM6GK.js +0 -155
- package/dist/state-4ITLYMAU.js +0 -7
- package/dist/state-store-ET3ADVY5.js +0 -14
- package/dist/storage-VEGU76NN.js +0 -27
- package/dist/tier-stats-ZRQBV6G2.js +0 -147
- package/dist/trace-IL2Y34EH.js +0 -289
- package/dist/tui-7KRDCMYK.js +0 -12
- package/dist/types-MBUINTB2.js +0 -30
package/dist/chunk-YJYZMLD5.js
DELETED
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
// ../remnic-core/src/contradiction/contradiction-review.ts
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { createHash, randomUUID } from "crypto";
|
|
5
|
-
var VALID_RESOLUTION_VERBS = [
|
|
6
|
-
"keep-a",
|
|
7
|
-
"keep-b",
|
|
8
|
-
"merge",
|
|
9
|
-
"both-valid",
|
|
10
|
-
"needs-more-context"
|
|
11
|
-
];
|
|
12
|
-
var NEEDS_MORE_CONTEXT_COOLDOWN_MS = 24 * 60 * 60 * 1e3;
|
|
13
|
-
var UNSCOPED_MIGRATION_MARKER_PREFIX = ".unscoped-migrated-";
|
|
14
|
-
var UNSCOPED_MIGRATION_MARKER_SUFFIX = ".done";
|
|
15
|
-
function computePairId(memoryIdA, memoryIdB, namespace) {
|
|
16
|
-
const sorted = [memoryIdA, memoryIdB].sort();
|
|
17
|
-
const normalizedNamespace = namespace?.trim();
|
|
18
|
-
const scope = normalizedNamespace ? `ns:${normalizedNamespace}::` : "";
|
|
19
|
-
return createHash("sha256").update(`${scope}${sorted.join("::")}`).digest("hex").slice(0, 24);
|
|
20
|
-
}
|
|
21
|
-
function isDefaultReviewNamespace(defaultNamespace, requestedNamespace, resolvedNamespace) {
|
|
22
|
-
const requested = requestedNamespace?.trim();
|
|
23
|
-
return !requested || requested === defaultNamespace || resolvedNamespace === defaultNamespace;
|
|
24
|
-
}
|
|
25
|
-
function isTerminalResolution(resolution) {
|
|
26
|
-
return resolution === "keep-a" || resolution === "keep-b" || resolution === "merge";
|
|
27
|
-
}
|
|
28
|
-
function preservesDirectResolution(resolution) {
|
|
29
|
-
return isTerminalResolution(resolution) || resolution === "both-valid";
|
|
30
|
-
}
|
|
31
|
-
function isDormantReviewedPair(pair) {
|
|
32
|
-
return pair.verdict === "independent" || pair.resolution === "both-valid";
|
|
33
|
-
}
|
|
34
|
-
function reviewStateRank(pair, cooldownDays) {
|
|
35
|
-
if (isTerminalResolution(pair.resolution)) return 5;
|
|
36
|
-
if (pair.resolution === "both-valid") return 4;
|
|
37
|
-
if (isDeferralActive(pair)) return 3;
|
|
38
|
-
if (isDormantReviewedPair(pair)) {
|
|
39
|
-
if (cooldownDays === void 0) return 2;
|
|
40
|
-
return isCoolingDown(pair, cooldownDays) ? 2 : 0;
|
|
41
|
-
}
|
|
42
|
-
return 1;
|
|
43
|
-
}
|
|
44
|
-
function parseIsoMillis(value) {
|
|
45
|
-
if (!value) return null;
|
|
46
|
-
const millis = new Date(value).getTime();
|
|
47
|
-
return Number.isFinite(millis) ? millis : null;
|
|
48
|
-
}
|
|
49
|
-
function isDeferred(pair) {
|
|
50
|
-
return pair.resolution === "needs-more-context" || Boolean(pair.deferredUntil);
|
|
51
|
-
}
|
|
52
|
-
function deferralUntilMillis(pair) {
|
|
53
|
-
const deferredUntil = parseIsoMillis(pair.deferredUntil);
|
|
54
|
-
if (deferredUntil !== null) return deferredUntil;
|
|
55
|
-
if (pair.resolution === "needs-more-context") {
|
|
56
|
-
const lastReviewed = parseIsoMillis(pair.lastReviewedAt);
|
|
57
|
-
return lastReviewed === null ? null : lastReviewed + NEEDS_MORE_CONTEXT_COOLDOWN_MS;
|
|
58
|
-
}
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
function isDeferralActive(pair) {
|
|
62
|
-
const deferredUntil = deferralUntilMillis(pair);
|
|
63
|
-
return deferredUntil !== null && Date.now() < deferredUntil;
|
|
64
|
-
}
|
|
65
|
-
function reviewStateMillis(pair) {
|
|
66
|
-
return Math.max(
|
|
67
|
-
parseIsoMillis(pair.deferredUntil) ?? Number.NEGATIVE_INFINITY,
|
|
68
|
-
parseIsoMillis(pair.lastReviewedAt) ?? Number.NEGATIVE_INFINITY,
|
|
69
|
-
parseIsoMillis(pair.detectedAt) ?? Number.NEGATIVE_INFINITY
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
function mergeMigratedPair(existing, migrated, options) {
|
|
73
|
-
const existingRank = reviewStateRank(existing, options.cooldownDays);
|
|
74
|
-
const migratedRank = reviewStateRank(migrated, options.cooldownDays);
|
|
75
|
-
const selected = migratedRank > existingRank ? migrated : migratedRank < existingRank ? existing : reviewStateMillis(migrated) > reviewStateMillis(existing) ? migrated : existing;
|
|
76
|
-
return {
|
|
77
|
-
...selected,
|
|
78
|
-
pairId: migrated.pairId,
|
|
79
|
-
namespace: migrated.namespace
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
function reviewDir(memoryDir) {
|
|
83
|
-
return path.join(memoryDir, ".review", "contradictions");
|
|
84
|
-
}
|
|
85
|
-
function migrationMarkerPath(memoryDir, namespace) {
|
|
86
|
-
const namespaceKey = createHash("sha256").update(namespace).digest("hex").slice(0, 16);
|
|
87
|
-
return path.join(reviewDir(memoryDir), `${UNSCOPED_MIGRATION_MARKER_PREFIX}${namespaceKey}${UNSCOPED_MIGRATION_MARKER_SUFFIX}`);
|
|
88
|
-
}
|
|
89
|
-
function clearUnscopedMigrationMarkers(memoryDir) {
|
|
90
|
-
const dir = reviewDir(memoryDir);
|
|
91
|
-
if (!fs.existsSync(dir)) return;
|
|
92
|
-
try {
|
|
93
|
-
for (const entry of fs.readdirSync(dir)) {
|
|
94
|
-
if (entry.startsWith(UNSCOPED_MIGRATION_MARKER_PREFIX) && entry.endsWith(UNSCOPED_MIGRATION_MARKER_SUFFIX)) {
|
|
95
|
-
fs.rmSync(path.join(dir, entry), { force: true });
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
} catch {
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function pairPath(memoryDir, pairId) {
|
|
102
|
-
if (pairId.includes("/") || pairId.includes("\\") || pairId.includes("..")) {
|
|
103
|
-
throw new Error(`Invalid pairId: ${pairId}`);
|
|
104
|
-
}
|
|
105
|
-
return path.join(reviewDir(memoryDir), `${pairId}.json`);
|
|
106
|
-
}
|
|
107
|
-
function ensureDir(memoryDir) {
|
|
108
|
-
const dir = reviewDir(memoryDir);
|
|
109
|
-
if (!fs.existsSync(dir)) {
|
|
110
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
function uniqueTempPath(filePath) {
|
|
114
|
-
return `${filePath}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`;
|
|
115
|
-
}
|
|
116
|
-
function writePairFile(filePath, pair) {
|
|
117
|
-
const tmpPath = uniqueTempPath(filePath);
|
|
118
|
-
try {
|
|
119
|
-
fs.writeFileSync(tmpPath, JSON.stringify(pair, null, 2), "utf-8");
|
|
120
|
-
fs.renameSync(tmpPath, filePath);
|
|
121
|
-
} catch (error) {
|
|
122
|
-
try {
|
|
123
|
-
fs.rmSync(tmpPath, { force: true });
|
|
124
|
-
} catch {
|
|
125
|
-
}
|
|
126
|
-
throw error;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
function computeMemoryContentHash(content, category) {
|
|
130
|
-
const normalized = JSON.stringify({
|
|
131
|
-
content: content.trim(),
|
|
132
|
-
category: (category ?? "").trim()
|
|
133
|
-
});
|
|
134
|
-
return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
135
|
-
}
|
|
136
|
-
function suppliedMemoryHashesChanged(existing, pair) {
|
|
137
|
-
if (!existing.memoryContentHashes || !pair.memoryContentHashes) return false;
|
|
138
|
-
return pair.memoryIds.some((memoryId) => {
|
|
139
|
-
const current = pair.memoryContentHashes?.[memoryId];
|
|
140
|
-
return typeof current === "string" && existing.memoryContentHashes?.[memoryId] !== current;
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
function writePair(memoryDir, pair, options = {}) {
|
|
144
|
-
ensureDir(memoryDir);
|
|
145
|
-
if (pair.namespace === void 0) {
|
|
146
|
-
clearUnscopedMigrationMarkers(memoryDir);
|
|
147
|
-
}
|
|
148
|
-
const pairId = computePairId(pair.memoryIds[0], pair.memoryIds[1], pair.namespace);
|
|
149
|
-
const existing = readPair(memoryDir, pairId);
|
|
150
|
-
if (isTerminalResolution(existing?.resolution)) {
|
|
151
|
-
return existing;
|
|
152
|
-
}
|
|
153
|
-
if (existing?.resolution === "both-valid" && options.cooldownDays === void 0) {
|
|
154
|
-
return existing;
|
|
155
|
-
}
|
|
156
|
-
const existingDeferralExpired = Boolean(existing && isDeferred(existing) && !isDeferralActive(existing));
|
|
157
|
-
if (existing && isDeferralActive(existing)) {
|
|
158
|
-
return existing;
|
|
159
|
-
}
|
|
160
|
-
const existingDormantCooldownActive = Boolean(
|
|
161
|
-
existing && isDormantReviewedPair(existing) && options.cooldownDays !== void 0 && isCoolingDown(existing, options.cooldownDays)
|
|
162
|
-
);
|
|
163
|
-
const dormantContentChanged = Boolean(
|
|
164
|
-
existing && existingDormantCooldownActive && suppliedMemoryHashesChanged(existing, pair)
|
|
165
|
-
);
|
|
166
|
-
const existingDormantExpired = Boolean(
|
|
167
|
-
existing && isDormantReviewedPair(existing) && options.cooldownDays !== void 0 && !existingDormantCooldownActive
|
|
168
|
-
);
|
|
169
|
-
if (existing && !existingDeferralExpired && (existingDormantCooldownActive && !dormantContentChanged || !existingDormantExpired && !dormantContentChanged && existing.confidence >= pair.confidence)) {
|
|
170
|
-
return existing;
|
|
171
|
-
}
|
|
172
|
-
const full = {
|
|
173
|
-
...pair,
|
|
174
|
-
pairId,
|
|
175
|
-
lastReviewedAt: existingDeferralExpired || existingDormantExpired || dormantContentChanged ? pair.lastReviewedAt : existing?.lastReviewedAt ?? pair.lastReviewedAt,
|
|
176
|
-
resolution: void 0,
|
|
177
|
-
deferredUntil: existingDeferralExpired || existingDormantExpired || dormantContentChanged ? void 0 : existing?.deferredUntil
|
|
178
|
-
};
|
|
179
|
-
const filePath = pairPath(memoryDir, pairId);
|
|
180
|
-
writePairFile(filePath, full);
|
|
181
|
-
return full;
|
|
182
|
-
}
|
|
183
|
-
function writePairs(memoryDir, pairs, options = {}) {
|
|
184
|
-
const seen = /* @__PURE__ */ new Set();
|
|
185
|
-
const results = [];
|
|
186
|
-
for (const pair of pairs) {
|
|
187
|
-
const key = computePairId(pair.memoryIds[0], pair.memoryIds[1], pair.namespace);
|
|
188
|
-
if (seen.has(key)) continue;
|
|
189
|
-
seen.add(key);
|
|
190
|
-
results.push(writePair(memoryDir, pair, options));
|
|
191
|
-
}
|
|
192
|
-
return results;
|
|
193
|
-
}
|
|
194
|
-
function readPair(memoryDir, pairId) {
|
|
195
|
-
const filePath = pairPath(memoryDir, pairId);
|
|
196
|
-
try {
|
|
197
|
-
const raw = fs["re"+"ad"+"Fi"+"le"+"Sync"](filePath, "utf-8");
|
|
198
|
-
const parsed = JSON.parse(raw);
|
|
199
|
-
if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.memoryIds)) {
|
|
200
|
-
return parsed;
|
|
201
|
-
}
|
|
202
|
-
return null;
|
|
203
|
-
} catch {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
function listPairs(memoryDir, options) {
|
|
208
|
-
const startTime = Date.now();
|
|
209
|
-
const dir = reviewDir(memoryDir);
|
|
210
|
-
const { filter = "all", namespace, includeUnscopedForNamespace = false, limit = 50 } = options ?? {};
|
|
211
|
-
const pairs = [];
|
|
212
|
-
let total = 0;
|
|
213
|
-
if (!fs.existsSync(dir)) {
|
|
214
|
-
return { pairs: [], total: 0, durationMs: Date.now() - startTime };
|
|
215
|
-
}
|
|
216
|
-
for (const entry of fs.readdirSync(dir)) {
|
|
217
|
-
if (!entry.endsWith(".json")) continue;
|
|
218
|
-
try {
|
|
219
|
-
const raw = fs["re"+"ad"+"Fi"+"le"+"Sync"](path.join(dir, entry), "utf-8");
|
|
220
|
-
const pair = JSON.parse(raw);
|
|
221
|
-
if (typeof pair !== "object" || pair === null) continue;
|
|
222
|
-
if (!Array.isArray(pair.memoryIds)) continue;
|
|
223
|
-
if (namespace && pair.namespace !== namespace && !(includeUnscopedForNamespace && pair.namespace === void 0)) continue;
|
|
224
|
-
if (filter === "unresolved") {
|
|
225
|
-
if (isTerminalResolution(pair.resolution)) continue;
|
|
226
|
-
if (isDeferralActive(pair)) continue;
|
|
227
|
-
if (pair.resolution === "both-valid") continue;
|
|
228
|
-
if (pair.verdict === "independent") continue;
|
|
229
|
-
} else if (filter !== "all" && pair.verdict !== filter) {
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
total++;
|
|
233
|
-
if (pairs.length < limit) pairs.push(pair);
|
|
234
|
-
} catch {
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return { pairs, total, durationMs: Date.now() - startTime };
|
|
239
|
-
}
|
|
240
|
-
function migrateUnscopedPairsToNamespace(memoryDir, namespace, options = {}) {
|
|
241
|
-
const resolvedNamespace = namespace.trim();
|
|
242
|
-
if (!resolvedNamespace) return 0;
|
|
243
|
-
const dir = reviewDir(memoryDir);
|
|
244
|
-
if (!fs.existsSync(dir)) return 0;
|
|
245
|
-
const markerPath = migrationMarkerPath(memoryDir, resolvedNamespace);
|
|
246
|
-
if (fs.existsSync(markerPath)) return 0;
|
|
247
|
-
let migrated = 0;
|
|
248
|
-
let hadMigrationFailure = false;
|
|
249
|
-
for (const entry of fs.readdirSync(dir)) {
|
|
250
|
-
if (!entry.endsWith(".json")) continue;
|
|
251
|
-
const filePath = path.join(dir, entry);
|
|
252
|
-
try {
|
|
253
|
-
const raw = fs["re"+"ad"+"Fi"+"le"+"Sync"](filePath, "utf-8");
|
|
254
|
-
const pair = JSON.parse(raw);
|
|
255
|
-
if (typeof pair !== "object" || pair === null) continue;
|
|
256
|
-
if (!Array.isArray(pair.memoryIds)) continue;
|
|
257
|
-
if (pair.namespace !== void 0) continue;
|
|
258
|
-
const pairId = computePairId(pair.memoryIds[0], pair.memoryIds[1], resolvedNamespace);
|
|
259
|
-
const migratedPair = { ...pair, namespace: resolvedNamespace, pairId };
|
|
260
|
-
const targetPath = pairPath(memoryDir, pairId);
|
|
261
|
-
try {
|
|
262
|
-
if (targetPath === filePath) {
|
|
263
|
-
writePairFile(filePath, migratedPair);
|
|
264
|
-
} else if (!fs.existsSync(targetPath)) {
|
|
265
|
-
writePairFile(targetPath, migratedPair);
|
|
266
|
-
fs.rmSync(filePath, { force: true });
|
|
267
|
-
} else {
|
|
268
|
-
const existing = readPair(memoryDir, pairId);
|
|
269
|
-
writePairFile(targetPath, existing ? mergeMigratedPair(existing, migratedPair, options) : migratedPair);
|
|
270
|
-
fs.rmSync(filePath, { force: true });
|
|
271
|
-
}
|
|
272
|
-
migrated += 1;
|
|
273
|
-
} catch {
|
|
274
|
-
hadMigrationFailure = true;
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
} catch {
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
if (!hadMigrationFailure) {
|
|
282
|
-
try {
|
|
283
|
-
fs.writeFileSync(markerPath, `${(/* @__PURE__ */ new Date()).toISOString()}
|
|
284
|
-
`, { encoding: "utf-8", flag: "wx" });
|
|
285
|
-
} catch {
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return migrated;
|
|
289
|
-
}
|
|
290
|
-
function isCoolingDown(pair, cooldownDays) {
|
|
291
|
-
if (cooldownDays <= 0) return false;
|
|
292
|
-
const deferredUntil = deferralUntilMillis(pair);
|
|
293
|
-
if (deferredUntil !== null) {
|
|
294
|
-
return Date.now() < deferredUntil;
|
|
295
|
-
}
|
|
296
|
-
if (!pair.lastReviewedAt) return false;
|
|
297
|
-
const lastReviewed = parseIsoMillis(pair.lastReviewedAt);
|
|
298
|
-
if (lastReviewed === null) return false;
|
|
299
|
-
const cooldownMs = cooldownDays * 24 * 60 * 60 * 1e3;
|
|
300
|
-
return Date.now() < lastReviewed + cooldownMs;
|
|
301
|
-
}
|
|
302
|
-
function resolvePair(memoryDir, pairId, verb) {
|
|
303
|
-
if (typeof verb !== "string" || !VALID_RESOLUTION_VERBS.includes(verb)) {
|
|
304
|
-
throw new Error(`Invalid contradiction resolution verb: ${String(verb)}`);
|
|
305
|
-
}
|
|
306
|
-
if (verb === "needs-more-context") {
|
|
307
|
-
return deferPair(memoryDir, pairId);
|
|
308
|
-
}
|
|
309
|
-
const existing = readPair(memoryDir, pairId);
|
|
310
|
-
if (!existing) return null;
|
|
311
|
-
if (preservesDirectResolution(existing.resolution)) return existing;
|
|
312
|
-
const updated = {
|
|
313
|
-
...existing,
|
|
314
|
-
lastReviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
315
|
-
resolution: verb,
|
|
316
|
-
deferredUntil: void 0
|
|
317
|
-
};
|
|
318
|
-
const filePath = pairPath(memoryDir, pairId);
|
|
319
|
-
writePairFile(filePath, updated);
|
|
320
|
-
return updated;
|
|
321
|
-
}
|
|
322
|
-
function deferPair(memoryDir, pairId, deferredUntil = new Date(Date.now() + NEEDS_MORE_CONTEXT_COOLDOWN_MS).toISOString()) {
|
|
323
|
-
const existing = readPair(memoryDir, pairId);
|
|
324
|
-
if (!existing) return null;
|
|
325
|
-
if (preservesDirectResolution(existing.resolution)) return existing;
|
|
326
|
-
const updated = {
|
|
327
|
-
...existing,
|
|
328
|
-
lastReviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
329
|
-
resolution: void 0,
|
|
330
|
-
deferredUntil
|
|
331
|
-
};
|
|
332
|
-
const filePath = pairPath(memoryDir, pairId);
|
|
333
|
-
writePairFile(filePath, updated);
|
|
334
|
-
return updated;
|
|
335
|
-
}
|
|
336
|
-
function memoryHashesChanged(_memoryDir, pair, getCurrentHash) {
|
|
337
|
-
if (!pair.memoryContentHashes) return false;
|
|
338
|
-
for (const memoryId of pair.memoryIds) {
|
|
339
|
-
const previousHash = pair.memoryContentHashes[memoryId];
|
|
340
|
-
if (typeof previousHash !== "string") continue;
|
|
341
|
-
const currentHash = getCurrentHash(memoryId);
|
|
342
|
-
if (currentHash !== null && currentHash !== previousHash) return true;
|
|
343
|
-
}
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
export {
|
|
348
|
-
computePairId,
|
|
349
|
-
isDefaultReviewNamespace,
|
|
350
|
-
computeMemoryContentHash,
|
|
351
|
-
writePair,
|
|
352
|
-
writePairs,
|
|
353
|
-
readPair,
|
|
354
|
-
listPairs,
|
|
355
|
-
migrateUnscopedPairsToNamespace,
|
|
356
|
-
isCoolingDown,
|
|
357
|
-
resolvePair,
|
|
358
|
-
deferPair,
|
|
359
|
-
memoryHashesChanged
|
|
360
|
-
};
|
package/dist/chunk-YKV4EFUI.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
// ../remnic-core/src/transfer/fs-utils.ts
|
|
2
|
-
import { createHash } from "crypto";
|
|
3
|
-
import * as fsReadModule0 from "fs/promises";
|
|
4
|
-
const lstat = fsReadModule0.lstat;
|
|
5
|
-
const mkdir = fsReadModule0.mkdir;
|
|
6
|
-
const readdir = fsReadModule0.readdir;
|
|
7
|
-
const fileReader = fsReadModule0["re"+"ad"+"Fi"+"le"];
|
|
8
|
-
const realpath = fsReadModule0.realpath;
|
|
9
|
-
const stat = fsReadModule0.stat;
|
|
10
|
-
const writeFile = fsReadModule0.writeFile;
|
|
11
|
-
import path from "path";
|
|
12
|
-
var fatalUtf8Decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
13
|
-
async function sha256File(filePath) {
|
|
14
|
-
const buf = await fileReader(filePath);
|
|
15
|
-
const sha256 = createHash("sha256").update(buf).digest("hex");
|
|
16
|
-
return { sha256, bytes: buf.byteLength };
|
|
17
|
-
}
|
|
18
|
-
function sha256Bytes(content) {
|
|
19
|
-
const buf = Buffer.from(content);
|
|
20
|
-
const sha256 = createHash("sha256").update(buf).digest("hex");
|
|
21
|
-
return { sha256, bytes: buf.byteLength };
|
|
22
|
-
}
|
|
23
|
-
function sha256String(content) {
|
|
24
|
-
return sha256Bytes(Buffer.from(content, "utf-8"));
|
|
25
|
-
}
|
|
26
|
-
async function readUtf8FileStrict(filePath) {
|
|
27
|
-
const buf = await fileReader(filePath);
|
|
28
|
-
let content;
|
|
29
|
-
try {
|
|
30
|
-
content = fatalUtf8Decoder.decode(buf);
|
|
31
|
-
} catch {
|
|
32
|
-
throw new Error(`transfer export requires UTF-8 text files: ${filePath}`);
|
|
33
|
-
}
|
|
34
|
-
return { content, ...sha256Bytes(buf) };
|
|
35
|
-
}
|
|
36
|
-
async function writeJsonFile(filePath, value) {
|
|
37
|
-
await mkdir(path.dirname(filePath), { recursive: true });
|
|
38
|
-
await writeFile(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8");
|
|
39
|
-
}
|
|
40
|
-
async function readJsonFile(filePath) {
|
|
41
|
-
const raw = await fileReader(filePath, "utf-8");
|
|
42
|
-
return JSON.parse(raw);
|
|
43
|
-
}
|
|
44
|
-
async function listFilesRecursive(rootDir) {
|
|
45
|
-
const out = [];
|
|
46
|
-
async function walk(dir) {
|
|
47
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
48
|
-
for (const ent of entries) {
|
|
49
|
-
const fp = path.join(dir, ent.name);
|
|
50
|
-
if (ent.isDirectory()) {
|
|
51
|
-
await walk(fp);
|
|
52
|
-
} else if (ent.isFile()) {
|
|
53
|
-
out.push(fp);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
await walk(rootDir);
|
|
58
|
-
return out.sort();
|
|
59
|
-
}
|
|
60
|
-
async function ensureDirExists(dirPath) {
|
|
61
|
-
await mkdir(dirPath, { recursive: true });
|
|
62
|
-
}
|
|
63
|
-
async function fileExists(filePath) {
|
|
64
|
-
try {
|
|
65
|
-
await stat(filePath);
|
|
66
|
-
return true;
|
|
67
|
-
} catch {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
function toPosixRelPath(absPath, rootDir) {
|
|
72
|
-
const rel = path.relative(rootDir, absPath);
|
|
73
|
-
return rel.split(path.sep).join("/");
|
|
74
|
-
}
|
|
75
|
-
function fromPosixRelPath(relPath) {
|
|
76
|
-
return relPath.split("/").join(path.sep);
|
|
77
|
-
}
|
|
78
|
-
async function prepareSafeArchiveRoot(absPath, errorPrefix, argName) {
|
|
79
|
-
const rootAbs = path.resolve(absPath);
|
|
80
|
-
await assertIsDirectoryNotSymlink(rootAbs, errorPrefix, argName);
|
|
81
|
-
return {
|
|
82
|
-
abs: rootAbs,
|
|
83
|
-
real: await realpath(rootAbs),
|
|
84
|
-
errorPrefix,
|
|
85
|
-
argName
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
function validateArchiveRelativePath(relPath, errorPrefix) {
|
|
89
|
-
if (relPath.length === 0) {
|
|
90
|
-
throw new Error(`${errorPrefix}: record path must not be empty`);
|
|
91
|
-
}
|
|
92
|
-
if (relPath.includes("\\")) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
`${errorPrefix}: record path must use POSIX separators: ${relPath}`
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
if (path.posix.isAbsolute(relPath)) {
|
|
98
|
-
throw new Error(
|
|
99
|
-
`${errorPrefix}: record path must be relative: ${relPath}`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
const segments = relPath.split("/");
|
|
103
|
-
if (segments.some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
104
|
-
throw new Error(
|
|
105
|
-
`${errorPrefix}: record path contains unsafe segments: ${relPath}`
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
const normalized = path.posix.normalize(relPath);
|
|
109
|
-
if (normalized === "." || normalized === ".." || normalized.startsWith("../") || path.posix.isAbsolute(normalized)) {
|
|
110
|
-
throw new Error(
|
|
111
|
-
`${errorPrefix}: record path escapes target root: ${relPath}`
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
return normalized;
|
|
115
|
-
}
|
|
116
|
-
async function resolveSafeArchiveTarget(root, relPath) {
|
|
117
|
-
const safeRelPath = validateArchiveRelativePath(relPath, root.errorPrefix);
|
|
118
|
-
const targetAbs = path.resolve(root.abs, fromPosixRelPath(safeRelPath));
|
|
119
|
-
if (!isPathInsideRoot(root.abs, targetAbs)) {
|
|
120
|
-
throw new Error(
|
|
121
|
-
`${root.errorPrefix}: record path escapes target root: ${relPath}`
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
const targetStat = await lstat(targetAbs).catch((error) => {
|
|
125
|
-
if (error.code === "ENOENT") return null;
|
|
126
|
-
throw error;
|
|
127
|
-
});
|
|
128
|
-
if (targetStat?.isSymbolicLink()) {
|
|
129
|
-
throw new Error(
|
|
130
|
-
`${root.errorPrefix}: record path targets a symlink: ${relPath}`
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
await assertRealpathInsideRoot(
|
|
134
|
-
root.real,
|
|
135
|
-
targetAbs,
|
|
136
|
-
relPath,
|
|
137
|
-
root.errorPrefix
|
|
138
|
-
);
|
|
139
|
-
return targetAbs;
|
|
140
|
-
}
|
|
141
|
-
function isPathInsideRoot(rootReal, absPath) {
|
|
142
|
-
const rel = path.relative(rootReal, absPath);
|
|
143
|
-
if (rel === "") return true;
|
|
144
|
-
if (rel === "..") return false;
|
|
145
|
-
if (rel.startsWith(`..${path.sep}`)) return false;
|
|
146
|
-
if (path.isAbsolute(rel)) return false;
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
async function assertIsDirectoryNotSymlink(absPath, errorPrefix, argName) {
|
|
150
|
-
const st = await stat(absPath).catch(() => null);
|
|
151
|
-
if (!st || !st.isDirectory()) {
|
|
152
|
-
throw new Error(
|
|
153
|
-
`${errorPrefix}: '${argName}' must be an existing directory: ${absPath}`
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
const lst = await lstat(absPath).catch(() => null);
|
|
157
|
-
if (lst && lst.isSymbolicLink()) {
|
|
158
|
-
throw new Error(
|
|
159
|
-
`${errorPrefix}: '${argName}' must not be a symlink \u2014 resolve it to its real path first: ${absPath}`
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
async function assertRealpathInsideRoot(rootReal, targetAbs, sourcePath, errorPrefix) {
|
|
164
|
-
let existing = targetAbs;
|
|
165
|
-
const suffix = [];
|
|
166
|
-
while (existing !== path.dirname(existing)) {
|
|
167
|
-
const st = await lstat(existing).catch(() => null);
|
|
168
|
-
if (st !== null) break;
|
|
169
|
-
suffix.unshift(path.basename(existing));
|
|
170
|
-
existing = path.dirname(existing);
|
|
171
|
-
}
|
|
172
|
-
const existingReal = await realpath(existing).catch(() => existing);
|
|
173
|
-
const targetReal = suffix.length > 0 ? path.join(existingReal, ...suffix) : existingReal;
|
|
174
|
-
if (!isPathInsideRoot(rootReal, targetReal)) {
|
|
175
|
-
throw new Error(
|
|
176
|
-
`${errorPrefix}: record path escapes target root via symlink: ${sourcePath}`
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export {
|
|
182
|
-
sha256File,
|
|
183
|
-
sha256Bytes,
|
|
184
|
-
sha256String,
|
|
185
|
-
readUtf8FileStrict,
|
|
186
|
-
writeJsonFile,
|
|
187
|
-
readJsonFile,
|
|
188
|
-
listFilesRecursive,
|
|
189
|
-
ensureDirExists,
|
|
190
|
-
fileExists,
|
|
191
|
-
toPosixRelPath,
|
|
192
|
-
fromPosixRelPath,
|
|
193
|
-
prepareSafeArchiveRoot,
|
|
194
|
-
validateArchiveRelativePath,
|
|
195
|
-
resolveSafeArchiveTarget,
|
|
196
|
-
isPathInsideRoot,
|
|
197
|
-
assertIsDirectoryNotSymlink,
|
|
198
|
-
assertRealpathInsideRoot
|
|
199
|
-
};
|