blun-king-cli 9.1.102 → 9.1.104

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/LIESMICH.txt CHANGED
@@ -91,6 +91,8 @@ Ab BLUN King 9.1.98 kann King einen abgeschlossenen Arbeitsabschnitt verdichten,
91
91
 
92
92
  Große textbasierte Werkzeugergebnisse bleiben nicht mehr vollständig im Modellkontext. Ab 12.001 Zeichen speichert BLUN King das vollständige Ergebnis in einer privaten Datei im Sitzungsordner `tool-results`. Im Modellkontext verbleiben die ersten 1.000 und die letzten 1.000 Zeichen, die genaue Zahl der ausgelassenen Zeichen und der `output_path`. Der Agent kann das vollständige Ergebnis anschließend mit `Read` seitenweise über diesen Pfad lesen. Ergebnisse bis einschließlich 12.000 Zeichen, gemischte Medienergebnisse und bereits gekürzte Ergebnisse bleiben unverändert. Auch eine spätere Mikroverdichtung bewahrt den Dateiverweis. Beispiel: Bei einem Suchergebnis mit 30.000 Zeichen sehen folgende Modellanfragen den Anfang und das abschließende Ergebnis oder den Fehler; der vollständige Text bleibt lokal verfügbar.
93
93
 
94
+ Version 9.1.104 lässt Shell-Befehle im Vordergrund auch bei sehr großen Ausgaben bis zum regulären Ende laufen. King schreibt bis zu 16 MiB fortlaufend in das private Aufgabenprotokoll, verwirft darüber hinausgehende Ausgaben und meldet den tatsächlichen Exit-Code, statt den Prozess wegen der Ausgabemenge zu beenden. Kleine Ausgaben, Hintergrundaufgaben, Zeitgrenzen und manuelle Abbrüche bleiben unverändert.
95
+
94
96
  Ab BLUN King 9.1.99 werden auch direkt aufeinanderfolgende reine Textergebnisse als Stapel betrachtet. Enthalten sie zusammen mehr als 12.000 Zeichen, obwohl kein einzelnes Ergebnis diese Grenze überschreitet, speichert King so viele der größten geeigneten Ergebnisse wie nötig in privaten Dateien. In der Modellprojektion verbleiben lesbare Verweise. Der unveränderte Sitzungsrohverlauf bleibt vollständig erhalten. Gemischte Medienergebnisse, einzelne Ergebnisse unter 3.000 Zeichen und Stapel bis einschließlich 12.000 Zeichen bleiben unverändert. Beispiel: Bei zwei Suchergebnissen mit 7.000 und 6.000 Zeichen wird das größere Ergebnis privat gespeichert; Anfang, Ende, ausgelassene Zeichenzahl und `output_path` bleiben für den Agenten sichtbar.
95
97
 
96
98
  Ab BLUN King 9.1.100 beendet eine begrenzte Grep-Inhaltssuche ripgrep, sobald der Versatz, die angeforderten Zeilen und eine zusätzliche Vorschauzeile vollständig vorliegen. Die Vorschauzeile belegt, ob eine weitere Seite existiert, ohne vorher bis zu 10 MB einzulesen. Unbegrenzte Suchen, Trefferzählungen und nach Änderungszeit sortierte Dateilisten laufen weiterhin vollständig durch.
@@ -103,7 +105,7 @@ Das Telemetrieereignis `tool_result_batch_offloaded` meldet ausschließlich die
103
105
 
104
106
  Reguläre `Agent`-Teilaufgaben verwenden eine eigene `ContextMemory` und eine eigene `wire.jsonl` in einem getrennten Agentenverzeichnis. Der Hauptagent erhält nur die Ergebniszusammenfassung, sodass lange Teilaufgaben nicht den Hauptverlauf füllen. `TodoList` speichert Pläne weiterhin maschinenlesbar im Sitzungs-Wire; `blun handoff` übergibt sie zusammen mit prüfbaren Hashes zwischen CLI, Desktop und Web.
105
107
 
106
- Verliert ein delegierter Einzelagent die Provider-Verbindung, erhält er eine leere Provider-Antwort, trifft er auf einen Leerlaufabbruch des Streams oder meldet der Server einen wiederholbaren Status, setzt BLUN King denselben Agenten anhand seines dauerhaften Verlaufs fort. Die erste Fortsetzung wartet zwei Sekunden, die zweite fünf Sekunden; danach bleibt der ursprüngliche Fehler sichtbar. Die Fortsetzungsanweisung fordert den Agenten ausdrücklich auf, den erhaltenen Arbeitsstand zu prüfen und abgeschlossene Schritte nicht zu wiederholen. Authentifizierungs-, Guthaben-, Sicherheits-, Kontext- sowie beliebige Code- und Werkzeugfehler und manuelle Abbrüche bleiben endgültig. Dieser Schutz gilt für einen delegierten Einzelagenten; für Schwärme gelten weiterhin deren bestehende Zeitgrenzen- und Überlastungsregeln.
108
+ Verliert ein delegierter Einzelagent oder ein Mitglied eines Agentenschwarms die Provider-Verbindung, erhält es eine leere Provider-Antwort, bricht sein Stream wegen Leerlaufs ab oder meldet der Server HTTP 408/500/502/503/504, setzt BLUN King denselben Agenten anhand seines dauerhaften Verlaufs fort. Bei Einzelagenten sowie bei Schwarm-Unterbrechungen außerhalb von HTTP 429 wartet die erste Fortsetzung zwei Sekunden und die zweite fünf Sekunden; danach bleibt der ursprüngliche Fehler sichtbar. HTTP 429 behält im Schwarm seine getrennte, längere Überlastungsregel. Authentifizierungs-, Zahlungs- oder Kontingent-, Richtlinien-, Kontext-, Werkzeug- und Codefehler sowie manuelle Abbrüche lösen keine automatische Fortsetzung aus. Jeder Fortsetzungsversuch verwendet die bestehende Agenten-ID, damit bereits abgeschlossene Arbeit nicht wiederholt wird.
107
109
 
108
110
  Rein lesende Sitzungsdiagnose
109
111
  --------------------------------
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.100
12
+ npm install -g blun-king-cli@9.1.104
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
@@ -111,6 +111,8 @@ Ab BLUN King 9.1.98 kann King einen abgeschlossenen Arbeitsabschnitt verdichten,
111
111
 
112
112
  Große textbasierte Werkzeugergebnisse bleiben nicht mehr vollständig im Modellkontext. Ab 12.001 Zeichen speichert BLUN King das vollständige Ergebnis in einer privaten Datei im Sitzungsordner `tool-results`. Im Modellkontext verbleiben die ersten 1.000 und die letzten 1.000 Zeichen, die genaue Zahl der ausgelassenen Zeichen und der `output_path`. Der Agent kann das vollständige Ergebnis anschließend mit `Read` seitenweise über diesen Pfad lesen. Ergebnisse bis einschließlich 12.000 Zeichen, gemischte Medienergebnisse und bereits gekürzte Ergebnisse bleiben unverändert. Auch eine spätere Mikroverdichtung bewahrt den Dateiverweis. Beispiel: Bei einem Suchergebnis mit 30.000 Zeichen sehen folgende Modellanfragen den Anfang und das abschließende Ergebnis oder den Fehler; der vollständige Text bleibt lokal verfügbar.
113
113
 
114
+ Version 9.1.104 lässt Shell-Befehle im Vordergrund auch bei sehr großen Ausgaben bis zum regulären Ende laufen. King schreibt bis zu 16 MiB fortlaufend in das private Aufgabenprotokoll, verwirft darüber hinausgehende Ausgaben und meldet den tatsächlichen Exit-Code, statt den Prozess wegen der Ausgabemenge zu beenden. Kleine Ausgaben, Hintergrundaufgaben, Zeitgrenzen und manuelle Abbrüche bleiben unverändert.
115
+
114
116
  Ab BLUN King 9.1.99 werden auch direkt aufeinanderfolgende reine Textergebnisse als Stapel betrachtet. Enthalten sie zusammen mehr als 12.000 Zeichen, obwohl kein einzelnes Ergebnis diese Grenze überschreitet, speichert King so viele der größten geeigneten Ergebnisse wie nötig in privaten Dateien. In der Modellprojektion verbleiben lesbare Verweise. Der unveränderte Sitzungsrohverlauf bleibt vollständig erhalten. Gemischte Medienergebnisse, einzelne Ergebnisse unter 3.000 Zeichen und Stapel bis einschließlich 12.000 Zeichen bleiben unverändert. Beispiel: Bei zwei Suchergebnissen mit 7.000 und 6.000 Zeichen wird das größere Ergebnis privat gespeichert; Anfang, Ende, ausgelassene Zeichenzahl und `output_path` bleiben für den Agenten sichtbar.
115
117
 
116
118
  Ab BLUN King 9.1.100 beendet eine begrenzte Grep-Inhaltssuche ripgrep, sobald der Versatz, die angeforderten Zeilen und eine zusätzliche Vorschauzeile vollständig vorliegen. Die Vorschauzeile belegt, ob eine weitere Seite existiert, ohne vorher bis zu 10 MB einzulesen. Unbegrenzte Suchen, Trefferzählungen und nach Änderungszeit sortierte Dateilisten laufen weiterhin vollständig durch.
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ const MAX_FOREGROUND_CAPTURE_BYTES = 16 * 1024 * 1024;
4
+
5
+ function utf8PrefixWithinBytes(text, maxBytes) {
6
+ if (maxBytes <= 0 || text.length === 0) return '';
7
+ if (Buffer.byteLength(text, 'utf8') <= maxBytes) return text;
8
+
9
+ let low = 0;
10
+ let high = text.length;
11
+ while (low < high) {
12
+ const middle = Math.ceil((low + high) / 2);
13
+ if (Buffer.byteLength(text.slice(0, middle), 'utf8') <= maxBytes) low = middle;
14
+ else high = middle - 1;
15
+ }
16
+ if (low > 0 && low < text.length) {
17
+ const last = text.charCodeAt(low - 1);
18
+ if (last >= 0xD800 && last <= 0xDBFF) low -= 1;
19
+ }
20
+ return text.slice(0, low);
21
+ }
22
+
23
+ function captureForegroundOutputChunk(text, capturedBytes, maxBytes = MAX_FOREGROUND_CAPTURE_BYTES) {
24
+ const observedBytes = Buffer.byteLength(text, 'utf8');
25
+ const remainingBytes = Math.max(0, maxBytes - Math.max(0, capturedBytes));
26
+ const capturedText = utf8PrefixWithinBytes(text, remainingBytes);
27
+ const newCapturedBytes = Buffer.byteLength(capturedText, 'utf8');
28
+ return {
29
+ capturedText,
30
+ observedBytes,
31
+ capturedBytes: newCapturedBytes,
32
+ droppedBytes: observedBytes - newCapturedBytes,
33
+ capped: newCapturedBytes < observedBytes,
34
+ };
35
+ }
36
+
37
+ module.exports = {
38
+ MAX_FOREGROUND_CAPTURE_BYTES,
39
+ captureForegroundOutputChunk,
40
+ utf8PrefixWithinBytes,
41
+ };
@@ -74,6 +74,18 @@ function isRetryableSubagentFailure(error) {
74
74
  return RETRYABLE_MESSAGE_RE.test(message);
75
75
  }
76
76
 
77
+ function transientSubagentRetryDelayMs(retryCount) {
78
+ if (!Number.isInteger(retryCount) || retryCount < 1) {
79
+ throw new Error("retryCount must be a positive integer.");
80
+ }
81
+ return DEFAULT_TRANSIENT_RETRY_DELAYS_MS[retryCount - 1]
82
+ ?? DEFAULT_TRANSIENT_RETRY_DELAYS_MS.at(-1);
83
+ }
84
+
85
+ function shouldStopTransientSubagentContinuation(retryCount) {
86
+ return retryCount >= MAX_TRANSIENT_SUBAGENT_CONTINUATIONS;
87
+ }
88
+
77
89
  function waitForRetryDelay(delayMs, signal) {
78
90
  if (delayMs <= 0) return Promise.resolve();
79
91
  if (signal.aborted) return Promise.reject(abortError(signal.reason));
@@ -134,7 +146,8 @@ async function runAgentWithTimeoutContinuation({
134
146
  throw result.error;
135
147
  }
136
148
  const attempt = transientContinuations + 1;
137
- const delayMs = retryDelaysMs[transientContinuations] ?? retryDelaysMs.at(-1) ?? 0;
149
+ const delayMs = retryDelaysMs[transientContinuations]
150
+ ?? transientSubagentRetryDelayMs(attempt);
138
151
  transientContinuations = attempt;
139
152
  await waitForRetryDelay(delayMs, signal);
140
153
  currentHandle = await retrySameAgent(currentHandle.agentId, {
@@ -164,4 +177,6 @@ module.exports = {
164
177
  isRetryableSubagentFailure,
165
178
  resolveSubagentTimeoutMs,
166
179
  runAgentWithTimeoutContinuation,
180
+ shouldStopTransientSubagentContinuation,
181
+ transientSubagentRetryDelayMs,
167
182
  };
package/blun.mjs CHANGED
@@ -29316,9 +29316,6 @@ function isBackgroundTaskTerminal(status) {
29316
29316
  return TERMINAL_STATUSES.has(status);
29317
29317
  }
29318
29318
  /** Terminal `stopReason` recorded when a foreground command trips the output ceiling. */
29319
- function foregroundOutputLimitReason() {
29320
- return `Output limit exceeded: the command produced more than ${Math.floor(MAX_FOREGROUND_OUTPUT_BYTES / (1024 * 1024))} MiB and was terminated. Redirect large output to a file (e.g. \`command > out.txt\`) and inspect it in slices instead.`;
29321
- }
29322
29319
  /**
29323
29320
  * Generate `{prefix}-{8 base36 chars}`.
29324
29321
  *
@@ -29378,7 +29375,7 @@ function buildBackgroundTaskNotificationBody(info) {
29378
29375
  "The subagent retains its full prior context across the restart, but any in-flight tool call lost its result and may need to be redone."
29379
29376
  ].join("\n")}`;
29380
29377
  }
29381
- var MAX_OUTPUT_BYTES$2, NOTIFICATION_FALLBACK_PREVIEW_BYTES, MAX_FOREGROUND_OUTPUT_BYTES, SIGTERM_GRACE_MS$1, USER_INTERRUPT_REASON$1, _ALPHABET, BackgroundManager;
29378
+ var MAX_OUTPUT_BYTES$2, NOTIFICATION_FALLBACK_PREVIEW_BYTES, MAX_FOREGROUND_CAPTURE_BYTES, captureForegroundOutputChunk, SIGTERM_GRACE_MS$1, USER_INTERRUPT_REASON$1, _ALPHABET, BackgroundManager;
29382
29379
  var init_background = __esmMin((() => {
29383
29380
  init_dist$4();
29384
29381
  init_errors$4();
@@ -29392,7 +29389,7 @@ var init_background = __esmMin((() => {
29392
29389
  init_question_task();
29393
29390
  MAX_OUTPUT_BYTES$2 = 1024 * 1024;
29394
29391
  NOTIFICATION_FALLBACK_PREVIEW_BYTES = 3e3;
29395
- MAX_FOREGROUND_OUTPUT_BYTES = 16 * 1024 * 1024;
29392
+ ({ MAX_FOREGROUND_CAPTURE_BYTES, captureForegroundOutputChunk } = createRequire(import.meta.url)("./bin/foreground-output-capture-policy.cjs"));
29396
29393
  SIGTERM_GRACE_MS$1 = 5e3;
29397
29394
  USER_INTERRUPT_REASON$1 = "Interrupted by user";
29398
29395
  _ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz";
@@ -29470,7 +29467,8 @@ var init_background = __esmMin((() => {
29470
29467
  outputChunks: [],
29471
29468
  outputRingChars: 0,
29472
29469
  outputSizeBytes: 0,
29473
- outputLimitTripped: false,
29470
+ outputCapturedBytes: 0,
29471
+ outputCaptureCapped: false,
29474
29472
  status: "running",
29475
29473
  options: entryOptions,
29476
29474
  startedAt: Date.now(),
@@ -29708,27 +29706,32 @@ var init_background = __esmMin((() => {
29708
29706
  return entry.persistWriteQueue;
29709
29707
  }
29710
29708
  appendOutput(entry, chunk) {
29711
- entry.outputSizeBytes += Buffer.byteLength(chunk, "utf-8");
29712
- entry.outputChunks.push(chunk);
29713
- entry.outputRingChars += chunk.length;
29709
+ const capture = this.isDetached(entry) ? {
29710
+ capturedText: chunk,
29711
+ observedBytes: Buffer.byteLength(chunk, "utf-8"),
29712
+ capturedBytes: Buffer.byteLength(chunk, "utf-8"),
29713
+ droppedBytes: 0,
29714
+ capped: false
29715
+ } : captureForegroundOutputChunk(chunk, entry.outputCapturedBytes);
29716
+ entry.outputSizeBytes += capture.observedBytes;
29717
+ entry.outputCapturedBytes += capture.capturedBytes;
29718
+ if (capture.capped) entry.outputCaptureCapped = true;
29719
+ if (capture.capturedText.length === 0) return;
29720
+ entry.outputChunks.push(capture.capturedText);
29721
+ entry.outputRingChars += capture.capturedText.length;
29714
29722
  while (entry.outputRingChars > MAX_OUTPUT_BYTES$2 && entry.outputChunks.length > 1) {
29715
29723
  const removed = entry.outputChunks.shift();
29716
29724
  if (removed === void 0) break;
29717
29725
  entry.outputRingChars -= removed.length;
29718
29726
  }
29719
- if (!entry.outputLimitTripped && !this.isDetached(entry) && entry.outputSizeBytes > MAX_FOREGROUND_OUTPUT_BYTES) {
29720
- entry.outputLimitTripped = true;
29721
- this.stop(entry.taskId, foregroundOutputLimitReason());
29722
- }
29723
- if (entry.outputLimitTripped) return;
29724
29727
  if (this.persistence === void 0) return;
29725
29728
  if (!entry.outputPersistStarted) {
29726
- entry.pendingOutput.push(chunk);
29727
- entry.pendingOutputBytes += Buffer.byteLength(chunk, "utf-8");
29729
+ entry.pendingOutput.push(capture.capturedText);
29730
+ entry.pendingOutputBytes += capture.capturedBytes;
29728
29731
  if (entry.pendingOutputBytes > MAX_OUTPUT_BYTES$2) this.startOutputPersist(entry);
29729
29732
  return;
29730
29733
  }
29731
- this.appendTaskOutput(entry, chunk);
29734
+ this.appendTaskOutput(entry, capture.capturedText);
29732
29735
  }
29733
29736
  /** Enqueue an `output.log` append, serialized per task. No-op when detached managers omit persistence. */
29734
29737
  appendTaskOutput(entry, chunk) {
@@ -29925,6 +29928,7 @@ var init_background = __esmMin((() => {
29925
29928
  endedAt: entry.endedAt,
29926
29929
  stopReason: entry.stopReason,
29927
29930
  terminalNotificationSuppressed: entry.terminalNotificationSuppressed,
29931
+ outputCaptureCapped: entry.outputCaptureCapped,
29928
29932
  timeoutMs: entry.options.timeoutMs
29929
29933
  };
29930
29934
  return entry.task.toInfo(base);
@@ -251353,18 +251357,20 @@ function resolveSwarmMaxConcurrency(env = process.env) {
251353
251357
  if (!Number.isInteger(value) || value <= 0) throw new Error(`${AGENT_SWARM_MAX_CONCURRENCY_ENV} must be a positive integer, got ${JSON.stringify(raw)}.`);
251354
251358
  return value;
251355
251359
  }
251356
- var import_retry, INITIAL_LAUNCH_LIMIT, INITIAL_LAUNCH_INTERVAL_MS, RATE_LIMIT_RETRY_BASE_MS, RATE_LIMIT_RETRY_FACTOR, RATE_LIMIT_CAPACITY_SHRINK_INTERVAL_MS, RATE_LIMIT_CAPACITY_RECOVERY_INTERVAL_MS, RATE_LIMIT_SUSPENDED_REASON, AGENT_SWARM_MAX_CONCURRENCY_ENV, MAX_AUTOMATIC_RATE_LIMIT_RESUMES, rateLimitRetryDelayMs, shouldCompactBeforeRateLimitResume, shouldStopAutomaticRateLimitResume, SubagentBatch;
251360
+ var import_retry, INITIAL_LAUNCH_LIMIT, INITIAL_LAUNCH_INTERVAL_MS, RATE_LIMIT_RETRY_BASE_MS, RATE_LIMIT_RETRY_FACTOR, RATE_LIMIT_CAPACITY_SHRINK_INTERVAL_MS, RATE_LIMIT_CAPACITY_RECOVERY_INTERVAL_MS, RATE_LIMIT_SUSPENDED_REASON, TRANSIENT_PROVIDER_SUSPENDED_REASON, AGENT_SWARM_MAX_CONCURRENCY_ENV, MAX_AUTOMATIC_RATE_LIMIT_RESUMES, MAX_TRANSIENT_SUBAGENT_CONTINUATIONS, isRetryableSubagentFailure, rateLimitRetryDelayMs, shouldCompactBeforeRateLimitResume, shouldStopAutomaticRateLimitResume, shouldStopTransientSubagentContinuation, transientSubagentRetryDelayMs, SubagentBatch;
251357
251361
  var init_subagent_batch = __esmMin((() => {
251358
251362
  init_src$4();
251359
251363
  import_retry = /* @__PURE__ */ __toESM(require_retry$1(), 1);
251360
251364
  init_abort();
251361
251365
  ({ MAX_AUTOMATIC_RATE_LIMIT_RESUMES, RATE_LIMIT_RETRY_BASE_MS, rateLimitRetryDelayMs, shouldCompactBeforeRateLimitResume, shouldStopAutomaticRateLimitResume } = createRequire(import.meta.url)("./bin/rate-limit-recovery-policy.cjs"));
251366
+ ({ MAX_TRANSIENT_SUBAGENT_CONTINUATIONS, isRetryableSubagentFailure, shouldStopTransientSubagentContinuation, transientSubagentRetryDelayMs } = createRequire(import.meta.url)("./bin/subagent-timeout-policy.cjs"));
251362
251367
  INITIAL_LAUNCH_LIMIT = 5;
251363
251368
  INITIAL_LAUNCH_INTERVAL_MS = 700;
251364
251369
  RATE_LIMIT_RETRY_FACTOR = 2;
251365
251370
  RATE_LIMIT_CAPACITY_SHRINK_INTERVAL_MS = 2e3;
251366
251371
  RATE_LIMIT_CAPACITY_RECOVERY_INTERVAL_MS = 180 * 1e3;
251367
251372
  RATE_LIMIT_SUSPENDED_REASON = "Provider rate limit; subagent requeued for retry.";
251373
+ TRANSIENT_PROVIDER_SUSPENDED_REASON = "Transient provider interruption; subagent requeued for continuation.";
251368
251374
  AGENT_SWARM_MAX_CONCURRENCY_ENV = "BLUN_AGENT_SWARM_MAX_CONCURRENCY";
251369
251375
  SubagentBatch = class {
251370
251376
  launcher;
@@ -251379,6 +251385,7 @@ var init_subagent_batch = __esmMin((() => {
251379
251385
  normalLaunchCount = 0;
251380
251386
  normalLaunchTimer;
251381
251387
  rateLimitLaunchTimer;
251388
+ transientRetryTimers = /* @__PURE__ */ new Set();
251382
251389
  resolve;
251383
251390
  reject;
251384
251391
  finished = false;
@@ -251398,6 +251405,7 @@ var init_subagent_batch = __esmMin((() => {
251398
251405
  index,
251399
251406
  task,
251400
251407
  retryCount: 0,
251408
+ transientRetryCount: 0,
251401
251409
  retryReadyAt: 0,
251402
251410
  started: false
251403
251411
  }));
@@ -251540,6 +251548,11 @@ var init_subagent_batch = __esmMin((() => {
251540
251548
  agentId: handle.agentId,
251541
251549
  error: this.attemptErrorMessage(attempt, error, "failed")
251542
251550
  };
251551
+ if (isRetryableSubagentFailure(error)) return {
251552
+ type: "transient_provider",
251553
+ agentId: handle.agentId,
251554
+ error: this.attemptErrorMessage(attempt, error, "failed")
251555
+ };
251543
251556
  return this.failedAttemptOutcome(attempt, error);
251544
251557
  }
251545
251558
  }
@@ -251571,6 +251584,14 @@ var init_subagent_batch = __esmMin((() => {
251571
251584
  this.requeueTimedOut(attempt, outcome.agentId);
251572
251585
  }
251573
251586
  else if ("status" in outcome) this.results[attempt.state.index] = outcome;
251587
+ else if (outcome.type === "transient_provider" && shouldStopTransientSubagentContinuation(attempt.state.transientRetryCount)) this.results[attempt.state.index] = {
251588
+ task: attempt.state.task,
251589
+ agentId: outcome.agentId,
251590
+ status: "failed",
251591
+ state: "started",
251592
+ error: `${outcome.error} Automatic continuation stopped after ${String(MAX_TRANSIENT_SUBAGENT_CONTINUATIONS)} attempts; agent ${outcome.agentId} remains resumable.`
251593
+ };
251594
+ else if (outcome.type === "transient_provider") this.requeueTransientProvider(attempt, outcome.agentId);
251574
251595
  else if (shouldStopAutomaticRateLimitResume(attempt.state.retryCount)) this.results[attempt.state.index] = {
251575
251596
  task: attempt.state.task,
251576
251597
  agentId: outcome.agentId,
@@ -251604,6 +251625,26 @@ var init_subagent_batch = __esmMin((() => {
251604
251625
  attempt.cleanup();
251605
251626
  return true;
251606
251627
  }
251628
+ requeueTransientProvider(attempt, agentId) {
251629
+ const state = attempt.state;
251630
+ state.agentId = agentId;
251631
+ state.retryAgentId = agentId;
251632
+ state.transientRetryCount += 1;
251633
+ this.launcher.suspended?.({
251634
+ task: state.task,
251635
+ agentId,
251636
+ reason: TRANSIENT_PROVIDER_SUSPENDED_REASON
251637
+ });
251638
+ const retryDelay = transientSubagentRetryDelayMs(state.transientRetryCount);
251639
+ const timer = setTimeout(() => {
251640
+ this.transientRetryTimers.delete(timer);
251641
+ if (this.finished || this.controller.signal.aborted) return;
251642
+ state.retryReadyAt = 0;
251643
+ this.pending.unshift(state);
251644
+ this.schedule();
251645
+ }, retryDelay);
251646
+ this.transientRetryTimers.add(timer);
251647
+ }
251607
251648
  requeueRateLimited(attempt, agentId) {
251608
251649
  const state = attempt.state;
251609
251650
  state.agentId = agentId;
@@ -251714,6 +251755,8 @@ var init_subagent_batch = __esmMin((() => {
251714
251755
  this.batchSignal?.removeEventListener("abort", this.batchAbortListener);
251715
251756
  this.clearNormalTimer();
251716
251757
  this.clearRateLimitTimer();
251758
+ for (const timer of this.transientRetryTimers) clearTimeout(timer);
251759
+ this.transientRetryTimers.clear();
251717
251760
  for (const attempt of this.active.values()) attempt.cleanup();
251718
251761
  this.active.clear();
251719
251762
  }
@@ -262103,7 +262146,7 @@ var init_bash = __esmMin((() => {
262103
262146
  MAX_TIMEOUT_S,
262104
262147
  MAX_BACKGROUND_TIMEOUT_S
262105
262148
  };
262106
- bash_default = "Execute a `{{ SHELL_NAME }}` command for pipes, environment variables, processes, git, package managers, build or test runners, and other genuine shell semantics.\n\nPrefer the dedicated tools when they fit: `Read` for a known file, `Write` to create or replace a file, `Edit` for exact changes, `Glob` to locate files, and `Grep` to search contents. Their output is bounded and their permissions are clearer.\n\nStdout and stderr are combined. Long output may be truncated. A non-zero command ends with its exit code; timeouts and user interrupts are reported separately.\n\nEach call runs in a fresh shell environment. Variables, `cd`, and shell history do not carry into later calls; pass `cwd` or use absolute paths. Foreground commands default to {{ DEFAULT_TIMEOUT_S }}s and allow up to {{ MAX_TIMEOUT_S }}s through `timeout`. Do not run interactive commands or commands that may run forever in the foreground.\n\nWith `run_in_background=true`, provide a short `description`; the tool returns a task ID and notifies you on completion. Background tasks default to {{ DEFAULT_BACKGROUND_TIMEOUT_S }}s and allow up to {{ MAX_BACKGROUND_TIMEOUT_S }}s. Use `disable_timeout=true` only when no deadline is appropriate. Use `TaskOutput` for a status or output snapshot and `TaskStop` only to cancel. After launch, normally return control instead of immediately waiting.\n\nQuote paths containing spaces. Chain dependent commands with `&&`; issue independent read-only checks as parallel tool calls. Use `;`, `||`, pipes, redirects, and shell control flow when their semantics are required.\n\nStay inside the working directory unless the user explicitly requests otherwise. Avoid `..`, and never require superuser privileges without explicit instruction. Command availability depends on the host; verify unfamiliar commands before relying on them.";
262149
+ bash_default = "Execute a `{{ SHELL_NAME }}` command for pipes, environment variables, processes, git, package managers, build or test runners, and other genuine shell semantics.\n\nPrefer the dedicated tools when they fit: `Read` for a known file, `Write` to create or replace a file, `Edit` for exact changes, `Glob` to locate files, and `Grep` to search contents. Their output is bounded and their permissions are clearer.\n\nStdout and stderr are combined. Long foreground output is streamed to a private file; capture stops at a safe size while the command continues to its real exit code. A non-zero command ends with its exit code; timeouts and user interrupts are reported separately.\n\nEach call runs in a fresh shell environment. Variables, `cd`, and shell history do not carry into later calls; pass `cwd` or use absolute paths. Foreground commands default to {{ DEFAULT_TIMEOUT_S }}s and allow up to {{ MAX_TIMEOUT_S }}s through `timeout`. Do not run interactive commands or commands that may run forever in the foreground.\n\nWith `run_in_background=true`, provide a short `description`; the tool returns a task ID and notifies you on completion. Background tasks default to {{ DEFAULT_BACKGROUND_TIMEOUT_S }}s and allow up to {{ MAX_BACKGROUND_TIMEOUT_S }}s. Use `disable_timeout=true` only when no deadline is appropriate. Use `TaskOutput` for a status or output snapshot and `TaskStop` only to cancel. After launch, normally return control instead of immediately waiting.\n\nQuote paths containing spaces. Chain dependent commands with `&&`; issue independent read-only checks as parallel tool calls. Use `;`, `||`, pipes, redirects, and shell control flow when their semantics are required.\n\nStay inside the working directory unless the user explicitly requests otherwise. Avoid `..`, and never require superuser privileges without explicit instruction. Command availability depends on the host; verify unfamiliar commands before relying on them.";
262107
262150
  BashTool = class {
262108
262151
  kaos;
262109
262152
  cwd;
@@ -262269,8 +262312,10 @@ var init_bash = __esmMin((() => {
262269
262312
  if (!result.truncated) return result;
262270
262313
  const output = await this.backgroundManager.getOutputSnapshot(taskId, 0);
262271
262314
  if (!output.fullOutputAvailable || output.outputPath === void 0) return result;
262315
+ const captureCapped = this.backgroundManager.getTask(taskId)?.outputCaptureCapped === true;
262272
262316
  const taskOutputHint = this.allowBackground ? `, or TaskOutput(task_id="${taskId}", block=false)` : "";
262273
- const reference = `\n\n[Full output saved]\ntask_id: ${taskId}\noutput_path: ${output.outputPath}\noutput_size_bytes: ${String(output.outputSizeBytes)}\nnext_step: Use Read with output_path to page through the full log${taskOutputHint}.`;
262317
+ const captureNotice = captureCapped ? `\n[Capture capped at ${String(MAX_FOREGROUND_CAPTURE_BYTES)} bytes. Additional output was discarded, but the command continued to its real exit code.]` : "";
262318
+ const reference = `\n\n[Full output saved]\ntask_id: ${taskId}\noutput_path: ${output.outputPath}\noutput_size_bytes: ${String(output.outputSizeBytes)}${captureNotice}\nnext_step: Use Read with output_path to page through the full log${taskOutputHint}.`;
262274
262319
  return {
262275
262320
  ...result,
262276
262321
  output: `${result.output}${reference}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.102",
3
+ "version": "9.1.104",
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": {