blun-king-cli 9.1.390 → 9.1.392
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.
|
@@ -2,14 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
|
|
4
4
|
|
|
5
|
-
const COGNITIVE_MEMORY_ADAPTER_VERSION =
|
|
5
|
+
const COGNITIVE_MEMORY_ADAPTER_VERSION = 6;
|
|
6
6
|
const KIND_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
7
7
|
const RETENTION_CLASSES = new Set(['operational', 'durable', 'relationship', 'audit']);
|
|
8
|
-
const
|
|
8
|
+
const ACCESS_REQUIRED_KEYS = Object.freeze([
|
|
9
9
|
'actorId', 'agentId', 'channelId', 'conversationId', 'permissionContext',
|
|
10
10
|
'portalId', 'requestedScope', 'tenantId', 'userId',
|
|
11
11
|
]);
|
|
12
|
-
const
|
|
12
|
+
const ACCESS_OPTIONAL_KEYS = Object.freeze(['identityLink']);
|
|
13
|
+
const PERMISSION_REQUIRED_KEYS = Object.freeze(['authority', 'decision', 'receiptId']);
|
|
14
|
+
const PERMISSION_OPTIONAL_KEYS = Object.freeze(['identityReceiptId']);
|
|
15
|
+
const IDENTITY_LINK_KEYS = Object.freeze([
|
|
16
|
+
'authority', 'canonicalUserId', 'confirmedAt', 'method', 'receiptId',
|
|
17
|
+
'sourcePortal', 'sourceSubjectId', 'status', 'tenantId', 'version',
|
|
18
|
+
]);
|
|
19
|
+
const IDENTITY_LINK_AUTHORITIES = new Map([
|
|
20
|
+
['verified_oauth', 'oauth_verifier'],
|
|
21
|
+
['secure_account_link', 'account_link_service'],
|
|
22
|
+
['explicit_confirmed', 'identity_confirmation_service'],
|
|
23
|
+
]);
|
|
13
24
|
const REQUIRED_METHODS = Object.freeze([
|
|
14
25
|
'commit',
|
|
15
26
|
'read',
|
|
@@ -31,13 +42,70 @@ function exactKeys(value, expected) {
|
|
|
31
42
|
&& Object.keys(value).sort().join('\0') === [...expected].sort().join('\0');
|
|
32
43
|
}
|
|
33
44
|
|
|
45
|
+
function requiredAndOptionalKeys(value, required, optional) {
|
|
46
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
47
|
+
const allowed = new Set([...required, ...optional]);
|
|
48
|
+
return required.every((key) => Object.prototype.hasOwnProperty.call(value, key))
|
|
49
|
+
&& Object.keys(value).every((key) => allowed.has(key));
|
|
50
|
+
}
|
|
51
|
+
|
|
34
52
|
function safeId(value) {
|
|
35
53
|
const text = String(value ?? '').trim();
|
|
36
54
|
return KIND_RE.test(text) ? text : '';
|
|
37
55
|
}
|
|
38
56
|
|
|
57
|
+
function normalizeIdentityLink(access, normalized) {
|
|
58
|
+
const link = access.identityLink;
|
|
59
|
+
const identityReceiptId = normalized.permissionContext.identityReceiptId;
|
|
60
|
+
if (normalized.userId === normalized.actorId) {
|
|
61
|
+
if (link !== undefined || identityReceiptId !== undefined) fail('COGNITIVE_IDENTITY_LINK_INVALID');
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
if (link === undefined || link === null) fail('COGNITIVE_IDENTITY_LINK_REQUIRED');
|
|
65
|
+
if (!exactKeys(link, IDENTITY_LINK_KEYS)) fail('COGNITIVE_IDENTITY_LINK_INVALID');
|
|
66
|
+
if (String(link.status ?? '') === 'revoked') fail('COGNITIVE_IDENTITY_LINK_REVOKED');
|
|
67
|
+
const method = String(link.method ?? '');
|
|
68
|
+
const normalizedLink = {
|
|
69
|
+
version: Number(link.version),
|
|
70
|
+
tenantId: safeId(link.tenantId),
|
|
71
|
+
canonicalUserId: safeId(link.canonicalUserId),
|
|
72
|
+
sourcePortal: safeId(link.sourcePortal),
|
|
73
|
+
sourceSubjectId: safeId(link.sourceSubjectId),
|
|
74
|
+
method,
|
|
75
|
+
status: String(link.status ?? ''),
|
|
76
|
+
confirmedAt: String(link.confirmedAt ?? '').trim(),
|
|
77
|
+
authority: safeId(link.authority),
|
|
78
|
+
receiptId: safeId(link.receiptId),
|
|
79
|
+
};
|
|
80
|
+
if (normalizedLink.version !== 1 || normalizedLink.status !== 'active'
|
|
81
|
+
|| Number.isNaN(Date.parse(normalizedLink.confirmedAt))
|
|
82
|
+
|| IDENTITY_LINK_AUTHORITIES.get(method) !== normalizedLink.authority
|
|
83
|
+
|| normalizedLink.tenantId !== normalized.tenantId
|
|
84
|
+
|| normalizedLink.canonicalUserId !== normalized.userId
|
|
85
|
+
|| normalizedLink.sourcePortal !== normalized.portalId
|
|
86
|
+
|| normalizedLink.sourceSubjectId !== normalized.actorId
|
|
87
|
+
|| !identityReceiptId || normalizedLink.receiptId !== identityReceiptId) {
|
|
88
|
+
fail('COGNITIVE_IDENTITY_LINK_INVALID');
|
|
89
|
+
}
|
|
90
|
+
const canonicalScope = `relationship:${normalized.userId}:private`;
|
|
91
|
+
const personalScope = `user:${normalized.userId}:private`;
|
|
92
|
+
if ((normalized.requestedScope.startsWith('relationship:') && normalized.requestedScope !== canonicalScope)
|
|
93
|
+
|| (normalized.requestedScope.startsWith('user:') && normalized.requestedScope !== personalScope)) {
|
|
94
|
+
fail('COGNITIVE_IDENTITY_SCOPE_MISMATCH');
|
|
95
|
+
}
|
|
96
|
+
return Object.freeze({
|
|
97
|
+
...normalizedLink,
|
|
98
|
+
confirmedAt: new Date(normalizedLink.confirmedAt).toISOString(),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
39
102
|
function normalizeMemoryAccess(access, request) {
|
|
40
|
-
if (!
|
|
103
|
+
if (!requiredAndOptionalKeys(access, ACCESS_REQUIRED_KEYS, ACCESS_OPTIONAL_KEYS)
|
|
104
|
+
|| !requiredAndOptionalKeys(
|
|
105
|
+
access.permissionContext,
|
|
106
|
+
PERMISSION_REQUIRED_KEYS,
|
|
107
|
+
PERMISSION_OPTIONAL_KEYS,
|
|
108
|
+
)) {
|
|
41
109
|
fail('COGNITIVE_MEMORY_ACCESS_INVALID');
|
|
42
110
|
}
|
|
43
111
|
const normalized = {
|
|
@@ -53,6 +121,9 @@ function normalizeMemoryAccess(access, request) {
|
|
|
53
121
|
authority: safeId(access.permissionContext.authority),
|
|
54
122
|
decision: String(access.permissionContext.decision ?? ''),
|
|
55
123
|
receiptId: safeId(access.permissionContext.receiptId),
|
|
124
|
+
...(Object.prototype.hasOwnProperty.call(access.permissionContext, 'identityReceiptId')
|
|
125
|
+
? { identityReceiptId: safeId(access.permissionContext.identityReceiptId) }
|
|
126
|
+
: {}),
|
|
56
127
|
},
|
|
57
128
|
};
|
|
58
129
|
if (!normalized.tenantId || !normalized.userId || !normalized.actorId || !normalized.agentId
|
|
@@ -66,6 +137,8 @@ function normalizeMemoryAccess(access, request) {
|
|
|
66
137
|
|| requestTenant !== normalized.tenantId || requestAgent !== normalized.agentId) {
|
|
67
138
|
fail('COGNITIVE_MEMORY_ACCESS_SCOPE_MISMATCH');
|
|
68
139
|
}
|
|
140
|
+
const identityLink = normalizeIdentityLink(access, normalized);
|
|
141
|
+
if (identityLink) normalized.identityLink = identityLink;
|
|
69
142
|
normalized.permissionContext = Object.freeze(normalized.permissionContext);
|
|
70
143
|
return Object.freeze(normalized);
|
|
71
144
|
}
|
|
@@ -473,7 +473,7 @@ function createCognitiveTurnLifecycle({
|
|
|
473
473
|
const authorization = input?.authorization;
|
|
474
474
|
const memoryAccess = {
|
|
475
475
|
tenantId: tenant,
|
|
476
|
-
userId:
|
|
476
|
+
userId: agent,
|
|
477
477
|
actorId: agent,
|
|
478
478
|
agentId: agent,
|
|
479
479
|
portalId: 'cli',
|
|
@@ -6,6 +6,10 @@ const TRAILING_WORK_PERMISSION_QUESTION = /(?:^|\r?\n\s*\r?\n)(?:kann|darf|soll)
|
|
|
6
6
|
const INTERNAL_CONTROL_MARKER = /\b(?:cron|loop|checkpoint|handoff|resume|session|sha|tool|werkzeug|hook|queue|lane|inbound|outbound|arbeitsstand|arbeitsauftrag|bau freigabe|freigabe dieser lane|turn|zug|status|private nachricht|telegram nachricht|reply|verlauf|basis|qa gate|wartezustand|f\d+|m\d+|w\d+)\b/gu;
|
|
7
7
|
const NO_USER_VALUE = /\b(?:keine neue aktion|keine neue information|keine neue nachricht|kein neuer auftrag|kein neuer zweck|kein neuer inbound bedarf|kein offener handlungsbedarf|nichts neues zu melden|nichts zu melden|nichts weiteres|bleibt pausiert|warte auf (?:dein|sein|ihr|papas) (?:zeichen|go|freigabe|antwort)|ich warte|ich sende nichts|wiederholen wäre spam|keine weitere nachricht|bereits geantwortet|bereits gesendet|kein werkzeugaufruf nötig|stand unverändert|zug läuft seit|kein bau ohne|qa gate steht noch aus|wartezustand)\b/u;
|
|
8
8
|
|
|
9
|
+
const MEDIA_PROGRESS_MARKER = /\b(?:bildgenerierung|bildjob|generateimage|getmedia|media job|medienjob)\b/u;
|
|
10
|
+
const MEDIA_PENDING_STATE = /\b(?:auftrag wurde angenommen|job wurde angenommen|job angenommen|aufruf wurde abgesetzt|angestossen|angestoßen|processing|verarbeitung)\b/u;
|
|
11
|
+
const MEDIA_NO_RESULT = /\b(?:kein neues bild|noch kein bild|kein bild liefern|nichts angekommen|nichts neues gelandet|nicht verfuegbar|nicht verfügbar|getmedia fehlt)\b/u;
|
|
12
|
+
|
|
9
13
|
function normalize(text) {
|
|
10
14
|
return String(text ?? '')
|
|
11
15
|
.normalize('NFKC')
|
|
@@ -27,6 +31,7 @@ function isPrivateInternalStatusReply(chatId, text) {
|
|
|
27
31
|
const value = normalize(sanitized.length === 0 ? text : sanitized);
|
|
28
32
|
if (value.length === 0) return false;
|
|
29
33
|
if (sanitized.length === 0 && WORK_PERMISSION_QUESTION.test(value)) return true;
|
|
34
|
+
if (MEDIA_PROGRESS_MARKER.test(value) && MEDIA_PENDING_STATE.test(value) && MEDIA_NO_RESULT.test(value)) return true;
|
|
30
35
|
|
|
31
36
|
const internalMarkers = value.match(INTERNAL_CONTROL_MARKER) ?? [];
|
|
32
37
|
return internalMarkers.length > 0 && NO_USER_VALUE.test(value);
|
package/package.json
CHANGED
|
@@ -6,6 +6,10 @@ const TRAILING_WORK_PERMISSION_QUESTION = /(?:^|\r?\n\s*\r?\n)(?:kann|darf|soll)
|
|
|
6
6
|
const INTERNAL_CONTROL_MARKER = /\b(?:cron|loop|checkpoint|handoff|resume|session|sha|tool|werkzeug|hook|queue|lane|inbound|outbound|arbeitsstand|arbeitsauftrag|bau freigabe|freigabe dieser lane|turn|zug|status|private nachricht|telegram nachricht|reply|verlauf|basis|qa gate|wartezustand|f\d+|m\d+|w\d+)\b/gu;
|
|
7
7
|
const NO_USER_VALUE = /\b(?:keine neue aktion|keine neue information|keine neue nachricht|kein neuer auftrag|kein neuer zweck|kein neuer inbound bedarf|kein offener handlungsbedarf|nichts neues zu melden|nichts zu melden|nichts weiteres|bleibt pausiert|warte auf (?:dein|sein|ihr|papas) (?:zeichen|go|freigabe|antwort)|ich warte|ich sende nichts|wiederholen wäre spam|keine weitere nachricht|bereits geantwortet|bereits gesendet|kein werkzeugaufruf nötig|stand unverändert|zug läuft seit|kein bau ohne|qa gate steht noch aus|wartezustand)\b/u;
|
|
8
8
|
|
|
9
|
+
const MEDIA_PROGRESS_MARKER = /\b(?:bildgenerierung|bildjob|generateimage|getmedia|media job|medienjob)\b/u;
|
|
10
|
+
const MEDIA_PENDING_STATE = /\b(?:auftrag wurde angenommen|job wurde angenommen|job angenommen|aufruf wurde abgesetzt|angestossen|angestoßen|processing|verarbeitung)\b/u;
|
|
11
|
+
const MEDIA_NO_RESULT = /\b(?:kein neues bild|noch kein bild|kein bild liefern|nichts angekommen|nichts neues gelandet|nicht verfuegbar|nicht verfügbar|getmedia fehlt)\b/u;
|
|
12
|
+
|
|
9
13
|
function normalize(text) {
|
|
10
14
|
return String(text ?? '')
|
|
11
15
|
.normalize('NFKC')
|
|
@@ -27,6 +31,7 @@ function isPrivateInternalStatusReply(chatId, text) {
|
|
|
27
31
|
const value = normalize(sanitized.length === 0 ? text : sanitized);
|
|
28
32
|
if (value.length === 0) return false;
|
|
29
33
|
if (sanitized.length === 0 && WORK_PERMISSION_QUESTION.test(value)) return true;
|
|
34
|
+
if (MEDIA_PROGRESS_MARKER.test(value) && MEDIA_PENDING_STATE.test(value) && MEDIA_NO_RESULT.test(value)) return true;
|
|
30
35
|
|
|
31
36
|
const internalMarkers = value.match(INTERNAL_CONTROL_MARKER) ?? [];
|
|
32
37
|
return internalMarkers.length > 0 && NO_USER_VALUE.test(value);
|