blun-king-cli 9.1.303 → 9.1.305

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.
@@ -0,0 +1,249 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const { DatabaseSync } = require('node:sqlite');
7
+
8
+ const SAFE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
9
+ const DOMAINS = new Set(['self', 'world', 'team', 'goal', 'open_thread', 'assumption', 'next_trigger', 'expected_evidence']);
10
+ const FORBIDDEN_KEY_RE = /(?:^|_)(?:acl|api_key|capability|password|permission|secret|token)(?:_|$)/iu;
11
+ const MAX_EVENT_BYTES = 64 * 1024;
12
+ const MAX_OBSERVATIONS = 32;
13
+
14
+ function fail(code) {
15
+ const error = new Error(code);
16
+ error.code = code;
17
+ throw error;
18
+ }
19
+
20
+ function safeId(value) {
21
+ const text = String(value ?? '').trim();
22
+ return SAFE_ID_RE.test(text) ? text : '';
23
+ }
24
+
25
+ function cleanText(value, max = 512) {
26
+ const text = String(value ?? '').replace(/[\u0000-\u001f\u007f]+/gu, ' ').replace(/\s+/gu, ' ').trim();
27
+ return text && text.length <= max ? text : '';
28
+ }
29
+
30
+ function hasForbiddenKey(value) {
31
+ if (!value || typeof value !== 'object') return false;
32
+ if (Array.isArray(value)) return value.some(hasForbiddenKey);
33
+ return Object.entries(value).some(([key, child]) => FORBIDDEN_KEY_RE.test(key) || hasForbiddenKey(child));
34
+ }
35
+
36
+ function exactKeys(value, keys) {
37
+ return value && typeof value === 'object' && !Array.isArray(value)
38
+ && Object.keys(value).every((key) => keys.has(key));
39
+ }
40
+
41
+ function normalizeSource(source) {
42
+ const allowed = new Set(['provider', 'actor_id', 'context_id', 'message_id']);
43
+ if (!exactKeys(source, allowed) || hasForbiddenKey(source)) fail('COGNITIVE_FORBIDDEN_FIELD');
44
+ const normalized = {
45
+ provider: safeId(source.provider),
46
+ actor_id: safeId(source.actor_id),
47
+ context_id: safeId(source.context_id),
48
+ message_id: safeId(source.message_id),
49
+ };
50
+ if (Object.values(normalized).some((value) => !value)) fail('COGNITIVE_INVALID_EVENT');
51
+ return normalized;
52
+ }
53
+
54
+ function normalizeObservation(value) {
55
+ const allowed = new Set(['observation_id', 'domain', 'key', 'value', 'confidence', 'scope']);
56
+ if (!exactKeys(value, allowed) || hasForbiddenKey(value)) fail('COGNITIVE_FORBIDDEN_FIELD');
57
+ const observation = {
58
+ observation_id: safeId(value.observation_id),
59
+ domain: String(value.domain ?? ''),
60
+ key: cleanText(value.key, 128),
61
+ value: cleanText(value.value, 2048),
62
+ confidence: Number(value.confidence),
63
+ scope: cleanText(value.scope, 128),
64
+ };
65
+ if (!observation.observation_id || !DOMAINS.has(observation.domain) || !observation.key
66
+ || !observation.value || !Number.isFinite(observation.confidence)
67
+ || observation.confidence < 0 || observation.confidence > 1 || !observation.scope) {
68
+ fail('COGNITIVE_INVALID_EVENT');
69
+ }
70
+ if (FORBIDDEN_KEY_RE.test(observation.key)) fail('COGNITIVE_FORBIDDEN_FIELD');
71
+ return observation;
72
+ }
73
+
74
+ function normalizeEvent(input) {
75
+ const tenantId = safeId(input.tenantId);
76
+ const agentId = safeId(input.agentId);
77
+ const eventId = safeId(input.eventId);
78
+ const expectedVersion = Number(input.expectedVersion);
79
+ const occurredAt = String(input.occurredAt ?? '').trim();
80
+ if (!tenantId || !agentId || !eventId || !Number.isSafeInteger(expectedVersion)
81
+ || expectedVersion < 0 || Number.isNaN(Date.parse(occurredAt))
82
+ || !Array.isArray(input.observations) || input.observations.length < 1
83
+ || input.observations.length > MAX_OBSERVATIONS) fail('COGNITIVE_INVALID_EVENT');
84
+ const normalized = {
85
+ tenant_id: tenantId,
86
+ agent_id: agentId,
87
+ event_id: eventId,
88
+ expected_version: expectedVersion,
89
+ occurred_at: occurredAt,
90
+ source: normalizeSource(input.source),
91
+ observations: input.observations.map(normalizeObservation),
92
+ };
93
+ const ids = new Set(normalized.observations.map((item) => item.observation_id));
94
+ if (ids.size !== normalized.observations.length) fail('COGNITIVE_INVALID_EVENT');
95
+ const payload = JSON.stringify(normalized);
96
+ if (Buffer.byteLength(payload) > MAX_EVENT_BYTES) fail('COGNITIVE_INVALID_EVENT');
97
+ return { normalized, payload };
98
+ }
99
+
100
+ function ensureHome(home) {
101
+ const root = path.resolve(String(home ?? ''));
102
+ try {
103
+ const stat = fs.lstatSync(root);
104
+ if (!stat.isDirectory() || stat.isSymbolicLink()) fail('COGNITIVE_UNSAFE_HOME');
105
+ return fs.realpathSync(root);
106
+ } catch (error) {
107
+ if (error?.code === 'COGNITIVE_UNSAFE_HOME') throw error;
108
+ fail('COGNITIVE_UNSAFE_HOME');
109
+ }
110
+ }
111
+
112
+ function initialize(db) {
113
+ db.exec(`
114
+ PRAGMA foreign_keys = ON;
115
+ PRAGMA journal_mode = WAL;
116
+ PRAGMA busy_timeout = 5000;
117
+ CREATE TABLE IF NOT EXISTS cognitive_streams (
118
+ tenant_id TEXT NOT NULL,
119
+ agent_id TEXT NOT NULL,
120
+ version INTEGER NOT NULL,
121
+ updated_at TEXT NOT NULL,
122
+ PRIMARY KEY (tenant_id, agent_id)
123
+ );
124
+ CREATE TABLE IF NOT EXISTS cognitive_events (
125
+ event_id TEXT PRIMARY KEY,
126
+ tenant_id TEXT NOT NULL,
127
+ agent_id TEXT NOT NULL,
128
+ expected_version INTEGER NOT NULL,
129
+ new_version INTEGER NOT NULL,
130
+ occurred_at TEXT NOT NULL,
131
+ payload_json TEXT NOT NULL,
132
+ previous_hash TEXT NOT NULL,
133
+ event_hash TEXT NOT NULL UNIQUE
134
+ );
135
+ CREATE TABLE IF NOT EXISTS cognitive_observations (
136
+ observation_id TEXT PRIMARY KEY,
137
+ event_id TEXT NOT NULL REFERENCES cognitive_events(event_id),
138
+ tenant_id TEXT NOT NULL,
139
+ agent_id TEXT NOT NULL,
140
+ domain TEXT NOT NULL,
141
+ fact_key TEXT NOT NULL,
142
+ value_text TEXT NOT NULL,
143
+ confidence REAL NOT NULL,
144
+ scope TEXT NOT NULL,
145
+ source_json TEXT NOT NULL,
146
+ occurred_at TEXT NOT NULL
147
+ );
148
+ CREATE INDEX IF NOT EXISTS cognitive_observations_stream
149
+ ON cognitive_observations (tenant_id, agent_id, occurred_at, observation_id);
150
+ `);
151
+ }
152
+
153
+ function openCognitiveStateStore({ home } = {}) {
154
+ const root = ensureHome(home);
155
+ const stateRoot = path.join(root, 'state');
156
+ fs.mkdirSync(stateRoot, { recursive: true });
157
+ if (!fs.realpathSync(stateRoot).startsWith(`${root}${path.sep}`)) fail('COGNITIVE_UNSAFE_HOME');
158
+ const db = new DatabaseSync(path.join(stateRoot, 'cognitive-state.sqlite'));
159
+ initialize(db);
160
+
161
+ function commit(input) {
162
+ const { normalized, payload } = normalizeEvent(input);
163
+ const existing = db.prepare('SELECT payload_json, new_version, event_hash FROM cognitive_events WHERE event_id = ?').get(normalized.event_id);
164
+ if (existing) {
165
+ if (existing.payload_json !== payload) fail('COGNITIVE_EVENT_ID_REUSE');
166
+ return { version: existing.new_version, event_hash: existing.event_hash, idempotent: true };
167
+ }
168
+ db.exec('BEGIN IMMEDIATE');
169
+ try {
170
+ const stream = db.prepare('SELECT version FROM cognitive_streams WHERE tenant_id = ? AND agent_id = ?').get(normalized.tenant_id, normalized.agent_id);
171
+ const actualVersion = Number(stream?.version ?? 0);
172
+ if (actualVersion !== normalized.expected_version) fail('COGNITIVE_VERSION_CONFLICT');
173
+ const previous = db.prepare('SELECT event_hash FROM cognitive_events WHERE tenant_id = ? AND agent_id = ? ORDER BY new_version DESC LIMIT 1').get(normalized.tenant_id, normalized.agent_id);
174
+ const previousHash = String(previous?.event_hash ?? '0'.repeat(64));
175
+ const eventHash = crypto.createHash('sha256').update(`${previousHash}\0${payload}`).digest('hex');
176
+ const newVersion = actualVersion + 1;
177
+ db.prepare(`INSERT INTO cognitive_events
178
+ (event_id, tenant_id, agent_id, expected_version, new_version, occurred_at, payload_json, previous_hash, event_hash)
179
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
180
+ .run(normalized.event_id, normalized.tenant_id, normalized.agent_id, actualVersion, newVersion, normalized.occurred_at, payload, previousHash, eventHash);
181
+ const insertObservation = db.prepare(`INSERT INTO cognitive_observations
182
+ (observation_id, event_id, tenant_id, agent_id, domain, fact_key, value_text, confidence, scope, source_json, occurred_at)
183
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
184
+ const sourceJson = JSON.stringify(normalized.source);
185
+ for (const observation of normalized.observations) {
186
+ insertObservation.run(observation.observation_id, normalized.event_id, normalized.tenant_id, normalized.agent_id,
187
+ observation.domain, observation.key, observation.value, observation.confidence, observation.scope, sourceJson, normalized.occurred_at);
188
+ }
189
+ db.prepare(`INSERT INTO cognitive_streams (tenant_id, agent_id, version, updated_at) VALUES (?, ?, ?, ?)
190
+ ON CONFLICT(tenant_id, agent_id) DO UPDATE SET version = excluded.version, updated_at = excluded.updated_at`)
191
+ .run(normalized.tenant_id, normalized.agent_id, newVersion, normalized.occurred_at);
192
+ db.exec('COMMIT');
193
+ return { version: newVersion, event_hash: eventHash };
194
+ } catch (error) {
195
+ try { db.exec('ROLLBACK'); } catch {}
196
+ throw error;
197
+ }
198
+ }
199
+
200
+ function read({ tenantId, agentId } = {}) {
201
+ const tenant = safeId(tenantId);
202
+ const agent = safeId(agentId);
203
+ if (!tenant || !agent) fail('COGNITIVE_INVALID_EVENT');
204
+ const stream = db.prepare('SELECT version, updated_at FROM cognitive_streams WHERE tenant_id = ? AND agent_id = ?').get(tenant, agent);
205
+ const rows = db.prepare(`SELECT domain, fact_key, value_text, confidence, scope, source_json, occurred_at, observation_id
206
+ FROM cognitive_observations WHERE tenant_id = ? AND agent_id = ? ORDER BY occurred_at, rowid`).all(tenant, agent);
207
+ return {
208
+ version: Number(stream?.version ?? 0),
209
+ ...(stream?.updated_at ? { updated_at: stream.updated_at } : {}),
210
+ observations: rows.map((row) => ({
211
+ observation_id: row.observation_id,
212
+ domain: row.domain,
213
+ key: row.fact_key,
214
+ value: row.value_text,
215
+ confidence: row.confidence,
216
+ scope: row.scope,
217
+ source: JSON.parse(row.source_json),
218
+ occurred_at: row.occurred_at,
219
+ })),
220
+ };
221
+ }
222
+
223
+ function verify({ tenantId, agentId } = {}) {
224
+ const tenant = safeId(tenantId);
225
+ const agent = safeId(agentId);
226
+ if (!tenant || !agent) fail('COGNITIVE_INVALID_EVENT');
227
+ const rows = db.prepare(`SELECT payload_json, previous_hash, event_hash FROM cognitive_events
228
+ WHERE tenant_id = ? AND agent_id = ? ORDER BY new_version`).all(tenant, agent);
229
+ let previousHash = '0'.repeat(64);
230
+ for (const row of rows) {
231
+ const calculated = crypto.createHash('sha256').update(`${previousHash}\0${row.payload_json}`).digest('hex');
232
+ if (row.previous_hash !== previousHash || row.event_hash !== calculated) return { valid: false, events: rows.length };
233
+ previousHash = row.event_hash;
234
+ }
235
+ return { valid: true, events: rows.length, head_hash: previousHash };
236
+ }
237
+
238
+ return {
239
+ commit,
240
+ read,
241
+ verify,
242
+ close: () => {
243
+ try { db.exec('PRAGMA wal_checkpoint(TRUNCATE)'); } catch {}
244
+ db.close();
245
+ },
246
+ };
247
+ }
248
+
249
+ module.exports = { openCognitiveStateStore };
@@ -0,0 +1,158 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
5
+
6
+ const SAFE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
7
+ const RIGHTS_AUTHORITIES = new Set(['runtime_user_prompt_hook', 'runtime_tool_policy']);
8
+ const RIGHTS_DECISIONS = new Set(['passed', 'blocked', 'not_applicable']);
9
+ const TURN_REASONS = new Set(['completed', 'cancelled', 'filtered', 'failed']);
10
+
11
+ function fail(code) {
12
+ const error = new Error(code);
13
+ error.code = code;
14
+ throw error;
15
+ }
16
+
17
+ function exactKeys(value, keys) {
18
+ return value && typeof value === 'object' && !Array.isArray(value)
19
+ && Object.keys(value).every((key) => keys.has(key));
20
+ }
21
+
22
+ function safeId(value) {
23
+ const text = String(value ?? '').trim();
24
+ return SAFE_ID_RE.test(text) ? text : '';
25
+ }
26
+
27
+ function safeTurnId(value) {
28
+ return Number.isSafeInteger(value) && value >= 0 ? value : null;
29
+ }
30
+
31
+ function digestId(prefix, values) {
32
+ const digest = crypto.createHash('sha256').update(values.join('\0')).digest('hex').slice(0, 40);
33
+ return `${prefix}-${digest}`;
34
+ }
35
+
36
+ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now = () => new Date().toISOString() } = {}) {
37
+ const tenant = safeId(tenantId);
38
+ const agent = safeId(agentId);
39
+ const runtime = safeId(runtimeId ?? `runtime-${process.pid}-${Date.now()}`);
40
+ if (!tenant || !agent || !runtime || typeof now !== 'function') fail('COGNITIVE_LIFECYCLE_INVALID');
41
+ const store = openCognitiveStateStore({ home });
42
+ const stageTimes = new Map();
43
+ const stageResults = new Map();
44
+
45
+ function stageTime(stageKey) {
46
+ if (!stageTimes.has(stageKey)) {
47
+ const occurredAt = String(now());
48
+ if (Number.isNaN(Date.parse(occurredAt))) fail('COGNITIVE_LIFECYCLE_INVALID');
49
+ stageTimes.set(stageKey, occurredAt);
50
+ }
51
+ return stageTimes.get(stageKey);
52
+ }
53
+
54
+ function commitStage(stageKey, observations) {
55
+ if (stageResults.has(stageKey)) return { ...stageResults.get(stageKey), idempotent: true };
56
+ const occurredAt = stageTime(stageKey);
57
+ const eventId = digestId('cycle', [tenant, agent, runtime, stageKey]);
58
+ const normalized = observations.map((item, index) => ({
59
+ observation_id: digestId('cycleobs', [eventId, String(index)]),
60
+ ...item,
61
+ }));
62
+ for (let attempt = 0; attempt < 4; attempt += 1) {
63
+ const expectedVersion = store.read({ tenantId: tenant, agentId: agent }).version;
64
+ try {
65
+ const result = store.commit({
66
+ tenantId: tenant,
67
+ agentId: agent,
68
+ eventId,
69
+ expectedVersion,
70
+ occurredAt,
71
+ source: {
72
+ provider: 'runtime',
73
+ actor_id: agent,
74
+ context_id: runtime,
75
+ message_id: stageKey,
76
+ },
77
+ observations: normalized,
78
+ });
79
+ stageResults.set(stageKey, result);
80
+ return result;
81
+ } catch (error) {
82
+ if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 3) throw error;
83
+ }
84
+ }
85
+ fail('COGNITIVE_VERSION_CONFLICT');
86
+ }
87
+
88
+ function startTurn(input) {
89
+ if (!exactKeys(input, new Set(['turnId', 'originKind']))) fail('COGNITIVE_LIFECYCLE_INVALID');
90
+ const turnId = safeTurnId(input.turnId);
91
+ const originKind = safeId(input.originKind);
92
+ if (turnId === null || !originKind) fail('COGNITIVE_LIFECYCLE_INVALID');
93
+ const key = `turn:${turnId}`;
94
+ return commitStage(`turn-${turnId}-start`, [
95
+ { domain: 'open_thread', key: `${key}:phase`, value: 'perceived', confidence: 1, scope: 'runtime' },
96
+ { domain: 'assumption', key: `${key}:classification`, value: `origin:${originKind}`, confidence: 1, scope: 'runtime' },
97
+ { domain: 'goal', key: `${key}:plan`, value: 'run-bounded-model-turn', confidence: 1, scope: 'runtime' },
98
+ { domain: 'next_trigger', key: `${key}:next`, value: 'runtime-policy-check', confidence: 1, scope: 'runtime' },
99
+ { domain: 'expected_evidence', key: `${key}:evidence`, value: 'turn.ended-event', confidence: 1, scope: 'runtime' },
100
+ ]);
101
+ }
102
+
103
+ function recordRightsCheck(input) {
104
+ if (!exactKeys(input, new Set(['turnId', 'decision', 'authority']))) fail('COGNITIVE_LIFECYCLE_INVALID');
105
+ const turnId = safeTurnId(input.turnId);
106
+ const decision = String(input.decision ?? '');
107
+ const authority = String(input.authority ?? '');
108
+ if (turnId === null || !RIGHTS_DECISIONS.has(decision)) fail('COGNITIVE_LIFECYCLE_INVALID');
109
+ if (!RIGHTS_AUTHORITIES.has(authority)) fail('COGNITIVE_RIGHTS_AUTHORITY_REQUIRED');
110
+ return commitStage(`turn-${turnId}-rights-${authority}`, [{
111
+ domain: 'world',
112
+ key: `turn:${turnId}:rights-check`,
113
+ value: `${decision}:${authority}`,
114
+ confidence: 1,
115
+ scope: 'runtime',
116
+ }]);
117
+ }
118
+
119
+ function endTurn(input) {
120
+ if (!exactKeys(input, new Set(['turnId', 'reason', 'durationMs']))) fail('COGNITIVE_LIFECYCLE_INVALID');
121
+ const turnId = safeTurnId(input.turnId);
122
+ const reason = String(input.reason ?? '');
123
+ const durationMs = Number(input.durationMs);
124
+ if (turnId === null || !TURN_REASONS.has(reason) || !Number.isSafeInteger(durationMs) || durationMs < 0) {
125
+ fail('COGNITIVE_LIFECYCLE_INVALID');
126
+ }
127
+ const key = `turn:${turnId}`;
128
+ return commitStage(`turn-${turnId}-end`, [
129
+ { domain: 'open_thread', key: `${key}:phase`, value: reason, confidence: 1, scope: 'runtime' },
130
+ { domain: 'expected_evidence', key: `${key}:result`, value: `turn.ended:${reason}:${durationMs}ms`, confidence: 1, scope: 'runtime' },
131
+ { domain: 'next_trigger', key: `${key}:next`, value: reason === 'completed' ? 'await-next-input' : 'inspect-turn-outcome', confidence: 1, scope: 'runtime' },
132
+ ]);
133
+ }
134
+
135
+ return {
136
+ startTurn,
137
+ recordRightsCheck,
138
+ endTurn,
139
+ read: () => store.read({ tenantId: tenant, agentId: agent }),
140
+ verify: () => store.verify({ tenantId: tenant, agentId: agent }),
141
+ close: () => store.close(),
142
+ };
143
+ }
144
+
145
+ function createRuntimeCognitiveTurnLifecycle({ home, agentName, runtimeId, now } = {}) {
146
+ const resolvedHome = String(home ?? '').trim();
147
+ const resolvedAgent = String(agentName ?? '').trim();
148
+ if (!resolvedHome || !resolvedAgent) fail('COGNITIVE_LIFECYCLE_INVALID');
149
+ return createCognitiveTurnLifecycle({
150
+ home: resolvedHome,
151
+ tenantId: digestId('home', [resolvedHome.toLowerCase()]),
152
+ agentId: digestId('agent', [resolvedAgent.toLowerCase()]),
153
+ runtimeId,
154
+ now,
155
+ });
156
+ }
157
+
158
+ module.exports = { createCognitiveTurnLifecycle, createRuntimeCognitiveTurnLifecycle };
package/blun.mjs CHANGED
@@ -261391,7 +261391,7 @@ function toolResultText(result) {
261391
261391
  function abandonedToolResultOutput(ended) {
261392
261392
  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.`;
261393
261393
  }
261394
- 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, 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;
261394
+ 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, 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;
261395
261395
  var init_turn = __esmMin((() => {
261396
261396
  init_dist$4();
261397
261397
  init_src$4();
@@ -261411,6 +261411,7 @@ var init_turn = __esmMin((() => {
261411
261411
  ({ CORE_TOOL_NAMES: BLUN_CORE_TOOL_NAMES, createDeferredToolLoader, mediaGenerationToolNamesForText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens } = createRequire(import.meta.url)("./bin/turn-tool-performance-policy.cjs"));
261412
261412
  ({ projectRecurringCronHistory } = createRequire(import.meta.url)("./bin/recurring-cron-history-policy.cjs"));
261413
261413
  ({ TelegramDeliveryLedger } = createRequire(import.meta.url)("./bin/repeated-user-message-projection.cjs"));
261414
+ ({ createRuntimeCognitiveTurnLifecycle } = createRequire(import.meta.url)("./bin/cognitive-turn-lifecycle.cjs"));
261414
261415
  BLUN_LEAN_TOOL_NAMES = new Set(BLUN_CORE_TOOL_NAMES);
261415
261416
  BLUN_ATTACHMENT_MARKER_RE = /\b(?:attachment_file_id|telegram-anhang|telegram attachment)\b/i;
261416
261417
  BLUN_TELEGRAM_OUTBOUND_TOOL_RE = /^mcp__[^\s]*telegram[^\s]*__(?:reply|react|edit_message)$/i;
@@ -261471,6 +261472,8 @@ var init_turn = __esmMin((() => {
261471
261472
  interruptedTelemetryTurnIds = /* @__PURE__ */ new Set();
261472
261473
  stepFailureByTurn = /* @__PURE__ */ new Map();
261473
261474
  currentStep = 0;
261475
+ cognitiveLifecycle;
261476
+ cognitiveLifecycleUnavailable = false;
261474
261477
  constructor(agent) {
261475
261478
  this.agent = agent;
261476
261479
  }
@@ -261478,6 +261481,33 @@ var init_turn = __esmMin((() => {
261478
261481
  get agentId() {
261479
261482
  return this.agent.homedir ? basename$2(this.agent.homedir) : this.agent.type;
261480
261483
  }
261484
+ getCognitiveLifecycle() {
261485
+ if (this.cognitiveLifecycleUnavailable) return null;
261486
+ if (this.cognitiveLifecycle !== void 0) return this.cognitiveLifecycle;
261487
+ const home = this.agent.blunHomeDir ?? this.agent.homedir;
261488
+ if (home === void 0) {
261489
+ this.cognitiveLifecycleUnavailable = true;
261490
+ return null;
261491
+ }
261492
+ try {
261493
+ this.cognitiveLifecycle = createRuntimeCognitiveTurnLifecycle({
261494
+ home,
261495
+ agentName: this.agent.activeProfile?.name ?? this.agent.type
261496
+ });
261497
+ return this.cognitiveLifecycle;
261498
+ } catch (error) {
261499
+ this.cognitiveLifecycleUnavailable = true;
261500
+ this.agent.telemetry.track("cognitive_lifecycle_error", { stage: "open", error_type: error?.code ?? error?.name ?? "Error" });
261501
+ return null;
261502
+ }
261503
+ }
261504
+ recordCognitiveStage(method, input) {
261505
+ try {
261506
+ this.getCognitiveLifecycle()?.[method](input);
261507
+ } catch (error) {
261508
+ this.agent.telemetry.track("cognitive_lifecycle_error", { stage: method, error_type: error?.code ?? error?.name ?? "Error" });
261509
+ }
261510
+ }
261481
261511
  prompt(input, origin = USER_PROMPT_ORIGIN) {
261482
261512
  return this.promptWithAcceptance(input, origin).turnId;
261483
261513
  }
@@ -261805,6 +261835,12 @@ var init_turn = __esmMin((() => {
261805
261835
  origin
261806
261836
  });
261807
261837
  this.agent.context.appendUserMessage(input, origin);
261838
+ this.recordCognitiveStage("startTurn", { turnId, originKind: origin.kind });
261839
+ this.recordCognitiveStage("recordRightsCheck", {
261840
+ turnId,
261841
+ decision: "not_applicable",
261842
+ authority: "runtime_user_prompt_hook"
261843
+ });
261808
261844
  const ended = {
261809
261845
  type: "turn.ended",
261810
261846
  turnId,
@@ -261812,6 +261848,7 @@ var init_turn = __esmMin((() => {
261812
261848
  durationMs: Date.now() - startedAt
261813
261849
  };
261814
261850
  this.agent.usage.endTurn();
261851
+ this.recordCognitiveStage("endTurn", { turnId, reason: ended.reason, durationMs: ended.durationMs ?? 0 });
261815
261852
  this.agent.emitEvent(ended);
261816
261853
  return ended;
261817
261854
  }
@@ -261841,6 +261878,7 @@ var init_turn = __esmMin((() => {
261841
261878
  origin
261842
261879
  });
261843
261880
  this.agent.context.appendUserMessage(input, origin);
261881
+ this.recordCognitiveStage("startTurn", { turnId, originKind: origin.kind });
261844
261882
  const startedAt = Date.now();
261845
261883
  let ended;
261846
261884
  let blockedByUserPromptHook = false;
@@ -261848,6 +261886,11 @@ var init_turn = __esmMin((() => {
261848
261886
  let errorEvent;
261849
261887
  try {
261850
261888
  const promptHookEnded = await this.applyUserPromptHook(turnId, input, origin, signal, startedAt);
261889
+ this.recordCognitiveStage("recordRightsCheck", {
261890
+ turnId,
261891
+ decision: origin.kind !== "user" ? "not_applicable" : promptHookEnded?.blocked === true ? "blocked" : "passed",
261892
+ authority: "runtime_user_prompt_hook"
261893
+ });
261851
261894
  if (promptHookEnded !== void 0) {
261852
261895
  ended = promptHookEnded.event;
261853
261896
  blockedByUserPromptHook = promptHookEnded.blocked;
@@ -261919,6 +261962,7 @@ var init_turn = __esmMin((() => {
261919
261962
  mode: this.telemetryModeByTurn.get(turnId) ?? this.telemetryMode(),
261920
261963
  ...this.requestProviderProps()
261921
261964
  });
261965
+ this.recordCognitiveStage("endTurn", { turnId, reason: ended.reason, durationMs: ended.durationMs ?? 0 });
261922
261966
  this.agent.emitEvent(ended);
261923
261967
  this.agent.endResponderTurn();
261924
261968
  if (standalone && this.currentId === turnId && this.agent.goal.getGoal().goal?.status !== "active") this.activeTurn = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.303",
3
+ "version": "9.1.305",
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": {