blun-king-cli 9.1.385 → 9.1.387

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.
@@ -20,7 +20,7 @@ function safeId(value) {
20
20
  return SAFE_ID_RE.test(text) ? text : '';
21
21
  }
22
22
 
23
- function authorizeAttentionCandidate({ store, tenantId, currentAgent, now, input } = {}) {
23
+ function authorizeAttentionCandidate({ store, tenantId, currentAgent, now, input, memoryAccess } = {}) {
24
24
  if (!store || typeof store.authorizeAttention !== 'function' || typeof now !== 'function'
25
25
  || !exactKeys(input, new Set(['candidate', 'channel', 'authorization']))) fail();
26
26
  const tenant = safeId(tenantId);
@@ -61,7 +61,7 @@ function authorizeAttentionCandidate({ store, tenantId, currentAgent, now, input
61
61
  receiptId,
62
62
  authority,
63
63
  authorizedAt: new Date(issuedAtMs).toISOString(),
64
- });
64
+ }, memoryAccess);
65
65
  if (!admitted.claimed) {
66
66
  return {
67
67
  accepted: false,
@@ -0,0 +1,135 @@
1
+ 'use strict';
2
+
3
+ const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
4
+
5
+ const COGNITIVE_MEMORY_ADAPTER_VERSION = 2;
6
+ const KIND_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
7
+ const ACCESS_KEYS = Object.freeze([
8
+ 'actorId', 'agentId', 'channelId', 'conversationId', 'permissionContext',
9
+ 'portalId', 'requestedScope', 'tenantId', 'userId',
10
+ ]);
11
+ const PERMISSION_KEYS = Object.freeze(['authority', 'decision', 'receiptId']);
12
+ const REQUIRED_METHODS = Object.freeze([
13
+ 'commit',
14
+ 'read',
15
+ 'hasEvent',
16
+ 'verify',
17
+ 'claimAttention',
18
+ 'authorizeAttention',
19
+ 'close',
20
+ ]);
21
+
22
+ function fail(code) {
23
+ const error = new Error(code);
24
+ error.code = code;
25
+ throw error;
26
+ }
27
+
28
+ function exactKeys(value, expected) {
29
+ return value && typeof value === 'object' && !Array.isArray(value)
30
+ && Object.keys(value).sort().join('\0') === [...expected].sort().join('\0');
31
+ }
32
+
33
+ function safeId(value) {
34
+ const text = String(value ?? '').trim();
35
+ return KIND_RE.test(text) ? text : '';
36
+ }
37
+
38
+ function normalizeMemoryAccess(access, request) {
39
+ if (!exactKeys(access, ACCESS_KEYS) || !exactKeys(access.permissionContext, PERMISSION_KEYS)) {
40
+ fail('COGNITIVE_MEMORY_ACCESS_INVALID');
41
+ }
42
+ const normalized = {
43
+ tenantId: safeId(access.tenantId),
44
+ userId: safeId(access.userId),
45
+ actorId: safeId(access.actorId),
46
+ agentId: safeId(access.agentId),
47
+ portalId: safeId(access.portalId),
48
+ channelId: safeId(access.channelId),
49
+ conversationId: safeId(access.conversationId),
50
+ requestedScope: safeId(access.requestedScope),
51
+ permissionContext: {
52
+ authority: safeId(access.permissionContext.authority),
53
+ decision: String(access.permissionContext.decision ?? ''),
54
+ receiptId: safeId(access.permissionContext.receiptId),
55
+ },
56
+ };
57
+ if (!normalized.tenantId || !normalized.userId || !normalized.actorId || !normalized.agentId
58
+ || !normalized.portalId || !normalized.channelId || !normalized.conversationId
59
+ || !normalized.requestedScope || !normalized.permissionContext.authority
60
+ || !normalized.permissionContext.receiptId) fail('COGNITIVE_MEMORY_ACCESS_INVALID');
61
+ if (normalized.permissionContext.decision !== 'passed') fail('COGNITIVE_MEMORY_ACCESS_DENIED');
62
+ const requestTenant = safeId(request?.tenantId);
63
+ const requestAgent = safeId(request?.agentId ?? request?.candidate?.responsible_agent ?? request?.claimedBy);
64
+ if (!requestTenant || !requestAgent
65
+ || requestTenant !== normalized.tenantId || requestAgent !== normalized.agentId) {
66
+ fail('COGNITIVE_MEMORY_ACCESS_SCOPE_MISMATCH');
67
+ }
68
+ normalized.permissionContext = Object.freeze(normalized.permissionContext);
69
+ return Object.freeze(normalized);
70
+ }
71
+
72
+ function assertCognitiveMemoryAdapter(adapter) {
73
+ if (!adapter || typeof adapter !== 'object' || Array.isArray(adapter)) {
74
+ fail('COGNITIVE_MEMORY_ADAPTER_INVALID');
75
+ }
76
+ if (adapter.contractVersion !== COGNITIVE_MEMORY_ADAPTER_VERSION) {
77
+ fail('COGNITIVE_MEMORY_ADAPTER_VERSION_UNSUPPORTED');
78
+ }
79
+ if (!KIND_RE.test(String(adapter.kind ?? ''))
80
+ || REQUIRED_METHODS.some((method) => typeof adapter[method] !== 'function')) {
81
+ fail('COGNITIVE_MEMORY_ADAPTER_INVALID');
82
+ }
83
+ return adapter;
84
+ }
85
+
86
+ function guardCognitiveMemoryAdapter(adapter) {
87
+ const raw = assertCognitiveMemoryAdapter(adapter);
88
+ const guarded = {
89
+ contractVersion: raw.contractVersion,
90
+ kind: raw.kind,
91
+ commit: (input, access) => raw.commit(input, normalizeMemoryAccess(access, input)),
92
+ read: (input, access) => raw.read(input, normalizeMemoryAccess(access, input)),
93
+ hasEvent: (input, access) => {
94
+ if (!exactKeys(input, ['agentId', 'eventId', 'tenantId']) || !safeId(input.eventId)) {
95
+ fail('COGNITIVE_MEMORY_ACCESS_INVALID');
96
+ }
97
+ return raw.hasEvent(input, normalizeMemoryAccess(access, input));
98
+ },
99
+ verify: (input, access) => raw.verify(input, normalizeMemoryAccess(access, input)),
100
+ claimAttention: (input, access) => raw.claimAttention(input, normalizeMemoryAccess(access, input)),
101
+ authorizeAttention: (input, access) => raw.authorizeAttention(input, normalizeMemoryAccess(access, input)),
102
+ close: () => raw.close(),
103
+ };
104
+ return Object.freeze(guarded);
105
+ }
106
+
107
+ function createLocalCognitiveMemoryAdapter({ home } = {}) {
108
+ const store = openCognitiveStateStore({ home });
109
+ return guardCognitiveMemoryAdapter({
110
+ contractVersion: COGNITIVE_MEMORY_ADAPTER_VERSION,
111
+ kind: 'local-cognitive-event-store',
112
+ commit: (input) => store.commit(input),
113
+ read: (input) => store.read(input),
114
+ hasEvent: (input) => store.hasEvent(input),
115
+ verify: (input) => store.verify(input),
116
+ claimAttention: (input) => store.claimAttention(input),
117
+ authorizeAttention: (input) => store.authorizeAttention(input),
118
+ close: () => store.close(),
119
+ });
120
+ }
121
+
122
+ function openCognitiveMemoryAdapter({ home, adapter } = {}) {
123
+ return adapter === undefined
124
+ ? createLocalCognitiveMemoryAdapter({ home })
125
+ : guardCognitiveMemoryAdapter(adapter);
126
+ }
127
+
128
+ module.exports = {
129
+ COGNITIVE_MEMORY_ADAPTER_VERSION,
130
+ REQUIRED_METHODS,
131
+ assertCognitiveMemoryAdapter,
132
+ createLocalCognitiveMemoryAdapter,
133
+ normalizeMemoryAccess,
134
+ openCognitiveMemoryAdapter,
135
+ };
@@ -289,8 +289,18 @@ function openCognitiveStateStore({ home } = {}) {
289
289
  };
290
290
  }
291
291
 
292
- function hasEvent(eventId) {
293
- const event = safeId(eventId);
292
+ function hasEvent(input) {
293
+ if (input && typeof input === 'object' && !Array.isArray(input)) {
294
+ const keys = Object.keys(input);
295
+ const event = safeId(input.eventId);
296
+ const tenant = safeId(input.tenantId);
297
+ const agent = safeId(input.agentId);
298
+ if (keys.length !== 3 || !keys.every((key) => ['agentId', 'eventId', 'tenantId'].includes(key))
299
+ || !event || !tenant || !agent) fail('COGNITIVE_INVALID_EVENT');
300
+ return Boolean(db.prepare(`SELECT 1 AS found FROM cognitive_events
301
+ WHERE event_id = ? AND tenant_id = ? AND agent_id = ?`).get(event, tenant, agent));
302
+ }
303
+ const event = safeId(input);
294
304
  if (!event) fail('COGNITIVE_INVALID_EVENT');
295
305
  return Boolean(db.prepare('SELECT 1 AS found FROM cognitive_events WHERE event_id = ?').get(event));
296
306
  }
@@ -3,7 +3,7 @@
3
3
  const crypto = require('node:crypto');
4
4
  const fs = require('node:fs');
5
5
  const path = require('node:path');
6
- const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
6
+ const { openCognitiveMemoryAdapter } = require('./cognitive-memory-adapter.cjs');
7
7
  const { buildCognitiveContextProjection } = require('./cognitive-context-projection.cjs');
8
8
  const { buildCognitiveFocusProjection } = require('./cognitive-focus-projection.cjs');
9
9
  const { authorizeAttentionCandidate } = require('./cognitive-attention-runtime.cjs');
@@ -69,12 +69,34 @@ function identityFromManifest(home) {
69
69
  }
70
70
  }
71
71
 
72
- function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now = () => new Date().toISOString() } = {}) {
72
+ function createCognitiveTurnLifecycle({
73
+ home,
74
+ tenantId,
75
+ agentId,
76
+ runtimeId,
77
+ memoryAdapter,
78
+ now = () => new Date().toISOString(),
79
+ } = {}) {
73
80
  const tenant = safeId(tenantId);
74
81
  const agent = safeId(agentId);
75
82
  const runtime = safeId(runtimeId ?? `runtime-${process.pid}-${Date.now()}`);
76
83
  if (!tenant || !agent || !runtime || typeof now !== 'function') fail('COGNITIVE_LIFECYCLE_INVALID');
77
- const store = openCognitiveStateStore({ home });
84
+ const store = openCognitiveMemoryAdapter({ home, adapter: memoryAdapter });
85
+ const internalMemoryAccess = Object.freeze({
86
+ tenantId: tenant,
87
+ userId: agent,
88
+ actorId: agent,
89
+ agentId: agent,
90
+ portalId: 'cli',
91
+ channelId: 'runtime',
92
+ conversationId: runtime,
93
+ requestedScope: 'agent:memory',
94
+ permissionContext: Object.freeze({
95
+ authority: 'runtime_internal',
96
+ decision: 'passed',
97
+ receiptId: runtime,
98
+ }),
99
+ });
78
100
  const stageTimes = new Map();
79
101
  const stageResults = new Map();
80
102
 
@@ -97,7 +119,7 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
97
119
  ...item,
98
120
  }));
99
121
  for (let attempt = 0; attempt < 4; attempt += 1) {
100
- const expectedVersion = store.read({ tenantId: tenant, agentId: agent }).version;
122
+ const expectedVersion = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess).version;
101
123
  try {
102
124
  const result = store.commit({
103
125
  tenantId: tenant,
@@ -112,7 +134,7 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
112
134
  message_id: stageKey,
113
135
  },
114
136
  observations: normalized,
115
- });
137
+ }, internalMemoryAccess);
116
138
  stageResults.set(stageKey, result);
117
139
  return result;
118
140
  } catch (error) {
@@ -125,7 +147,7 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
125
147
  function commitDurableStage(stageKey, observations) {
126
148
  if (stageResults.has(stageKey)) return { ...stageResults.get(stageKey), idempotent: true };
127
149
  const eventId = digestId('durable', [tenant, agent, stageKey]);
128
- if (store.hasEvent(eventId)) {
150
+ if (store.hasEvent({ eventId, tenantId: tenant, agentId: agent }, internalMemoryAccess)) {
129
151
  const result = { idempotent: true };
130
152
  stageResults.set(stageKey, result);
131
153
  return result;
@@ -136,12 +158,12 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
136
158
  ...item,
137
159
  }));
138
160
  for (let attempt = 0; attempt < 4; attempt += 1) {
139
- if (store.hasEvent(eventId)) {
161
+ if (store.hasEvent({ eventId, tenantId: tenant, agentId: agent }, internalMemoryAccess)) {
140
162
  const result = { idempotent: true };
141
163
  stageResults.set(stageKey, result);
142
164
  return result;
143
165
  }
144
- const expectedVersion = store.read({ tenantId: tenant, agentId: agent }).version;
166
+ const expectedVersion = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess).version;
145
167
  try {
146
168
  const result = store.commit({
147
169
  tenantId: tenant,
@@ -156,7 +178,7 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
156
178
  message_id: stageKey,
157
179
  },
158
180
  observations: normalized,
159
- });
181
+ }, internalMemoryAccess);
160
182
  stageResults.set(stageKey, result);
161
183
  return result;
162
184
  } catch (error) {
@@ -281,8 +303,23 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
281
303
  ...(correction ? { supersedes: targetObservationId } : { withdraws: targetObservationId }),
282
304
  };
283
305
  const normalizedOccurredAt = new Date(occurredAt).toISOString();
306
+ const revisionMemoryAccess = {
307
+ tenantId: tenant,
308
+ userId: normalizedSource.actor_id,
309
+ actorId: normalizedSource.actor_id,
310
+ agentId: agent,
311
+ portalId: normalizedSource.provider,
312
+ channelId: normalizedSource.provider,
313
+ conversationId: normalizedSource.context_id,
314
+ requestedScope: scope,
315
+ permissionContext: {
316
+ authority: input.authority,
317
+ decision: 'passed',
318
+ receiptId: requestId,
319
+ },
320
+ };
284
321
  for (let attempt = 0; attempt < 4; attempt += 1) {
285
- const current = store.read({ tenantId: tenant, agentId: agent });
322
+ const current = store.read({ tenantId: tenant, agentId: agent }, revisionMemoryAccess);
286
323
  const existing = current.observations.find((item) => item.observation_id === observationId);
287
324
  if (existing) {
288
325
  const matches = existing.domain === observation.domain && existing.key === observation.key
@@ -310,7 +347,7 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
310
347
  occurredAt: normalizedOccurredAt,
311
348
  source: normalizedSource,
312
349
  observations: [observation],
313
- });
350
+ }, revisionMemoryAccess);
314
351
  } catch (error) {
315
352
  if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 3) throw error;
316
353
  }
@@ -407,7 +444,7 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
407
444
  if (!exactKeys(input, new Set(['turnId', 'focusScopes']))) fail('COGNITIVE_LIFECYCLE_INVALID');
408
445
  const turnId = safeTurnId(input.turnId);
409
446
  if (turnId === null) fail('COGNITIVE_LIFECYCLE_INVALID');
410
- const state = store.read({ tenantId: tenant, agentId: agent });
447
+ const state = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess);
411
448
  const continuity = buildCognitiveContextProjection(state, {
412
449
  currentTurnId: turnId,
413
450
  currentRuntimeId: runtime,
@@ -417,12 +454,30 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
417
454
  }
418
455
 
419
456
  function authorizeAttention(input) {
457
+ const candidate = input?.candidate;
458
+ const authorization = input?.authorization;
459
+ const memoryAccess = {
460
+ tenantId: tenant,
461
+ userId: String(candidate?.subject_id ?? ''),
462
+ actorId: agent,
463
+ agentId: agent,
464
+ portalId: 'cli',
465
+ channelId: String(input?.channel ?? ''),
466
+ conversationId: runtime,
467
+ requestedScope: String(candidate?.evidence_scope ?? ''),
468
+ permissionContext: {
469
+ authority: String(authorization?.authority ?? ''),
470
+ decision: authorization?.decision === 'passed' ? 'passed' : 'blocked',
471
+ receiptId: String(authorization?.receiptId ?? ''),
472
+ },
473
+ };
420
474
  return authorizeAttentionCandidate({
421
475
  store,
422
476
  tenantId: tenant,
423
477
  currentAgent: agent,
424
478
  now,
425
479
  input,
480
+ memoryAccess,
426
481
  });
427
482
  }
428
483
 
@@ -438,13 +493,21 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
438
493
  authorizeAttention,
439
494
  projectForTurn,
440
495
  endTurn,
441
- read: () => store.read({ tenantId: tenant, agentId: agent }),
442
- verify: () => store.verify({ tenantId: tenant, agentId: agent }),
496
+ read: () => store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess),
497
+ verify: () => store.verify({ tenantId: tenant, agentId: agent }, internalMemoryAccess),
443
498
  close: () => store.close(),
444
499
  };
445
500
  }
446
501
 
447
- function createRuntimeCognitiveTurnLifecycle({ home, agentName, tenantId, agentId, runtimeId, now } = {}) {
502
+ function createRuntimeCognitiveTurnLifecycle({
503
+ home,
504
+ agentName,
505
+ tenantId,
506
+ agentId,
507
+ runtimeId,
508
+ memoryAdapter,
509
+ now,
510
+ } = {}) {
448
511
  const resolvedHome = String(home ?? '').trim();
449
512
  const resolvedAgent = String(agentName ?? '').trim();
450
513
  if (!resolvedHome || !resolvedAgent) fail('COGNITIVE_LIFECYCLE_INVALID');
@@ -464,6 +527,7 @@ function createRuntimeCognitiveTurnLifecycle({ home, agentName, tenantId, agentI
464
527
  tenantId: hasSharedIdentity ? identity.tenantId : digestId('home', [resolvedHome.toLowerCase()]),
465
528
  agentId: hasSharedIdentity ? identity.agentId : digestId('agent', [resolvedAgent.toLowerCase()]),
466
529
  runtimeId,
530
+ memoryAdapter,
467
531
  now,
468
532
  });
469
533
  }
@@ -3,7 +3,7 @@
3
3
  const crypto = require('node:crypto');
4
4
  const fs = require('node:fs');
5
5
  const path = require('node:path');
6
- const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
6
+ const { openCognitiveMemoryAdapter } = require('./cognitive-memory-adapter.cjs');
7
7
 
8
8
  const SAFE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
9
9
  const SENSITIVITIES = new Set(['low', 'medium']);
@@ -65,7 +65,7 @@ function normalizePresentation(input) {
65
65
  return normalized;
66
66
  }
67
67
 
68
- function createPersonalityMemoryAdapter({ identityRoot } = {}) {
68
+ function createPersonalityMemoryAdapter({ identityRoot, memoryAdapter } = {}) {
69
69
  const root = path.resolve(String(identityRoot ?? ''));
70
70
  try {
71
71
  const stat = fs.lstatSync(root);
@@ -78,7 +78,7 @@ function createPersonalityMemoryAdapter({ identityRoot } = {}) {
78
78
  }
79
79
  const realRoot = fs.realpathSync(root);
80
80
  const home = path.dirname(realRoot);
81
- const store = openCognitiveStateStore({ home });
81
+ const store = openCognitiveMemoryAdapter({ home, adapter: memoryAdapter });
82
82
 
83
83
  function claimCuriosityPresentation(input) {
84
84
  const value = normalizePresentation(input);
@@ -87,7 +87,24 @@ function createPersonalityMemoryAdapter({ identityRoot } = {}) {
87
87
  value.tenantId, value.agentId, value.actorId, value.sourcePortal, value.sourceChannel,
88
88
  value.conversationId, value.messageId, value.occurredAt, value.topic,
89
89
  ]);
90
- if (store.hasEvent(eventId)) return { claimed: true, idempotent: true };
90
+ const memoryAccess = {
91
+ tenantId: value.tenantId,
92
+ userId: value.actorId,
93
+ actorId: value.actorId,
94
+ agentId: value.agentId,
95
+ portalId: value.sourcePortal,
96
+ channelId: value.sourceChannel,
97
+ conversationId: value.conversationId,
98
+ requestedScope: relationshipScope(value.actorId),
99
+ permissionContext: {
100
+ authority: 'runtime_personality_policy',
101
+ decision: 'passed',
102
+ receiptId: eventId,
103
+ },
104
+ };
105
+ if (store.hasEvent({ eventId, tenantId: value.tenantId, agentId: value.agentId }, memoryAccess)) {
106
+ return { claimed: true, idempotent: true };
107
+ }
91
108
  const claim = store.claimAttention({
92
109
  tenantId: value.tenantId,
93
110
  candidate: {
@@ -107,10 +124,10 @@ function createPersonalityMemoryAdapter({ identityRoot } = {}) {
107
124
  },
108
125
  claimedBy: value.agentId,
109
126
  claimedAt: value.occurredAt,
110
- });
127
+ }, memoryAccess);
111
128
  if (!claim.claimed) return { claimed: false, next_allowed_at: claim.next_allowed_at };
112
129
  for (let attempt = 0; attempt < 3; attempt += 1) {
113
- const current = store.read({ tenantId: value.tenantId, agentId: value.agentId });
130
+ const current = store.read({ tenantId: value.tenantId, agentId: value.agentId }, memoryAccess);
114
131
  try {
115
132
  store.commit({
116
133
  tenantId: value.tenantId,
@@ -133,7 +150,7 @@ function createPersonalityMemoryAdapter({ identityRoot } = {}) {
133
150
  epistemic_state: 'verified',
134
151
  scope: relationshipScope(value.actorId),
135
152
  }],
136
- });
153
+ }, memoryAccess);
137
154
  return { claimed: true, idempotent: false };
138
155
  } catch (error) {
139
156
  if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 2) throw error;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.385",
3
+ "version": "9.1.387",
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": {