blun-king-cli 9.1.494 → 9.1.496
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 +14 -0
- package/LIESMICH.txt +17 -1
- package/README.md +17 -1
- package/bin/telegram-addressed-focus.cjs +10 -0
- package/blun.mjs +117 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 9.1.496 - 2026-08-30
|
|
4
|
+
|
|
5
|
+
- Delivers Telegram user messages automatically one at a time without depending on the manual Ctrl+S or Escape release counter.
|
|
6
|
+
- Retires only the exact accepted or answered Telegram message ID, preserving newer messages from the same chat and removing delivered items from the visible queue.
|
|
7
|
+
- Enforces truthful progress for every existing visible TodoList, including sessions without an active Goal, and rejects unchanged refreshes after extended work.
|
|
8
|
+
- Hides successful internal hook payloads from visible output while keeping blocking hook failures visible.
|
|
9
|
+
|
|
10
|
+
## 9.1.495 - 2026-08-30
|
|
11
|
+
|
|
12
|
+
- Starts every new or replaced goal with a fresh visible TodoList and requires a truthful refresh after at most eight work batches.
|
|
13
|
+
- Retires answered Telegram group focus immediately after a successful reply or edit instead of waiting for a long-running turn to end.
|
|
14
|
+
- Defers normal inbound checkpoint acknowledgement until turn end, so restart replay cannot lose a message accepted during an early model step.
|
|
15
|
+
- Adds real control-key decoding coverage for Ctrl+S and Ctrl+T, including Kitty keyboard sequences with Caps Lock active.
|
|
16
|
+
|
|
3
17
|
## 9.1.494 - 2026-08-30
|
|
4
18
|
|
|
5
19
|
- 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.
|
|
12
|
+
npm install -g blun-king-cli@9.1.496
|
|
13
13
|
|
|
14
14
|
Start
|
|
15
15
|
-----
|
|
@@ -65,6 +65,22 @@ 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.496 stellt Telegram-Nutzernachrichten automatisch einzeln zu, ohne
|
|
69
|
+
die automatische Zustellung an den manuellen Strg+S-/Escape-Zähler zu koppeln.
|
|
70
|
+
Nach Annahme oder Antwort wird nur die exakt verarbeitete Nachrichten-ID aus der
|
|
71
|
+
sichtbaren Queue entfernt; spätere Meldungen desselben Chats bleiben erhalten.
|
|
72
|
+
Vorhandene Todo-Listen bleiben auch ohne aktives Ziel verbindlich und müssen nach
|
|
73
|
+
längerer Arbeit belegbaren Fortschritt zeigen. Erfolgreiche interne Hook-Ausgaben
|
|
74
|
+
bleiben unsichtbar, blockierende Hook-Fehler werden weiterhin angezeigt.
|
|
75
|
+
|
|
76
|
+
Version 9.1.495 startet jedes neue Ziel mit einer frischen sichtbaren Todo-Liste,
|
|
77
|
+
erzwingt regelmäßige wahrheitsgemäße Fortschrittsstände und quittiert normale
|
|
78
|
+
Telegram-Nachrichten erst am Zugende. Dadurch bleiben sie nach einem Neustart
|
|
79
|
+
wiederholbar, bis ihre Verarbeitung wirklich abgeschlossen ist. Erfolgreich
|
|
80
|
+
beantwortete Gruppenmeldungen verschwinden sofort aus der sichtbaren Queue.
|
|
81
|
+
Zusätzliche Regressionstests prüfen Strg+S und Strg+T als echte Terminalsequenzen,
|
|
82
|
+
auch bei aktiver Feststelltaste.
|
|
83
|
+
|
|
68
84
|
Version 9.1.494 trennt die Tastenkürzel wieder eindeutig: Strg+S steuert nur
|
|
69
85
|
den Queue-Rückstand, Strg+T nur die Todo-Liste. Version 9.1.493 stellt die
|
|
70
86
|
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.
|
|
12
|
+
npm install -g blun-king-cli@9.1.496
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Reproduzierbares Staging und Packen
|
|
@@ -81,6 +81,22 @@ 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.496 stellt Telegram-Nutzernachrichten automatisch einzeln zu, ohne
|
|
85
|
+
die automatische Zustellung an den manuellen Strg+S-/Escape-Zähler zu koppeln.
|
|
86
|
+
Nach Annahme oder Antwort wird nur die exakt verarbeitete Nachrichten-ID aus der
|
|
87
|
+
sichtbaren Queue entfernt; spätere Meldungen desselben Chats bleiben erhalten.
|
|
88
|
+
Vorhandene Todo-Listen bleiben auch ohne aktives Ziel verbindlich und müssen nach
|
|
89
|
+
längerer Arbeit belegbaren Fortschritt zeigen. Erfolgreiche interne Hook-Ausgaben
|
|
90
|
+
bleiben unsichtbar, blockierende Hook-Fehler werden weiterhin angezeigt.
|
|
91
|
+
|
|
92
|
+
Version 9.1.495 startet jedes neue Ziel mit einer frischen sichtbaren Todo-Liste,
|
|
93
|
+
erzwingt regelmäßige wahrheitsgemäße Fortschrittsstände und quittiert normale
|
|
94
|
+
Telegram-Nachrichten erst am Zugende. Dadurch bleiben sie nach einem Neustart
|
|
95
|
+
wiederholbar, bis ihre Verarbeitung wirklich abgeschlossen ist. Erfolgreich
|
|
96
|
+
beantwortete Gruppenmeldungen verschwinden sofort aus der sichtbaren Queue.
|
|
97
|
+
Zusätzliche Regressionstests prüfen Strg+S und Strg+T als echte Terminalsequenzen,
|
|
98
|
+
auch bei aktiver Feststelltaste.
|
|
99
|
+
|
|
84
100
|
Version 9.1.494 trennt die Tastenkürzel wieder eindeutig: Strg+S steuert nur
|
|
85
101
|
den Queue-Rückstand, Strg+T nur die Todo-Liste. Version 9.1.493 stellt die
|
|
86
102
|
automatische Zustellung von User-Nachrichten auch
|
|
@@ -36,6 +36,16 @@ function createAddressedChannelFocusStore(options = {}) {
|
|
|
36
36
|
return true;
|
|
37
37
|
},
|
|
38
38
|
|
|
39
|
+
clearIds(ids) {
|
|
40
|
+
const expected = new Set(Array.from(ids ?? [], (id) => String(id)));
|
|
41
|
+
if (expected.size === 0) return false;
|
|
42
|
+
const next = items.filter((item) => !expected.has(item.id));
|
|
43
|
+
if (next.length === items.length) return false;
|
|
44
|
+
items = next;
|
|
45
|
+
publish();
|
|
46
|
+
return true;
|
|
47
|
+
},
|
|
48
|
+
|
|
39
49
|
snapshot,
|
|
40
50
|
};
|
|
41
51
|
}
|
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,
|
|
@@ -423202,9 +423203,15 @@ function validInitialIdeaPlan(value) {
|
|
|
423202
423203
|
return active === 1;
|
|
423203
423204
|
}
|
|
423204
423205
|
function enforceGoalTodoPolicy(agent, context) {
|
|
423205
|
-
if (isIdeaGoal(agent)
|
|
423206
|
+
if (isIdeaGoal(agent)) return;
|
|
423207
|
+
const activeGoal = agent.goal.getActiveGoal();
|
|
423206
423208
|
const todos = ideaTodos(agent);
|
|
423209
|
+
const progress = agent.goalTodoPolicyState ??= {
|
|
423210
|
+
workCallsSinceRefresh: 0,
|
|
423211
|
+
refreshRequired: false
|
|
423212
|
+
};
|
|
423207
423213
|
if (todos.length === 0) {
|
|
423214
|
+
if (activeGoal === null) return;
|
|
423208
423215
|
const firstCall = context.toolCalls[0];
|
|
423209
423216
|
if (context.toolCall.id !== firstCall?.id || context.toolCall.name !== "TodoList") return {
|
|
423210
423217
|
block: true,
|
|
@@ -423214,16 +423221,60 @@ function enforceGoalTodoPolicy(agent, context) {
|
|
|
423214
423221
|
block: true,
|
|
423215
423222
|
reason: "The first goal TodoList must contain at least one item, exactly one in_progress item, and only pending items otherwise."
|
|
423216
423223
|
};
|
|
423224
|
+
progress.workCallsSinceRefresh = 0;
|
|
423225
|
+
progress.refreshRequired = false;
|
|
423217
423226
|
return;
|
|
423218
423227
|
}
|
|
423219
|
-
if (context.toolCall.name
|
|
423220
|
-
|
|
423221
|
-
|
|
423222
|
-
|
|
423223
|
-
|
|
423224
|
-
|
|
423228
|
+
if (context.toolCall.name === "TodoList") {
|
|
423229
|
+
const nextTodos = context.args?.todos;
|
|
423230
|
+
if (!Array.isArray(nextTodos)) return;
|
|
423231
|
+
if (nextTodos.length === 0) {
|
|
423232
|
+
if (activeGoal !== null) return {
|
|
423233
|
+
block: true,
|
|
423234
|
+
reason: "An active goal keeps its TodoList until UpdateGoal records a truthful terminal state. Reconcile the list instead of clearing it."
|
|
423235
|
+
};
|
|
423236
|
+
if (todos.some((todo) => !IDEA_TERMINAL_TODO_STATUSES.includes(todo.status))) return {
|
|
423237
|
+
block: true,
|
|
423238
|
+
reason: "Do not clear unfinished TodoList work. Record a truthful terminal status for every item first."
|
|
423239
|
+
};
|
|
423240
|
+
} else {
|
|
423241
|
+
const inProgressCount = nextTodos.filter((todo) => todo?.status === "in_progress").length;
|
|
423242
|
+
const allTerminal = nextTodos.every((todo) => IDEA_TERMINAL_TODO_STATUSES.includes(todo?.status));
|
|
423243
|
+
if (!allTerminal && inProgressCount !== 1) return {
|
|
423244
|
+
block: true,
|
|
423245
|
+
reason: "A maintained TodoList must keep exactly one item in_progress while unfinished work remains."
|
|
423246
|
+
};
|
|
423247
|
+
}
|
|
423248
|
+
if (progress.refreshRequired) {
|
|
423249
|
+
const normalized = (value) => value.map((todo) => ({ title: String(todo?.title ?? "").trim(), status: todo?.status }));
|
|
423250
|
+
if (JSON.stringify(normalized(nextTodos)) === JSON.stringify(normalized(todos))) return {
|
|
423251
|
+
block: true,
|
|
423252
|
+
reason: "TodoList is unchanged after extended work. Mark evidenced progress, advance the active item, or refine its title to the concrete verified substep before continuing."
|
|
423253
|
+
};
|
|
423254
|
+
}
|
|
423255
|
+
progress.workCallsSinceRefresh = 0;
|
|
423256
|
+
progress.refreshRequired = false;
|
|
423257
|
+
return;
|
|
423258
|
+
}
|
|
423259
|
+
if (activeGoal !== null && context.toolCall.name === "UpdateGoal" && (context.args?.status === "complete" || context.args?.status === "blocked")) {
|
|
423260
|
+
if (todos.some((todo) => !IDEA_TERMINAL_TODO_STATUSES.includes(todo.status))) return {
|
|
423261
|
+
block: true,
|
|
423262
|
+
reason: "The goal cannot finish while a visible TodoList item has no truthful terminal status. Reconcile the list first."
|
|
423263
|
+
};
|
|
423264
|
+
if (context.args.status === "complete" && todos.some((todo) => todo.status !== "done")) return {
|
|
423265
|
+
block: true,
|
|
423266
|
+
reason: "The goal can complete only when every visible TodoList item is done. Use blocked when an item is blocked, waiting_approval, or aborted."
|
|
423267
|
+
};
|
|
423268
|
+
return;
|
|
423269
|
+
}
|
|
423270
|
+
if (context.toolCall.id === context.toolCalls[0]?.id) {
|
|
423271
|
+
progress.workCallsSinceRefresh += 1;
|
|
423272
|
+
if (progress.workCallsSinceRefresh > 8) progress.refreshRequired = true;
|
|
423273
|
+
}
|
|
423274
|
+
if (!progress.refreshRequired) return;
|
|
423275
|
+
return {
|
|
423225
423276
|
block: true,
|
|
423226
|
-
reason: "
|
|
423277
|
+
reason: "Refresh TodoList before more work. Mark only evidenced steps done, keep the actual current step in_progress, and leave later steps pending."
|
|
423227
423278
|
};
|
|
423228
423279
|
}
|
|
423229
423280
|
function ideaOutboundChannel(toolName, args) {
|
|
@@ -497053,7 +497104,7 @@ function runPromptTurn(session, prompt, outputFormat, stdout, stderr, model) {
|
|
|
497053
497104
|
outputWriter.writeAssistantDelta(event.delta);
|
|
497054
497105
|
return;
|
|
497055
497106
|
case "hook.result":
|
|
497056
|
-
outputWriter.writeHookResult(event);
|
|
497107
|
+
if (shouldDisplayHookResult(event)) outputWriter.writeHookResult(event);
|
|
497057
497108
|
return;
|
|
497058
497109
|
case "thinking.delta":
|
|
497059
497110
|
outputWriter.writeThinkingDelta(event.delta);
|
|
@@ -497117,6 +497168,9 @@ function promptInputText(input) {
|
|
|
497117
497168
|
const text = input.filter((part) => part.type === "text").map((part) => part.text).join("\n\n");
|
|
497118
497169
|
return text.trim().length > 0 ? text : void 0;
|
|
497119
497170
|
}
|
|
497171
|
+
function shouldDisplayHookResult(event) {
|
|
497172
|
+
return event.blocked === true;
|
|
497173
|
+
}
|
|
497120
497174
|
var PromptTranscriptWriter = class {
|
|
497121
497175
|
assistantWriter;
|
|
497122
497176
|
thinkingWriter;
|
|
@@ -503861,6 +503915,7 @@ var BtwPanelController = class {
|
|
|
503861
503915
|
this.armInactivityTimer(this.activeForAgent(event.agentId));
|
|
503862
503916
|
return true;
|
|
503863
503917
|
case "hook.result":
|
|
503918
|
+
if (!shouldDisplayHookResult(event)) return true;
|
|
503864
503919
|
this.clearInactivityTimer(this.activeForAgent(event.agentId));
|
|
503865
503920
|
panel.appendAnswer(formatHookResultPlain(event));
|
|
503866
503921
|
this.host.state.ui.requestRender();
|
|
@@ -507937,7 +507992,7 @@ var SubAgentEventHandler = class {
|
|
|
507937
507992
|
const toolCall = this.host.streamingUI.getToolComponent(parentToolCallId);
|
|
507938
507993
|
if (toolCall === void 0) return true;
|
|
507939
507994
|
toolCall.setSubagentMeta(childAgentId, info.name);
|
|
507940
|
-
if (event.type === "hook.result") toolCall.appendSubagentText(formatHookResultPlain(event), "text");
|
|
507995
|
+
if (event.type === "hook.result" && shouldDisplayHookResult(event)) toolCall.appendSubagentText(formatHookResultPlain(event), "text");
|
|
507941
507996
|
else if (event.type === "assistant.delta") toolCall.appendSubagentText(event.delta, "text");
|
|
507942
507997
|
else if (event.type === "thinking.delta") toolCall.appendSubagentText(event.delta, "thinking");
|
|
507943
507998
|
else if (event.type === "tool.call.started") toolCall.appendSubToolCall({
|
|
@@ -508810,6 +508865,7 @@ var SessionEventHandler = class {
|
|
|
508810
508865
|
this.turnWatchdog.stop();
|
|
508811
508866
|
this.host.restoreQueuedSteerAtTurnEnd(event.turnId);
|
|
508812
508867
|
this.host.settleChannelPromptAtTurnEnd(event.turnId, event.reason);
|
|
508868
|
+
this.host.flushDeferredChannelAcknowledgements(event.turnId);
|
|
508813
508869
|
const sessionId = this.host.session?.id;
|
|
508814
508870
|
if (sessionId !== void 0) finishPersonalMemoryRememberIntentTurn(sessionId, event.turnId);
|
|
508815
508871
|
this.host.streamingUI.flushNow();
|
|
@@ -508972,6 +509028,7 @@ var SessionEventHandler = class {
|
|
|
508972
509028
|
streamingUI.scheduleFlush();
|
|
508973
509029
|
}
|
|
508974
509030
|
handleHookResult(event) {
|
|
509031
|
+
if (!shouldDisplayHookResult(event)) return;
|
|
508975
509032
|
this.host.streamingUI.flushNow();
|
|
508976
509033
|
if (this.host.streamingUI.hasThinkingDraft()) this.host.streamingUI.flushThinkingToTranscript("idle");
|
|
508977
509034
|
this.host.streamingUI.finalizeAssistantStream();
|
|
@@ -509074,6 +509131,7 @@ var SessionEventHandler = class {
|
|
|
509074
509131
|
});
|
|
509075
509132
|
if (matchedCall !== void 0 && matchedCall.name !== "GetMedia" && isMediaToolName(matchedCall.name) && event.isError !== true) this.host.trackChannelMediaJob(event.output);
|
|
509076
509133
|
if (matchedCall?.name === "GetMedia" && event.isError !== true) this.host.runChannelMediaFallback(event.output);
|
|
509134
|
+
this.host.settleChannelReplyToolResult(matchedCall, event.isError === true);
|
|
509077
509135
|
this.subAgentEventHandler.handleAgentSwarmToolResult(event.toolCallId, resultData, event.isError === true);
|
|
509078
509136
|
if (matchedCall !== void 0 && matchedCall.name === "TodoList" && !event.isError) {
|
|
509079
509137
|
const rawTodos = matchedCall.args.todos;
|
|
@@ -510555,6 +510613,7 @@ var SessionReplayRenderer = class {
|
|
|
510555
510613
|
}
|
|
510556
510614
|
renderHookResult(context, message) {
|
|
510557
510615
|
if (message.origin?.kind !== "hook_result") return;
|
|
510616
|
+
if (message.origin.blocked !== true) return;
|
|
510558
510617
|
this.flushAssistant(context);
|
|
510559
510618
|
this.host.appendTranscriptEntry(replayEntry(context, "assistant", formatHookResultMessageForTranscript(contentPartsToText(message.content), message.origin.event, message.origin.blocked === true), "markdown"));
|
|
510560
510619
|
}
|
|
@@ -517933,6 +517992,7 @@ var BlunTUI = class {
|
|
|
517933
517992
|
queueFlushBatchRemaining = 0;
|
|
517934
517993
|
queueSteerInFlight;
|
|
517935
517994
|
channelPromptInFlight;
|
|
517995
|
+
deferredChannelAcknowledgements = /* @__PURE__ */ new Map();
|
|
517936
517996
|
editorReplacementActive = false;
|
|
517937
517997
|
editorReplacement;
|
|
517938
517998
|
editorReplacementGeneration = 0;
|
|
@@ -517943,7 +518003,7 @@ var BlunTUI = class {
|
|
|
517943
518003
|
canDeliverQueuedChannelHead() {
|
|
517944
518004
|
const item = this.state.queuedMessages[0];
|
|
517945
518005
|
const hasActiveTurn = this.streamingUI.hasActiveTurn() || (this.state.appState.streamingPhase !== "idle" && this.state.appState.streamingPhase !== "shell");
|
|
517946
|
-
if (this.isShuttingDown || this.queueCommandRunning || this.queueSteerInFlight !== void 0 || this.
|
|
518006
|
+
if (this.isShuttingDown || this.queueCommandRunning || this.queueSteerInFlight !== void 0 || this.editorReplacementActive || this.deferUserMessages || this.session === void 0 || this.state.appState.model.trim().length === 0 || !hasActiveTurn || item?.mode !== "channel") return false;
|
|
517947
518007
|
return true;
|
|
517948
518008
|
}
|
|
517949
518009
|
async deliverQueuedChannelHead() {
|
|
@@ -517972,7 +518032,8 @@ var BlunTUI = class {
|
|
|
517972
518032
|
}
|
|
517973
518033
|
const batchEnd = item.channelAttention === true ? 1 : item.channelUrgent === true ? this.state.queuedMessages.findIndex((queued) => queued.channelUrgent !== true) : item.channelDirect === true ? this.state.queuedMessages.findIndex((queued) => queued.channelDirect !== true) : item.channelAddressed === true ? this.state.queuedMessages.findIndex((queued) => queued.channelAddressed !== true) : this.state.queuedMessages.findIndex((queued) => queued.mode !== "channel" || queued.channelContextOnly === true || queued.channelAttention === true);
|
|
517974
518034
|
const candidateCount = batchEnd < 0 ? this.state.queuedMessages.length : batchEnd;
|
|
517975
|
-
const
|
|
518035
|
+
const deliveryLimit = this.queueFlushBatchRemaining > 0 ? this.queueFlushBatchRemaining : 1;
|
|
518036
|
+
const items = this.state.queuedMessages.slice(0, Math.min(candidateCount, deliveryLimit));
|
|
517976
518037
|
if (items.length === 0) return false;
|
|
517977
518038
|
this.state.queuedMessages = this.state.queuedMessages.slice(items.length);
|
|
517978
518039
|
this.updateQueueDisplay();
|
|
@@ -518011,9 +518072,14 @@ var BlunTUI = class {
|
|
|
518011
518072
|
stepStarted: false,
|
|
518012
518073
|
turnEnded: false,
|
|
518013
518074
|
onCommit: () => {
|
|
518075
|
+
this.clearAddressedChannelFocusIds(items.map((queued) => queued.channelFocusId));
|
|
518014
518076
|
renderTranscripts();
|
|
518015
518077
|
for (const queued of queuedItems) queued.channelTranscriptRendered = true;
|
|
518016
|
-
|
|
518078
|
+
const acknowledge = () => {
|
|
518079
|
+
for (const queued of items) queued.channelAcknowledge?.();
|
|
518080
|
+
};
|
|
518081
|
+
if (inFlight.duplicate === true) acknowledge();
|
|
518082
|
+
else this.deferChannelAcknowledgement(inFlight.turnId, acknowledge);
|
|
518017
518083
|
if (this.queueFlushBatchRemaining > 0) this.queueFlushBatchRemaining = Math.max(0, this.queueFlushBatchRemaining - items.length);
|
|
518018
518084
|
},
|
|
518019
518085
|
onRestore: () => {
|
|
@@ -518042,7 +518108,10 @@ var BlunTUI = class {
|
|
|
518042
518108
|
if (!result.accepted) return this.recoverRejectedActiveSteer(inFlight);
|
|
518043
518109
|
inFlight.turnId = String(result.turnId);
|
|
518044
518110
|
inFlight.accepted = true;
|
|
518045
|
-
if (result.duplicate === true)
|
|
518111
|
+
if (result.duplicate === true) {
|
|
518112
|
+
inFlight.duplicate = true;
|
|
518113
|
+
return this.commitQueuedSteer(inFlight);
|
|
518114
|
+
}
|
|
518046
518115
|
if (inFlight.turnEnded) return restoreHead();
|
|
518047
518116
|
if (!inFlight.stepStarted) {
|
|
518048
518117
|
inFlight.confirmationTimer = setTimeout(() => {
|
|
@@ -518071,12 +518140,27 @@ var BlunTUI = class {
|
|
|
518071
518140
|
const index = this.pendingChannelReplyGuards.indexOf(guard);
|
|
518072
518141
|
if (index >= 0) this.pendingChannelReplyGuards.splice(index, 1);
|
|
518073
518142
|
}
|
|
518143
|
+
settleChannelReplyToolResult(matchedCall, isError) {
|
|
518144
|
+
if (matchedCall === void 0 || isError) return;
|
|
518145
|
+
if (!/(?:^|__|:)(?:reply|edit_message)$/i.test(matchedCall.name ?? "")) return;
|
|
518146
|
+
const chatId = String(matchedCall.args?.["chat_id"] ?? matchedCall.args?.["chatId"] ?? "");
|
|
518147
|
+
if (chatId.length === 0) return;
|
|
518148
|
+
const delivered = this.pendingChannelReplyGuards.filter((guard) => guard.chatId === chatId);
|
|
518149
|
+
if (delivered.length === 0) return;
|
|
518150
|
+
this.pendingChannelReplyGuards = this.pendingChannelReplyGuards.filter((guard) => guard.chatId !== chatId);
|
|
518151
|
+
this.clearAddressedChannelFocusIds(delivered.map((guard) => guard.channelFocusId));
|
|
518152
|
+
for (const guard of delivered) if (guard.directFocus === true) this.directFocusController.noteReplyDelivered(chatId);
|
|
518153
|
+
this.updateAddressedChannelFocus();
|
|
518154
|
+
}
|
|
518074
518155
|
pinAddressedChannelFocus(chatId, origin, text) {
|
|
518075
518156
|
return this.addressedChannelFocusStore.pin({ chatId, origin, text });
|
|
518076
518157
|
}
|
|
518077
518158
|
clearAddressedChannelFocus(chatId) {
|
|
518078
518159
|
return this.addressedChannelFocusStore.clearChat(chatId);
|
|
518079
518160
|
}
|
|
518161
|
+
clearAddressedChannelFocusIds(ids) {
|
|
518162
|
+
return this.addressedChannelFocusStore.clearIds(ids.filter((id) => id !== void 0));
|
|
518163
|
+
}
|
|
518080
518164
|
updateAddressedChannelFocus() {
|
|
518081
518165
|
this.state.channelFocusContainer.clear();
|
|
518082
518166
|
const queuedFocusIds = new Set([
|
|
@@ -518115,11 +518199,24 @@ var BlunTUI = class {
|
|
|
518115
518199
|
if (inFlight.stepStarted || inFlight.userCancelled === true) this.commitQueuedSteer(inFlight);
|
|
518116
518200
|
else if (inFlight.accepted) this.restoreQueuedSteer(inFlight);
|
|
518117
518201
|
}
|
|
518202
|
+
deferChannelAcknowledgement(turnId, acknowledge) {
|
|
518203
|
+
const key = String(turnId);
|
|
518204
|
+
const pending = this.deferredChannelAcknowledgements.get(key) ?? [];
|
|
518205
|
+
pending.push(acknowledge);
|
|
518206
|
+
this.deferredChannelAcknowledgements.set(key, pending);
|
|
518207
|
+
}
|
|
518208
|
+
flushDeferredChannelAcknowledgements(turnId) {
|
|
518209
|
+
const key = String(turnId);
|
|
518210
|
+
const pending = this.deferredChannelAcknowledgements.get(key);
|
|
518211
|
+
if (pending === void 0) return;
|
|
518212
|
+
this.deferredChannelAcknowledgements.delete(key);
|
|
518213
|
+
for (const acknowledge of pending) acknowledge();
|
|
518214
|
+
}
|
|
518118
518215
|
commitChannelPromptAtStepStart(turnId) {
|
|
518119
518216
|
const inFlight = this.channelPromptInFlight;
|
|
518120
518217
|
if (inFlight === void 0 || inFlight.turnId !== String(turnId)) return;
|
|
518121
518218
|
this.channelPromptInFlight = void 0;
|
|
518122
|
-
inFlight.acknowledge
|
|
518219
|
+
this.deferChannelAcknowledgement(inFlight.turnId, inFlight.acknowledge);
|
|
518123
518220
|
}
|
|
518124
518221
|
settleChannelPromptAtTurnEnd(turnId, reason) {
|
|
518125
518222
|
const inFlight = this.channelPromptInFlight;
|
|
@@ -518442,9 +518539,7 @@ var BlunTUI = class {
|
|
|
518442
518539
|
else if (directEnvelope !== void 0) enqueueTelegramDirect(this.state.queuedMessages, item);
|
|
518443
518540
|
else if (addressed) enqueueTelegramAddressed(this.state.queuedMessages, item);
|
|
518444
518541
|
else this.state.queuedMessages.push(item);
|
|
518445
|
-
|
|
518446
|
-
if (activeTurn) this.releaseNextQueuedMessage();
|
|
518447
|
-
if (this.queueFlushBatchRemaining > 0) this.channelQueueDeadline.requestDeliveryNow();
|
|
518542
|
+
this.channelQueueDeadline.requestDeliveryNow();
|
|
518448
518543
|
this.scheduleQueueDrain();
|
|
518449
518544
|
this.track("input_queue");
|
|
518450
518545
|
this.updateQueueDisplay();
|
|
@@ -518639,6 +518734,7 @@ var BlunTUI = class {
|
|
|
518639
518734
|
}, imagePart] : focusedModelInput;
|
|
518640
518735
|
session.promptAccepted(promptInput, channelPromptOrigin(channelReportSources)).then((result) => {
|
|
518641
518736
|
if (result.duplicate === true) {
|
|
518737
|
+
if (channelFocusId !== void 0) this.clearAddressedChannelFocusIds([channelFocusId]);
|
|
518642
518738
|
finishPersonalMemoryRememberIntentTurn(session.id);
|
|
518643
518739
|
if (installedGuard !== void 0 && this.pendingChannelReplyGuard === installedGuard) this.pendingChannelReplyGuard = previousGuard;
|
|
518644
518740
|
this.setAppState({ streamingPhase: "idle" });
|
|
@@ -518650,6 +518746,7 @@ var BlunTUI = class {
|
|
|
518650
518746
|
return;
|
|
518651
518747
|
}
|
|
518652
518748
|
if (result.accepted) {
|
|
518749
|
+
if (channelFocusId !== void 0) this.clearAddressedChannelFocusIds([channelFocusId]);
|
|
518653
518750
|
if (acknowledge !== void 0 && result.turnId !== null && result.turnId !== void 0) {
|
|
518654
518751
|
this.channelPromptInFlight = {
|
|
518655
518752
|
turnId: String(result.turnId),
|
|
@@ -518783,7 +518880,7 @@ var BlunTUI = class {
|
|
|
518783
518880
|
const args = entry.toolCallData?.args;
|
|
518784
518881
|
return String(args?.["chat_id"] ?? args?.["chatId"] ?? "") === guard.chatId;
|
|
518785
518882
|
}) || outboxGrewForChat(guard.outboxMarker, guard.chatId)) {
|
|
518786
|
-
this.
|
|
518883
|
+
this.clearAddressedChannelFocusIds?.([guard.channelFocusId]);
|
|
518787
518884
|
if (guard.directFocus === true) this.directFocusController.noteReplyDelivered(guard.chatId);
|
|
518788
518885
|
continue;
|
|
518789
518886
|
}
|
|
@@ -518809,7 +518906,7 @@ var BlunTUI = class {
|
|
|
518809
518906
|
if (finalText.length === 0) continue;
|
|
518810
518907
|
sendReplyFallback(guard.chatId, finalText, guard.contextOnly).then((sent) => {
|
|
518811
518908
|
if (!sent) return;
|
|
518812
|
-
this.
|
|
518909
|
+
this.clearAddressedChannelFocusIds?.([guard.channelFocusId]);
|
|
518813
518910
|
if (guard.directFocus === true) this.directFocusController.noteReplyDelivered(guard.chatId);
|
|
518814
518911
|
this.showStatus(uiText("blunTui.telegram.fallbackDelivered"));
|
|
518815
518912
|
});
|