blun-king-cli 9.1.357 → 9.1.359

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.
@@ -36,6 +36,7 @@ function buildCognitiveFocusProjection(state, { focusScopes, maxItems = 6, maxCh
36
36
  if (scopes === null || !Number.isSafeInteger(maxItems) || maxItems < 1 || maxItems > 8
37
37
  || !Number.isSafeInteger(maxChars) || maxChars < 320 || maxChars > 1600
38
38
  || !Array.isArray(state?.observations)) return null;
39
+ if (scopes.length === 0) return null;
39
40
 
40
41
  const groups = new Map();
41
42
  state.observations.forEach((item, index) => {
@@ -48,7 +49,7 @@ function buildCognitiveFocusProjection(state, { focusScopes, maxItems = 6, maxCh
48
49
  if (!FOCUS_DOMAINS.has(domain) || !key || !value || !scope || scope === 'runtime'
49
50
  || !Number.isFinite(confidence) || confidence < 0.5 || confidence > 1
50
51
  || !Number.isFinite(occurredAt)) return;
51
- const groupKey = `${domain}\0${key}`;
52
+ const groupKey = `${scope}\0${domain}\0${key}`;
52
53
  const existing = groups.get(groupKey) ?? [];
53
54
  existing.push({ domain, key, value, scope, confidence, occurredAt, index });
54
55
  groups.set(groupKey, existing);
@@ -58,12 +59,12 @@ function buildCognitiveFocusProjection(state, { focusScopes, maxItems = 6, maxCh
58
59
  for (const entries of groups.values()) {
59
60
  entries.sort((left, right) => left.occurredAt - right.occurredAt || left.index - right.index);
60
61
  const latest = entries.at(-1);
62
+ if (!scopes.includes(latest.scope)) continue;
61
63
  const revised = entries.some((item) => item.value !== latest.value);
62
- const scopeScore = scopes.includes(latest.scope) ? 100 : 0;
63
64
  ranked.push({
64
65
  ...latest,
65
66
  revised,
66
- score: scopeScore + DOMAIN_WEIGHTS.get(latest.domain) + latest.confidence * 10,
67
+ score: DOMAIN_WEIGHTS.get(latest.domain) + latest.confidence * 10,
67
68
  });
68
69
  }
69
70
  ranked.sort((left, right) => right.score - left.score
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const CHANNEL_RE = /<channel\b([^>]*)>[\s\S]*?<\/channel>/giu;
4
+ const TELEGRAM_SOURCE_RE = /\bsource\s*=\s*["']telegram["']/iu;
5
+ const CHAT_ID_RE = /\bchat_id\s*=\s*["'](-?\d+)["']/iu;
6
+ const USER_ID_RE = /\buser_id\s*=\s*["'](\d+)["']/iu;
7
+ const DM_MARKER_RE = /^#?\s*\[tg\s+dm\b[^\]]*\bchat_id\s*=\s*(\d+)[^\]]*\]/gimu;
8
+
9
+ function inputText(input) {
10
+ if (!Array.isArray(input)) return '';
11
+ return input
12
+ .filter((part) => part?.type === 'text' && typeof part.text === 'string')
13
+ .map((part) => part.text)
14
+ .join('\n');
15
+ }
16
+
17
+ function relationshipScope(subjectId) {
18
+ return `relationship:telegram-${subjectId}:private`;
19
+ }
20
+
21
+ function cognitiveFocusScopesForTurn(input) {
22
+ const text = inputText(input);
23
+ if (!text) return [];
24
+ const scopes = [];
25
+ for (const match of text.matchAll(CHANNEL_RE)) {
26
+ const attributes = match[1] ?? '';
27
+ if (!TELEGRAM_SOURCE_RE.test(attributes)) continue;
28
+ const chatId = CHAT_ID_RE.exec(attributes)?.[1];
29
+ if (!chatId || chatId.startsWith('-')) continue;
30
+ const subjectId = USER_ID_RE.exec(attributes)?.[1] ?? chatId;
31
+ scopes.push(relationshipScope(subjectId));
32
+ }
33
+ for (const match of text.matchAll(DM_MARKER_RE)) scopes.push(relationshipScope(match[1]));
34
+ return [...new Set(scopes)].slice(0, 8);
35
+ }
36
+
37
+ module.exports = { cognitiveFocusScopesForTurn };
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  const crypto = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
4
6
  const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
5
7
  const { buildCognitiveContextProjection } = require('./cognitive-context-projection.cjs');
6
8
  const { buildCognitiveFocusProjection } = require('./cognitive-focus-projection.cjs');
@@ -45,6 +47,25 @@ function digestId(prefix, values) {
45
47
  return `${prefix}-${digest}`;
46
48
  }
47
49
 
50
+ function identityFromManifest(home) {
51
+ const root = fs.realpathSync(path.resolve(String(home ?? '')));
52
+ const identityRoot = path.join(root, 'identity');
53
+ const manifestPath = path.join(identityRoot, 'manifest.json');
54
+ try {
55
+ const identityStat = fs.lstatSync(identityRoot);
56
+ const manifestStat = fs.lstatSync(manifestPath);
57
+ if (!identityStat.isDirectory() || identityStat.isSymbolicLink()
58
+ || !manifestStat.isFile() || manifestStat.isSymbolicLink() || manifestStat.size > 64 * 1024) return null;
59
+ if (fs.realpathSync(identityRoot) !== identityRoot || fs.realpathSync(manifestPath) !== manifestPath) return null;
60
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
61
+ const tenantId = safeId(manifest?.tenant_id);
62
+ const agentId = safeId(manifest?.active_agent_id);
63
+ return manifest?.version === 1 && tenantId && agentId ? { tenantId, agentId } : null;
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+
48
69
  function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now = () => new Date().toISOString() } = {}) {
49
70
  const tenant = safeId(tenantId);
50
71
  const agent = safeId(agentId);
@@ -281,14 +302,25 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
281
302
  };
282
303
  }
283
304
 
284
- function createRuntimeCognitiveTurnLifecycle({ home, agentName, runtimeId, now } = {}) {
305
+ function createRuntimeCognitiveTurnLifecycle({ home, agentName, tenantId, agentId, runtimeId, now } = {}) {
285
306
  const resolvedHome = String(home ?? '').trim();
286
307
  const resolvedAgent = String(agentName ?? '').trim();
287
308
  if (!resolvedHome || !resolvedAgent) fail('COGNITIVE_LIFECYCLE_INVALID');
309
+ const explicitTenant = tenantId === undefined ? '' : safeId(tenantId);
310
+ const explicitAgent = agentId === undefined ? '' : safeId(agentId);
311
+ if ((tenantId !== undefined && !explicitTenant) || (agentId !== undefined && !explicitAgent)) {
312
+ fail('COGNITIVE_LIFECYCLE_INVALID');
313
+ }
314
+ const manifestIdentity = identityFromManifest(resolvedHome);
315
+ const identity = {
316
+ tenantId: explicitTenant || manifestIdentity?.tenantId || '',
317
+ agentId: explicitAgent || manifestIdentity?.agentId || '',
318
+ };
319
+ const hasSharedIdentity = Boolean(identity.tenantId && identity.agentId);
288
320
  return createCognitiveTurnLifecycle({
289
321
  home: resolvedHome,
290
- tenantId: digestId('home', [resolvedHome.toLowerCase()]),
291
- agentId: digestId('agent', [resolvedAgent.toLowerCase()]),
322
+ tenantId: hasSharedIdentity ? identity.tenantId : digestId('home', [resolvedHome.toLowerCase()]),
323
+ agentId: hasSharedIdentity ? identity.agentId : digestId('agent', [resolvedAgent.toLowerCase()]),
292
324
  runtimeId,
293
325
  now,
294
326
  });
@@ -68,6 +68,7 @@ const RUNNING_UPDATE_RESUME_SESSION_ENV = 'BLUN_RUNNING_UPDATE_RESUME_SESSION_ID
68
68
  const RUNTIME_READY_TIMEOUT_MS = 60_000;
69
69
  const RUNNING_UPDATE_RECHECK_MS = 5 * 60_000;
70
70
  const RUNNING_UPDATE_RECHECK_JITTER_MS = 2 * 60_000;
71
+ const RUNNING_UPDATE_ERROR_RETRY_MS = 10_000;
71
72
  const RUNNING_UPDATE_STABILIZATION_MS = 2 * 60 * 1000;
72
73
 
73
74
  function runningUpdateRecheckDelay(randomValue = Math.random()) {
@@ -87,6 +88,17 @@ function scheduleRunningUpdateRecheck(callback, options = {}) {
87
88
  return timer;
88
89
  }
89
90
 
91
+ function runningUpdateFailureDetails(error) {
92
+ const safeField = (value, fallback) => typeof value === 'string'
93
+ && /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u.test(value)
94
+ ? value
95
+ : fallback;
96
+ return {
97
+ errorName: safeField(error?.name, 'Error'),
98
+ errorCode: safeField(error?.code, 'UNKNOWN'),
99
+ };
100
+ }
101
+
90
102
  function normalizeWindowsPath(value) {
91
103
  return path.win32.normalize(value).replace(/\\+$/u, '').toLowerCase();
92
104
  }
@@ -350,7 +362,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
350
362
  if (typeof sharedHome !== 'string' || sharedHome.length === 0) return;
351
363
  (options.stageRuntime || stageRuntime)(sharedHome, preparedTarget, stagedRuntimeOptions());
352
364
  };
353
- const scheduleNextPreparation = (child) => {
365
+ const scheduleNextPreparation = (child, scheduleOptions = {}) => {
354
366
  clearRunningUpdatePoll();
355
367
  if (supervisionCompleted || updateStarted) return;
356
368
  runningUpdatePollTimer = (options.scheduleRunningUpdateRecheck || scheduleRunningUpdateRecheck)(() => {
@@ -358,7 +370,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
358
370
  refreshRunningUpdateMode();
359
371
  if (automaticMode()) startPreparation(child);
360
372
  else scheduleNextPreparation(child);
361
- });
373
+ }, scheduleOptions);
362
374
  };
363
375
  const startPreparation = (child) => {
364
376
  if (supervisionCompleted || updateStarted
@@ -417,7 +429,16 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
417
429
  }).catch((error) => {
418
430
  updateStarted = false;
419
431
  options.onRunningUpdateError?.(error);
420
- scheduleNextPreparation(child);
432
+ try {
433
+ (options.recordRunningUpdateEvent || recordRunningUpdateEvent)(sharedHome, {
434
+ event: 'prepare-failed',
435
+ runningVersion: readPackageVersionAt(packageRoot),
436
+ ...runningUpdateFailureDetails(error),
437
+ }, { now: options.nowImpl });
438
+ } catch (recordError) {
439
+ options.onRunningUpdateError?.(recordError);
440
+ }
441
+ scheduleNextPreparation(child, { delayMs: RUNNING_UPDATE_ERROR_RETRY_MS });
421
442
  });
422
443
  };
423
444
  const handleCoreMessage = (message, child) => {
@@ -931,6 +952,7 @@ async function runLauncher(options = {}) {
931
952
  }
932
953
 
933
954
  module.exports = {
955
+ RUNNING_UPDATE_ERROR_RETRY_MS,
934
956
  RUNNING_UPDATE_RECHECK_JITTER_MS,
935
957
  RUNNING_UPDATE_RECHECK_MS,
936
958
  RUNNING_UPDATE_STABILIZATION_MS,
package/blun.mjs CHANGED
@@ -261464,7 +261464,7 @@ function toolResultText(result) {
261464
261464
  function abandonedToolResultOutput(ended) {
261465
261465
  return `Tool call did not complete: ${ended.reason === "cancelled" ? "the turn was cancelled" : ended.reason === "failed" ? `the turn failed${ended.error !== void 0 ? ` (${ended.error.message})` : ""}` : "the turn ended"} before its result was recorded. Do not assume the tool completed successfully.`;
261466
261466
  }
261467
- var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, mediaGenerationToolNamesForText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, projectRecurringCronHistory, TelegramDeliveryLedger, createRuntimeCognitiveTurnLifecycle, buildAttentionQueueItem, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
261467
+ var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, mediaGenerationToolNamesForText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, projectRecurringCronHistory, TelegramDeliveryLedger, createRuntimeCognitiveTurnLifecycle, cognitiveFocusScopesForTurn, buildAttentionQueueItem, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
261468
261468
  var init_turn = __esmMin((() => {
261469
261469
  init_dist$4();
261470
261470
  init_src$4();
@@ -261485,6 +261485,7 @@ var init_turn = __esmMin((() => {
261485
261485
  ({ projectRecurringCronHistory } = createRequire(import.meta.url)("./bin/recurring-cron-history-policy.cjs"));
261486
261486
  ({ TelegramDeliveryLedger } = createRequire(import.meta.url)("./bin/repeated-user-message-projection.cjs"));
261487
261487
  ({ createRuntimeCognitiveTurnLifecycle } = createRequire(import.meta.url)("./bin/cognitive-turn-lifecycle.cjs"));
261488
+ ({ cognitiveFocusScopesForTurn } = createRequire(import.meta.url)("./bin/cognitive-focus-scope.cjs"));
261488
261489
  ({ buildAttentionQueueItem } = createRequire(import.meta.url)("./bin/cognitive-attention-delivery.cjs"));
261489
261490
  BLUN_LEAN_TOOL_NAMES = new Set(BLUN_CORE_TOOL_NAMES);
261490
261491
  BLUN_ATTACHMENT_MARKER_RE = /\b(?:attachment_file_id|telegram-anhang|telegram attachment)\b/i;
@@ -261568,7 +261569,9 @@ var init_turn = __esmMin((() => {
261568
261569
  try {
261569
261570
  this.cognitiveLifecycle = createRuntimeCognitiveTurnLifecycle({
261570
261571
  home,
261571
- agentName: this.agent.activeProfile?.name ?? this.agent.type
261572
+ agentName: this.agent.activeProfile?.name ?? this.agent.type,
261573
+ tenantId: process.env.BLUN_IDENTITY_TENANT_ID,
261574
+ agentId: process.env.BLUN_AGENT_ID
261572
261575
  });
261573
261576
  return this.cognitiveLifecycle;
261574
261577
  } catch (error) {
@@ -261618,9 +261621,10 @@ var init_turn = __esmMin((() => {
261618
261621
  this.recordCognitiveStage("recordToolPolicy", policy);
261619
261622
  }
261620
261623
  }
261621
- projectCognitiveState(turnId) {
261624
+ projectCognitiveState(turnId, input) {
261622
261625
  try {
261623
- return this.getCognitiveLifecycle()?.projectForTurn({ turnId }) ?? null;
261626
+ const focusScopes = cognitiveFocusScopesForTurn(input);
261627
+ return this.getCognitiveLifecycle()?.projectForTurn({ turnId, focusScopes }) ?? null;
261624
261628
  } catch (error) {
261625
261629
  this.agent.telemetry.track("cognitive_lifecycle_error", { stage: "projectForTurn", error_type: error?.code ?? error?.name ?? "Error" });
261626
261630
  return null;
@@ -262178,7 +262182,7 @@ var init_turn = __esmMin((() => {
262178
262182
  if (blunTurnNeedsInitialMcp(input, origin)) await this.agent.mcp?.waitForInitialLoad(signal);
262179
262183
  const personalMemoryRecall = await this.agent.injection.injectPersonalMemoryForTurn(turnId, input, origin, signal);
262180
262184
  await this.agent.injection.injectGoal();
262181
- const cognitiveProjection = this.projectCognitiveState(turnId);
262185
+ const cognitiveProjection = this.projectCognitiveState(turnId, input);
262182
262186
  if (cognitiveProjection !== null) this.agent.context.appendSystemReminder(cognitiveProjection, {
262183
262187
  kind: "injection",
262184
262188
  variant: "cognitive_continuity"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.357",
3
+ "version": "9.1.359",
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": {