blun-king-cli 9.1.435 → 9.1.436

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.
@@ -6,6 +6,7 @@ const { join } = require('node:path');
6
6
  const STATUS_FILE = 'telegram-console-status.json';
7
7
  const MAX_STATUS_BYTES = 16_384;
8
8
  const MAX_TASK_CHARS = 240;
9
+ const MAX_TOOL_NAME_CHARS = 80;
9
10
 
10
11
  function validInstant(value) {
11
12
  if (typeof value !== 'string' || value.length === 0) return undefined;
@@ -18,6 +19,39 @@ function boundedTask(value) {
18
19
  return title.length > 0 ? title.slice(0, MAX_TASK_CHARS) : undefined;
19
20
  }
20
21
 
22
+ function boundedToolName(value) {
23
+ if (typeof value !== 'string') return undefined;
24
+ const name = value.replace(/\s+/gu, ' ').trim();
25
+ return name.length > 0 ? name.slice(0, MAX_TOOL_NAME_CHARS) : undefined;
26
+ }
27
+
28
+ function instantFromMilliseconds(value) {
29
+ if (!Number.isFinite(value) || value < 0) return undefined;
30
+ try {
31
+ return new Date(value).toISOString();
32
+ } catch {
33
+ return undefined;
34
+ }
35
+ }
36
+
37
+ function buildTurnDiagnostics(turnActive, activity) {
38
+ if (!turnActive || activity?.active !== true) return {};
39
+ const turnStartedAt = instantFromMilliseconds(activity.startedAtMs);
40
+ const lastProgressAt = instantFromMilliseconds(activity.lastProgressAtMs);
41
+ const lastToolName = boundedToolName(activity.lastToolName);
42
+ const failedRepetitions = Number.isSafeInteger(activity.failedRepetitions)
43
+ && activity.failedRepetitions >= 0
44
+ && activity.failedRepetitions <= 100
45
+ ? activity.failedRepetitions
46
+ : undefined;
47
+ return {
48
+ ...(turnStartedAt === undefined ? {} : { turnStartedAt }),
49
+ ...(lastProgressAt === undefined ? {} : { lastProgressAt }),
50
+ ...(lastToolName === undefined ? {} : { lastToolName }),
51
+ ...(failedRepetitions === undefined ? {} : { failedRepetitions }),
52
+ };
53
+ }
54
+
21
55
  function buildTelegramConsoleStatus(input = {}) {
22
56
  const capturedAt = validInstant(input.capturedAt);
23
57
  const processStartedAt = validInstant(input.processStartedAt);
@@ -38,6 +72,7 @@ function buildTelegramConsoleStatus(input = {}) {
38
72
  turnActive: input.turnActive,
39
73
  step,
40
74
  ...(activeTask === undefined ? {} : { activeTask }),
75
+ ...buildTurnDiagnostics(input.turnActive, input.turnActivity),
41
76
  };
42
77
  }
43
78
 
@@ -53,6 +88,25 @@ function parseTelegramConsoleStatus(value, options = {}) {
53
88
  || typeof parsed.turnActive !== 'boolean'
54
89
  || !Number.isSafeInteger(parsed.step) || parsed.step < 0) return undefined;
55
90
  const activeTask = boundedTask(parsed.activeTask);
91
+ const hasTurnStartedAt = Object.hasOwn(parsed, 'turnStartedAt');
92
+ const hasLastProgressAt = Object.hasOwn(parsed, 'lastProgressAt');
93
+ const hasLastToolName = Object.hasOwn(parsed, 'lastToolName');
94
+ const hasFailedRepetitions = Object.hasOwn(parsed, 'failedRepetitions');
95
+ const turnStartedAt = validInstant(parsed.turnStartedAt);
96
+ const lastProgressAt = validInstant(parsed.lastProgressAt);
97
+ const lastToolName = boundedToolName(parsed.lastToolName);
98
+ const failedRepetitions = parsed.failedRepetitions;
99
+ if ((hasTurnStartedAt && turnStartedAt === undefined)
100
+ || (hasLastProgressAt && lastProgressAt === undefined)
101
+ || (hasLastToolName && lastToolName === undefined)
102
+ || (hasFailedRepetitions && (!Number.isSafeInteger(failedRepetitions)
103
+ || failedRepetitions < 0 || failedRepetitions > 100))) return undefined;
104
+ const diagnostics = parsed.turnActive ? {
105
+ ...(turnStartedAt === undefined ? {} : { turnStartedAt }),
106
+ ...(lastProgressAt === undefined ? {} : { lastProgressAt }),
107
+ ...(lastToolName === undefined ? {} : { lastToolName }),
108
+ ...(hasFailedRepetitions ? { failedRepetitions } : {}),
109
+ } : {};
56
110
  return {
57
111
  version: 1,
58
112
  pid: parsed.pid,
@@ -61,6 +115,7 @@ function parseTelegramConsoleStatus(value, options = {}) {
61
115
  turnActive: parsed.turnActive,
62
116
  step: parsed.step,
63
117
  ...(parsed.turnActive && activeTask !== undefined ? { activeTask } : {}),
118
+ ...diagnostics,
64
119
  };
65
120
  } catch {
66
121
  return undefined;
@@ -76,6 +76,14 @@ function buildTelegramRemoteStatus(input) {
76
76
  ? [
77
77
  `Arbeitsstatus: aktiv, Schritt ${input.consoleStatus.step}`,
78
78
  ...(input.consoleStatus.activeTask === undefined ? [] : [`Aktive Aufgabe: ${input.consoleStatus.activeTask}`]),
79
+ ...(formatAge(input.consoleStatus.turnStartedAt, input.capturedAt) === undefined
80
+ ? [] : [`Zugbeginn: ${formatAge(input.consoleStatus.turnStartedAt, input.capturedAt)}`]),
81
+ ...(formatAge(input.consoleStatus.lastProgressAt, input.capturedAt) === undefined
82
+ ? [] : [`Letzter Fortschritt: ${formatAge(input.consoleStatus.lastProgressAt, input.capturedAt)}`]),
83
+ ...(input.consoleStatus.lastToolName === undefined
84
+ ? [] : [`Letztes Werkzeug: ${input.consoleStatus.lastToolName}`]),
85
+ ...(input.consoleStatus.failedRepetitions === undefined
86
+ ? [] : [`Wiederholte Fehler: ${input.consoleStatus.failedRepetitions}`]),
79
87
  ]
80
88
  : ['Arbeitsstatus: Leerlauf'];
81
89
  return [
package/blun.mjs CHANGED
@@ -419609,6 +419609,7 @@ var TelegramChannelController = class {
419609
419609
  }
419610
419610
  try {
419611
419611
  writeFileSync(this.leaseFile, String(process.pid));
419612
+ this.host.streamingUI?.publishTelegramConsoleStatus?.();
419612
419613
  } catch (error) {
419613
419614
  this.host.warn(uiText("telegramChannel.leaseWriteFailed", { error: String(error) }));
419614
419615
  }
@@ -507622,6 +507623,7 @@ var TurnWatchdogController = class {
507622
507623
  clearTimer;
507623
507624
  onIdle;
507624
507625
  onAbort;
507626
+ onSnapshot;
507625
507627
  toolCalls = /* @__PURE__ */ new Map();
507626
507628
  active = false;
507627
507629
  startedAtMs = 0;
@@ -507638,6 +507640,7 @@ var TurnWatchdogController = class {
507638
507640
  this.clearTimer = options.clearTimer ?? clearTimeout;
507639
507641
  this.onIdle = options.onIdle;
507640
507642
  this.onAbort = options.onAbort;
507643
+ this.onSnapshot = options.onSnapshot ?? (() => {});
507641
507644
  }
507642
507645
  start() {
507643
507646
  this.stop();
@@ -507649,20 +507652,23 @@ var TurnWatchdogController = class {
507649
507652
  this.lastFailedKey = void 0;
507650
507653
  this.failedRepetitions = 0;
507651
507654
  this.idleReportedForProgressAtMs = void 0;
507655
+ this.publishSnapshot();
507652
507656
  this.scheduleIdleCheck();
507653
507657
  }
507654
507658
  stop() {
507659
+ const wasActive = this.active;
507655
507660
  this.active = false;
507656
507661
  this.toolCalls.clear();
507657
507662
  if (this.timer !== void 0) {
507658
507663
  this.clearTimer(this.timer);
507659
507664
  this.timer = void 0;
507660
507665
  }
507666
+ if (wasActive) this.publishSnapshot();
507661
507667
  }
507662
507668
  recordToolCall(toolCallId, name, args) {
507663
507669
  if (!this.active) return;
507664
- this.recordProgress();
507665
507670
  this.lastToolName = name;
507671
+ this.recordProgress();
507666
507672
  this.toolCalls.set(toolCallId, {
507667
507673
  name,
507668
507674
  key: `${name}\0${canonicalJson(args)}`
@@ -507677,6 +507683,7 @@ var TurnWatchdogController = class {
507677
507683
  if (!isError || toolCall === void 0) {
507678
507684
  this.lastFailedKey = void 0;
507679
507685
  this.failedRepetitions = 0;
507686
+ this.publishSnapshot();
507680
507687
  return;
507681
507688
  }
507682
507689
  if (toolCall.key === this.lastFailedKey) this.failedRepetitions += 1;
@@ -507684,6 +507691,7 @@ var TurnWatchdogController = class {
507684
507691
  this.lastFailedKey = toolCall.key;
507685
507692
  this.failedRepetitions = 1;
507686
507693
  }
507694
+ this.publishSnapshot();
507687
507695
  if (this.failedRepetitions < this.config.maxFailedRepetitions) return;
507688
507696
  const snapshot = {
507689
507697
  ...this.snapshot(),
@@ -507696,8 +507704,20 @@ var TurnWatchdogController = class {
507696
507704
  if (!this.active) return;
507697
507705
  this.lastProgressAtMs = this.now();
507698
507706
  this.idleReportedForProgressAtMs = void 0;
507707
+ this.publishSnapshot();
507699
507708
  this.scheduleIdleCheck();
507700
507709
  }
507710
+ publishSnapshot() {
507711
+ try {
507712
+ this.onSnapshot(this.active ? {
507713
+ active: true,
507714
+ startedAtMs: this.startedAtMs,
507715
+ lastProgressAtMs: this.lastProgressAtMs,
507716
+ lastToolName: this.lastToolName,
507717
+ failedRepetitions: this.failedRepetitions
507718
+ } : { active: false });
507719
+ } catch {}
507720
+ }
507701
507721
  scheduleIdleCheck() {
507702
507722
  if (!this.active) return;
507703
507723
  if (this.timer !== void 0) this.clearTimer(this.timer);
@@ -507775,7 +507795,8 @@ var SessionEventHandler = class {
507775
507795
  });
507776
507796
  this.turnWatchdog = new TurnWatchdogController({
507777
507797
  onIdle: (snapshot) => this.reportWatchdogIdle(snapshot),
507778
- onAbort: (snapshot) => this.abortWatchdogLoop(snapshot)
507798
+ onAbort: (snapshot) => this.abortWatchdogLoop(snapshot),
507799
+ onSnapshot: (snapshot) => this.host.streamingUI.setRemoteTurnActivity(snapshot)
507779
507800
  });
507780
507801
  }
507781
507802
  backgroundTasks = /* @__PURE__ */ new Map();
@@ -511183,6 +511204,7 @@ var StreamingUIController = class {
511183
511204
  _currentTurnId = void 0;
511184
511205
  _currentStep = 0;
511185
511206
  _remoteTodos = [];
511207
+ _remoteTurnActivity = { active: false };
511186
511208
  _remoteProcessStartedAt = new Date(Date.now() - process.uptime() * 1e3).toISOString();
511187
511209
  _liveTurnStartedAtMs = void 0;
511188
511210
  _liveOutputTokens = new LiveOutputTokenCounter();
@@ -511215,6 +511237,13 @@ var StreamingUIController = class {
511215
511237
  this._currentStep = step;
511216
511238
  this.publishTelegramConsoleStatus();
511217
511239
  }
511240
+ setRemoteTurnActivity(activity) {
511241
+ const previous = this._remoteTurnActivity;
511242
+ this._remoteTurnActivity = activity?.active === true ? activity : { active: false };
511243
+ if (previous.active !== this._remoteTurnActivity.active
511244
+ || previous.lastToolName !== this._remoteTurnActivity.lastToolName
511245
+ || previous.failedRepetitions !== this._remoteTurnActivity.failedRepetitions) this.publishTelegramConsoleStatus();
511246
+ }
511218
511247
  publishTelegramConsoleStatus() {
511219
511248
  if (!telegramChannelAttachEnabled()) return;
511220
511249
  try {
@@ -511225,6 +511254,7 @@ var StreamingUIController = class {
511225
511254
  processStartedAt: this._remoteProcessStartedAt,
511226
511255
  step: this._currentStep,
511227
511256
  todos: this._remoteTodos,
511257
+ turnActivity: this._remoteTurnActivity,
511228
511258
  turnActive: this._currentTurnId !== void 0
511229
511259
  });
511230
511260
  } catch {}
@@ -511536,6 +511566,7 @@ var StreamingUIController = class {
511536
511566
  this._currentTurnId = void 0;
511537
511567
  this._currentStep = 0;
511538
511568
  this._remoteTodos = [];
511569
+ this._remoteTurnActivity = { active: false };
511539
511570
  this._streamingToolCallArguments.clear();
511540
511571
  this.pendingToolCallFlushIds.clear();
511541
511572
  this.publishTelegramConsoleStatus();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.435",
3
+ "version": "9.1.436",
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": {