blun-king-cli 9.1.485 → 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 (99) hide show
  1. package/LIESMICH.txt +33 -17
  2. package/README.md +20 -8
  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 +22 -1
  93. package/bin/plugin-bootstrap.js +68 -27
  94. package/bin/startup-preferences.cjs +130 -0
  95. package/bin/turn-thinking-policy.cjs +5 -4
  96. package/bin/turn-tool-performance-policy.cjs +15 -2
  97. package/bin/update-notice.js +104 -43
  98. package/blun.mjs +108 -32
  99. 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
@@ -342525,6 +342530,7 @@ const NotificationsConfigSchema = object({
342525
342530
  enabled: boolean$1(),
342526
342531
  condition: NotificationConditionSchema
342527
342532
  });
342533
+ const UpgradePreferencesSchema = object({ autoInstall: boolean$1() });
342528
342534
  const InlineSuggestConfigSchema = object({ languages: record(string(), boolean$1()) });
342529
342535
  const HexColorSchema = string().regex(/^#[0-9A-Fa-f]{6}$/u);
342530
342536
  const AppearanceConfigSchema = object({
@@ -342541,7 +342547,8 @@ const TuiConfigFileSchema = object({
342541
342547
  notifications: object({
342542
342548
  enabled: boolean$1().optional(),
342543
342549
  notification_condition: NotificationConditionSchema.optional()
342544
- }).optional()
342550
+ }).optional(),
342551
+ upgrade: object({ auto_install: boolean$1().optional() }).optional()
342545
342552
  });
342546
342553
  const TuiConfigSchema = object({
342547
342554
  theme: TuiThemeSchema,
@@ -342550,12 +342557,14 @@ const TuiConfigSchema = object({
342550
342557
  disablePasteBurst: boolean$1(),
342551
342558
  editorCommand: string().nullable(),
342552
342559
  notifications: NotificationsConfigSchema,
342560
+ upgrade: UpgradePreferencesSchema,
342553
342561
  inlineSuggest: InlineSuggestConfigSchema
342554
342562
  });
342555
342563
  const DEFAULT_NOTIFICATIONS_CONFIG = {
342556
342564
  enabled: true,
342557
342565
  condition: "unfocused"
342558
342566
  };
342567
+ const DEFAULT_UPGRADE_PREFERENCES = { autoInstall: true };
342559
342568
  /**
342560
342569
  * F2 Tippen-mit-Vorschlag: Code-Sprachen standardmäßig an, md/plain aus.
342561
342570
  * Unbekannte Sprachen fallen auf "an" zurück (Opt-out über tui.toml).
@@ -342573,6 +342582,7 @@ const DEFAULT_TUI_CONFIG = TuiConfigSchema.parse({
342573
342582
  disablePasteBurst: false,
342574
342583
  editorCommand: null,
342575
342584
  notifications: DEFAULT_NOTIFICATIONS_CONFIG,
342585
+ upgrade: DEFAULT_UPGRADE_PREFERENCES,
342576
342586
  inlineSuggest: { languages: DEFAULT_INLINE_SUGGEST_LANGUAGES }
342577
342587
  });
342578
342588
  /**
@@ -342649,6 +342659,7 @@ function normalizeTuiConfig(config) {
342649
342659
  enabled: config.notifications?.enabled ?? DEFAULT_NOTIFICATIONS_CONFIG.enabled,
342650
342660
  condition: config.notifications?.notification_condition ?? DEFAULT_NOTIFICATIONS_CONFIG.condition
342651
342661
  },
342662
+ upgrade: { autoInstall: config.upgrade?.auto_install ?? DEFAULT_UPGRADE_PREFERENCES.autoInstall },
342652
342663
  inlineSuggest: { languages: {
342653
342664
  ...DEFAULT_INLINE_SUGGEST_LANGUAGES,
342654
342665
  ...config.inline_suggest?.languages
@@ -342673,6 +342684,9 @@ command = "${escapeTomlBasicString(config.editorCommand ?? "")}" # Empty uses $V
342673
342684
  enabled = ${String(config.notifications.enabled)} # true | false
342674
342685
  notification_condition = "${config.notifications.condition}" # "unfocused" | "always"
342675
342686
 
342687
+ [upgrade]
342688
+ auto_install = ${String(config.upgrade.autoInstall)} # true | false
342689
+
342676
342690
  # F2 Tippen-mit-Vorschlag: Inline-Suggest je Sprache an/aus (wirkt ohne Neustart)
342677
342691
  [inline_suggest.languages]
342678
342692
  ${renderInlineSuggestLanguages(config.inlineSuggest.languages)}
@@ -403765,6 +403779,13 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
403765
403779
  priority: 60,
403766
403780
  availability: "always"
403767
403781
  },
403782
+ {
403783
+ name: "agent-spine",
403784
+ aliases: [],
403785
+ descriptionKey: "command.plugins.description",
403786
+ priority: 61,
403787
+ availability: "idle-only"
403788
+ },
403768
403789
  {
403769
403790
  name: "telegram-access",
403770
403791
  aliases: ["telegram-acces"],
@@ -420717,6 +420738,7 @@ async function currentTuiConfig(host) {
420717
420738
  editorCommand: host.state.appState.editorCommand,
420718
420739
  disablePasteBurst: host.state.appState.disablePasteBurst ?? DEFAULT_TUI_CONFIG.disablePasteBurst,
420719
420740
  notifications: host.state.appState.notifications,
420741
+ upgrade: host.state.appState.upgrade ?? DEFAULT_UPGRADE_PREFERENCES,
420720
420742
  inlineSuggest
420721
420743
  };
420722
420744
  }
@@ -496438,6 +496460,9 @@ async function handleBuiltInSlashCommand(host, name, args) {
496438
496460
  case "plugins":
496439
496461
  await handlePluginsCommand(host, args);
496440
496462
  return;
496463
+ case "agent-spine":
496464
+ await handlePluginsCommand(host, "info agent-spine");
496465
+ return;
496441
496466
  case "telegram-access":
496442
496467
  handleTelegramAccessCommand(host);
496443
496468
  return;
@@ -503951,8 +503976,8 @@ const CHANNEL_QUEUE_RETRY_MS = 5e3;
503951
503976
  //#endregion
503952
503977
  //#region src/tui/controllers/channel-queue-deadline.ts
503953
503978
  /**
503954
- * Steers queued channel work into the active turn as soon as it arrives. A busy
503955
- * 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.
503956
503981
  */
503957
503982
  var ChannelQueueDeadlineController = class {
503958
503983
  host;
@@ -503975,10 +504000,7 @@ var ChannelQueueDeadlineController = class {
503975
504000
  }
503976
504001
  requestDeliveryNow() {
503977
504002
  if (this.retainReleaseWhileDeliveryIsInFlight()) return;
503978
- if (this.host.hasWaitingWork() && !this.host.canDeliverWork()) {
503979
- this.scheduleRetry();
503980
- return;
503981
- }
504003
+ if (this.host.hasWaitingWork() && !this.host.canDeliverWork()) return;
503982
504004
  this.requestDelivery();
503983
504005
  }
503984
504006
  retainReleaseWhileDeliveryIsInFlight() {
@@ -504006,7 +504028,10 @@ var ChannelQueueDeadlineController = class {
504006
504028
  this.deliveryInFlight = true;
504007
504029
  this.clearRetryTimer();
504008
504030
  Promise.resolve().then(() => this.host.deliverOne()).catch(() => false).then((delivered) => {
504009
- if (!delivered && this.host.hasWaitingWork()) this.scheduleRetry();
504031
+ if (!delivered && this.host.hasWaitingWork()) {
504032
+ this.pendingReleaseCount = 0;
504033
+ this.scheduleRetry();
504034
+ }
504010
504035
  }).finally(() => {
504011
504036
  this.deliveryInFlight = false;
504012
504037
  this.pumpDelivery();
@@ -505461,7 +505486,10 @@ var EditorKeyboardController = class {
505461
505486
  return;
505462
505487
  }
505463
505488
  if (host.state.appState.isCompacting && host.streamingUI.hasActiveTurn()) {
505464
- host.discardQueuedSlashCommands();
505489
+ if (host.releaseNextQueuedMessage()) {
505490
+ this.clearPendingUndoEsc();
505491
+ return;
505492
+ }
505465
505493
  this.cancelCurrentStream();
505466
505494
  this.clearPendingUndoEsc();
505467
505495
  return;
@@ -505476,7 +505504,10 @@ var EditorKeyboardController = class {
505476
505504
  return;
505477
505505
  }
505478
505506
  if (host.queueSteerInFlight !== void 0 || host.streamingUI.hasActiveTurn() || host.state.appState.streamingPhase !== "idle") {
505479
- host.discardQueuedSlashCommands();
505507
+ if (host.releaseNextQueuedMessage()) {
505508
+ this.clearPendingUndoEsc();
505509
+ return;
505510
+ }
505480
505511
  this.cancelCurrentStream();
505481
505512
  this.clearPendingUndoEsc();
505482
505513
  return;
@@ -505485,10 +505516,6 @@ var EditorKeyboardController = class {
505485
505516
  this.clearPendingUndoEsc();
505486
505517
  return;
505487
505518
  }
505488
- if (host.discardQueuedSlashCommands() > 0) {
505489
- this.clearPendingUndoEsc();
505490
- return;
505491
- }
505492
505519
  if (this.pendingUndoEsc !== null) {
505493
505520
  this.clearPendingUndoEsc();
505494
505521
  host.openUndoSelector();
@@ -516915,6 +516942,7 @@ function createInitialAppState(input) {
516915
516942
  editorCommand: input.tuiConfig.editorCommand,
516916
516943
  disablePasteBurst: input.tuiConfig.disablePasteBurst,
516917
516944
  notifications: input.tuiConfig.notifications,
516945
+ upgrade: input.tuiConfig.upgrade,
516918
516946
  availableModels: {},
516919
516947
  availableProviders: {},
516920
516948
  sessionTitle: null,
@@ -517876,8 +517904,7 @@ var BlunTUI = class {
517876
517904
  canDeliverQueuedChannelHead() {
517877
517905
  const item = this.state.queuedMessages[0];
517878
517906
  const hasActiveTurn = this.streamingUI.hasActiveTurn() || (this.state.appState.streamingPhase !== "idle" && this.state.appState.streamingPhase !== "shell");
517879
- 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;
517880
- 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;
517881
517908
  return true;
517882
517909
  }
517883
517910
  async deliverQueuedChannelHead() {
@@ -517901,10 +517928,12 @@ var BlunTUI = class {
517901
517928
  this.syncChannelQueueDeadline();
517902
517929
  this.updateQueueDisplay();
517903
517930
  this.state.ui.requestRender();
517931
+ this.steerQueueFlushPrefix();
517904
517932
  return true;
517905
517933
  }
517906
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);
517907
- 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));
517908
517937
  if (items.length === 0) return false;
517909
517938
  this.state.queuedMessages = this.state.queuedMessages.slice(items.length);
517910
517939
  this.updateQueueDisplay();
@@ -517944,6 +517973,7 @@ var BlunTUI = class {
517944
517973
  turnEnded: false,
517945
517974
  onCommit: () => {
517946
517975
  renderTranscripts();
517976
+ for (const queued of queuedItems) queued.channelTranscriptRendered = true;
517947
517977
  for (const queued of items) queued.channelAcknowledge?.();
517948
517978
  if (this.queueFlushBatchRemaining > 0) this.queueFlushBatchRemaining = Math.max(0, this.queueFlushBatchRemaining - items.length);
517949
517979
  },
@@ -518010,7 +518040,11 @@ var BlunTUI = class {
518010
518040
  }
518011
518041
  updateAddressedChannelFocus() {
518012
518042
  this.state.channelFocusContainer.clear();
518013
- 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));
518014
518048
  if (items.length > 0) this.state.channelFocusContainer.addChild(new AddressedChannelFocusPaneComponent(items));
518015
518049
  this.state.ui.requestRender();
518016
518050
  }
@@ -518020,15 +518054,23 @@ var BlunTUI = class {
518020
518054
  inFlight.stepStarted = true;
518021
518055
  this.commitQueuedSteerIfReady(inFlight);
518022
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
+ }
518023
518067
  restoreQueuedSteerAtTurnEnd(turnId) {
518068
+ const turnKey = String(turnId);
518024
518069
  const inFlight = this.queueSteerInFlight;
518025
- if (inFlight === void 0 || inFlight.turnId !== String(turnId)) return;
518070
+ if (inFlight === void 0 || inFlight.turnId !== turnKey) return;
518026
518071
  inFlight.turnEnded = true;
518027
- if (inFlight.stepStarted) {
518028
- this.commitQueuedSteer(inFlight);
518029
- return;
518030
- }
518031
- if (inFlight.accepted) this.restoreQueuedSteer(inFlight);
518072
+ if (inFlight.stepStarted) this.commitQueuedSteer(inFlight);
518073
+ else if (inFlight.accepted) this.restoreQueuedSteer(inFlight);
518032
518074
  }
518033
518075
  commitQueuedSteerIfReady(inFlight) {
518034
518076
  if (this.queueSteerInFlight !== inFlight || !inFlight.accepted || !inFlight.stepStarted || inFlight.turnEnded) return;
@@ -518045,13 +518087,24 @@ var BlunTUI = class {
518045
518087
  this.scheduleQueueDrain();
518046
518088
  }
518047
518089
  recoverRejectedActiveSteer(inFlight) {
518048
- 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();
518049
518102
  if (!this.streamingUI.hasActiveTurn()) {
518050
518103
  this.setAppState({ streamingPhase: "idle" });
518051
518104
  this.resetLivePane();
518052
518105
  this.scheduleQueueDrain();
518053
518106
  }
518054
- return restored;
518107
+ return false;
518055
518108
  }
518056
518109
  quarantineQueuedSteer(inFlight, error) {
518057
518110
  if (this.queueSteerInFlight !== inFlight) return false;
@@ -518114,7 +518167,7 @@ var BlunTUI = class {
518114
518167
  })), ...this.state.queuedMessages];
518115
518168
  this.updateQueueDisplay();
518116
518169
  this.state.ui.requestRender();
518117
- if (this.state.queuedMessages[0]?.mode === "channel") this.channelQueueDeadline.requestDeliveryNow();
518170
+ if (this.queueFlushBatchRemaining > 0 && this.state.queuedMessages[0]?.mode === "channel") this.channelQueueDeadline.requestDeliveryNow();
518118
518171
  this.scheduleQueueDrain();
518119
518172
  return false;
518120
518173
  }
@@ -518122,6 +518175,7 @@ var BlunTUI = class {
518122
518175
  this.channelQueueDeadline?.sync();
518123
518176
  }
518124
518177
  releaseChannelQueueAtSafePoint() {
518178
+ if (this.queueFlushBatchRemaining === 0) return;
518125
518179
  this.channelQueueDeadline.requestDeliveryAtSafePoint();
518126
518180
  }
518127
518181
  canDrainQueue() {
@@ -518456,6 +518510,16 @@ var BlunTUI = class {
518456
518510
  modelFallbackAllowed: false
518457
518511
  });
518458
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
+ }
518459
518523
  if (result.accepted) {
518460
518524
  context.item.channelAcknowledge?.();
518461
518525
  return;
@@ -518509,6 +518573,17 @@ var BlunTUI = class {
518509
518573
  text: focusedModelInput
518510
518574
  }, imagePart] : focusedModelInput;
518511
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
+ }
518512
518587
  if (result.accepted) {
518513
518588
  acknowledge?.();
518514
518589
  return;
@@ -519869,6 +519944,7 @@ var BlunTUI = class {
519869
519944
  return this.state.livePane.mode;
519870
519945
  }
519871
519946
  updateQueueDisplay() {
519947
+ this.updateAddressedChannelFocus();
519872
519948
  this.state.queueContainer.clear();
519873
519949
  const queued = this.state.queuedMessages;
519874
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.485",
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
  ],