blun-king-cli 9.1.390 → 9.1.391

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;
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 ACCESS_KEYS = Object.freeze([
8
+ const ACCESS_REQUIRED_KEYS = Object.freeze([
9
9
  'actorId', 'agentId', 'channelId', 'conversationId', 'permissionContext',
10
10
  'portalId', 'requestedScope', 'tenantId', 'userId',
11
11
  ]);
12
- const PERMISSION_KEYS = Object.freeze(['authority', 'decision', 'receiptId']);
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 (!exactKeys(access, ACCESS_KEYS) || !exactKeys(access.permissionContext, PERMISSION_KEYS)) {
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: String(candidate?.subject_id ?? ''),
476
+ userId: agent,
477
477
  actorId: agent,
478
478
  agentId: agent,
479
479
  portalId: 'cli',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.390",
3
+ "version": "9.1.391",
4
4
  "description": "BLUN CLI - your own AI agent with a Telegram channel. Get it done. With BLUN.",
5
5
  "license": "MIT",
6
6
  "bin": {