@agenr/openclaw-plugin 1.5.0 → 2026.6.2
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/LICENSE +21 -661
- package/README.md +1 -0
- package/dist/build-before-turn-artifact-NPUHVWFE.js +71 -0
- package/dist/build-recall-artifact-F3LS3PZX.js +62 -0
- package/dist/chunk-5AXMFBHR.js +14 -0
- package/dist/chunk-5AYIXQRF.js +4452 -0
- package/dist/chunk-5TIP2EPP.js +6944 -0
- package/dist/chunk-GAERET5Q.js +2070 -0
- package/dist/chunk-GF3PX3VM.js +41 -0
- package/dist/chunk-GKZQ5AG5.js +44 -0
- package/dist/chunk-LDJN7CVU.js +3231 -0
- package/dist/chunk-MC3C2XM5.js +148 -0
- package/dist/chunk-NBS62ES5.js +3012 -0
- package/dist/chunk-NSLTJBUC.js +270 -0
- package/dist/chunk-OJSIZDZD.js +9 -0
- package/dist/chunk-OWGQWQUP.js +45 -0
- package/dist/chunk-Q5UTJXHZ.js +1069 -0
- package/dist/chunk-SOQW7356.js +2416 -0
- package/dist/chunk-VBPYU7GO.js +597 -0
- package/dist/chunk-VTHBPXDQ.js +1750 -0
- package/dist/chunk-XFJ4S4G2.js +1679 -0
- package/dist/chunk-Y5NB3FTH.js +106 -0
- package/dist/chunk-ZX55JBV2.js +4451 -0
- package/dist/index.js +1905 -15298
- package/dist/lifecycle-checkpoint-IAC5FCQU.js +154 -0
- package/dist/scan-6JKPOQHD.js +6 -0
- package/dist/service-EKFACEN6.js +15 -0
- package/dist/service-RHNB5AEQ.js +861 -0
- package/dist/sink-AUAAWC5O.js +8 -0
- package/openclaw.plugin.json +148 -11
- package/package.json +7 -5
- package/dist/anthropic-RE4XNAKE.js +0 -5515
- package/dist/azure-openai-responses-IQLXOCZS.js +0 -190
- package/dist/chunk-6DQXEU2A.js +0 -32306
- package/dist/chunk-EAQYK3U2.js +0 -41
- package/dist/chunk-HNWLZUWE.js +0 -31
- package/dist/chunk-JRUUYSFL.js +0 -262
- package/dist/chunk-OLOUBEE5.js +0 -14022
- package/dist/chunk-P5HNPYGQ.js +0 -174
- package/dist/chunk-RD7BUOBD.js +0 -416
- package/dist/chunk-RWWH2U4W.js +0 -7056
- package/dist/chunk-SEOMNQGB.js +0 -86
- package/dist/chunk-SQLXP7LT.js +0 -4792
- package/dist/chunk-URGOKODJ.js +0 -17
- package/dist/dist-R6ESEJ6P.js +0 -1244
- package/dist/google-NAVXTQLO.js +0 -371
- package/dist/google-gemini-cli-NKYJWHX2.js +0 -712
- package/dist/google-vertex-ZBJ2EDRH.js +0 -414
- package/dist/mistral-SBQYC4J5.js +0 -38407
- package/dist/multipart-parser-DV373IRF.js +0 -371
- package/dist/openai-codex-responses-XN3T3DEN.js +0 -712
- package/dist/openai-completions-75ZFOFU6.js +0 -657
- package/dist/openai-responses-DCK4BVNT.js +0 -198
- package/dist/src-T5RRS2HN.js +0 -1408
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
// src/core/claim-key.ts
|
|
2
|
+
var UNKNOWN_SEGMENT = "unknown";
|
|
3
|
+
var SELF_REFERENTIAL_ENTITIES = /* @__PURE__ */ new Set(["i", "me", "myself", "the_user", "user", "we", "our_team", "the_project", "this_project"]);
|
|
4
|
+
var GENERIC_ENTITIES = /* @__PURE__ */ new Set([
|
|
5
|
+
"app",
|
|
6
|
+
"company",
|
|
7
|
+
"config",
|
|
8
|
+
"data",
|
|
9
|
+
"device",
|
|
10
|
+
"entity",
|
|
11
|
+
"environment",
|
|
12
|
+
"item",
|
|
13
|
+
"organization",
|
|
14
|
+
"person",
|
|
15
|
+
"place",
|
|
16
|
+
"project",
|
|
17
|
+
"service",
|
|
18
|
+
"setting",
|
|
19
|
+
"system",
|
|
20
|
+
"team",
|
|
21
|
+
"thing",
|
|
22
|
+
"user",
|
|
23
|
+
"workspace"
|
|
24
|
+
]);
|
|
25
|
+
var GENERIC_ATTRIBUTES = /* @__PURE__ */ new Set(["info", "details", "config", "stuff", "thing", "data"]);
|
|
26
|
+
var COMPACTION_RELATION_TOKENS = /* @__PURE__ */ new Set([
|
|
27
|
+
"after",
|
|
28
|
+
"before",
|
|
29
|
+
"depend",
|
|
30
|
+
"depends",
|
|
31
|
+
"follows",
|
|
32
|
+
"follow",
|
|
33
|
+
"keep",
|
|
34
|
+
"keeps",
|
|
35
|
+
"maintain",
|
|
36
|
+
"maintains",
|
|
37
|
+
"need",
|
|
38
|
+
"needs",
|
|
39
|
+
"precede",
|
|
40
|
+
"precedes",
|
|
41
|
+
"preserve",
|
|
42
|
+
"preserves",
|
|
43
|
+
"require",
|
|
44
|
+
"required",
|
|
45
|
+
"requires",
|
|
46
|
+
"retain",
|
|
47
|
+
"retains"
|
|
48
|
+
]);
|
|
49
|
+
var COMPACTION_BREAK_TOKENS = /* @__PURE__ */ new Set(["about", "across", "and", "between", "during", "for", "from", "into", "onto", "or", "to", "with"]);
|
|
50
|
+
var COMPACTION_WEAK_LEADING_TOKENS = /* @__PURE__ */ new Set(["actual", "authoritative", "canonical", "concrete", "current", "durable", "existing", "real"]);
|
|
51
|
+
var ACTION_CONDITION_TOKENS = /* @__PURE__ */ new Set(["activate", "activation", "apply", "fire", "launch", "run", "start", "trigger"]);
|
|
52
|
+
var TRAILING_OBJECT_COMPACTION_PREPOSITIONS = /* @__PURE__ */ new Set(["about", "for", "from", "into", "onto", "to", "with"]);
|
|
53
|
+
var TRAILING_OBJECT_TRANSFER_HEADS = /* @__PURE__ */ new Set([
|
|
54
|
+
"access",
|
|
55
|
+
"boundary",
|
|
56
|
+
"condition",
|
|
57
|
+
"contract",
|
|
58
|
+
"guide",
|
|
59
|
+
"path",
|
|
60
|
+
"policy",
|
|
61
|
+
"preference",
|
|
62
|
+
"process",
|
|
63
|
+
"rule",
|
|
64
|
+
"schedule",
|
|
65
|
+
"support",
|
|
66
|
+
"surface",
|
|
67
|
+
"window",
|
|
68
|
+
"workflow"
|
|
69
|
+
]);
|
|
70
|
+
var STABLE_ATTRIBUTE_HEADS = /* @__PURE__ */ new Set([
|
|
71
|
+
"access",
|
|
72
|
+
"boundary",
|
|
73
|
+
"condition",
|
|
74
|
+
"contract",
|
|
75
|
+
"default",
|
|
76
|
+
"dependency",
|
|
77
|
+
"guide",
|
|
78
|
+
"mode",
|
|
79
|
+
"order",
|
|
80
|
+
"path",
|
|
81
|
+
"policy",
|
|
82
|
+
"preference",
|
|
83
|
+
"preservation",
|
|
84
|
+
"process",
|
|
85
|
+
"requirement",
|
|
86
|
+
"rule",
|
|
87
|
+
"schedule",
|
|
88
|
+
"setting",
|
|
89
|
+
"status",
|
|
90
|
+
"strategy",
|
|
91
|
+
"support",
|
|
92
|
+
"surface",
|
|
93
|
+
"timezone",
|
|
94
|
+
"truth",
|
|
95
|
+
"version",
|
|
96
|
+
"window",
|
|
97
|
+
"workflow"
|
|
98
|
+
]);
|
|
99
|
+
function normalizeClaimKeySegment(value) {
|
|
100
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
|
101
|
+
}
|
|
102
|
+
function normalizeClaimKey(value) {
|
|
103
|
+
const trimmed = value.trim();
|
|
104
|
+
if (trimmed.length === 0) {
|
|
105
|
+
return { ok: false, reason: "empty" };
|
|
106
|
+
}
|
|
107
|
+
const slashCount = Array.from(trimmed).filter((character) => character === "/").length;
|
|
108
|
+
if (slashCount === 0) {
|
|
109
|
+
return { ok: false, reason: "missing_separator" };
|
|
110
|
+
}
|
|
111
|
+
if (slashCount !== 1) {
|
|
112
|
+
return { ok: false, reason: "too_many_segments" };
|
|
113
|
+
}
|
|
114
|
+
const [rawEntity = "", rawAttribute = ""] = trimmed.split("/");
|
|
115
|
+
const entity = normalizeClaimKeySegment(rawEntity);
|
|
116
|
+
if (entity.length === 0) {
|
|
117
|
+
return { ok: false, reason: "empty_entity" };
|
|
118
|
+
}
|
|
119
|
+
const attribute = normalizeClaimKeySegment(rawAttribute);
|
|
120
|
+
if (attribute.length === 0) {
|
|
121
|
+
return { ok: false, reason: "empty_attribute" };
|
|
122
|
+
}
|
|
123
|
+
if (entity === UNKNOWN_SEGMENT && attribute === UNKNOWN_SEGMENT) {
|
|
124
|
+
return { ok: false, reason: "unknown_pair" };
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
ok: true,
|
|
128
|
+
value: {
|
|
129
|
+
claimKey: `${entity}/${attribute}`,
|
|
130
|
+
entity,
|
|
131
|
+
attribute
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function compactClaimKey(claimKey) {
|
|
136
|
+
const normalized = normalizeClaimKey(claimKey);
|
|
137
|
+
if (!normalized.ok) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
let attributeTokens = normalized.value.attribute.split("_").filter((token) => token.length > 0);
|
|
141
|
+
const entityTokens = normalized.value.entity.split("_").filter((token) => token.length > 0);
|
|
142
|
+
const reasons = [];
|
|
143
|
+
if (entityTokens.length > 0 && startsWithTokens(attributeTokens, entityTokens) && attributeTokens.length > entityTokens.length) {
|
|
144
|
+
attributeTokens = attributeTokens.slice(entityTokens.length);
|
|
145
|
+
reasons.push("removed duplicated entity prefix from attribute");
|
|
146
|
+
}
|
|
147
|
+
if (entityTokens.length > 0 && attributeTokens.length > entityTokens.length + 1 && endsWithTokens(attributeTokens, entityTokens) && TRAILING_OBJECT_COMPACTION_PREPOSITIONS.has(attributeTokens[attributeTokens.length - entityTokens.length - 1] ?? "")) {
|
|
148
|
+
attributeTokens = attributeTokens.slice(0, attributeTokens.length - entityTokens.length - 1);
|
|
149
|
+
reasons.push("removed duplicated entity suffix from attribute");
|
|
150
|
+
}
|
|
151
|
+
const sourceOfTruthCompaction = compactSourceOfTruthAttribute(attributeTokens);
|
|
152
|
+
if (sourceOfTruthCompaction) {
|
|
153
|
+
attributeTokens = sourceOfTruthCompaction.attributeTokens;
|
|
154
|
+
reasons.push(sourceOfTruthCompaction.reason);
|
|
155
|
+
} else {
|
|
156
|
+
const relationCompaction = compactRelationAttribute(attributeTokens);
|
|
157
|
+
if (relationCompaction) {
|
|
158
|
+
attributeTokens = relationCompaction.attributeTokens;
|
|
159
|
+
reasons.push(relationCompaction.reason);
|
|
160
|
+
} else {
|
|
161
|
+
const trailingObjectCompaction = compactTrailingObjectAttribute(attributeTokens);
|
|
162
|
+
if (trailingObjectCompaction) {
|
|
163
|
+
attributeTokens = trailingObjectCompaction.attributeTokens;
|
|
164
|
+
reasons.push(trailingObjectCompaction.reason);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const attribute = attributeTokens.join("_");
|
|
169
|
+
if (attribute.length === 0) {
|
|
170
|
+
return {
|
|
171
|
+
claimKey: normalized.value.claimKey,
|
|
172
|
+
entity: normalized.value.entity,
|
|
173
|
+
attribute: normalized.value.attribute,
|
|
174
|
+
compactedFrom: null,
|
|
175
|
+
reason: null
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const compactedClaimKey = `${normalized.value.entity}/${attribute}`;
|
|
179
|
+
return {
|
|
180
|
+
claimKey: compactedClaimKey,
|
|
181
|
+
entity: normalized.value.entity,
|
|
182
|
+
attribute,
|
|
183
|
+
compactedFrom: compactedClaimKey !== normalized.value.claimKey ? normalized.value.claimKey : null,
|
|
184
|
+
reason: reasons.length > 0 ? joinCompactionReasons(reasons) : null
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function validateExtractedClaimKey(claimKey) {
|
|
188
|
+
if (SELF_REFERENTIAL_ENTITIES.has(claimKey.entity)) {
|
|
189
|
+
return {
|
|
190
|
+
ok: false,
|
|
191
|
+
reason: "self_referential_entity",
|
|
192
|
+
value: claimKey
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
if (GENERIC_ATTRIBUTES.has(claimKey.attribute)) {
|
|
196
|
+
return {
|
|
197
|
+
ok: false,
|
|
198
|
+
reason: "generic_attribute",
|
|
199
|
+
value: claimKey
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (isValueShapedAttribute(claimKey.attribute)) {
|
|
203
|
+
return {
|
|
204
|
+
ok: false,
|
|
205
|
+
reason: "value_shaped_attribute",
|
|
206
|
+
value: claimKey
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
ok: true,
|
|
211
|
+
value: claimKey
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function inspectClaimKey(value) {
|
|
215
|
+
const rawClaimKey = value.trim();
|
|
216
|
+
const normalized = normalizeClaimKey(rawClaimKey);
|
|
217
|
+
if (!normalized.ok) {
|
|
218
|
+
return {
|
|
219
|
+
rawClaimKey,
|
|
220
|
+
canonical: false,
|
|
221
|
+
normalizationFailure: normalized.reason,
|
|
222
|
+
suspectReasons: []
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const suspectReasons = /* @__PURE__ */ new Set();
|
|
226
|
+
const validation = validateExtractedClaimKey(normalized.value);
|
|
227
|
+
if (!validation.ok) {
|
|
228
|
+
suspectReasons.add(validation.reason);
|
|
229
|
+
}
|
|
230
|
+
if (GENERIC_ENTITIES.has(normalized.value.entity)) {
|
|
231
|
+
suspectReasons.add("generic_entity");
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
rawClaimKey,
|
|
235
|
+
canonical: normalized.value.claimKey === rawClaimKey,
|
|
236
|
+
normalized: normalized.value,
|
|
237
|
+
suspectReasons: [...suspectReasons]
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function isTrustedClaimKeyForCleanup(value) {
|
|
241
|
+
const inspection = inspectClaimKey(value);
|
|
242
|
+
return Boolean(inspection.canonical && inspection.normalized && inspection.suspectReasons.length === 0);
|
|
243
|
+
}
|
|
244
|
+
function describeClaimKeyNormalizationFailure(reason) {
|
|
245
|
+
switch (reason) {
|
|
246
|
+
case "empty":
|
|
247
|
+
return "claim key was empty";
|
|
248
|
+
case "missing_separator":
|
|
249
|
+
return "claim key must contain exactly one '/'";
|
|
250
|
+
case "too_many_segments":
|
|
251
|
+
return "claim key must contain exactly one '/'";
|
|
252
|
+
case "empty_entity":
|
|
253
|
+
return "claim key entity was empty after normalization";
|
|
254
|
+
case "empty_attribute":
|
|
255
|
+
return "claim key attribute was empty after normalization";
|
|
256
|
+
case "unknown_pair":
|
|
257
|
+
return 'claim key "unknown/unknown" is not allowed';
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function describeExtractedClaimKeyRejection(reason, claimKey) {
|
|
261
|
+
switch (reason) {
|
|
262
|
+
case "self_referential_entity":
|
|
263
|
+
return `entity "${claimKey.entity}" is self-referential`;
|
|
264
|
+
case "generic_attribute":
|
|
265
|
+
return `attribute "${claimKey.attribute}" is too generic`;
|
|
266
|
+
case "value_shaped_attribute":
|
|
267
|
+
return `attribute "${claimKey.attribute}" looks value-shaped`;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function describeClaimKeySuspicion(reason, claimKey) {
|
|
271
|
+
switch (reason) {
|
|
272
|
+
case "generic_entity":
|
|
273
|
+
return `entity "${claimKey.entity}" is too generic`;
|
|
274
|
+
case "self_referential_entity":
|
|
275
|
+
case "generic_attribute":
|
|
276
|
+
case "value_shaped_attribute":
|
|
277
|
+
return describeExtractedClaimKeyRejection(reason, claimKey);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function isValueShapedAttribute(attribute) {
|
|
281
|
+
return /^\d+(?:_\d+)*$/u.test(attribute) || /^v\d+(?:_\d+)*$/u.test(attribute);
|
|
282
|
+
}
|
|
283
|
+
function compactSourceOfTruthAttribute(attributeTokens) {
|
|
284
|
+
const sourceOfTruthIndex = findSourceOfTruthPhraseIndex(attributeTokens);
|
|
285
|
+
if (sourceOfTruthIndex === -1) {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
const normalizedPhrase = ["source", "of", "truth"];
|
|
289
|
+
if (attributeTokens.length === normalizedPhrase.length && startsWithTokens(attributeTokens, normalizedPhrase)) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
const before = attributeTokens.slice(0, sourceOfTruthIndex);
|
|
293
|
+
const after = attributeTokens.slice(sourceOfTruthIndex + normalizedPhrase.length);
|
|
294
|
+
const leadingAllowed = before.every((token) => COMPACTION_WEAK_LEADING_TOKENS.has(token));
|
|
295
|
+
const hasMixedStableFamily = before.some((token) => STABLE_ATTRIBUTE_HEADS.has(token)) || after.some((token) => STABLE_ATTRIBUTE_HEADS.has(token));
|
|
296
|
+
const hasConjunctionNoise = before.includes("and") || before.includes("or") || after.includes("and") || after.includes("or");
|
|
297
|
+
if (!leadingAllowed || hasMixedStableFamily || hasConjunctionNoise) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
attributeTokens: normalizedPhrase,
|
|
302
|
+
reason: "collapsed source-of-truth phrasing into the stable canonical slot"
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function compactRelationAttribute(attributeTokens) {
|
|
306
|
+
const relationIndex = attributeTokens.findIndex((token) => COMPACTION_RELATION_TOKENS.has(token));
|
|
307
|
+
if (relationIndex === -1) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
const relation = attributeTokens[relationIndex] ?? "";
|
|
311
|
+
const left = attributeTokens.slice(0, relationIndex);
|
|
312
|
+
const right = attributeTokens.slice(relationIndex + 1);
|
|
313
|
+
if (left.length === 0 && right.length === 0) {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
if (isRequirementRelation(relation)) {
|
|
317
|
+
const conditionAction = extractConditionAction(right);
|
|
318
|
+
if (conditionAction) {
|
|
319
|
+
return {
|
|
320
|
+
attributeTokens: [conditionAction, "condition"],
|
|
321
|
+
reason: `collapsed a sentence-like ${conditionAction} requirement into a stable condition slot`
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
const requirementFocus = extractCompactionFocus(right, 2) ?? extractCompactionFocus(left, 2);
|
|
325
|
+
if (!requirementFocus) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
return {
|
|
329
|
+
attributeTokens: [...requirementFocus, "requirement"],
|
|
330
|
+
reason: "collapsed a sentence-like requirement phrase into a stable requirement slot"
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
if (isOrderingRelation(relation)) {
|
|
334
|
+
const orderingFocus = extractCompactionFocus(right, 2) ?? extractCompactionFocus(left, 2);
|
|
335
|
+
if (!orderingFocus) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
attributeTokens: [...orderingFocus, "order"],
|
|
340
|
+
reason: "collapsed a sentence-like ordering phrase into a stable order slot"
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
if (isPreservationRelation(relation)) {
|
|
344
|
+
const preservationFocus = extractCompactionFocus(right, 2) ?? extractCompactionFocus(left, 2);
|
|
345
|
+
if (!preservationFocus) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
attributeTokens: [...preservationFocus, "preservation"],
|
|
350
|
+
reason: "collapsed a sentence-like preservation phrase into a stable preservation slot"
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
function compactTrailingObjectAttribute(attributeTokens) {
|
|
356
|
+
const prepositionIndex = attributeTokens.findIndex((token) => TRAILING_OBJECT_COMPACTION_PREPOSITIONS.has(token));
|
|
357
|
+
if (prepositionIndex <= 0 || prepositionIndex >= attributeTokens.length - 1) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
const left = trimWeakLeadingTokens(attributeTokens.slice(0, prepositionIndex));
|
|
361
|
+
const right = attributeTokens.slice(prepositionIndex + 1);
|
|
362
|
+
if (left.length === 0 || left.length > 3 || left.includes("and") || left.includes("or") || left.some((token) => COMPACTION_RELATION_TOKENS.has(token))) {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
const head = left[left.length - 1];
|
|
366
|
+
if (!head || !TRAILING_OBJECT_TRANSFER_HEADS.has(head)) {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
const objectFocus = extractCompactionFocus(right, 2);
|
|
370
|
+
if (!objectFocus) {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
const headCore = extractStableHeadCore(left, 2);
|
|
374
|
+
if (!headCore) {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
attributeTokens: [...objectFocus, ...headCore],
|
|
379
|
+
reason: "collapsed a trailing object phrase into a compact stable slot name"
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
function findSourceOfTruthPhraseIndex(tokens) {
|
|
383
|
+
for (let index = 0; index <= tokens.length - 3; index += 1) {
|
|
384
|
+
if (tokens[index] === "source" && tokens[index + 1] === "of" && tokens[index + 2] === "truth") {
|
|
385
|
+
return index;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return -1;
|
|
389
|
+
}
|
|
390
|
+
function extractConditionAction(tokens) {
|
|
391
|
+
for (let index = tokens.length - 1; index >= 0; index -= 1) {
|
|
392
|
+
const token = tokens[index];
|
|
393
|
+
if (token && ACTION_CONDITION_TOKENS.has(token)) {
|
|
394
|
+
return token;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
function extractCompactionFocus(tokens, limit) {
|
|
400
|
+
const compactable = trimWeakLeadingTokens(tokens).filter((token) => token.length > 0);
|
|
401
|
+
const segments = splitTokensOnBreaks(compactable).filter((segment) => segment.length > 0);
|
|
402
|
+
const preferredSegment = segments[0];
|
|
403
|
+
if (!preferredSegment || preferredSegment.length === 0) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
return preferredSegment.slice(0, limit);
|
|
407
|
+
}
|
|
408
|
+
function extractStableHeadCore(tokens, limit) {
|
|
409
|
+
const compactable = trimWeakLeadingTokens(tokens).filter((token) => token.length > 0);
|
|
410
|
+
const head = compactable[compactable.length - 1];
|
|
411
|
+
if (!head || !STABLE_ATTRIBUTE_HEADS.has(head)) {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
return compactable.slice(Math.max(0, compactable.length - limit));
|
|
415
|
+
}
|
|
416
|
+
function splitTokensOnBreaks(tokens) {
|
|
417
|
+
const segments = [];
|
|
418
|
+
let current = [];
|
|
419
|
+
for (const token of tokens) {
|
|
420
|
+
if (COMPACTION_BREAK_TOKENS.has(token)) {
|
|
421
|
+
if (current.length > 0) {
|
|
422
|
+
segments.push(current);
|
|
423
|
+
current = [];
|
|
424
|
+
}
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
current.push(token);
|
|
428
|
+
}
|
|
429
|
+
if (current.length > 0) {
|
|
430
|
+
segments.push(current);
|
|
431
|
+
}
|
|
432
|
+
return segments;
|
|
433
|
+
}
|
|
434
|
+
function trimWeakLeadingTokens(tokens) {
|
|
435
|
+
let start = 0;
|
|
436
|
+
while (start < tokens.length && COMPACTION_WEAK_LEADING_TOKENS.has(tokens[start] ?? "")) {
|
|
437
|
+
start += 1;
|
|
438
|
+
}
|
|
439
|
+
return tokens.slice(start);
|
|
440
|
+
}
|
|
441
|
+
function joinCompactionReasons(reasons) {
|
|
442
|
+
if (reasons.length <= 1) {
|
|
443
|
+
return reasons[0] ?? "";
|
|
444
|
+
}
|
|
445
|
+
return `${reasons.slice(0, -1).join(", ")} and ${reasons[reasons.length - 1]}`;
|
|
446
|
+
}
|
|
447
|
+
function isRequirementRelation(token) {
|
|
448
|
+
return token === "depend" || token === "depends" || token === "need" || token === "needs" || token === "required" || token === "require" || token === "requires";
|
|
449
|
+
}
|
|
450
|
+
function isOrderingRelation(token) {
|
|
451
|
+
return token === "after" || token === "before" || token === "follow" || token === "follows" || token === "precede" || token === "precedes";
|
|
452
|
+
}
|
|
453
|
+
function isPreservationRelation(token) {
|
|
454
|
+
return token === "keep" || token === "keeps" || token === "maintain" || token === "maintains" || token === "preserve" || token === "preserves" || token === "retain" || token === "retains";
|
|
455
|
+
}
|
|
456
|
+
function startsWithTokens(tokens, prefix) {
|
|
457
|
+
return prefix.every((token, index) => tokens[index] === token);
|
|
458
|
+
}
|
|
459
|
+
function endsWithTokens(tokens, suffix) {
|
|
460
|
+
return suffix.every((token, index) => tokens[tokens.length - suffix.length + index] === token);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// src/core/keyed-durable-lifecycle.ts
|
|
464
|
+
function hasKeyedDurableLifecycleStatus(entry) {
|
|
465
|
+
return Boolean(entry.claim_key?.trim() && entry.claim_key_status);
|
|
466
|
+
}
|
|
467
|
+
function assertKeyedDurableHasLifecycle(entry) {
|
|
468
|
+
if (!entry.claim_key?.trim()) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (!entry.claim_key_status) {
|
|
472
|
+
const idSuffix = entry.id ? ` "${entry.id}"` : "";
|
|
473
|
+
throw new Error(`Missing claim_key_status for keyed durable${idSuffix}.`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function resolveKeyedDurableLifecycleStatus(entry) {
|
|
477
|
+
if (!entry.claim_key?.trim()) {
|
|
478
|
+
return "no_key";
|
|
479
|
+
}
|
|
480
|
+
assertKeyedDurableHasLifecycle(entry);
|
|
481
|
+
return entry.claim_key_status;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// src/core/temporal-validity.ts
|
|
485
|
+
function validateTemporalValidityRange(validFrom, validTo) {
|
|
486
|
+
const normalizedValidFrom = normalizeOptionalTimestamp(validFrom);
|
|
487
|
+
if (validFrom !== void 0 && validFrom !== null && normalizedValidFrom === null) {
|
|
488
|
+
return {
|
|
489
|
+
ok: false,
|
|
490
|
+
code: "invalid_valid_from",
|
|
491
|
+
message: "valid_from must be a valid ISO 8601 timestamp."
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
const normalizedValidTo = normalizeOptionalTimestamp(validTo);
|
|
495
|
+
if (validTo !== void 0 && validTo !== null && normalizedValidTo === null) {
|
|
496
|
+
return {
|
|
497
|
+
ok: false,
|
|
498
|
+
code: "invalid_valid_to",
|
|
499
|
+
message: "valid_to must be a valid ISO 8601 timestamp."
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
if (normalizedValidFrom !== void 0 && normalizedValidFrom !== null && normalizedValidTo !== void 0 && normalizedValidTo !== null && Date.parse(normalizedValidFrom) >= Date.parse(normalizedValidTo)) {
|
|
503
|
+
return {
|
|
504
|
+
ok: false,
|
|
505
|
+
code: "invalid_range",
|
|
506
|
+
message: "valid_from must be earlier than valid_to."
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
const validFromValue = normalizedValidFrom ?? void 0;
|
|
510
|
+
const validToValue = normalizedValidTo ?? void 0;
|
|
511
|
+
return {
|
|
512
|
+
ok: true,
|
|
513
|
+
value: {
|
|
514
|
+
validFrom: validFromValue,
|
|
515
|
+
validTo: validToValue
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function isWithinValidityWindow(validFrom, validTo, asOfMs) {
|
|
520
|
+
const fromMs = parseInstantMs(validFrom);
|
|
521
|
+
if (fromMs !== null && asOfMs < fromMs) {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
const toMs = parseInstantMs(validTo);
|
|
525
|
+
if (toMs !== null && asOfMs > toMs) {
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
function isCurrentlyValidMemory(row, nowMs) {
|
|
531
|
+
const supersededBy = row.superseded_by?.trim();
|
|
532
|
+
if (supersededBy) {
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
const toMs = parseInstantMs(row.valid_to);
|
|
536
|
+
if (toMs !== null && nowMs >= toMs) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
function isStaleMemory(row, nowMs) {
|
|
542
|
+
const supersededBy = row.superseded_by?.trim();
|
|
543
|
+
if (supersededBy) {
|
|
544
|
+
return false;
|
|
545
|
+
}
|
|
546
|
+
const toMs = parseInstantMs(row.valid_to);
|
|
547
|
+
if (toMs === null) {
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
return nowMs >= toMs;
|
|
551
|
+
}
|
|
552
|
+
function parseInstantMs(value) {
|
|
553
|
+
if (value === void 0 || value === null) {
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
const trimmed = value.trim();
|
|
557
|
+
if (trimmed.length === 0) {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
const parsed = Date.parse(trimmed);
|
|
561
|
+
if (Number.isNaN(parsed)) {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
return parsed;
|
|
565
|
+
}
|
|
566
|
+
function normalizeOptionalTimestamp(value) {
|
|
567
|
+
if (value === void 0 || value === null) {
|
|
568
|
+
return void 0;
|
|
569
|
+
}
|
|
570
|
+
const normalized = value.trim();
|
|
571
|
+
if (normalized.length === 0) {
|
|
572
|
+
return void 0;
|
|
573
|
+
}
|
|
574
|
+
if (!normalized.includes("T") || Number.isNaN(Date.parse(normalized))) {
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
return normalized;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
export {
|
|
581
|
+
normalizeClaimKeySegment,
|
|
582
|
+
normalizeClaimKey,
|
|
583
|
+
compactClaimKey,
|
|
584
|
+
validateExtractedClaimKey,
|
|
585
|
+
inspectClaimKey,
|
|
586
|
+
isTrustedClaimKeyForCleanup,
|
|
587
|
+
describeClaimKeyNormalizationFailure,
|
|
588
|
+
describeExtractedClaimKeyRejection,
|
|
589
|
+
describeClaimKeySuspicion,
|
|
590
|
+
hasKeyedDurableLifecycleStatus,
|
|
591
|
+
assertKeyedDurableHasLifecycle,
|
|
592
|
+
resolveKeyedDurableLifecycleStatus,
|
|
593
|
+
validateTemporalValidityRange,
|
|
594
|
+
isWithinValidityWindow,
|
|
595
|
+
isCurrentlyValidMemory,
|
|
596
|
+
isStaleMemory
|
|
597
|
+
};
|