@remnic/core 9.3.573 → 9.3.575
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/chunk-KDUFBSBF.js +532 -0
- package/dist/chunk-KDUFBSBF.js.map +1 -0
- package/dist/{chunk-2FHLI4U6.js → chunk-QNXFFUWA.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/schemas.d.ts +22 -22
- package/dist/semantic-rule-promotion.d.ts +12 -1
- package/dist/semantic-rule-promotion.js +5 -3
- package/dist/transfer/types.d.ts +12 -12
- package/package.json +1 -1
- package/src/semantic-rule-promotion.ts +502 -37
- package/dist/chunk-74VA26CT.js +0 -135
- package/dist/chunk-74VA26CT.js.map +0 -1
- /package/dist/{chunk-2FHLI4U6.js.map → chunk-QNXFFUWA.js.map} +0 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StorageManager
|
|
3
|
+
} from "./chunk-IRFF6LSF.js";
|
|
4
|
+
|
|
5
|
+
// src/semantic-rule-promotion.ts
|
|
6
|
+
import { createHash, randomUUID } from "crypto";
|
|
7
|
+
import { link, mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { setTimeout as sleep } from "timers/promises";
|
|
10
|
+
var PROMOTION_LOCK_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
11
|
+
var PROMOTION_LOCK_RETRY_MS = 25;
|
|
12
|
+
var PROMOTION_LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
13
|
+
var PROMOTION_LOCK_OWNERLESS_GRACE_MS = 1e3;
|
|
14
|
+
var PROMOTION_LOCK_HEARTBEAT_MS = 30 * 1e3;
|
|
15
|
+
var testHooks = null;
|
|
16
|
+
function setSemanticRulePromotionTestHooks(hooks) {
|
|
17
|
+
testHooks = hooks;
|
|
18
|
+
}
|
|
19
|
+
function promotionLockTimeoutMs() {
|
|
20
|
+
return testHooks?.lockTimeoutMs ?? PROMOTION_LOCK_TIMEOUT_MS;
|
|
21
|
+
}
|
|
22
|
+
function promotionLockRetryMs() {
|
|
23
|
+
return testHooks?.lockRetryMs ?? PROMOTION_LOCK_RETRY_MS;
|
|
24
|
+
}
|
|
25
|
+
function promotionLockStaleMs() {
|
|
26
|
+
return testHooks?.staleLockMs ?? PROMOTION_LOCK_STALE_MS;
|
|
27
|
+
}
|
|
28
|
+
function promotionLockOwnerlessGraceMs() {
|
|
29
|
+
return testHooks?.ownerlessGraceMs ?? PROMOTION_LOCK_OWNERLESS_GRACE_MS;
|
|
30
|
+
}
|
|
31
|
+
function promotionLockHeartbeatMs() {
|
|
32
|
+
return testHooks?.heartbeatMs ?? PROMOTION_LOCK_HEARTBEAT_MS;
|
|
33
|
+
}
|
|
34
|
+
function isErrnoCode(err, code) {
|
|
35
|
+
return typeof err === "object" && err !== null && "code" in err && err.code === code;
|
|
36
|
+
}
|
|
37
|
+
function promotionLockDir(memoryDir, ruleKey) {
|
|
38
|
+
const digest = createHash("sha256").update(ruleKey).digest("hex");
|
|
39
|
+
return path.join(path.resolve(memoryDir), "state", "semantic-rule-promotion-locks", `${digest}.lock`);
|
|
40
|
+
}
|
|
41
|
+
function promotionHeartbeatPath(lockDir, token) {
|
|
42
|
+
return path.join(lockDir, `heartbeat.${token}.json`);
|
|
43
|
+
}
|
|
44
|
+
function promotionReapDir(lockDir) {
|
|
45
|
+
return `${lockDir}.reap`;
|
|
46
|
+
}
|
|
47
|
+
function promotionReleaseDir(lockDir) {
|
|
48
|
+
return `${lockDir}.release`;
|
|
49
|
+
}
|
|
50
|
+
async function pathExists(targetPath) {
|
|
51
|
+
try {
|
|
52
|
+
await stat(targetPath);
|
|
53
|
+
return true;
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function readPromotionLockOwner(lockDir) {
|
|
60
|
+
try {
|
|
61
|
+
const owner = JSON.parse(await readFile(path.join(lockDir, "owner.json"), "utf8"));
|
|
62
|
+
const acquiredAtMs = typeof owner.acquiredAt === "string" ? Date.parse(owner.acquiredAt) : Number.NaN;
|
|
63
|
+
const heartbeatAtMs = typeof owner.heartbeatAt === "string" ? Date.parse(owner.heartbeatAt) : Number.NaN;
|
|
64
|
+
return {
|
|
65
|
+
acquiredAtMs: Number.isFinite(acquiredAtMs) ? acquiredAtMs : null,
|
|
66
|
+
heartbeatAtMs: Number.isFinite(heartbeatAtMs) ? heartbeatAtMs : null,
|
|
67
|
+
token: typeof owner.token === "string" ? owner.token : null
|
|
68
|
+
};
|
|
69
|
+
} catch {
|
|
70
|
+
return {
|
|
71
|
+
acquiredAtMs: null,
|
|
72
|
+
heartbeatAtMs: null,
|
|
73
|
+
token: null
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function tryWritePromotionLockOwner(lockDir, owner) {
|
|
78
|
+
const ownerPath = path.join(lockDir, "owner.json");
|
|
79
|
+
const tempPath = path.join(lockDir, `owner.${process.pid}.${randomUUID()}.tmp`);
|
|
80
|
+
await testHooks?.beforeLockOwnerWrite?.(lockDir, owner.token);
|
|
81
|
+
try {
|
|
82
|
+
await writeFile(
|
|
83
|
+
tempPath,
|
|
84
|
+
`${JSON.stringify(
|
|
85
|
+
{
|
|
86
|
+
pid: process.pid,
|
|
87
|
+
token: owner.token,
|
|
88
|
+
acquiredAt: owner.acquiredAt
|
|
89
|
+
},
|
|
90
|
+
null,
|
|
91
|
+
2
|
|
92
|
+
)}
|
|
93
|
+
`
|
|
94
|
+
);
|
|
95
|
+
await link(tempPath, ownerPath);
|
|
96
|
+
return true;
|
|
97
|
+
} catch (err) {
|
|
98
|
+
if (isErrnoCode(err, "EEXIST") || isErrnoCode(err, "ENOENT")) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
throw err;
|
|
102
|
+
} finally {
|
|
103
|
+
await rm(tempPath, { force: true });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function writePromotionLockHeartbeat(lockDir, token) {
|
|
107
|
+
const heartbeatPath = promotionHeartbeatPath(lockDir, token);
|
|
108
|
+
const tempPath = path.join(lockDir, `heartbeat.${process.pid}.${randomUUID()}.tmp`);
|
|
109
|
+
try {
|
|
110
|
+
await writeFile(
|
|
111
|
+
tempPath,
|
|
112
|
+
`${JSON.stringify(
|
|
113
|
+
{
|
|
114
|
+
pid: process.pid,
|
|
115
|
+
token,
|
|
116
|
+
heartbeatAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
117
|
+
},
|
|
118
|
+
null,
|
|
119
|
+
2
|
|
120
|
+
)}
|
|
121
|
+
`
|
|
122
|
+
);
|
|
123
|
+
await rename(tempPath, heartbeatPath);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
await rm(tempPath, { force: true });
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function refreshPromotionLockHeartbeat(lockDir, token) {
|
|
130
|
+
const owner = await readPromotionLockOwner(lockDir);
|
|
131
|
+
if (owner.token !== token) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
await writePromotionLockHeartbeat(lockDir, token);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
async function readPromotionLockHeartbeatMs(lockDir, token) {
|
|
138
|
+
if (!token) return null;
|
|
139
|
+
try {
|
|
140
|
+
return (await stat(promotionHeartbeatPath(lockDir, token))).mtimeMs;
|
|
141
|
+
} catch (err) {
|
|
142
|
+
if (isErrnoCode(err, "ENOENT")) return null;
|
|
143
|
+
throw err;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function reapAbandonedPromotionGuard(guardDir) {
|
|
147
|
+
let reapStat;
|
|
148
|
+
try {
|
|
149
|
+
reapStat = await stat(guardDir);
|
|
150
|
+
} catch (err) {
|
|
151
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
if (Date.now() - reapStat.mtimeMs < promotionLockStaleMs()) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
const staleReapDir = `${guardDir}.stale-${process.pid}-${randomUUID()}`;
|
|
158
|
+
try {
|
|
159
|
+
await rename(guardDir, staleReapDir);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
162
|
+
throw err;
|
|
163
|
+
}
|
|
164
|
+
await rm(staleReapDir, { recursive: true, force: true });
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
async function reapAbandonedPromotionGuards(lockDir) {
|
|
168
|
+
const reapedReapGuard = await reapAbandonedPromotionGuard(promotionReapDir(lockDir));
|
|
169
|
+
const reapedReleaseGuard = await reapAbandonedPromotionGuard(promotionReleaseDir(lockDir));
|
|
170
|
+
return reapedReapGuard || reapedReleaseGuard;
|
|
171
|
+
}
|
|
172
|
+
async function hasPromotionGuard(lockDir) {
|
|
173
|
+
return await pathExists(promotionReapDir(lockDir)) || await pathExists(promotionReleaseDir(lockDir));
|
|
174
|
+
}
|
|
175
|
+
async function reapStalePromotionLock(lockDir) {
|
|
176
|
+
if (await hasPromotionGuard(lockDir)) {
|
|
177
|
+
await reapAbandonedPromotionGuards(lockDir);
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
const reapDir = promotionReapDir(lockDir);
|
|
181
|
+
try {
|
|
182
|
+
await mkdir(reapDir);
|
|
183
|
+
} catch (err) {
|
|
184
|
+
if (isErrnoCode(err, "EEXIST")) return false;
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
let staleDir = null;
|
|
188
|
+
try {
|
|
189
|
+
return await reapStalePromotionLockWithGuard(lockDir, (value) => {
|
|
190
|
+
staleDir = value;
|
|
191
|
+
});
|
|
192
|
+
} finally {
|
|
193
|
+
if (staleDir) {
|
|
194
|
+
await rm(staleDir, { recursive: true, force: true });
|
|
195
|
+
}
|
|
196
|
+
await rm(reapDir, { recursive: true, force: true });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async function reapStalePromotionLockWithGuard(lockDir, setStaleDir) {
|
|
200
|
+
let lockStat;
|
|
201
|
+
try {
|
|
202
|
+
lockStat = await stat(lockDir);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
const owner = await readPromotionLockOwner(lockDir);
|
|
208
|
+
const heartbeatMs = await readPromotionLockHeartbeatMs(lockDir, owner.token);
|
|
209
|
+
const lockedAtMs = heartbeatMs ?? owner.heartbeatAtMs ?? owner.acquiredAtMs ?? lockStat.mtimeMs;
|
|
210
|
+
const ownerlessLock = owner.token === null && owner.heartbeatAtMs === null && owner.acquiredAtMs === null;
|
|
211
|
+
const staleAfterMs = ownerlessLock ? promotionLockOwnerlessGraceMs() : promotionLockStaleMs();
|
|
212
|
+
if (Date.now() - lockedAtMs < staleAfterMs) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
const staleDir = `${lockDir}.stale-${process.pid}-${randomUUID()}`;
|
|
216
|
+
try {
|
|
217
|
+
await rename(lockDir, staleDir);
|
|
218
|
+
setStaleDir(staleDir);
|
|
219
|
+
} catch (err) {
|
|
220
|
+
if (isErrnoCode(err, "ENOENT")) return false;
|
|
221
|
+
throw err;
|
|
222
|
+
}
|
|
223
|
+
const staleOwner = await readPromotionLockOwner(staleDir);
|
|
224
|
+
const staleHeartbeatMs = await readPromotionLockHeartbeatMs(staleDir, staleOwner.token);
|
|
225
|
+
const staleLockedAtMs = staleHeartbeatMs ?? staleOwner.heartbeatAtMs ?? staleOwner.acquiredAtMs ?? lockStat.mtimeMs;
|
|
226
|
+
const staleOwnerlessLock = staleOwner.token === null && staleOwner.heartbeatAtMs === null && staleOwner.acquiredAtMs === null;
|
|
227
|
+
const staleAfterRecheckMs = staleOwnerlessLock ? promotionLockOwnerlessGraceMs() : promotionLockStaleMs();
|
|
228
|
+
if (Date.now() - staleLockedAtMs < staleAfterRecheckMs) {
|
|
229
|
+
await rename(staleDir, lockDir);
|
|
230
|
+
setStaleDir("");
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
await rm(staleDir, { recursive: true, force: true });
|
|
234
|
+
setStaleDir("");
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
async function releasePromotionLock(lockDir, token) {
|
|
238
|
+
const releaseDir = promotionReleaseDir(lockDir);
|
|
239
|
+
const deadline = Date.now() + promotionLockTimeoutMs();
|
|
240
|
+
await testHooks?.beforeLockRelease?.(lockDir, token);
|
|
241
|
+
for (; ; ) {
|
|
242
|
+
try {
|
|
243
|
+
await mkdir(releaseDir);
|
|
244
|
+
break;
|
|
245
|
+
} catch (err) {
|
|
246
|
+
if (!isErrnoCode(err, "EEXIST")) {
|
|
247
|
+
throw err;
|
|
248
|
+
}
|
|
249
|
+
const owner = await readPromotionLockOwner(lockDir);
|
|
250
|
+
if (owner.token !== token) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
await reapAbandonedPromotionGuard(releaseDir);
|
|
254
|
+
if (Date.now() >= deadline) {
|
|
255
|
+
throw new Error("Timed out releasing semantic rule promotion lock");
|
|
256
|
+
}
|
|
257
|
+
await sleep(promotionLockRetryMs());
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
try {
|
|
261
|
+
const owner = await readPromotionLockOwner(lockDir);
|
|
262
|
+
if (owner.token !== token) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
await rm(lockDir, { recursive: true, force: true });
|
|
266
|
+
} finally {
|
|
267
|
+
await rm(releaseDir, { recursive: true, force: true });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async function withPromotionLock(memoryDir, ruleKey, fn) {
|
|
271
|
+
const lockDir = promotionLockDir(memoryDir, ruleKey);
|
|
272
|
+
const lockRoot = path.dirname(lockDir);
|
|
273
|
+
const deadline = Date.now() + promotionLockTimeoutMs();
|
|
274
|
+
let lockToken = null;
|
|
275
|
+
let heartbeat = null;
|
|
276
|
+
await mkdir(lockRoot, { recursive: true });
|
|
277
|
+
for (; ; ) {
|
|
278
|
+
try {
|
|
279
|
+
if (await hasPromotionGuard(lockDir)) {
|
|
280
|
+
await reapAbandonedPromotionGuards(lockDir);
|
|
281
|
+
if (Date.now() >= deadline) {
|
|
282
|
+
throw new Error("Timed out acquiring semantic rule promotion lock");
|
|
283
|
+
}
|
|
284
|
+
await sleep(promotionLockRetryMs());
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
await mkdir(lockDir);
|
|
288
|
+
if (await hasPromotionGuard(lockDir)) {
|
|
289
|
+
await reapAbandonedPromotionGuards(lockDir);
|
|
290
|
+
if (Date.now() >= deadline) {
|
|
291
|
+
throw new Error("Timed out acquiring semantic rule promotion lock");
|
|
292
|
+
}
|
|
293
|
+
await sleep(promotionLockRetryMs());
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
lockToken = randomUUID();
|
|
298
|
+
const lockOwner = {
|
|
299
|
+
token: lockToken,
|
|
300
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
301
|
+
};
|
|
302
|
+
const wroteOwner = await tryWritePromotionLockOwner(lockDir, lockOwner);
|
|
303
|
+
if (!wroteOwner) {
|
|
304
|
+
lockToken = null;
|
|
305
|
+
if (Date.now() >= deadline) {
|
|
306
|
+
throw new Error("Timed out acquiring semantic rule promotion lock");
|
|
307
|
+
}
|
|
308
|
+
await sleep(promotionLockRetryMs());
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
await writePromotionLockHeartbeat(lockDir, lockToken);
|
|
312
|
+
const heartbeatToken = lockToken;
|
|
313
|
+
const heartbeatMs = promotionLockHeartbeatMs();
|
|
314
|
+
if (heartbeatMs > 0) {
|
|
315
|
+
heartbeat = setInterval(() => {
|
|
316
|
+
void refreshPromotionLockHeartbeat(lockDir, heartbeatToken).then((ownsLock) => {
|
|
317
|
+
if (!ownsLock && heartbeat) {
|
|
318
|
+
clearInterval(heartbeat);
|
|
319
|
+
heartbeat = null;
|
|
320
|
+
}
|
|
321
|
+
}).catch(() => void 0);
|
|
322
|
+
}, heartbeatMs);
|
|
323
|
+
}
|
|
324
|
+
} catch (err) {
|
|
325
|
+
lockToken = null;
|
|
326
|
+
if (heartbeat) {
|
|
327
|
+
clearInterval(heartbeat);
|
|
328
|
+
heartbeat = null;
|
|
329
|
+
}
|
|
330
|
+
await rm(lockDir, { recursive: true, force: true });
|
|
331
|
+
throw err;
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
} catch (err) {
|
|
335
|
+
if (!isErrnoCode(err, "EEXIST")) {
|
|
336
|
+
throw err;
|
|
337
|
+
}
|
|
338
|
+
if (await reapStalePromotionLock(lockDir)) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
if (Date.now() >= deadline) {
|
|
342
|
+
throw new Error("Timed out acquiring semantic rule promotion lock");
|
|
343
|
+
}
|
|
344
|
+
await sleep(promotionLockRetryMs());
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
const assertHeld = async () => {
|
|
348
|
+
if (!lockToken) {
|
|
349
|
+
throw new Error("Semantic rule promotion lock is no longer held");
|
|
350
|
+
}
|
|
351
|
+
const ownsLock = await refreshPromotionLockHeartbeat(lockDir, lockToken);
|
|
352
|
+
if (!ownsLock) {
|
|
353
|
+
throw new Error("Semantic rule promotion lock is no longer held");
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
let hasResult = false;
|
|
357
|
+
let result;
|
|
358
|
+
let callbackError;
|
|
359
|
+
let releaseError;
|
|
360
|
+
try {
|
|
361
|
+
await assertHeld();
|
|
362
|
+
result = await fn({
|
|
363
|
+
assertHeld,
|
|
364
|
+
beforePromotedRuleWrite: async () => {
|
|
365
|
+
if (!lockToken) {
|
|
366
|
+
throw new Error("Semantic rule promotion lock is no longer held");
|
|
367
|
+
}
|
|
368
|
+
await testHooks?.beforePromotedRuleWrite?.(lockDir, lockToken);
|
|
369
|
+
await assertHeld();
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
hasResult = true;
|
|
373
|
+
} catch (err) {
|
|
374
|
+
callbackError = err;
|
|
375
|
+
} finally {
|
|
376
|
+
if (heartbeat) {
|
|
377
|
+
clearInterval(heartbeat);
|
|
378
|
+
}
|
|
379
|
+
if (lockToken) {
|
|
380
|
+
try {
|
|
381
|
+
await releasePromotionLock(lockDir, lockToken);
|
|
382
|
+
} catch (err) {
|
|
383
|
+
if (!hasResult && !callbackError) {
|
|
384
|
+
releaseError = err;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (releaseError) {
|
|
390
|
+
throw releaseError;
|
|
391
|
+
}
|
|
392
|
+
if (callbackError) {
|
|
393
|
+
throw callbackError;
|
|
394
|
+
}
|
|
395
|
+
return result;
|
|
396
|
+
}
|
|
397
|
+
function normalizeRuleWhitespace(value) {
|
|
398
|
+
return value.replace(/\s+/g, " ").trim();
|
|
399
|
+
}
|
|
400
|
+
function stripTrailingClausePunctuation(value) {
|
|
401
|
+
return value.replace(/[,:;]+$/g, "").trim();
|
|
402
|
+
}
|
|
403
|
+
function canonicalizeRuleContent(value) {
|
|
404
|
+
return extractExplicitIfThenRule(value) ?? normalizeRuleWhitespace(value);
|
|
405
|
+
}
|
|
406
|
+
function canonicalizeRuleKey(value) {
|
|
407
|
+
return canonicalizeRuleContent(value).toLowerCase();
|
|
408
|
+
}
|
|
409
|
+
function extractExplicitIfThenRule(content) {
|
|
410
|
+
const match = content.match(/\bif\b([\s\S]+?)\bthen\b([\s\S]+?)(?:[.!?](?:\s|$)|$)/i);
|
|
411
|
+
if (!match) return null;
|
|
412
|
+
const condition = stripTrailingClausePunctuation(normalizeRuleWhitespace(match[1] ?? ""));
|
|
413
|
+
const outcome = stripTrailingClausePunctuation(normalizeRuleWhitespace(match[2] ?? ""));
|
|
414
|
+
if (condition.length === 0 || outcome.length === 0) return null;
|
|
415
|
+
return `IF ${condition} THEN ${outcome}.`;
|
|
416
|
+
}
|
|
417
|
+
function promotionConfidence(memory) {
|
|
418
|
+
const base = Number.isFinite(memory.frontmatter.confidence) ? memory.frontmatter.confidence : 0.8;
|
|
419
|
+
return Math.max(0.6, Math.min(0.98, base));
|
|
420
|
+
}
|
|
421
|
+
function promotionTags(memory) {
|
|
422
|
+
return Array.from(/* @__PURE__ */ new Set([...memory.frontmatter.tags ?? [], "semantic-rule", "promoted-rule"]));
|
|
423
|
+
}
|
|
424
|
+
function buildSupportLinks(sourceMemoryId, confidence) {
|
|
425
|
+
return [
|
|
426
|
+
{
|
|
427
|
+
targetId: sourceMemoryId,
|
|
428
|
+
linkType: "supports",
|
|
429
|
+
strength: confidence,
|
|
430
|
+
reason: "Promoted from verified episodic memory"
|
|
431
|
+
}
|
|
432
|
+
];
|
|
433
|
+
}
|
|
434
|
+
async function promoteSemanticRuleFromMemory(options) {
|
|
435
|
+
const report = {
|
|
436
|
+
enabled: options.enabled,
|
|
437
|
+
dryRun: options.dryRun === true,
|
|
438
|
+
promoted: [],
|
|
439
|
+
skipped: []
|
|
440
|
+
};
|
|
441
|
+
if (!options.enabled) {
|
|
442
|
+
report.skipped.push({
|
|
443
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
444
|
+
reason: "disabled"
|
|
445
|
+
});
|
|
446
|
+
return report;
|
|
447
|
+
}
|
|
448
|
+
const storage = new StorageManager(options.memoryDir);
|
|
449
|
+
const sourceMemory = await storage.getMemoryById(options.sourceMemoryId);
|
|
450
|
+
if (!sourceMemory) {
|
|
451
|
+
report.skipped.push({
|
|
452
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
453
|
+
reason: "source-memory-missing"
|
|
454
|
+
});
|
|
455
|
+
return report;
|
|
456
|
+
}
|
|
457
|
+
if (sourceMemory.frontmatter.status === "forgotten") {
|
|
458
|
+
report.skipped.push({
|
|
459
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
460
|
+
reason: "source-memory-forgotten"
|
|
461
|
+
});
|
|
462
|
+
return report;
|
|
463
|
+
}
|
|
464
|
+
if (sourceMemory.frontmatter.status === "archived" || sourceMemory.frontmatter.memoryKind !== "episode") {
|
|
465
|
+
report.skipped.push({
|
|
466
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
467
|
+
reason: "source-memory-not-episode"
|
|
468
|
+
});
|
|
469
|
+
return report;
|
|
470
|
+
}
|
|
471
|
+
const content = extractExplicitIfThenRule(sourceMemory.content);
|
|
472
|
+
if (!content) {
|
|
473
|
+
report.skipped.push({
|
|
474
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
475
|
+
reason: "no-explicit-rule"
|
|
476
|
+
});
|
|
477
|
+
return report;
|
|
478
|
+
}
|
|
479
|
+
const ruleKey = canonicalizeRuleKey(content);
|
|
480
|
+
const confidence = promotionConfidence(sourceMemory);
|
|
481
|
+
const candidateBase = {
|
|
482
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
483
|
+
content,
|
|
484
|
+
confidence,
|
|
485
|
+
tags: promotionTags(sourceMemory),
|
|
486
|
+
memoryKind: "note",
|
|
487
|
+
lineage: [options.sourceMemoryId]
|
|
488
|
+
};
|
|
489
|
+
return withPromotionLock(options.memoryDir, ruleKey, async (lock) => {
|
|
490
|
+
storage.invalidateAllMemoriesCacheForDir();
|
|
491
|
+
const existingRule = (await storage.readAllMemories()).find(
|
|
492
|
+
(memory) => memory.frontmatter.category === "rule" && memory.frontmatter.status !== "archived" && memory.frontmatter.status !== "forgotten" && canonicalizeRuleKey(memory.content) === ruleKey
|
|
493
|
+
);
|
|
494
|
+
if (existingRule) {
|
|
495
|
+
report.skipped.push({
|
|
496
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
497
|
+
reason: "duplicate-rule",
|
|
498
|
+
existingRuleId: existingRule.frontmatter.id
|
|
499
|
+
});
|
|
500
|
+
return report;
|
|
501
|
+
}
|
|
502
|
+
if (options.dryRun === true) {
|
|
503
|
+
await lock.assertHeld();
|
|
504
|
+
report.promoted.push({
|
|
505
|
+
id: `dry-run:${options.sourceMemoryId}`,
|
|
506
|
+
...candidateBase
|
|
507
|
+
});
|
|
508
|
+
return report;
|
|
509
|
+
}
|
|
510
|
+
await lock.beforePromotedRuleWrite();
|
|
511
|
+
const id = await storage.writeMemory("rule", content, {
|
|
512
|
+
confidence,
|
|
513
|
+
tags: candidateBase.tags,
|
|
514
|
+
source: "semantic-rule-promotion",
|
|
515
|
+
lineage: candidateBase.lineage,
|
|
516
|
+
sourceMemoryId: options.sourceMemoryId,
|
|
517
|
+
memoryKind: "note",
|
|
518
|
+
links: buildSupportLinks(options.sourceMemoryId, confidence)
|
|
519
|
+
});
|
|
520
|
+
report.promoted.push({
|
|
521
|
+
id,
|
|
522
|
+
...candidateBase
|
|
523
|
+
});
|
|
524
|
+
return report;
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export {
|
|
529
|
+
setSemanticRulePromotionTestHooks,
|
|
530
|
+
promoteSemanticRuleFromMemory
|
|
531
|
+
};
|
|
532
|
+
//# sourceMappingURL=chunk-KDUFBSBF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/semantic-rule-promotion.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { link, mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { StorageManager } from \"./storage.js\";\nimport type { MemoryFile, MemoryLink } from \"./types.js\";\n\nexport interface SemanticRulePromotionCandidate {\n id: string;\n sourceMemoryId: string;\n content: string;\n confidence: number;\n tags: string[];\n memoryKind: \"note\";\n lineage: string[];\n}\n\nexport interface SemanticRulePromotionSkip {\n sourceMemoryId: string;\n reason:\n | \"disabled\"\n | \"source-memory-missing\"\n | \"source-memory-forgotten\"\n | \"source-memory-not-episode\"\n | \"no-explicit-rule\"\n | \"duplicate-rule\";\n existingRuleId?: string;\n}\n\nexport interface SemanticRulePromotionReport {\n enabled: boolean;\n dryRun: boolean;\n promoted: SemanticRulePromotionCandidate[];\n skipped: SemanticRulePromotionSkip[];\n}\n\nconst PROMOTION_LOCK_TIMEOUT_MS = 10 * 60 * 1000;\nconst PROMOTION_LOCK_RETRY_MS = 25;\nconst PROMOTION_LOCK_STALE_MS = 5 * 60 * 1000;\nconst PROMOTION_LOCK_OWNERLESS_GRACE_MS = 1000;\nconst PROMOTION_LOCK_HEARTBEAT_MS = 30 * 1000;\n\ntype SemanticRulePromotionTestHooks = {\n beforeLockOwnerWrite?: (lockDir: string, ownerToken: string) => Promise<void> | void;\n beforeLockRelease?: (lockDir: string, ownerToken: string) => Promise<void> | void;\n beforePromotedRuleWrite?: (lockDir: string, ownerToken: string) => Promise<void> | void;\n lockTimeoutMs?: number;\n lockRetryMs?: number;\n staleLockMs?: number;\n ownerlessGraceMs?: number;\n heartbeatMs?: number;\n};\n\nlet testHooks: SemanticRulePromotionTestHooks | null = null;\n\nexport function setSemanticRulePromotionTestHooks(hooks: SemanticRulePromotionTestHooks | null): void {\n testHooks = hooks;\n}\n\nfunction promotionLockTimeoutMs(): number {\n return testHooks?.lockTimeoutMs ?? PROMOTION_LOCK_TIMEOUT_MS;\n}\n\nfunction promotionLockRetryMs(): number {\n return testHooks?.lockRetryMs ?? PROMOTION_LOCK_RETRY_MS;\n}\n\nfunction promotionLockStaleMs(): number {\n return testHooks?.staleLockMs ?? PROMOTION_LOCK_STALE_MS;\n}\n\nfunction promotionLockOwnerlessGraceMs(): number {\n return testHooks?.ownerlessGraceMs ?? PROMOTION_LOCK_OWNERLESS_GRACE_MS;\n}\n\nfunction promotionLockHeartbeatMs(): number {\n return testHooks?.heartbeatMs ?? PROMOTION_LOCK_HEARTBEAT_MS;\n}\n\nfunction isErrnoCode(err: unknown, code: string): boolean {\n return typeof err === \"object\" && err !== null && \"code\" in err && (err as { code?: unknown }).code === code;\n}\n\nfunction promotionLockDir(memoryDir: string, ruleKey: string): string {\n const digest = createHash(\"sha256\").update(ruleKey).digest(\"hex\");\n return path.join(path.resolve(memoryDir), \"state\", \"semantic-rule-promotion-locks\", `${digest}.lock`);\n}\n\nfunction promotionHeartbeatPath(lockDir: string, token: string): string {\n return path.join(lockDir, `heartbeat.${token}.json`);\n}\n\nfunction promotionReapDir(lockDir: string): string {\n return `${lockDir}.reap`;\n}\n\nfunction promotionReleaseDir(lockDir: string): string {\n return `${lockDir}.release`;\n}\n\nasync function pathExists(targetPath: string): Promise<boolean> {\n try {\n await stat(targetPath);\n return true;\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return false;\n throw err;\n }\n}\n\nasync function readPromotionLockOwner(lockDir: string): Promise<{\n acquiredAtMs: number | null;\n heartbeatAtMs: number | null;\n token: string | null;\n}> {\n try {\n const owner = JSON.parse(await readFile(path.join(lockDir, \"owner.json\"), \"utf8\")) as {\n acquiredAt?: unknown;\n heartbeatAt?: unknown;\n token?: unknown;\n };\n const acquiredAtMs = typeof owner.acquiredAt === \"string\" ? Date.parse(owner.acquiredAt) : Number.NaN;\n const heartbeatAtMs = typeof owner.heartbeatAt === \"string\" ? Date.parse(owner.heartbeatAt) : Number.NaN;\n return {\n acquiredAtMs: Number.isFinite(acquiredAtMs) ? acquiredAtMs : null,\n heartbeatAtMs: Number.isFinite(heartbeatAtMs) ? heartbeatAtMs : null,\n token: typeof owner.token === \"string\" ? owner.token : null,\n };\n } catch {\n return {\n acquiredAtMs: null,\n heartbeatAtMs: null,\n token: null,\n };\n }\n}\n\nasync function tryWritePromotionLockOwner(\n lockDir: string,\n owner: { token: string; acquiredAt: string }\n): Promise<boolean> {\n const ownerPath = path.join(lockDir, \"owner.json\");\n const tempPath = path.join(lockDir, `owner.${process.pid}.${randomUUID()}.tmp`);\n await testHooks?.beforeLockOwnerWrite?.(lockDir, owner.token);\n try {\n await writeFile(\n tempPath,\n `${JSON.stringify(\n {\n pid: process.pid,\n token: owner.token,\n acquiredAt: owner.acquiredAt,\n },\n null,\n 2\n )}\\n`\n );\n await link(tempPath, ownerPath);\n return true;\n } catch (err) {\n if (isErrnoCode(err, \"EEXIST\") || isErrnoCode(err, \"ENOENT\")) {\n return false;\n }\n throw err;\n } finally {\n await rm(tempPath, { force: true });\n }\n}\n\nasync function writePromotionLockHeartbeat(lockDir: string, token: string): Promise<void> {\n const heartbeatPath = promotionHeartbeatPath(lockDir, token);\n const tempPath = path.join(lockDir, `heartbeat.${process.pid}.${randomUUID()}.tmp`);\n try {\n await writeFile(\n tempPath,\n `${JSON.stringify(\n {\n pid: process.pid,\n token,\n heartbeatAt: new Date().toISOString(),\n },\n null,\n 2\n )}\\n`\n );\n await rename(tempPath, heartbeatPath);\n } catch (err) {\n await rm(tempPath, { force: true });\n throw err;\n }\n}\n\nasync function refreshPromotionLockHeartbeat(lockDir: string, token: string): Promise<boolean> {\n const owner = await readPromotionLockOwner(lockDir);\n if (owner.token !== token) {\n return false;\n }\n await writePromotionLockHeartbeat(lockDir, token);\n return true;\n}\n\nasync function readPromotionLockHeartbeatMs(lockDir: string, token: string | null): Promise<number | null> {\n if (!token) return null;\n try {\n return (await stat(promotionHeartbeatPath(lockDir, token))).mtimeMs;\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return null;\n throw err;\n }\n}\n\nasync function reapAbandonedPromotionGuard(guardDir: string): Promise<boolean> {\n let reapStat: { mtimeMs: number };\n try {\n reapStat = await stat(guardDir);\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return false;\n throw err;\n }\n if (Date.now() - reapStat.mtimeMs < promotionLockStaleMs()) {\n return false;\n }\n\n const staleReapDir = `${guardDir}.stale-${process.pid}-${randomUUID()}`;\n try {\n await rename(guardDir, staleReapDir);\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return false;\n throw err;\n }\n await rm(staleReapDir, { recursive: true, force: true });\n return true;\n}\n\nasync function reapAbandonedPromotionGuards(lockDir: string): Promise<boolean> {\n const reapedReapGuard = await reapAbandonedPromotionGuard(promotionReapDir(lockDir));\n const reapedReleaseGuard = await reapAbandonedPromotionGuard(promotionReleaseDir(lockDir));\n return reapedReapGuard || reapedReleaseGuard;\n}\n\nasync function hasPromotionGuard(lockDir: string): Promise<boolean> {\n return (await pathExists(promotionReapDir(lockDir))) || (await pathExists(promotionReleaseDir(lockDir)));\n}\n\nasync function reapStalePromotionLock(lockDir: string): Promise<boolean> {\n if (await hasPromotionGuard(lockDir)) {\n await reapAbandonedPromotionGuards(lockDir);\n return false;\n }\n\n const reapDir = promotionReapDir(lockDir);\n try {\n await mkdir(reapDir);\n } catch (err) {\n if (isErrnoCode(err, \"EEXIST\")) return false;\n throw err;\n }\n\n let staleDir: string | null = null;\n try {\n return await reapStalePromotionLockWithGuard(lockDir, (value) => {\n staleDir = value;\n });\n } finally {\n if (staleDir) {\n await rm(staleDir, { recursive: true, force: true });\n }\n await rm(reapDir, { recursive: true, force: true });\n }\n}\n\nasync function reapStalePromotionLockWithGuard(\n lockDir: string,\n setStaleDir: (staleDir: string) => void\n): Promise<boolean> {\n let lockStat: { mtimeMs: number };\n try {\n lockStat = await stat(lockDir);\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return false;\n throw err;\n }\n\n const owner = await readPromotionLockOwner(lockDir);\n const heartbeatMs = await readPromotionLockHeartbeatMs(lockDir, owner.token);\n const lockedAtMs = heartbeatMs ?? owner.heartbeatAtMs ?? owner.acquiredAtMs ?? lockStat.mtimeMs;\n const ownerlessLock = owner.token === null && owner.heartbeatAtMs === null && owner.acquiredAtMs === null;\n const staleAfterMs = ownerlessLock ? promotionLockOwnerlessGraceMs() : promotionLockStaleMs();\n if (Date.now() - lockedAtMs < staleAfterMs) {\n return false;\n }\n\n const staleDir = `${lockDir}.stale-${process.pid}-${randomUUID()}`;\n try {\n await rename(lockDir, staleDir);\n setStaleDir(staleDir);\n } catch (err) {\n if (isErrnoCode(err, \"ENOENT\")) return false;\n throw err;\n }\n\n const staleOwner = await readPromotionLockOwner(staleDir);\n const staleHeartbeatMs = await readPromotionLockHeartbeatMs(staleDir, staleOwner.token);\n const staleLockedAtMs = staleHeartbeatMs ?? staleOwner.heartbeatAtMs ?? staleOwner.acquiredAtMs ?? lockStat.mtimeMs;\n const staleOwnerlessLock =\n staleOwner.token === null && staleOwner.heartbeatAtMs === null && staleOwner.acquiredAtMs === null;\n const staleAfterRecheckMs = staleOwnerlessLock ? promotionLockOwnerlessGraceMs() : promotionLockStaleMs();\n if (Date.now() - staleLockedAtMs < staleAfterRecheckMs) {\n await rename(staleDir, lockDir);\n setStaleDir(\"\");\n return false;\n }\n\n await rm(staleDir, { recursive: true, force: true });\n setStaleDir(\"\");\n return true;\n}\n\nasync function releasePromotionLock(lockDir: string, token: string): Promise<void> {\n const releaseDir = promotionReleaseDir(lockDir);\n const deadline = Date.now() + promotionLockTimeoutMs();\n await testHooks?.beforeLockRelease?.(lockDir, token);\n for (;;) {\n try {\n await mkdir(releaseDir);\n break;\n } catch (err) {\n if (!isErrnoCode(err, \"EEXIST\")) {\n throw err;\n }\n const owner = await readPromotionLockOwner(lockDir);\n if (owner.token !== token) {\n return;\n }\n await reapAbandonedPromotionGuard(releaseDir);\n if (Date.now() >= deadline) {\n throw new Error(\"Timed out releasing semantic rule promotion lock\");\n }\n await sleep(promotionLockRetryMs());\n }\n }\n\n try {\n const owner = await readPromotionLockOwner(lockDir);\n if (owner.token !== token) {\n return;\n }\n await rm(lockDir, { recursive: true, force: true });\n } finally {\n await rm(releaseDir, { recursive: true, force: true });\n }\n}\n\ntype PromotionLockLease = {\n assertHeld: () => Promise<void>;\n beforePromotedRuleWrite: () => Promise<void>;\n};\n\nasync function withPromotionLock<T>(\n memoryDir: string,\n ruleKey: string,\n fn: (lease: PromotionLockLease) => Promise<T>\n): Promise<T> {\n const lockDir = promotionLockDir(memoryDir, ruleKey);\n const lockRoot = path.dirname(lockDir);\n const deadline = Date.now() + promotionLockTimeoutMs();\n let lockToken: string | null = null;\n let heartbeat: NodeJS.Timeout | null = null;\n\n await mkdir(lockRoot, { recursive: true });\n for (;;) {\n try {\n if (await hasPromotionGuard(lockDir)) {\n await reapAbandonedPromotionGuards(lockDir);\n if (Date.now() >= deadline) {\n throw new Error(\"Timed out acquiring semantic rule promotion lock\");\n }\n await sleep(promotionLockRetryMs());\n continue;\n }\n await mkdir(lockDir);\n if (await hasPromotionGuard(lockDir)) {\n await reapAbandonedPromotionGuards(lockDir);\n if (Date.now() >= deadline) {\n throw new Error(\"Timed out acquiring semantic rule promotion lock\");\n }\n await sleep(promotionLockRetryMs());\n continue;\n }\n try {\n lockToken = randomUUID();\n const lockOwner = {\n token: lockToken,\n acquiredAt: new Date().toISOString(),\n };\n const wroteOwner = await tryWritePromotionLockOwner(lockDir, lockOwner);\n if (!wroteOwner) {\n lockToken = null;\n if (Date.now() >= deadline) {\n throw new Error(\"Timed out acquiring semantic rule promotion lock\");\n }\n await sleep(promotionLockRetryMs());\n continue;\n }\n await writePromotionLockHeartbeat(lockDir, lockToken);\n const heartbeatToken = lockToken;\n const heartbeatMs = promotionLockHeartbeatMs();\n if (heartbeatMs > 0) {\n heartbeat = setInterval(() => {\n void refreshPromotionLockHeartbeat(lockDir, heartbeatToken)\n .then((ownsLock) => {\n if (!ownsLock && heartbeat) {\n clearInterval(heartbeat);\n heartbeat = null;\n }\n })\n .catch(() => undefined);\n }, heartbeatMs);\n }\n } catch (err) {\n lockToken = null;\n if (heartbeat) {\n clearInterval(heartbeat);\n heartbeat = null;\n }\n await rm(lockDir, { recursive: true, force: true });\n throw err;\n }\n break;\n } catch (err) {\n if (!isErrnoCode(err, \"EEXIST\")) {\n throw err;\n }\n if (await reapStalePromotionLock(lockDir)) {\n continue;\n }\n if (Date.now() >= deadline) {\n throw new Error(\"Timed out acquiring semantic rule promotion lock\");\n }\n await sleep(promotionLockRetryMs());\n }\n }\n\n const assertHeld = async () => {\n if (!lockToken) {\n throw new Error(\"Semantic rule promotion lock is no longer held\");\n }\n const ownsLock = await refreshPromotionLockHeartbeat(lockDir, lockToken);\n if (!ownsLock) {\n throw new Error(\"Semantic rule promotion lock is no longer held\");\n }\n };\n\n let hasResult = false;\n let result: T | undefined;\n let callbackError: unknown;\n let releaseError: unknown;\n try {\n await assertHeld();\n result = await fn({\n assertHeld,\n beforePromotedRuleWrite: async () => {\n if (!lockToken) {\n throw new Error(\"Semantic rule promotion lock is no longer held\");\n }\n await testHooks?.beforePromotedRuleWrite?.(lockDir, lockToken);\n await assertHeld();\n },\n });\n hasResult = true;\n } catch (err) {\n callbackError = err;\n } finally {\n if (heartbeat) {\n clearInterval(heartbeat);\n }\n if (lockToken) {\n try {\n await releasePromotionLock(lockDir, lockToken);\n } catch (err) {\n if (!hasResult && !callbackError) {\n releaseError = err;\n }\n }\n }\n }\n if (releaseError) {\n throw releaseError;\n }\n if (callbackError) {\n throw callbackError;\n }\n return result as T;\n}\n\nfunction normalizeRuleWhitespace(value: string): string {\n return value.replace(/\\s+/g, \" \").trim();\n}\n\nfunction stripTrailingClausePunctuation(value: string): string {\n return value.replace(/[,:;]+$/g, \"\").trim();\n}\n\nfunction canonicalizeRuleContent(value: string): string {\n return extractExplicitIfThenRule(value) ?? normalizeRuleWhitespace(value);\n}\n\nfunction canonicalizeRuleKey(value: string): string {\n return canonicalizeRuleContent(value).toLowerCase();\n}\n\nfunction extractExplicitIfThenRule(content: string): string | null {\n const match = content.match(/\\bif\\b([\\s\\S]+?)\\bthen\\b([\\s\\S]+?)(?:[.!?](?:\\s|$)|$)/i);\n if (!match) return null;\n const condition = stripTrailingClausePunctuation(normalizeRuleWhitespace(match[1] ?? \"\"));\n const outcome = stripTrailingClausePunctuation(normalizeRuleWhitespace(match[2] ?? \"\"));\n if (condition.length === 0 || outcome.length === 0) return null;\n return `IF ${condition} THEN ${outcome}.`;\n}\n\nfunction promotionConfidence(memory: MemoryFile): number {\n const base = Number.isFinite(memory.frontmatter.confidence) ? memory.frontmatter.confidence : 0.8;\n return Math.max(0.6, Math.min(0.98, base));\n}\n\nfunction promotionTags(memory: MemoryFile): string[] {\n return Array.from(new Set([...(memory.frontmatter.tags ?? []), \"semantic-rule\", \"promoted-rule\"]));\n}\n\nfunction buildSupportLinks(sourceMemoryId: string, confidence: number): MemoryLink[] {\n return [\n {\n targetId: sourceMemoryId,\n linkType: \"supports\",\n strength: confidence,\n reason: \"Promoted from verified episodic memory\",\n },\n ];\n}\n\nexport async function promoteSemanticRuleFromMemory(options: {\n memoryDir: string;\n enabled: boolean;\n sourceMemoryId: string;\n dryRun?: boolean;\n}): Promise<SemanticRulePromotionReport> {\n const report: SemanticRulePromotionReport = {\n enabled: options.enabled,\n dryRun: options.dryRun === true,\n promoted: [],\n skipped: [],\n };\n if (!options.enabled) {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"disabled\",\n });\n return report;\n }\n\n const storage = new StorageManager(options.memoryDir);\n const sourceMemory = await storage.getMemoryById(options.sourceMemoryId);\n if (!sourceMemory) {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"source-memory-missing\",\n });\n return report;\n }\n if (sourceMemory.frontmatter.status === \"forgotten\") {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"source-memory-forgotten\",\n });\n return report;\n }\n if (sourceMemory.frontmatter.status === \"archived\" || sourceMemory.frontmatter.memoryKind !== \"episode\") {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"source-memory-not-episode\",\n });\n return report;\n }\n\n const content = extractExplicitIfThenRule(sourceMemory.content);\n if (!content) {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"no-explicit-rule\",\n });\n return report;\n }\n\n const ruleKey = canonicalizeRuleKey(content);\n const confidence = promotionConfidence(sourceMemory);\n const candidateBase = {\n sourceMemoryId: options.sourceMemoryId,\n content,\n confidence,\n tags: promotionTags(sourceMemory),\n memoryKind: \"note\" as const,\n lineage: [options.sourceMemoryId],\n };\n\n return withPromotionLock(options.memoryDir, ruleKey, async (lock) => {\n storage.invalidateAllMemoriesCacheForDir();\n const existingRule = (await storage.readAllMemories()).find(\n (memory) =>\n memory.frontmatter.category === \"rule\" &&\n memory.frontmatter.status !== \"archived\" &&\n memory.frontmatter.status !== \"forgotten\" &&\n canonicalizeRuleKey(memory.content) === ruleKey\n );\n if (existingRule) {\n report.skipped.push({\n sourceMemoryId: options.sourceMemoryId,\n reason: \"duplicate-rule\",\n existingRuleId: existingRule.frontmatter.id,\n });\n return report;\n }\n\n if (options.dryRun === true) {\n await lock.assertHeld();\n report.promoted.push({\n id: `dry-run:${options.sourceMemoryId}`,\n ...candidateBase,\n });\n return report;\n }\n\n await lock.beforePromotedRuleWrite();\n const id = await storage.writeMemory(\"rule\", content, {\n confidence,\n tags: candidateBase.tags,\n source: \"semantic-rule-promotion\",\n lineage: candidateBase.lineage,\n sourceMemoryId: options.sourceMemoryId,\n memoryKind: \"note\",\n links: buildSupportLinks(options.sourceMemoryId, confidence),\n });\n report.promoted.push({\n id,\n ...candidateBase,\n });\n return report;\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
} from "./chunk-YR6GIWWY.js";
|
|
71
71
|
import {
|
|
72
72
|
promoteSemanticRuleFromMemory
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-KDUFBSBF.js";
|
|
74
74
|
import {
|
|
75
75
|
buildResumeBundleFromState,
|
|
76
76
|
getResumeBundleStatus,
|
|
@@ -6616,4 +6616,4 @@ export {
|
|
|
6616
6616
|
resolveMemoryDirForNamespace,
|
|
6617
6617
|
registerCli
|
|
6618
6618
|
};
|
|
6619
|
-
//# sourceMappingURL=chunk-
|
|
6619
|
+
//# sourceMappingURL=chunk-QNXFFUWA.js.map
|
package/dist/cli.js
CHANGED
|
@@ -89,7 +89,7 @@ import {
|
|
|
89
89
|
runWorkProductStatusCliCommand,
|
|
90
90
|
runWorkProjectCliCommand,
|
|
91
91
|
runWorkTaskCliCommand
|
|
92
|
-
} from "./chunk-
|
|
92
|
+
} from "./chunk-QNXFFUWA.js";
|
|
93
93
|
import "./chunk-LQHDIS7L.js";
|
|
94
94
|
import "./chunk-7F7Z6MOS.js";
|
|
95
95
|
import "./chunk-4RR6ROTB.js";
|
|
@@ -117,7 +117,7 @@ import "./chunk-WMWVO45V.js";
|
|
|
117
117
|
import "./chunk-H2NCNXMS.js";
|
|
118
118
|
import "./chunk-PU44GBL4.js";
|
|
119
119
|
import "./chunk-YR6GIWWY.js";
|
|
120
|
-
import "./chunk-
|
|
120
|
+
import "./chunk-KDUFBSBF.js";
|
|
121
121
|
import "./chunk-Z4R6RI2N.js";
|
|
122
122
|
import "./chunk-TGQ2NTWH.js";
|
|
123
123
|
import "./chunk-CF3ZF2YU.js";
|
package/dist/index.js
CHANGED
|
@@ -93,7 +93,7 @@ import {
|
|
|
93
93
|
listTrainingExportAdapters,
|
|
94
94
|
registerTrainingExportAdapter,
|
|
95
95
|
runBulkImportCliCommand
|
|
96
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-QNXFFUWA.js";
|
|
97
97
|
import "./chunk-LQHDIS7L.js";
|
|
98
98
|
import "./chunk-7F7Z6MOS.js";
|
|
99
99
|
import "./chunk-4RR6ROTB.js";
|
|
@@ -134,7 +134,7 @@ import {
|
|
|
134
134
|
validateImportTurn
|
|
135
135
|
} from "./chunk-PU44GBL4.js";
|
|
136
136
|
import "./chunk-YR6GIWWY.js";
|
|
137
|
-
import "./chunk-
|
|
137
|
+
import "./chunk-KDUFBSBF.js";
|
|
138
138
|
import "./chunk-Z4R6RI2N.js";
|
|
139
139
|
import {
|
|
140
140
|
clearAuthTokenSecretCache,
|