blun-king-cli 9.1.493 → 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,17 @@
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
+
10
+ ## 9.1.494 - 2026-08-30
11
+
12
+ - Removes the conflicting Ctrl+S fallback that opened or collapsed the Todo panel when no queue item was visible.
13
+ - Keeps Todo expansion exclusively on Ctrl+T and queue-backlog release exclusively on Ctrl+S.
14
+
3
15
  ## 9.1.493 - 2026-08-30
4
16
 
5
17
  - Automatically authorizes every new Telegram user message for delivery at the next safe handoff, including messages from groups, instead of requiring Ctrl+S or Escape first.
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.493
12
+ npm install -g blun-king-cli@9.1.495
13
13
 
14
14
  Start
15
15
  -----
@@ -65,7 +65,17 @@ 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.493 stellt die automatische Zustellung von User-Nachrichten auch
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
+
76
+ Version 9.1.494 trennt die Tastenkürzel wieder eindeutig: Strg+S steuert nur
77
+ den Queue-Rückstand, Strg+T nur die Todo-Liste. Version 9.1.493 stellt die
78
+ automatische Zustellung von User-Nachrichten auch
69
79
  für Telegram-Gruppen wieder her. Version 9.1.492 schützt Veröffentlichungen
70
80
  zusätzlich mit einer verpflichtenden
71
81
  Metadatenprüfung. Packen und Veröffentlichen brechen ab, wenn Paketversion,
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.493
12
+ npm install -g blun-king-cli@9.1.495
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
@@ -81,7 +81,17 @@ 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.493 stellt die automatische Zustellung von User-Nachrichten auch
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
+
92
+ Version 9.1.494 trennt die Tastenkürzel wieder eindeutig: Strg+S steuert nur
93
+ den Queue-Rückstand, Strg+T nur die Todo-Liste. Version 9.1.493 stellt die
94
+ automatische Zustellung von User-Nachrichten auch
85
95
  für Telegram-Gruppen wieder her. Version 9.1.492 schützt Veröffentlichungen
86
96
  zusätzlich mit einer verpflichtenden
87
97
  Metadatenprüfung. Packen und Veröffentlichen brechen ab, wenn Paketversion,
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) {
@@ -504008,8 +504031,9 @@ const CHANNEL_QUEUE_RETRY_MS = 5e3;
504008
504031
  //#endregion
504009
504032
  //#region src/tui/controllers/channel-queue-deadline.ts
504010
504033
  /**
504011
- * Delivers channel work only after Ctrl+S or Escape releases it. A busy runtime
504012
- * is retried without cancelling the turn or crossing the FIFO barrier.
504034
+ * Delivers authorized channel work during the active turn. User messages
504035
+ * authorize themselves on arrival; Ctrl+S and Escape remain explicit controls.
504036
+ * A busy runtime is retried without cancelling the turn or crossing FIFO.
504013
504037
  */
504014
504038
  var ChannelQueueDeadlineController = class {
504015
504039
  host;
@@ -505593,12 +505617,6 @@ var EditorKeyboardController = class {
505593
505617
  return true;
505594
505618
  };
505595
505619
  editor.onCtrlS = () => {
505596
- if (editor.getText().trim().length === 0 && host.state.queuedMessages.length === 0 && host.state.todoPanel.hasOverflow()) {
505597
- this.clearPendingExit();
505598
- host.track("shortcut_todo_expand");
505599
- host.toggleTodoPanelExpansion();
505600
- return;
505601
- }
505602
505620
  if (!host.streamingUI.hasActiveTurn() && host.state.appState.streamingPhase === "idle") return;
505603
505621
  host.flushQueuedMessages(editor.getText().trim(), editor.inputMode);
505604
505622
  host.updateQueueDisplay();
@@ -508815,6 +508833,7 @@ var SessionEventHandler = class {
508815
508833
  this.turnWatchdog.stop();
508816
508834
  this.host.restoreQueuedSteerAtTurnEnd(event.turnId);
508817
508835
  this.host.settleChannelPromptAtTurnEnd(event.turnId, event.reason);
508836
+ this.host.flushDeferredChannelAcknowledgements(event.turnId);
508818
508837
  const sessionId = this.host.session?.id;
508819
508838
  if (sessionId !== void 0) finishPersonalMemoryRememberIntentTurn(sessionId, event.turnId);
508820
508839
  this.host.streamingUI.flushNow();
@@ -509079,6 +509098,7 @@ var SessionEventHandler = class {
509079
509098
  });
509080
509099
  if (matchedCall !== void 0 && matchedCall.name !== "GetMedia" && isMediaToolName(matchedCall.name) && event.isError !== true) this.host.trackChannelMediaJob(event.output);
509081
509100
  if (matchedCall?.name === "GetMedia" && event.isError !== true) this.host.runChannelMediaFallback(event.output);
509101
+ this.host.settleChannelReplyToolResult(matchedCall, event.isError === true);
509082
509102
  this.subAgentEventHandler.handleAgentSwarmToolResult(event.toolCallId, resultData, event.isError === true);
509083
509103
  if (matchedCall !== void 0 && matchedCall.name === "TodoList" && !event.isError) {
509084
509104
  const rawTodos = matchedCall.args.todos;
@@ -517938,6 +517958,7 @@ var BlunTUI = class {
517938
517958
  queueFlushBatchRemaining = 0;
517939
517959
  queueSteerInFlight;
517940
517960
  channelPromptInFlight;
517961
+ deferredChannelAcknowledgements = /* @__PURE__ */ new Map();
517941
517962
  editorReplacementActive = false;
517942
517963
  editorReplacement;
517943
517964
  editorReplacementGeneration = 0;
@@ -518018,7 +518039,11 @@ var BlunTUI = class {
518018
518039
  onCommit: () => {
518019
518040
  renderTranscripts();
518020
518041
  for (const queued of queuedItems) queued.channelTranscriptRendered = true;
518021
- 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);
518022
518047
  if (this.queueFlushBatchRemaining > 0) this.queueFlushBatchRemaining = Math.max(0, this.queueFlushBatchRemaining - items.length);
518023
518048
  },
518024
518049
  onRestore: () => {
@@ -518047,7 +518072,10 @@ var BlunTUI = class {
518047
518072
  if (!result.accepted) return this.recoverRejectedActiveSteer(inFlight);
518048
518073
  inFlight.turnId = String(result.turnId);
518049
518074
  inFlight.accepted = true;
518050
- if (result.duplicate === true) return this.commitQueuedSteer(inFlight);
518075
+ if (result.duplicate === true) {
518076
+ inFlight.duplicate = true;
518077
+ return this.commitQueuedSteer(inFlight);
518078
+ }
518051
518079
  if (inFlight.turnEnded) return restoreHead();
518052
518080
  if (!inFlight.stepStarted) {
518053
518081
  inFlight.confirmationTimer = setTimeout(() => {
@@ -518076,6 +518104,18 @@ var BlunTUI = class {
518076
518104
  const index = this.pendingChannelReplyGuards.indexOf(guard);
518077
518105
  if (index >= 0) this.pendingChannelReplyGuards.splice(index, 1);
518078
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
+ }
518079
518119
  pinAddressedChannelFocus(chatId, origin, text) {
518080
518120
  return this.addressedChannelFocusStore.pin({ chatId, origin, text });
518081
518121
  }
@@ -518120,11 +518160,24 @@ var BlunTUI = class {
518120
518160
  if (inFlight.stepStarted || inFlight.userCancelled === true) this.commitQueuedSteer(inFlight);
518121
518161
  else if (inFlight.accepted) this.restoreQueuedSteer(inFlight);
518122
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
+ }
518123
518176
  commitChannelPromptAtStepStart(turnId) {
518124
518177
  const inFlight = this.channelPromptInFlight;
518125
518178
  if (inFlight === void 0 || inFlight.turnId !== String(turnId)) return;
518126
518179
  this.channelPromptInFlight = void 0;
518127
- inFlight.acknowledge();
518180
+ this.deferChannelAcknowledgement(inFlight.turnId, inFlight.acknowledge);
518128
518181
  }
518129
518182
  settleChannelPromptAtTurnEnd(turnId, reason) {
518130
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.493",
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": {