blun-king-cli 9.1.494 → 9.1.495

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.1.495 - 2026-08-30
4
+
5
+ - Starts every new or replaced goal with a fresh visible TodoList and requires a truthful refresh after at most eight work batches.
6
+ - Retires answered Telegram group focus immediately after a successful reply or edit instead of waiting for a long-running turn to end.
7
+ - Defers normal inbound checkpoint acknowledgement until turn end, so restart replay cannot lose a message accepted during an early model step.
8
+ - Adds real control-key decoding coverage for Ctrl+S and Ctrl+T, including Kitty keyboard sequences with Caps Lock active.
9
+
3
10
  ## 9.1.494 - 2026-08-30
4
11
 
5
12
  - Removes the conflicting Ctrl+S fallback that opened or collapsed the Todo panel when no queue item was visible.
package/LIESMICH.txt CHANGED
@@ -9,7 +9,7 @@ Installation
9
9
  ------------
10
10
  Die geprüfte Version exakt global installieren:
11
11
 
12
- npm install -g blun-king-cli@9.1.494
12
+ npm install -g blun-king-cli@9.1.495
13
13
 
14
14
  Start
15
15
  -----
@@ -65,6 +65,14 @@ geschriebenen Entwurf zu löschen. Das gilt auch bei
65
65
  Autovervollständigung, Geistervorschlägen, Bash-Eingabe und einer offenen
66
66
  Mehrzeileneingabe.
67
67
 
68
+ Version 9.1.495 startet jedes neue Ziel mit einer frischen sichtbaren Todo-Liste,
69
+ erzwingt regelmäßige wahrheitsgemäße Fortschrittsstände und quittiert normale
70
+ Telegram-Nachrichten erst am Zugende. Dadurch bleiben sie nach einem Neustart
71
+ wiederholbar, bis ihre Verarbeitung wirklich abgeschlossen ist. Erfolgreich
72
+ beantwortete Gruppenmeldungen verschwinden sofort aus der sichtbaren Queue.
73
+ Zusätzliche Regressionstests prüfen Strg+S und Strg+T als echte Terminalsequenzen,
74
+ auch bei aktiver Feststelltaste.
75
+
68
76
  Version 9.1.494 trennt die Tastenkürzel wieder eindeutig: Strg+S steuert nur
69
77
  den Queue-Rückstand, Strg+T nur die Todo-Liste. Version 9.1.493 stellt die
70
78
  automatische Zustellung von User-Nachrichten auch
package/README.md CHANGED
@@ -9,7 +9,7 @@ Voraussetzung ist Node.js 24.15 oder neuer. Die geprüfte Version wird exakt
9
9
  installiert:
10
10
 
11
11
  ```powershell
12
- npm install -g blun-king-cli@9.1.494
12
+ npm install -g blun-king-cli@9.1.495
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
@@ -81,6 +81,14 @@ konkurrierenden Start zurückgewiesen und bleiben an der Spitze der
81
81
  FIFO-Warteschlange. Für diesen normalen Wartestatus erscheint kein
82
82
  `turn.agent_busy`-Fehler.
83
83
 
84
+ Version 9.1.495 startet jedes neue Ziel mit einer frischen sichtbaren Todo-Liste,
85
+ erzwingt regelmäßige wahrheitsgemäße Fortschrittsstände und quittiert normale
86
+ Telegram-Nachrichten erst am Zugende. Dadurch bleiben sie nach einem Neustart
87
+ wiederholbar, bis ihre Verarbeitung wirklich abgeschlossen ist. Erfolgreich
88
+ beantwortete Gruppenmeldungen verschwinden sofort aus der sichtbaren Queue.
89
+ Zusätzliche Regressionstests prüfen Strg+S und Strg+T als echte Terminalsequenzen,
90
+ auch bei aktiver Feststelltaste.
91
+
84
92
  Version 9.1.494 trennt die Tastenkürzel wieder eindeutig: Strg+S steuert nur
85
93
  den Queue-Rückstand, Strg+T nur die Todo-Liste. Version 9.1.493 stellt die
86
94
  automatische Zustellung von User-Nachrichten auch
package/blun.mjs CHANGED
@@ -230323,6 +230323,7 @@ var init_goal$1 = __esmMin((() => {
230323
230323
  });
230324
230324
  }
230325
230325
  this.persistState(state);
230326
+ this.agent.tools.updateStore(TODO_STORE_KEY, []);
230326
230327
  this.agent.records.logRecord({
230327
230328
  type: "goal.create",
230328
230329
  goalId: state.goalId,
@@ -423204,6 +423205,10 @@ function validInitialIdeaPlan(value) {
423204
423205
  function enforceGoalTodoPolicy(agent, context) {
423205
423206
  if (isIdeaGoal(agent) || agent.goal.getActiveGoal() === null) return;
423206
423207
  const todos = ideaTodos(agent);
423208
+ const progress = agent.goalTodoPolicyState ??= {
423209
+ workCallsSinceRefresh: 0,
423210
+ refreshRequired: false
423211
+ };
423207
423212
  if (todos.length === 0) {
423208
423213
  const firstCall = context.toolCalls[0];
423209
423214
  if (context.toolCall.id !== firstCall?.id || context.toolCall.name !== "TodoList") return {
@@ -423214,16 +423219,34 @@ function enforceGoalTodoPolicy(agent, context) {
423214
423219
  block: true,
423215
423220
  reason: "The first goal TodoList must contain at least one item, exactly one in_progress item, and only pending items otherwise."
423216
423221
  };
423222
+ progress.workCallsSinceRefresh = 0;
423223
+ progress.refreshRequired = false;
423217
423224
  return;
423218
423225
  }
423219
- if (context.toolCall.name !== "UpdateGoal" || context.args?.status !== "complete" && context.args?.status !== "blocked") return;
423220
- if (todos.some((todo) => !IDEA_TERMINAL_TODO_STATUSES.includes(todo.status))) return {
423221
- block: true,
423222
- reason: "The goal cannot finish while a visible TodoList item has no truthful terminal status. Reconcile the list first."
423223
- };
423224
- if (context.args.status === "complete" && todos.some((todo) => todo.status !== "done")) return {
423226
+ if (context.toolCall.name === "TodoList") {
423227
+ progress.workCallsSinceRefresh = 0;
423228
+ progress.refreshRequired = false;
423229
+ return;
423230
+ }
423231
+ if (context.toolCall.name === "UpdateGoal" && (context.args?.status === "complete" || context.args?.status === "blocked")) {
423232
+ if (todos.some((todo) => !IDEA_TERMINAL_TODO_STATUSES.includes(todo.status))) return {
423233
+ block: true,
423234
+ reason: "The goal cannot finish while a visible TodoList item has no truthful terminal status. Reconcile the list first."
423235
+ };
423236
+ if (context.args.status === "complete" && todos.some((todo) => todo.status !== "done")) return {
423237
+ block: true,
423238
+ reason: "The goal can complete only when every visible TodoList item is done. Use blocked when an item is blocked, waiting_approval, or aborted."
423239
+ };
423240
+ return;
423241
+ }
423242
+ if (context.toolCall.id === context.toolCalls[0]?.id) {
423243
+ progress.workCallsSinceRefresh += 1;
423244
+ if (progress.workCallsSinceRefresh > 8) progress.refreshRequired = true;
423245
+ }
423246
+ if (!progress.refreshRequired) return;
423247
+ return {
423225
423248
  block: true,
423226
- reason: "The goal can complete only when every visible TodoList item is done. Use blocked when an item is blocked, waiting_approval, or aborted."
423249
+ reason: "Refresh TodoList before more work. Mark only evidenced steps done, keep the actual current step in_progress, and leave later steps pending."
423227
423250
  };
423228
423251
  }
423229
423252
  function ideaOutboundChannel(toolName, args) {
@@ -508810,6 +508833,7 @@ var SessionEventHandler = class {
508810
508833
  this.turnWatchdog.stop();
508811
508834
  this.host.restoreQueuedSteerAtTurnEnd(event.turnId);
508812
508835
  this.host.settleChannelPromptAtTurnEnd(event.turnId, event.reason);
508836
+ this.host.flushDeferredChannelAcknowledgements(event.turnId);
508813
508837
  const sessionId = this.host.session?.id;
508814
508838
  if (sessionId !== void 0) finishPersonalMemoryRememberIntentTurn(sessionId, event.turnId);
508815
508839
  this.host.streamingUI.flushNow();
@@ -509074,6 +509098,7 @@ var SessionEventHandler = class {
509074
509098
  });
509075
509099
  if (matchedCall !== void 0 && matchedCall.name !== "GetMedia" && isMediaToolName(matchedCall.name) && event.isError !== true) this.host.trackChannelMediaJob(event.output);
509076
509100
  if (matchedCall?.name === "GetMedia" && event.isError !== true) this.host.runChannelMediaFallback(event.output);
509101
+ this.host.settleChannelReplyToolResult(matchedCall, event.isError === true);
509077
509102
  this.subAgentEventHandler.handleAgentSwarmToolResult(event.toolCallId, resultData, event.isError === true);
509078
509103
  if (matchedCall !== void 0 && matchedCall.name === "TodoList" && !event.isError) {
509079
509104
  const rawTodos = matchedCall.args.todos;
@@ -517933,6 +517958,7 @@ var BlunTUI = class {
517933
517958
  queueFlushBatchRemaining = 0;
517934
517959
  queueSteerInFlight;
517935
517960
  channelPromptInFlight;
517961
+ deferredChannelAcknowledgements = /* @__PURE__ */ new Map();
517936
517962
  editorReplacementActive = false;
517937
517963
  editorReplacement;
517938
517964
  editorReplacementGeneration = 0;
@@ -518013,7 +518039,11 @@ var BlunTUI = class {
518013
518039
  onCommit: () => {
518014
518040
  renderTranscripts();
518015
518041
  for (const queued of queuedItems) queued.channelTranscriptRendered = true;
518016
- for (const queued of items) queued.channelAcknowledge?.();
518042
+ const acknowledge = () => {
518043
+ for (const queued of items) queued.channelAcknowledge?.();
518044
+ };
518045
+ if (inFlight.duplicate === true) acknowledge();
518046
+ else this.deferChannelAcknowledgement(inFlight.turnId, acknowledge);
518017
518047
  if (this.queueFlushBatchRemaining > 0) this.queueFlushBatchRemaining = Math.max(0, this.queueFlushBatchRemaining - items.length);
518018
518048
  },
518019
518049
  onRestore: () => {
@@ -518042,7 +518072,10 @@ var BlunTUI = class {
518042
518072
  if (!result.accepted) return this.recoverRejectedActiveSteer(inFlight);
518043
518073
  inFlight.turnId = String(result.turnId);
518044
518074
  inFlight.accepted = true;
518045
- if (result.duplicate === true) return this.commitQueuedSteer(inFlight);
518075
+ if (result.duplicate === true) {
518076
+ inFlight.duplicate = true;
518077
+ return this.commitQueuedSteer(inFlight);
518078
+ }
518046
518079
  if (inFlight.turnEnded) return restoreHead();
518047
518080
  if (!inFlight.stepStarted) {
518048
518081
  inFlight.confirmationTimer = setTimeout(() => {
@@ -518071,6 +518104,18 @@ var BlunTUI = class {
518071
518104
  const index = this.pendingChannelReplyGuards.indexOf(guard);
518072
518105
  if (index >= 0) this.pendingChannelReplyGuards.splice(index, 1);
518073
518106
  }
518107
+ settleChannelReplyToolResult(matchedCall, isError) {
518108
+ if (matchedCall === void 0 || isError) return;
518109
+ if (!/(?:^|__|:)(?:reply|edit_message)$/i.test(matchedCall.name ?? "")) return;
518110
+ const chatId = String(matchedCall.args?.["chat_id"] ?? matchedCall.args?.["chatId"] ?? "");
518111
+ if (chatId.length === 0) return;
518112
+ const delivered = this.pendingChannelReplyGuards.filter((guard) => guard.chatId === chatId);
518113
+ if (delivered.length === 0) return;
518114
+ this.pendingChannelReplyGuards = this.pendingChannelReplyGuards.filter((guard) => guard.chatId !== chatId);
518115
+ this.clearAddressedChannelFocus(chatId);
518116
+ for (const guard of delivered) if (guard.directFocus === true) this.directFocusController.noteReplyDelivered(chatId);
518117
+ this.updateAddressedChannelFocus();
518118
+ }
518074
518119
  pinAddressedChannelFocus(chatId, origin, text) {
518075
518120
  return this.addressedChannelFocusStore.pin({ chatId, origin, text });
518076
518121
  }
@@ -518115,11 +518160,24 @@ var BlunTUI = class {
518115
518160
  if (inFlight.stepStarted || inFlight.userCancelled === true) this.commitQueuedSteer(inFlight);
518116
518161
  else if (inFlight.accepted) this.restoreQueuedSteer(inFlight);
518117
518162
  }
518163
+ deferChannelAcknowledgement(turnId, acknowledge) {
518164
+ const key = String(turnId);
518165
+ const pending = this.deferredChannelAcknowledgements.get(key) ?? [];
518166
+ pending.push(acknowledge);
518167
+ this.deferredChannelAcknowledgements.set(key, pending);
518168
+ }
518169
+ flushDeferredChannelAcknowledgements(turnId) {
518170
+ const key = String(turnId);
518171
+ const pending = this.deferredChannelAcknowledgements.get(key);
518172
+ if (pending === void 0) return;
518173
+ this.deferredChannelAcknowledgements.delete(key);
518174
+ for (const acknowledge of pending) acknowledge();
518175
+ }
518118
518176
  commitChannelPromptAtStepStart(turnId) {
518119
518177
  const inFlight = this.channelPromptInFlight;
518120
518178
  if (inFlight === void 0 || inFlight.turnId !== String(turnId)) return;
518121
518179
  this.channelPromptInFlight = void 0;
518122
- inFlight.acknowledge();
518180
+ this.deferChannelAcknowledgement(inFlight.turnId, inFlight.acknowledge);
518123
518181
  }
518124
518182
  settleChannelPromptAtTurnEnd(turnId, reason) {
518125
518183
  const inFlight = this.channelPromptInFlight;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.494",
3
+ "version": "9.1.495",
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": {