blun-king-cli 9.1.486 → 9.1.488

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.
Files changed (97) hide show
  1. package/LIESMICH.txt +26 -7
  2. package/README.md +14 -3
  3. package/agent-spine-plugin/.claude-plugin/marketplace.json +20 -0
  4. package/agent-spine-plugin/.claude-plugin/plugin.json +14 -0
  5. package/agent-spine-plugin/.codex-plugin/plugin.json +34 -0
  6. package/agent-spine-plugin/.mcp.json +8 -0
  7. package/agent-spine-plugin/CHANGELOG.md +277 -0
  8. package/agent-spine-plugin/LICENSE +186 -0
  9. package/agent-spine-plugin/README.md +342 -0
  10. package/agent-spine-plugin/assets/agentspine-banner.svg +32 -0
  11. package/agent-spine-plugin/bin/agentspine-mcp.js +4 -0
  12. package/agent-spine-plugin/bin/agentspine.js +7 -0
  13. package/agent-spine-plugin/blun.plugin.json +33 -0
  14. package/agent-spine-plugin/docs/acceptance.md +61 -0
  15. package/agent-spine-plugin/docs/architecture.md +183 -0
  16. package/agent-spine-plugin/docs/attention.md +121 -0
  17. package/agent-spine-plugin/docs/automatic-continuity.md +79 -0
  18. package/agent-spine-plugin/docs/channel-runtime.md +92 -0
  19. package/agent-spine-plugin/docs/coordination.md +138 -0
  20. package/agent-spine-plugin/docs/feed-transport.md +99 -0
  21. package/agent-spine-plugin/docs/gateway-runtime.md +109 -0
  22. package/agent-spine-plugin/docs/harness-reference.md +45 -0
  23. package/agent-spine-plugin/docs/host-integration.md +129 -0
  24. package/agent-spine-plugin/docs/https-transport.md +116 -0
  25. package/agent-spine-plugin/docs/learning.md +98 -0
  26. package/agent-spine-plugin/docs/object-transport.md +93 -0
  27. package/agent-spine-plugin/docs/peer-transport.md +88 -0
  28. package/agent-spine-plugin/docs/preservation-contract.md +53 -0
  29. package/agent-spine-plugin/docs/quality-gates.md +50 -0
  30. package/agent-spine-plugin/docs/relationships.md +67 -0
  31. package/agent-spine-plugin/docs/releasing.md +83 -0
  32. package/agent-spine-plugin/docs/roadmap.md +307 -0
  33. package/agent-spine-plugin/docs/selfstarter.md +88 -0
  34. package/agent-spine-plugin/docs/session-briefing.md +74 -0
  35. package/agent-spine-plugin/docs/shared-memory.md +259 -0
  36. package/agent-spine-plugin/docs/source-roots.md +86 -0
  37. package/agent-spine-plugin/docs/sqlite-transport.md +76 -0
  38. package/agent-spine-plugin/hooks/hooks.json +95 -0
  39. package/agent-spine-plugin/hooks/version.json +5 -0
  40. package/agent-spine-plugin/package.json +69 -0
  41. package/agent-spine-plugin/scripts/check-hosts.js +193 -0
  42. package/agent-spine-plugin/scripts/check-install.js +551 -0
  43. package/agent-spine-plugin/scripts/check-syntax.js +29 -0
  44. package/agent-spine-plugin/scripts/github-actions.js +11 -0
  45. package/agent-spine-plugin/scripts/release-check.js +127 -0
  46. package/agent-spine-plugin/scripts/run-acceptance.js +19 -0
  47. package/agent-spine-plugin/scripts/run-checks.js +46 -0
  48. package/agent-spine-plugin/scripts/run-tests-hermetic.js +73 -0
  49. package/agent-spine-plugin/skill/SKILL.md +76 -0
  50. package/agent-spine-plugin/skills/agent-spine/SKILL.md +84 -0
  51. package/agent-spine-plugin/spine-example/1-identity.md +12 -0
  52. package/agent-spine-plugin/spine-example/2-voice.md +6 -0
  53. package/agent-spine-plugin/spine-example/3-conduct.md +8 -0
  54. package/agent-spine-plugin/spine-example/4-history.md +4 -0
  55. package/agent-spine-plugin/src/cli.js +950 -0
  56. package/agent-spine-plugin/src/hook.js +646 -0
  57. package/agent-spine-plugin/src/index.js +84 -0
  58. package/agent-spine-plugin/src/lib/acceptance.js +294 -0
  59. package/agent-spine-plugin/src/lib/attention.js +755 -0
  60. package/agent-spine-plugin/src/lib/audit.js +308 -0
  61. package/agent-spine-plugin/src/lib/authentication.js +513 -0
  62. package/agent-spine-plugin/src/lib/briefing.js +305 -0
  63. package/agent-spine-plugin/src/lib/catalog.js +142 -0
  64. package/agent-spine-plugin/src/lib/channel-runtime.js +665 -0
  65. package/agent-spine-plugin/src/lib/context.js +154 -0
  66. package/agent-spine-plugin/src/lib/continuity.js +333 -0
  67. package/agent-spine-plugin/src/lib/coordination.js +577 -0
  68. package/agent-spine-plugin/src/lib/documents.js +199 -0
  69. package/agent-spine-plugin/src/lib/feed-transport.js +497 -0
  70. package/agent-spine-plugin/src/lib/filesystem-retry.js +27 -0
  71. package/agent-spine-plugin/src/lib/gateway-runtime.js +760 -0
  72. package/agent-spine-plugin/src/lib/graph.js +284 -0
  73. package/agent-spine-plugin/src/lib/https-transport.js +392 -0
  74. package/agent-spine-plugin/src/lib/indexed-memory-offline.js +40 -0
  75. package/agent-spine-plugin/src/lib/indexed-memory.js +281 -0
  76. package/agent-spine-plugin/src/lib/learning.js +645 -0
  77. package/agent-spine-plugin/src/lib/object-transport.js +206 -0
  78. package/agent-spine-plugin/src/lib/paths.js +60 -0
  79. package/agent-spine-plugin/src/lib/peer-transport.js +283 -0
  80. package/agent-spine-plugin/src/lib/persona-runtime.js +503 -0
  81. package/agent-spine-plugin/src/lib/runtime.js +13 -0
  82. package/agent-spine-plugin/src/lib/selfstarter.js +819 -0
  83. package/agent-spine-plugin/src/lib/sharing.js +969 -0
  84. package/agent-spine-plugin/src/lib/source-roots.js +451 -0
  85. package/agent-spine-plugin/src/lib/sqlite-transport.js +501 -0
  86. package/agent-spine-plugin/src/lib/telegram-adapter.js +119 -0
  87. package/agent-spine-plugin/src/lib/voice-runtime.js +39 -0
  88. package/agent-spine-plugin/src/mcp.js +526 -0
  89. package/agent-spine-plugin/src/version.js +1 -0
  90. package/agent-spine-plugin/src/worker.js +178 -0
  91. package/bin/identity-context-policy.cjs +51 -1
  92. package/bin/launcher-runtime.js +9 -1
  93. package/bin/plugin-bootstrap.js +68 -27
  94. package/bin/turn-thinking-policy.cjs +5 -4
  95. package/bin/turn-tool-performance-policy.cjs +15 -2
  96. package/blun.mjs +96 -31
  97. package/package.json +2 -1
package/blun.mjs CHANGED
@@ -262128,12 +262128,14 @@ var init_turn = __esmMin((() => {
262128
262128
  return {
262129
262129
  accepted: true,
262130
262130
  buffered: false,
262131
+ duplicate: true,
262131
262132
  turnId: null
262132
262133
  };
262133
262134
  }
262134
262135
  if (this.activeTurn !== null) return {
262135
262136
  accepted: false,
262136
262137
  buffered: false,
262138
+ duplicate: false,
262137
262139
  turnId: null
262138
262140
  };
262139
262141
  this.telegramDeliveryLedger.remember(input, origin);
@@ -262147,6 +262149,7 @@ var init_turn = __esmMin((() => {
262147
262149
  return {
262148
262150
  accepted: true,
262149
262151
  buffered,
262152
+ duplicate: false,
262150
262153
  turnId
262151
262154
  };
262152
262155
  }
@@ -262776,10 +262779,11 @@ var init_turn = __esmMin((() => {
262776
262779
  const steerInput = pendingSteers.flatMap((steer) => [...steer.input]);
262777
262780
  const steerThinkingEffort = "low";
262778
262781
  const steerPendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
262779
- const steerLLM = this.agent.llmForTurn(steerThinkingEffort, blunPendingMediaSystemPrompt(this.agent.fastConversationSystemPrompt, steerPendingMediaJobIds));
262780
262782
  const steerText = blunExtractText(steerInput);
262781
262783
  const steerRequiredToolNames = mediaToolNamesForTurnText(steerText);
262782
262784
  for (const name of rankedToolNamesForTurnText(eligibleTools, steerText)) steerRequiredToolNames.add(name);
262785
+ const steerNeedsActionTools = steerRequiredToolNames.size > 0;
262786
+ const steerLLM = this.agent.llmForTurn(steerThinkingEffort, blunPendingMediaSystemPrompt(steerNeedsActionTools ? this.agent.effectiveSystemPrompt : this.agent.fastConversationSystemPrompt, steerPendingMediaJobIds));
262783
262787
  const steerTools = [...blunFastConversationTools(eligibleTools, steerInput, steerPendingMediaJobIds, steerRequiredToolNames)];
262784
262788
  const steerHistory = () => blunFastConversationHistory(this.agent.context.history);
262785
262789
  const buildSteerMessages = () => this.agent.context.project(steerHistory(), { dropOrphanResults: true });
@@ -326885,7 +326889,7 @@ var Session = class {
326885
326889
  buffered: false,
326886
326890
  turnId: null
326887
326891
  };
326888
- }, (result) => result.accepted);
326892
+ }, (result) => result.accepted && result.duplicate !== true);
326889
326893
  }
326890
326894
  /** Execute a user-initiated `!` shell command (silent — does not prompt the
326891
326895
  * model). Resolves with the command's stdout/stderr for immediate display.
@@ -329199,7 +329203,7 @@ var AsyncTransport = class {
329199
329203
  constructor(options) {
329200
329204
  this.homeDir = options.homeDir;
329201
329205
  this.deviceId = options.deviceId;
329202
- this.endpoint = options.endpoint ?? "https://telemetry-logs.blun.ai/v1/event";
329206
+ this.endpoint = options.endpoint ?? "";
329203
329207
  this.getAccessToken = options.getAccessToken ?? null;
329204
329208
  this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
329205
329209
  this.retryBackoffsMs = options.retryBackoffsMs ?? RETRY_BACKOFFS_MS;
@@ -329208,7 +329212,7 @@ var AsyncTransport = class {
329208
329212
  this.now = options.now ?? Date.now;
329209
329213
  }
329210
329214
  async send(events, signal) {
329211
- if (events.length === 0) return;
329215
+ if (events.length === 0 || !isBlunTelemetryHost(this.endpoint)) return;
329212
329216
  let savedToDisk = false;
329213
329217
  const saveEventsToDisk = () => {
329214
329218
  if (savedToDisk) return;
@@ -329248,7 +329252,7 @@ var AsyncTransport = class {
329248
329252
  saveEventsToDisk();
329249
329253
  }
329250
329254
  saveToDisk(events) {
329251
- if (events.length === 0) return;
329255
+ if (events.length === 0 || !isBlunTelemetryHost(this.endpoint)) return;
329252
329256
  const path = join(this.telemetryDir(), `failed_${randomBytes(6).toString("hex")}.jsonl`);
329253
329257
  writeFileSync(path, events.map((event) => JSON.stringify(event)).join("\n") + "\n", {
329254
329258
  encoding: "utf-8",
@@ -329290,6 +329294,7 @@ var AsyncTransport = class {
329290
329294
  return new Set(pruned.map((entry) => entry.name));
329291
329295
  }
329292
329296
  async retryDiskEvents() {
329297
+ if (!isBlunTelemetryHost(this.endpoint)) return;
329293
329298
  const spoolEntries = this.readSpoolEntries();
329294
329299
  const prunedNames = this.pruneDiskSpool(spoolEntries);
329295
329300
  const retryEntries = selectTelemetryRetryEntries(spoolEntries
@@ -403774,6 +403779,13 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
403774
403779
  priority: 60,
403775
403780
  availability: "always"
403776
403781
  },
403782
+ {
403783
+ name: "agent-spine",
403784
+ aliases: [],
403785
+ descriptionKey: "command.plugins.description",
403786
+ priority: 61,
403787
+ availability: "idle-only"
403788
+ },
403777
403789
  {
403778
403790
  name: "telegram-access",
403779
403791
  aliases: ["telegram-acces"],
@@ -496448,6 +496460,9 @@ async function handleBuiltInSlashCommand(host, name, args) {
496448
496460
  case "plugins":
496449
496461
  await handlePluginsCommand(host, args);
496450
496462
  return;
496463
+ case "agent-spine":
496464
+ await handlePluginsCommand(host, "info agent-spine");
496465
+ return;
496451
496466
  case "telegram-access":
496452
496467
  handleTelegramAccessCommand(host);
496453
496468
  return;
@@ -503961,8 +503976,8 @@ const CHANNEL_QUEUE_RETRY_MS = 5e3;
503961
503976
  //#endregion
503962
503977
  //#region src/tui/controllers/channel-queue-deadline.ts
503963
503978
  /**
503964
- * Steers queued channel work into the active turn as soon as it arrives. A busy
503965
- * runtime is retried without ever cancelling the turn or crossing a FIFO barrier.
503979
+ * Delivers channel work only after Ctrl+S or Escape releases it. A busy runtime
503980
+ * is retried without cancelling the turn or crossing the FIFO barrier.
503966
503981
  */
503967
503982
  var ChannelQueueDeadlineController = class {
503968
503983
  host;
@@ -503985,10 +504000,7 @@ var ChannelQueueDeadlineController = class {
503985
504000
  }
503986
504001
  requestDeliveryNow() {
503987
504002
  if (this.retainReleaseWhileDeliveryIsInFlight()) return;
503988
- if (this.host.hasWaitingWork() && !this.host.canDeliverWork()) {
503989
- this.scheduleRetry();
503990
- return;
503991
- }
504003
+ if (this.host.hasWaitingWork() && !this.host.canDeliverWork()) return;
503992
504004
  this.requestDelivery();
503993
504005
  }
503994
504006
  retainReleaseWhileDeliveryIsInFlight() {
@@ -504016,7 +504028,10 @@ var ChannelQueueDeadlineController = class {
504016
504028
  this.deliveryInFlight = true;
504017
504029
  this.clearRetryTimer();
504018
504030
  Promise.resolve().then(() => this.host.deliverOne()).catch(() => false).then((delivered) => {
504019
- if (!delivered && this.host.hasWaitingWork()) this.scheduleRetry();
504031
+ if (!delivered && this.host.hasWaitingWork()) {
504032
+ this.pendingReleaseCount = 0;
504033
+ this.scheduleRetry();
504034
+ }
504020
504035
  }).finally(() => {
504021
504036
  this.deliveryInFlight = false;
504022
504037
  this.pumpDelivery();
@@ -505471,7 +505486,10 @@ var EditorKeyboardController = class {
505471
505486
  return;
505472
505487
  }
505473
505488
  if (host.state.appState.isCompacting && host.streamingUI.hasActiveTurn()) {
505474
- host.discardQueuedSlashCommands();
505489
+ if (host.releaseNextQueuedMessage()) {
505490
+ this.clearPendingUndoEsc();
505491
+ return;
505492
+ }
505475
505493
  this.cancelCurrentStream();
505476
505494
  this.clearPendingUndoEsc();
505477
505495
  return;
@@ -505486,7 +505504,10 @@ var EditorKeyboardController = class {
505486
505504
  return;
505487
505505
  }
505488
505506
  if (host.queueSteerInFlight !== void 0 || host.streamingUI.hasActiveTurn() || host.state.appState.streamingPhase !== "idle") {
505489
- host.discardQueuedSlashCommands();
505507
+ if (host.releaseNextQueuedMessage()) {
505508
+ this.clearPendingUndoEsc();
505509
+ return;
505510
+ }
505490
505511
  this.cancelCurrentStream();
505491
505512
  this.clearPendingUndoEsc();
505492
505513
  return;
@@ -505495,10 +505516,6 @@ var EditorKeyboardController = class {
505495
505516
  this.clearPendingUndoEsc();
505496
505517
  return;
505497
505518
  }
505498
- if (host.discardQueuedSlashCommands() > 0) {
505499
- this.clearPendingUndoEsc();
505500
- return;
505501
- }
505502
505519
  if (this.pendingUndoEsc !== null) {
505503
505520
  this.clearPendingUndoEsc();
505504
505521
  host.openUndoSelector();
@@ -517887,8 +517904,7 @@ var BlunTUI = class {
517887
517904
  canDeliverQueuedChannelHead() {
517888
517905
  const item = this.state.queuedMessages[0];
517889
517906
  const hasActiveTurn = this.streamingUI.hasActiveTurn() || (this.state.appState.streamingPhase !== "idle" && this.state.appState.streamingPhase !== "shell");
517890
- 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;
517891
- if (this.directFocusController.isPaused() && item.channelDirect !== true && item.channelUrgent !== true) return false;
517907
+ if (this.isShuttingDown || this.queueCommandRunning || this.queueSteerInFlight !== void 0 || this.queueFlushBatchRemaining === 0 || this.editorReplacementActive || this.deferUserMessages || this.session === void 0 || this.state.appState.model.trim().length === 0 || !hasActiveTurn || item?.mode !== "channel") return false;
517892
517908
  return true;
517893
517909
  }
517894
517910
  async deliverQueuedChannelHead() {
@@ -517912,10 +517928,12 @@ var BlunTUI = class {
517912
517928
  this.syncChannelQueueDeadline();
517913
517929
  this.updateQueueDisplay();
517914
517930
  this.state.ui.requestRender();
517931
+ this.steerQueueFlushPrefix();
517915
517932
  return true;
517916
517933
  }
517917
517934
  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);
517918
- const items = this.state.queuedMessages.slice(0, batchEnd < 0 ? this.state.queuedMessages.length : batchEnd);
517935
+ const candidateCount = batchEnd < 0 ? this.state.queuedMessages.length : batchEnd;
517936
+ const items = this.state.queuedMessages.slice(0, Math.min(candidateCount, this.queueFlushBatchRemaining));
517919
517937
  if (items.length === 0) return false;
517920
517938
  this.state.queuedMessages = this.state.queuedMessages.slice(items.length);
517921
517939
  this.updateQueueDisplay();
@@ -517955,6 +517973,7 @@ var BlunTUI = class {
517955
517973
  turnEnded: false,
517956
517974
  onCommit: () => {
517957
517975
  renderTranscripts();
517976
+ for (const queued of queuedItems) queued.channelTranscriptRendered = true;
517958
517977
  for (const queued of items) queued.channelAcknowledge?.();
517959
517978
  if (this.queueFlushBatchRemaining > 0) this.queueFlushBatchRemaining = Math.max(0, this.queueFlushBatchRemaining - items.length);
517960
517979
  },
@@ -518021,7 +518040,11 @@ var BlunTUI = class {
518021
518040
  }
518022
518041
  updateAddressedChannelFocus() {
518023
518042
  this.state.channelFocusContainer.clear();
518024
- const items = this.addressedChannelFocusStore.snapshot();
518043
+ const queuedFocusIds = new Set([
518044
+ ...this.state.queuedMessages,
518045
+ ...this.queueSteerInFlight?.items ?? []
518046
+ ].map((item) => item.channelFocusId).filter((id) => id !== void 0));
518047
+ const items = this.addressedChannelFocusStore.snapshot().filter((item) => !queuedFocusIds.has(item.id));
518025
518048
  if (items.length > 0) this.state.channelFocusContainer.addChild(new AddressedChannelFocusPaneComponent(items));
518026
518049
  this.state.ui.requestRender();
518027
518050
  }
@@ -518031,15 +518054,23 @@ var BlunTUI = class {
518031
518054
  inFlight.stepStarted = true;
518032
518055
  this.commitQueuedSteerIfReady(inFlight);
518033
518056
  }
518057
+ releaseNextQueuedMessage() {
518058
+ const inFlightCount = this.queueSteerInFlight?.items.length ?? 0;
518059
+ const authorizedQueuedCount = Math.max(0, this.queueFlushBatchRemaining - inFlightCount);
518060
+ if (authorizedQueuedCount >= this.state.queuedMessages.length) return false;
518061
+ this.queueFlushBatchRemaining += 1;
518062
+ this.steerQueueFlushPrefix();
518063
+ this.updateQueueDisplay();
518064
+ this.state.ui.requestRender();
518065
+ return true;
518066
+ }
518034
518067
  restoreQueuedSteerAtTurnEnd(turnId) {
518068
+ const turnKey = String(turnId);
518035
518069
  const inFlight = this.queueSteerInFlight;
518036
- if (inFlight === void 0 || inFlight.turnId !== String(turnId)) return;
518070
+ if (inFlight === void 0 || inFlight.turnId !== turnKey) return;
518037
518071
  inFlight.turnEnded = true;
518038
- if (inFlight.stepStarted) {
518039
- this.commitQueuedSteer(inFlight);
518040
- return;
518041
- }
518042
- if (inFlight.accepted) this.restoreQueuedSteer(inFlight);
518072
+ if (inFlight.stepStarted) this.commitQueuedSteer(inFlight);
518073
+ else if (inFlight.accepted) this.restoreQueuedSteer(inFlight);
518043
518074
  }
518044
518075
  commitQueuedSteerIfReady(inFlight) {
518045
518076
  if (this.queueSteerInFlight !== inFlight || !inFlight.accepted || !inFlight.stepStarted || inFlight.turnEnded) return;
@@ -518056,13 +518087,24 @@ var BlunTUI = class {
518056
518087
  this.scheduleQueueDrain();
518057
518088
  }
518058
518089
  recoverRejectedActiveSteer(inFlight) {
518059
- const restored = this.restoreQueuedSteer(inFlight);
518090
+ if (this.queueSteerInFlight !== inFlight) return false;
518091
+ if (inFlight.confirmationTimer !== void 0) clearTimeout(inFlight.confirmationTimer);
518092
+ this.queueSteerInFlight = void 0;
518093
+ inFlight.onRestore?.();
518094
+ const restoredItems = inFlight.items.map((item) => {
518095
+ const copy = { ...item };
518096
+ delete copy.channelDeliveryFailures;
518097
+ return copy;
518098
+ });
518099
+ this.state.queuedMessages = [...restoredItems, ...this.state.queuedMessages];
518100
+ this.updateQueueDisplay();
518101
+ this.state.ui.requestRender();
518060
518102
  if (!this.streamingUI.hasActiveTurn()) {
518061
518103
  this.setAppState({ streamingPhase: "idle" });
518062
518104
  this.resetLivePane();
518063
518105
  this.scheduleQueueDrain();
518064
518106
  }
518065
- return restored;
518107
+ return false;
518066
518108
  }
518067
518109
  quarantineQueuedSteer(inFlight, error) {
518068
518110
  if (this.queueSteerInFlight !== inFlight) return false;
@@ -518125,7 +518167,7 @@ var BlunTUI = class {
518125
518167
  })), ...this.state.queuedMessages];
518126
518168
  this.updateQueueDisplay();
518127
518169
  this.state.ui.requestRender();
518128
- if (this.state.queuedMessages[0]?.mode === "channel") this.channelQueueDeadline.requestDeliveryNow();
518170
+ if (this.queueFlushBatchRemaining > 0 && this.state.queuedMessages[0]?.mode === "channel") this.channelQueueDeadline.requestDeliveryNow();
518129
518171
  this.scheduleQueueDrain();
518130
518172
  return false;
518131
518173
  }
@@ -518133,6 +518175,7 @@ var BlunTUI = class {
518133
518175
  this.channelQueueDeadline?.sync();
518134
518176
  }
518135
518177
  releaseChannelQueueAtSafePoint() {
518178
+ if (this.queueFlushBatchRemaining === 0) return;
518136
518179
  this.channelQueueDeadline.requestDeliveryAtSafePoint();
518137
518180
  }
518138
518181
  canDrainQueue() {
@@ -518467,6 +518510,16 @@ var BlunTUI = class {
518467
518510
  modelFallbackAllowed: false
518468
518511
  });
518469
518512
  session.promptAccepted(options?.parts ?? input).then((result) => {
518513
+ if (result.duplicate === true) {
518514
+ if (this.pendingChannelReplyGuard === installedGuard) this.pendingChannelReplyGuard = previousGuard;
518515
+ this.setAppState({ streamingPhase: "idle" });
518516
+ this.resetLivePane();
518517
+ context.item.channelAcknowledge?.();
518518
+ this.scheduleQueueDrain();
518519
+ this.updateQueueDisplay();
518520
+ this.state.ui.requestRender();
518521
+ return;
518522
+ }
518470
518523
  if (result.accepted) {
518471
518524
  context.item.channelAcknowledge?.();
518472
518525
  return;
@@ -518520,6 +518573,17 @@ var BlunTUI = class {
518520
518573
  text: focusedModelInput
518521
518574
  }, imagePart] : focusedModelInput;
518522
518575
  session.promptAccepted(promptInput, channelPromptOrigin(channelReportSources)).then((result) => {
518576
+ if (result.duplicate === true) {
518577
+ finishPersonalMemoryRememberIntentTurn(session.id);
518578
+ if (installedGuard !== void 0 && this.pendingChannelReplyGuard === installedGuard) this.pendingChannelReplyGuard = previousGuard;
518579
+ this.setAppState({ streamingPhase: "idle" });
518580
+ this.resetLivePane();
518581
+ acknowledge?.();
518582
+ this.scheduleQueueDrain();
518583
+ this.updateQueueDisplay();
518584
+ this.state.ui.requestRender();
518585
+ return;
518586
+ }
518523
518587
  if (result.accepted) {
518524
518588
  acknowledge?.();
518525
518589
  return;
@@ -519880,6 +519944,7 @@ var BlunTUI = class {
519880
519944
  return this.state.livePane.mode;
519881
519945
  }
519882
519946
  updateQueueDisplay() {
519947
+ this.updateAddressedChannelFocus();
519883
519948
  this.state.queueContainer.clear();
519884
519949
  const queued = this.state.queuedMessages;
519885
519950
  if (queued.length === 0) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.486",
3
+ "version": "9.1.488",
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": {
@@ -37,6 +37,7 @@
37
37
  "scripts/fix-node-pty-perms.js",
38
38
  "standard-skills/",
39
39
  "standard-tools/",
40
+ "agent-spine-plugin/",
40
41
  "telegram-plugin/",
41
42
  "LIESMICH.txt"
42
43
  ],