blun-king-cli 9.1.40 → 9.1.41

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 (4) hide show
  1. package/LIESMICH.txt +1 -12
  2. package/README.md +1 -11
  3. package/blun.mjs +96 -282
  4. package/package.json +1 -1
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.40
12
+ npm install -g blun-king-cli@9.1.36
13
13
 
14
14
  Start
15
15
  -----
@@ -20,17 +20,6 @@ Start
20
20
  Beide Startbefehle verwenden dieselbe Version, dasselbe Konto, dasselbe Modell
21
21
  und dieselben Befehle.
22
22
 
23
- Zug-Wächter
24
- -----------
25
- Läuft ein Zug 20 Minuten ohne neues Werkzeugergebnis, meldet die Konsole den
26
- Stand auch im verbundenen Telegram-Kanal. Fünf aufeinanderfolgende identische
27
- fehlgeschlagene Werkzeugaufrufe beenden den Zug mit einer Fehlermeldung.
28
-
29
- Die Grenzwerte lassen sich vor dem Start über diese Umgebungsvariablen ändern:
30
-
31
- BLUN_TURN_WATCHDOG_IDLE_MINUTES
32
- BLUN_TURN_WATCHDOG_MAX_FAILED_REPETITIONS
33
-
34
23
  Nachweisbare Arbeitsabläufe
35
24
  ---------------------------
36
25
 
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.40
12
+ npm install -g blun-king-cli@9.1.36
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
@@ -35,16 +35,6 @@ an. Version, Konto, Modell und Befehle sind ansonsten identisch. Der Unterschied
35
35
  gilt nur für den laufenden Prozess; die gespeicherte
36
36
  Plugin-Konfiguration wird nicht umgeschrieben.
37
37
 
38
- ## Zug-Wächter
39
-
40
- Läuft ein Zug 20 Minuten ohne neues Werkzeugergebnis, meldet die Konsole den
41
- Stand auch im verbundenen Telegram-Kanal. Fünf aufeinanderfolgende identische
42
- fehlgeschlagene Werkzeugaufrufe beenden den Zug mit einer Fehlermeldung.
43
-
44
- Die Grenzwerte lassen sich vor dem Start mit
45
- `BLUN_TURN_WATCHDOG_IDLE_MINUTES` und
46
- `BLUN_TURN_WATCHDOG_MAX_FAILED_REPETITIONS` ändern.
47
-
48
38
  Beim ersten Start werden das Telegram-Plugin und die mitgelieferten Skills
49
39
  eingerichtet. Die Anmeldung erfolgt anschließend in der
50
40
  Konsole mit `/login` über den BLUN-OAuth-Server. Das Paket erzeugt keine
package/blun.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:8bb145d6572cc54a356af3540ba025543ec8c802f66e02a12df23fcd2fcc2bc0
2
+ // BLUN_BUILD_INPUT_SHA256:6009b58ca14a14c742deab1a33fcd60086908033898c436965fbdad7c20c9073
3
3
  import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
4
4
  import { dirname as __cjsShimDirname } from 'node:path';
5
5
  const __filename = __cjsShimFileURLToPath(import.meta.url);
@@ -1765,6 +1765,18 @@ function createFetchHttpClient(options) {
1765
1765
  files: { create: (params, requestOptions) => transport.uploadFile(params, requestOptions) }
1766
1766
  };
1767
1767
  }
1768
+ function exactBodyBytes(body) {
1769
+ if (typeof body === "string") return Buffer.byteLength(body, "utf8");
1770
+ if (body instanceof URLSearchParams) return Buffer.byteLength(body.toString(), "utf8");
1771
+ if (body instanceof Blob) return body.size;
1772
+ if (body instanceof ArrayBuffer) return body.byteLength;
1773
+ if (ArrayBuffer.isView(body)) return body.byteLength;
1774
+ }
1775
+ function notifyTransportAttempt(callback, stats) {
1776
+ try {
1777
+ callback?.(stats);
1778
+ } catch {}
1779
+ }
1768
1780
  function normalizeMaxRetries(value) {
1769
1781
  if (value === void 0) return DEFAULT_MAX_RETRIES$1;
1770
1782
  if (!Number.isSafeInteger(value) || value < 0) throw new ChatProviderError("transportMaxRetries must be a non-negative integer.");
@@ -1950,7 +1962,7 @@ var init_fetch_http_client = __esmMin((() => {
1950
1962
  headers,
1951
1963
  body: JSON.stringify(params),
1952
1964
  signal: options?.signal
1953
- }, options?.maxRetries);
1965
+ }, options);
1954
1966
  if (isStream) return parseServerSentJson(response);
1955
1967
  return readJson$1(response);
1956
1968
  }
@@ -1965,7 +1977,7 @@ var init_fetch_http_client = __esmMin((() => {
1965
1977
  headers,
1966
1978
  body: form,
1967
1979
  signal: options?.signal
1968
- }, options?.maxRetries));
1980
+ }, options));
1969
1981
  if (typeof uploaded.id !== "string" || uploaded.id.length === 0) throw new ChatProviderError("File upload response did not include a file id.");
1970
1982
  return { id: uploaded.id };
1971
1983
  }
@@ -1974,28 +1986,49 @@ var init_fetch_http_client = __esmMin((() => {
1974
1986
  if (!headers.has("authorization")) headers.set("authorization", `Bearer ${this.apiKey}`);
1975
1987
  return headers;
1976
1988
  }
1977
- async fetchWithRetries(pathname, init, configuredMaxRetries) {
1978
- const maxRetries = normalizeMaxRetries(configuredMaxRetries);
1989
+ async fetchWithRetries(pathname, init, requestOptions) {
1990
+ const maxRetries = normalizeMaxRetries(requestOptions?.maxRetries);
1991
+ const requestBytes = exactBodyBytes(init.body);
1979
1992
  let attempt = 0;
1980
- while (true) try {
1981
- const response = await this.fetch(`${this.baseUrl}${pathname}`, init);
1982
- if (response.ok) return response;
1983
- if (attempt < maxRetries && shouldRetryResponse(response)) {
1984
- const delayMs = retryDelayMs(response.headers, attempt);
1985
- await response.body?.cancel();
1986
- await waitForRetry(delayMs, init.signal);
1987
- attempt += 1;
1988
- continue;
1989
- }
1990
- throw await responseError(response);
1991
- } catch (error) {
1992
- if (error instanceof ChatProviderError) throw error;
1993
- if (attempt < maxRetries && init.signal?.aborted !== true && isRetryableTransportFailure(error)) {
1994
- await waitForRetry(retryDelayMs(void 0, attempt), init.signal);
1995
- attempt += 1;
1996
- continue;
1993
+ while (true) {
1994
+ const startedAt = performance.now();
1995
+ try {
1996
+ const response = await this.fetch(`${this.baseUrl}${pathname}`, init);
1997
+ const willRetry = attempt < maxRetries && shouldRetryResponse(response);
1998
+ notifyTransportAttempt(requestOptions?.onTransportAttempt, {
1999
+ transportAttempt: attempt + 1,
2000
+ ...requestBytes === void 0 ? {} : { requestBytes },
2001
+ elapsedMs: performance.now() - startedAt,
2002
+ statusCode: response.status,
2003
+ outcome: "response",
2004
+ willRetry
2005
+ });
2006
+ if (response.ok) return response;
2007
+ if (willRetry) {
2008
+ const delayMs = retryDelayMs(response.headers, attempt);
2009
+ await response.body?.cancel();
2010
+ await waitForRetry(delayMs, init.signal);
2011
+ attempt += 1;
2012
+ continue;
2013
+ }
2014
+ throw await responseError(response);
2015
+ } catch (error) {
2016
+ if (error instanceof ChatProviderError) throw error;
2017
+ const willRetry = attempt < maxRetries && init.signal?.aborted !== true && isRetryableTransportFailure(error);
2018
+ notifyTransportAttempt(requestOptions?.onTransportAttempt, {
2019
+ transportAttempt: attempt + 1,
2020
+ ...requestBytes === void 0 ? {} : { requestBytes },
2021
+ elapsedMs: performance.now() - startedAt,
2022
+ outcome: "transport_error",
2023
+ willRetry
2024
+ });
2025
+ if (willRetry) {
2026
+ await waitForRetry(retryDelayMs(void 0, attempt), init.signal);
2027
+ attempt += 1;
2028
+ continue;
2029
+ }
2030
+ throw normalizeFetchHttpError(error);
1997
2031
  }
1998
- throw normalizeFetchHttpError(error);
1999
2032
  }
2000
2033
  }
2001
2034
  };
@@ -2800,9 +2833,10 @@ var init_blun = __esmMin((() => {
2800
2833
  if (this._stream) createParams["stream_options"] = { include_usage: true };
2801
2834
  try {
2802
2835
  const client = this._createClient(options?.auth);
2803
- const requestOptions = options?.signal !== void 0 || options?.transportMaxRetries !== void 0 ? {
2836
+ const requestOptions = options?.signal !== void 0 || options?.transportMaxRetries !== void 0 || options?.onTransportAttempt !== void 0 ? {
2804
2837
  ...options.signal !== void 0 ? { signal: options.signal } : {},
2805
- ...options.transportMaxRetries !== void 0 ? { maxRetries: options.transportMaxRetries } : {}
2838
+ ...options.transportMaxRetries !== void 0 ? { maxRetries: options.transportMaxRetries } : {},
2839
+ ...options.onTransportAttempt !== void 0 ? { onTransportAttempt: options.onTransportAttempt } : {}
2806
2840
  } : void 0;
2807
2841
  options?.onRequestSent?.();
2808
2842
  return new BlunStreamedMessage(await client.chat.completions.create(createParams, requestOptions), this._stream, reasoningRequested);
@@ -258794,7 +258828,7 @@ var init_read_media = __esmMin((() => {
258794
258828
  //#region ../../packages/agent-core/src/tools/builtin/file/write.md?raw
258795
258829
  var write_default;
258796
258830
  var init_write$1 = __esmMin((() => {
258797
- write_default = "Create, append to, or replace a file entirely.\n\n- Missing parent directories are created automatically (like `mkdir(parents=True, exist_ok=True)`).\n- Mode defaults to overwrite; append adds content at EOF without adding a newline.\n- Write is NOT ALLOWED for incremental changes to existing files, including trivial, one-line, quick, or cosmetic edits. Use Edit instead.\n- Use Write only when the file does not exist, you intend a complete replacement, or the new contents have little continuity with the old contents.\n- Do not create unsolicited documentation files (`*.md` write-ups, `README`s, summaries) just because a task finished — write one only when the user asks for it, or when a task or project instruction requires it (e.g. the plan-mode plan file, created with Write when plan mode directs you to, or a changeset the repo mandates).\n- Read before overwriting an existing file.\n- Write ignores the Read/Edit line-number view. NEVER include line prefixes.\n- Write outputs content literally, including supplied line endings: \\n stays LF, \\r\\n stays CRLF.\n- Source files may contain at most 500 lines. Split larger implementations into focused files; append cannot bypass the limit.\n- Set `single_file_override=true` only when the latest direct user message explicitly requires one single file. The accepted override is reported visibly.\n- For any new or completely replaced file with content too large for one call, use `continuation`. Keep each chunk at or below the configured limit. The default is 2,048 UTF-8 bytes, a conservative safety margin for unstable model output rather than a measured hard model limit; operators can set `BLUN_WRITE_CONTINUATION_MAX_BYTES` from 512 through 16,384. End every chunk on a complete line with `\\n`. Set the exact final `expected_lines`; include `expected_sha256` when a source hash is available. Use overwrite and `start_line=1` for the first chunk, then use append for every later chunk and copy the exact `next_start_line` returned by the previous Write result; never continue from a planned boundary. Use consecutive part numbers. The target file remains unchanged until the final line-count and optional SHA-256 checks pass. To discard an unfinished sequence, restart with part 1, overwrite, `start_line=1`, and `reset=true`.\n- Never use continuation to modify an existing file incrementally. Use Edit for incremental changes.\n- Runaway generated JavaScript/TypeScript identifiers are rejected before disk I/O. Regenerate only the affected section as a smaller focused chunk.\n";
258831
+ write_default = "Create, append to, or replace a file entirely.\n\n- Missing parent directories are created automatically (like `mkdir(parents=True, exist_ok=True)`).\n- Mode defaults to overwrite; append adds content at EOF without adding a newline.\n- Write is NOT ALLOWED for incremental changes to existing files, including trivial, one-line, quick, or cosmetic edits. Use Edit instead.\n- Use Write only when the file does not exist, you intend a complete replacement, or the new contents have little continuity with the old contents.\n- Do not create unsolicited documentation files (`*.md` write-ups, `README`s, summaries) just because a task finished — write one only when the user asks for it, or when a task or project instruction requires it (e.g. the plan-mode plan file, created with Write when plan mode directs you to, or a changeset the repo mandates).\n- Read before overwriting an existing file.\n- Write ignores the Read/Edit line-number view. NEVER include line prefixes.\n- Write outputs content literally, including supplied line endings: \\n stays LF, \\r\\n stays CRLF.\n- Source files may contain at most 500 lines. Split larger implementations into focused files; append cannot bypass the limit.\n- Set `single_file_override=true` only when the latest direct user message explicitly requires one single file. The accepted override is reported visibly.\n- For any new or completely replaced file with content too large for one call, use `continuation`. Keep every chunk at or below 2,048 UTF-8 bytes and end every chunk on a complete line with `\\n`. Set the exact final `expected_lines`; include `expected_sha256` when a source hash is available. Use overwrite for the first chunk, then append for every later chunk, with consecutive part numbers. The target file remains unchanged until the final line-count and optional SHA-256 checks pass.\n- Never use continuation to modify an existing file incrementally. Use Edit for incremental changes.\n- Runaway generated JavaScript/TypeScript identifiers are rejected before disk I/O. Regenerate only the affected section as a smaller focused chunk.\n";
258798
258832
  }));
258799
258833
  //#endregion
258800
258834
  //#region ../../packages/agent-core/src/tools/builtin/file/generated-source-health.ts
@@ -258907,19 +258941,12 @@ var init_generated_source_health = __esmMin((() => {
258907
258941
  }));
258908
258942
  //#endregion
258909
258943
  //#region ../../packages/agent-core/src/tools/builtin/file/write.ts
258910
- function resolveWriteContinuationChunkBytes(env = process.env) {
258911
- const raw = env[CONTINUATION_CHUNK_BYTES_ENV]?.trim();
258912
- if (raw === void 0 || raw === "") return DEFAULT_CONTINUATION_CHUNK_BYTES;
258913
- const parsed = Number(raw);
258914
- if (!Number.isSafeInteger(parsed) || parsed < MIN_CONTINUATION_CHUNK_BYTES || parsed > MAX_CONTINUATION_CHUNK_BYTES) throw new Error(`${CONTINUATION_CHUNK_BYTES_ENV} must be an integer between ${String(MIN_CONTINUATION_CHUNK_BYTES)} and ${String(MAX_CONTINUATION_CHUNK_BYTES)} bytes; received ${JSON.stringify(raw)}.`);
258915
- return parsed;
258916
- }
258917
258944
  function countCompletedLines(content) {
258918
258945
  let count = 0;
258919
258946
  for (const character of content) if (character === "\n") count += 1;
258920
258947
  return count;
258921
258948
  }
258922
- var S_IFMT, S_IFDIR, DEFAULT_CONTINUATION_CHUNK_BYTES, MIN_CONTINUATION_CHUNK_BYTES, MAX_CONTINUATION_CHUNK_BYTES, CONTINUATION_CHUNK_BYTES_ENV, WriteContinuationSchema, WriteInputSchema, WriteTool;
258949
+ var S_IFMT, S_IFDIR, MAX_CONTINUATION_CHUNK_BYTES, WriteContinuationSchema, WriteInputSchema, WriteTool;
258923
258950
  var init_write = __esmMin((() => {
258924
258951
  init_dist$6();
258925
258952
  init_zod$1();
@@ -258933,24 +258960,19 @@ var init_write = __esmMin((() => {
258933
258960
  init_lsp_diagnostics();
258934
258961
  S_IFMT = 61440;
258935
258962
  S_IFDIR = 16384;
258936
- DEFAULT_CONTINUATION_CHUNK_BYTES = 2048;
258937
- MIN_CONTINUATION_CHUNK_BYTES = 512;
258938
- MAX_CONTINUATION_CHUNK_BYTES = 16384;
258939
- CONTINUATION_CHUNK_BYTES_ENV = "BLUN_WRITE_CONTINUATION_MAX_BYTES";
258963
+ MAX_CONTINUATION_CHUNK_BYTES = 2048;
258940
258964
  WriteContinuationSchema = object({
258941
258965
  part: number$1().int().positive().describe("One-based chunk number. Start with 1 and increment by exactly one."),
258942
- start_line: number$1().int().positive().describe("One-based line where this chunk starts. Use 1 for part 1; for every later part, copy next_start_line from the preceding tool result instead of using a planned boundary."),
258943
258966
  expected_lines: number$1().int().positive().describe("Exact completed-line count expected in the final file."),
258944
258967
  final: boolean$1().describe("Set true only for the last chunk, when the complete file is present."),
258945
- expected_sha256: string().regex(/^[0-9a-f]{64}$/i).optional().describe("Optional SHA-256 of the complete expected file for byte-for-byte verification."),
258946
- reset: boolean$1().optional().describe("Set true only with part 1 and overwrite to discard an unfinished staged write.")
258968
+ expected_sha256: string().regex(/^[0-9a-f]{64}$/i).optional().describe("Optional SHA-256 of the complete expected file for byte-for-byte verification.")
258947
258969
  });
258948
258970
  WriteInputSchema = object({
258949
258971
  path: string().describe("Path to the file to create, append to, or completely overwrite. Relative paths resolve against the working directory; a path outside the working directory must be absolute. Missing parent directories are created automatically."),
258950
258972
  content: string().describe("Raw full file content to write exactly as provided. This does not use the Read/Edit text view."),
258951
258973
  mode: _enum(["overwrite", "append"]).optional().describe("Write mode. Defaults to overwrite. append adds content to the end exactly as provided and does not add a newline."),
258952
258974
  single_file_override: boolean$1().optional().describe("Set true only when the latest direct user message explicitly requires one single source file. The tool verifies that request and reports the override visibly."),
258953
- continuation: WriteContinuationSchema.optional().describe("Safe long-write protocol. Split generated files into complete-line chunks within the configured limit (2,048 UTF-8 bytes by default; operator override BLUN_WRITE_CONTINUATION_MAX_BYTES). Part 1 uses overwrite and start_line=1; later parts use append and the exact next_start_line returned by the previous call. The target file is changed only after the final line-count and optional SHA-256 checks pass.")
258975
+ continuation: WriteContinuationSchema.optional().describe("Safe long-write protocol. Split generated files into complete-line chunks of at most 2,048 UTF-8 bytes. Part 1 uses overwrite; later parts use append. The target file is changed only after the final line-count and optional SHA-256 checks pass.")
258954
258976
  });
258955
258977
  object({
258956
258978
  /** Number of UTF-8 bytes written to disk by this call. */
@@ -258960,17 +258982,15 @@ bytesWritten: number$1().int().nonnegative() });
258960
258982
  workspace;
258961
258983
  history;
258962
258984
  lsp;
258963
- maxContinuationChunkBytes;
258964
258985
  name = "Write";
258965
258986
  description = write_default;
258966
258987
  parameters = toInputJsonSchema(WriteInputSchema);
258967
258988
  pendingContinuations = /* @__PURE__ */ new Map();
258968
- constructor(kaos, workspace, history, lsp, maxContinuationChunkBytes = resolveWriteContinuationChunkBytes()) {
258989
+ constructor(kaos, workspace, history, lsp) {
258969
258990
  this.kaos = kaos;
258970
258991
  this.workspace = workspace;
258971
258992
  this.history = history;
258972
258993
  this.lsp = lsp;
258973
- this.maxContinuationChunkBytes = maxContinuationChunkBytes;
258974
258994
  }
258975
258995
  resolveExecution(args) {
258976
258996
  const path = resolvePathAccessPath(args.path, {
@@ -259009,30 +259029,20 @@ bytesWritten: number$1().int().nonnegative() });
259009
259029
  if (continuation === void 0) throw new Error("continuation is required");
259010
259030
  const mode = args.mode ?? "overwrite";
259011
259031
  const chunkBytes = Buffer.byteLength(args.content, "utf8");
259012
- if (chunkBytes > this.maxContinuationChunkBytes) return {
259032
+ if (chunkBytes > MAX_CONTINUATION_CHUNK_BYTES) return {
259013
259033
  isError: true,
259014
- output: `Refused continuation part ${String(continuation.part)} for ${args.path}: chunks may contain at most ${this.maxContinuationChunkBytes.toLocaleString("en-US")} UTF-8 bytes (${String(chunkBytes)} received). No content was staged and no file was written.`
259034
+ output: `Refused continuation part ${String(continuation.part)} for ${args.path}: chunks may contain at most ${MAX_CONTINUATION_CHUNK_BYTES.toLocaleString("en-US")} UTF-8 bytes (${String(chunkBytes)} received). No content was staged and no file was written.`
259015
259035
  };
259016
259036
  if (args.content.length === 0 || !args.content.endsWith("\n")) return {
259017
259037
  isError: true,
259018
259038
  output: `Refused continuation part ${String(continuation.part)} for ${args.path}: every chunk must end on a complete line with a newline. No content was staged and no file was written.`
259019
259039
  };
259020
- if (continuation.reset === true && (continuation.part !== 1 || mode !== "overwrite")) return {
259021
- isError: true,
259022
- output: `Refused continuation reset for ${args.path}: reset requires part 1 with mode=overwrite. No content was staged and no file was written.`
259023
- };
259024
- if (continuation.reset === true) this.pendingContinuations.delete(safePath);
259025
259040
  const current = this.pendingContinuations.get(safePath);
259026
259041
  const expectedPart = current === void 0 ? 1 : current.chunks.length + 1;
259027
259042
  if (continuation.part !== expectedPart) return {
259028
259043
  isError: true,
259029
259044
  output: `Refused continuation part ${String(continuation.part)} for ${args.path}: expected part ${String(expectedPart)}. No content was staged and no file was written.`
259030
259045
  };
259031
- const expectedStartLine = (current?.completedLines ?? 0) + 1;
259032
- if (continuation.start_line !== expectedStartLine) return {
259033
- isError: true,
259034
- output: `Refused continuation part ${String(continuation.part)} for ${args.path}: expected start_line ${String(expectedStartLine)} from the actually staged content, received ${String(continuation.start_line)}. No content was staged and no file was written.`
259035
- };
259036
259046
  if (continuation.part === 1 && mode !== "overwrite" || continuation.part > 1 && mode !== "append") return {
259037
259047
  isError: true,
259038
259048
  output: `Refused continuation part ${String(continuation.part)} for ${args.path}: part 1 must use overwrite and later parts must use append. No content was staged and no file was written.`
@@ -259083,7 +259093,7 @@ bytesWritten: number$1().int().nonnegative() });
259083
259093
  });
259084
259094
  if (!continuation.final) {
259085
259095
  this.pendingContinuations.set(safePath, staged);
259086
- return { output: `Write continuation part ${String(continuation.part)} staged lines ${boundary} of ${String(continuation.expected_lines)} (${String(percent)}%, ${String(chunkBytes)} bytes). Target unchanged. Continue with mode=append, part=${String(continuation.part + 1)}, next_start_line=${String(completedLines + 1)}.` };
259096
+ return { output: `Write continuation part ${String(continuation.part)} staged lines ${boundary} of ${String(continuation.expected_lines)} (${String(percent)}%, ${String(chunkBytes)} bytes). Target unchanged. Continue with mode=append, part=${String(continuation.part + 1)}.` };
259087
259097
  }
259088
259098
  const content = chunks.join("");
259089
259099
  const actualSha256 = createHash("sha256").update(content).digest("hex");
@@ -259098,20 +259108,6 @@ bytesWritten: number$1().int().nonnegative() });
259098
259108
  continuation: void 0
259099
259109
  }, safePath, true);
259100
259110
  if (result.isError === true) return result;
259101
- let persistedSha256;
259102
- try {
259103
- const persistedContent = await this.kaos.readText(safePath);
259104
- persistedSha256 = createHash("sha256").update(persistedContent).digest("hex");
259105
- } catch (error) {
259106
- return {
259107
- isError: true,
259108
- output: `Write continuation wrote ${args.path}, but could not verify the persisted bytes: ${error instanceof Error ? error.message : String(error)}. Inspect the target before continuing.`
259109
- };
259110
- }
259111
- if (persistedSha256 !== actualSha256) return {
259112
- isError: true,
259113
- output: `Write continuation integrity failure for ${args.path}: staged SHA-256 ${actualSha256}, persisted SHA-256 ${persistedSha256}. The target may be incomplete; inspect it before continuing.`
259114
- };
259115
259111
  this.pendingContinuations.delete(safePath);
259116
259112
  const writeOutput = typeof result.output === "string" ? result.output : "Write completed.";
259117
259113
  return {
@@ -259146,9 +259142,9 @@ bytesWritten: number$1().int().nonnegative() });
259146
259142
  output: lineLimit.error
259147
259143
  };
259148
259144
  const contentBytes = Buffer.byteLength(args.content, "utf8");
259149
- if (!allowLargeContent && contentBytes > this.maxContinuationChunkBytes) return {
259145
+ if (!allowLargeContent && contentBytes > MAX_CONTINUATION_CHUNK_BYTES) return {
259150
259146
  isError: true,
259151
- output: `Refused to write ${args.path}: the content is ${String(contentBytes)} UTF-8 bytes. Long generated writes must use the continuation protocol with complete-line chunks of at most ${this.maxContinuationChunkBytes.toLocaleString("en-US")} bytes. No file was written.`
259147
+ output: `Refused to write ${args.path}: the content is ${String(contentBytes)} UTF-8 bytes. Long generated writes must use the continuation protocol with complete-line chunks of at most ${MAX_CONTINUATION_CHUNK_BYTES.toLocaleString("en-US")} bytes. No file was written.`
259152
259148
  };
259153
259149
  const parentError = await this.ensureParentDirectory(safePath);
259154
259150
  if (parentError !== void 0) return {
@@ -262974,6 +262970,12 @@ var init_llm_request_logger = __esmMin((() => {
262974
262970
  if (partialMessageCount > 0) requestFields.partialMessageCount = partialMessageCount;
262975
262971
  this.log.info("llm request", requestFields);
262976
262972
  }
262973
+ logTransportAttempt(stats, fields) {
262974
+ this.log.info("llm transport attempt", {
262975
+ ...fields,
262976
+ ...stats
262977
+ });
262978
+ }
262977
262979
  };
262978
262980
  }));
262979
262981
  //#endregion
@@ -263143,9 +263145,14 @@ var init_agent = __esmMin((() => {
263143
263145
  generateForModel(modelAlias) {
263144
263146
  return async (provider, systemPrompt, tools, history, callbacks, options) => {
263145
263147
  const { requestLogFields, generateOptions } = splitGenerateOptions(options);
263148
+ const callerTransportAttempt = generateOptions?.onTransportAttempt;
263146
263149
  const ownedGenerateOptions = {
263147
263150
  ...generateOptions,
263148
- transportMaxRetries: 0
263151
+ transportMaxRetries: 0,
263152
+ onTransportAttempt: (stats) => {
263153
+ callerTransportAttempt?.(stats);
263154
+ this.llmRequestLogger.logTransportAttempt(stats, requestLogFields);
263155
+ }
263149
263156
  };
263150
263157
  const run = (requestOptions) => {
263151
263158
  this.llmRequestLogger.logRequest({
@@ -370242,7 +370249,7 @@ var require_constants$2 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370242
370249
  };
370243
370250
  }));
370244
370251
  //#endregion
370245
- //#region ../../../node_modules/node-gyp-build/node-gyp-build.js
370252
+ //#region ../../../../node_modules/node-gyp-build/node-gyp-build.js
370246
370253
  var require_node_gyp_build$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370247
370254
  var fs$3 = __require("fs");
370248
370255
  var path$5 = __require("path");
@@ -370398,14 +370405,14 @@ var require_node_gyp_build$1 = /* @__PURE__ */ __commonJSMin(((exports, module)
370398
370405
  load.compareTuples = compareTuples;
370399
370406
  }));
370400
370407
  //#endregion
370401
- //#region ../../../node_modules/node-gyp-build/index.js
370408
+ //#region ../../../../node_modules/node-gyp-build/index.js
370402
370409
  var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370403
370410
  const runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
370404
370411
  if (typeof runtimeRequire.addon === "function") module.exports = runtimeRequire.addon.bind(runtimeRequire);
370405
370412
  else module.exports = require_node_gyp_build$1();
370406
370413
  }));
370407
370414
  //#endregion
370408
- //#region ../../../node_modules/bufferutil/fallback.js
370415
+ //#region ../../../../node_modules/bufferutil/fallback.js
370409
370416
  var require_fallback$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370410
370417
  /**
370411
370418
  * Masks a buffer using the given mask.
@@ -370437,7 +370444,7 @@ var require_fallback$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370437
370444
  };
370438
370445
  }));
370439
370446
  //#endregion
370440
- //#region ../../../node_modules/bufferutil/index.js
370447
+ //#region ../../../../node_modules/bufferutil/index.js
370441
370448
  var require_bufferutil = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370442
370449
  try {
370443
370450
  module.exports = require_node_gyp_build()(__dirname);
@@ -370930,7 +370937,7 @@ var require_permessage_deflate = /* @__PURE__ */ __commonJSMin(((exports, module
370930
370937
  }
370931
370938
  }));
370932
370939
  //#endregion
370933
- //#region ../../../node_modules/utf-8-validate/fallback.js
370940
+ //#region ../../../../node_modules/utf-8-validate/fallback.js
370934
370941
  var require_fallback = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370935
370942
  /**
370936
370943
  * Checks if a given buffer contains only correct UTF-8.
@@ -370960,7 +370967,7 @@ var require_fallback = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370960
370967
  module.exports = isValidUTF8;
370961
370968
  }));
370962
370969
  //#endregion
370963
- //#region ../../../node_modules/utf-8-validate/index.js
370970
+ //#region ../../../../node_modules/utf-8-validate/index.js
370964
370971
  var require_utf_8_validate = /* @__PURE__ */ __commonJSMin(((exports, module) => {
370965
370972
  try {
370966
370973
  module.exports = require_node_gyp_build()(__dirname);
@@ -420014,15 +420021,6 @@ function isBusy(host) {
420014
420021
  //#endregion
420015
420022
  //#region src/tui/commands/loop.ts
420016
420023
  const LOOP_ARGUMENT_HINT = "/loop [interval] [prompt]";
420017
- const LOOP_CREATE_FILLERS = new Set([
420018
- "mit",
420019
- "alle",
420020
- "jede",
420021
- "jeden",
420022
- "every",
420023
- "each"
420024
- ]);
420025
- const LOOP_INTERVAL_TOKEN = /^\d+(?:m|h|d)$/i;
420026
420024
  function parseLoopCommand(rawArgs) {
420027
420025
  const args = rawArgs.trim();
420028
420026
  if (args.length === 0 || args.toLowerCase() === "status") return { kind: "status" };
@@ -420033,11 +420031,10 @@ function parseLoopCommand(rawArgs) {
420033
420031
  if (action === "resume") return { kind: "resume" };
420034
420032
  if (action === "stop") return { kind: "stop" };
420035
420033
  }
420036
- let startIndex = action === "start" ? 1 : 0;
420037
- if (LOOP_CREATE_FILLERS.has(tokens[startIndex]?.toLowerCase() ?? "")) startIndex += 1;
420034
+ const startIndex = action === "start" ? 1 : 0;
420038
420035
  const interval = tokens[startIndex];
420039
420036
  const prompt = tokens.slice(startIndex + 1).join(" ").trim();
420040
- if (interval === void 0 || !LOOP_INTERVAL_TOKEN.test(interval) || prompt.length === 0) return { kind: "error" };
420037
+ if (interval === void 0 || prompt.length === 0) return { kind: "error" };
420041
420038
  return {
420042
420039
  kind: "create",
420043
420040
  interval,
@@ -502396,9 +502393,7 @@ registerUiCatalogFragment({
502396
502393
  "sessionEvent.mcp.needsAuth": "MCP server \"{name}\" needs OAuth — run /mcp-config login {name}",
502397
502394
  "sessionEvent.mcp.disabled": "MCP server \"{name}\" disabled",
502398
502395
  "sessionEvent.mcp.connecting": "MCP server \"{name}\" connecting…",
502399
- "sessionEvent.skill.activated": "Activated skill: {skillName}",
502400
- "sessionEvent.watchdog.idle": "Turn running for {minutes} min; last tool: {tool}; repeated failures: {repetitions}.",
502401
- "sessionEvent.watchdog.aborted": "Turn stopped after {repetitions} repeated failed calls to {tool}."
502396
+ "sessionEvent.skill.activated": "Activated skill: {skillName}"
502402
502397
  },
502403
502398
  de: {
502404
502399
  "sessionEvent.error.mcpSync": "Der MCP-Serverstatus konnte nicht synchronisiert werden: {error}",
@@ -502425,9 +502420,7 @@ registerUiCatalogFragment({
502425
502420
  "sessionEvent.mcp.needsAuth": "MCP-Server „{name}“ benötigt OAuth — /mcp-config login {name} ausführen",
502426
502421
  "sessionEvent.mcp.disabled": "MCP-Server „{name}“ deaktiviert",
502427
502422
  "sessionEvent.mcp.connecting": "MCP-Server „{name}“ wird verbunden…",
502428
- "sessionEvent.skill.activated": "Skill aktiviert: {skillName}",
502429
- "sessionEvent.watchdog.idle": "Zug läuft seit {minutes} Min.; letztes Werkzeug: {tool}; wiederholte Fehler: {repetitions}.",
502430
- "sessionEvent.watchdog.aborted": "Zug nach {repetitions} wiederholten fehlgeschlagenen Aufrufen von {tool} beendet."
502423
+ "sessionEvent.skill.activated": "Skill aktiviert: {skillName}"
502431
502424
  },
502432
502425
  es: {
502433
502426
  "sessionEvent.error.mcpSync": "No se pudo sincronizar el estado de los servidores MCP: {error}",
@@ -502454,9 +502447,7 @@ registerUiCatalogFragment({
502454
502447
  "sessionEvent.mcp.needsAuth": "El servidor MCP «{name}» requiere OAuth; ejecuta /mcp-config login {name}",
502455
502448
  "sessionEvent.mcp.disabled": "Servidor MCP «{name}» desactivado",
502456
502449
  "sessionEvent.mcp.connecting": "Conectando el servidor MCP «{name}»…",
502457
- "sessionEvent.skill.activated": "Skill activado: {skillName}",
502458
- "sessionEvent.watchdog.idle": "El turno lleva {minutes} min en curso; última herramienta: {tool}; fallos repetidos: {repetitions}.",
502459
- "sessionEvent.watchdog.aborted": "Turno detenido tras {repetitions} llamadas fallidas repetidas a {tool}."
502450
+ "sessionEvent.skill.activated": "Skill activado: {skillName}"
502460
502451
  },
502461
502452
  fr: {
502462
502453
  "sessionEvent.error.mcpSync": "Impossible de synchroniser l’état des serveurs MCP : {error}",
@@ -502483,9 +502474,7 @@ registerUiCatalogFragment({
502483
502474
  "sessionEvent.mcp.needsAuth": "Le serveur MCP « {name} » requiert OAuth — exécutez /mcp-config login {name}",
502484
502475
  "sessionEvent.mcp.disabled": "Serveur MCP « {name} » désactivé",
502485
502476
  "sessionEvent.mcp.connecting": "Connexion du serveur MCP « {name} »…",
502486
- "sessionEvent.skill.activated": "Skill activé : {skillName}",
502487
- "sessionEvent.watchdog.idle": "Tour en cours depuis {minutes} min ; dernier outil : {tool} ; échecs répétés : {repetitions}.",
502488
- "sessionEvent.watchdog.aborted": "Tour arrêté après {repetitions} appels répétés ayant échoué pour l'outil {tool}."
502477
+ "sessionEvent.skill.activated": "Skill activé: {skillName}"
502489
502478
  },
502490
502479
  sv: {
502491
502480
  "sessionEvent.error.mcpSync": "Det gick inte att synkronisera MCP-serverstatus: {error}",
@@ -502512,9 +502501,7 @@ registerUiCatalogFragment({
502512
502501
  "sessionEvent.mcp.needsAuth": "MCP-servern ”{name}” behöver OAuth – kör /mcp-config login {name}",
502513
502502
  "sessionEvent.mcp.disabled": "MCP-servern ”{name}” är inaktiverad",
502514
502503
  "sessionEvent.mcp.connecting": "Ansluter MCP-servern ”{name}”…",
502515
- "sessionEvent.skill.activated": "Skill aktiverad: {skillName}",
502516
- "sessionEvent.watchdog.idle": "Körningen har pågått i {minutes} min. Senaste verktyg: {tool}. Upprepade fel: {repetitions}.",
502517
- "sessionEvent.watchdog.aborted": "Körningen stoppades efter {repetitions} upprepade misslyckade anrop till {tool}."
502504
+ "sessionEvent.skill.activated": "Skill aktiverad: {skillName}"
502518
502505
  },
502519
502506
  cs: {
502520
502507
  "sessionEvent.error.mcpSync": "Selhala synchronizace stavu serveru MCP: {error}",
@@ -502541,9 +502528,7 @@ registerUiCatalogFragment({
502541
502528
  "sessionEvent.mcp.needsAuth": "Server MCP \"{name}\" vyžaduje přihlášení přes OAuth — spusťte /mcp-config login {name}",
502542
502529
  "sessionEvent.mcp.disabled": "Server MCP \"{name}\" zakázán",
502543
502530
  "sessionEvent.mcp.connecting": "Server MCP \"{name}\" se připojuje…",
502544
- "sessionEvent.skill.activated": "Aktivována dovednost: {skillName}",
502545
- "sessionEvent.watchdog.idle": "Kolo běží {minutes} min; poslední nástroj: {tool}; opakovaná selhání: {repetitions}.",
502546
- "sessionEvent.watchdog.aborted": "Kolo bylo zastaveno po {repetitions} opakovaných neúspěšných voláních nástroje {tool}."
502531
+ "sessionEvent.skill.activated": "Aktivována dovednost: {skillName}"
502547
502532
  }
502548
502533
  });
502549
502534
  //#endregion
@@ -503685,140 +503670,6 @@ function isUserCancelledSubagentError(error) {
503685
503670
  }
503686
503671
  }
503687
503672
  //#endregion
503688
- //#region src/tui/controllers/turn-watchdog.ts
503689
- const DEFAULT_IDLE_MINUTES = 20;
503690
- const DEFAULT_MAX_FAILED_REPETITIONS = 5;
503691
- const MIN_IDLE_MINUTES = 1;
503692
- const MAX_IDLE_MINUTES = 1440;
503693
- const MIN_FAILED_REPETITIONS = 2;
503694
- const MAX_FAILED_REPETITIONS = 100;
503695
- const TURN_WATCHDOG_IDLE_MINUTES_ENV = "BLUN_TURN_WATCHDOG_IDLE_MINUTES";
503696
- const TURN_WATCHDOG_MAX_FAILED_REPETITIONS_ENV = "BLUN_TURN_WATCHDOG_MAX_FAILED_REPETITIONS";
503697
- function resolveTurnWatchdogConfig(env = process.env) {
503698
- const idleMinutes = parseBoundedInteger(env[TURN_WATCHDOG_IDLE_MINUTES_ENV], DEFAULT_IDLE_MINUTES, MIN_IDLE_MINUTES, MAX_IDLE_MINUTES);
503699
- const maxFailedRepetitions = parseBoundedInteger(env[TURN_WATCHDOG_MAX_FAILED_REPETITIONS_ENV], DEFAULT_MAX_FAILED_REPETITIONS, MIN_FAILED_REPETITIONS, MAX_FAILED_REPETITIONS);
503700
- return {
503701
- idleMs: idleMinutes * 6e4,
503702
- maxFailedRepetitions
503703
- };
503704
- }
503705
- var TurnWatchdogController = class {
503706
- config;
503707
- now;
503708
- setTimer;
503709
- clearTimer;
503710
- onIdle;
503711
- onAbort;
503712
- toolCalls = /* @__PURE__ */ new Map();
503713
- active = false;
503714
- startedAtMs = 0;
503715
- lastProgressAtMs = 0;
503716
- lastToolName = "none";
503717
- lastFailedKey;
503718
- failedRepetitions = 0;
503719
- idleReportedForProgressAtMs;
503720
- timer;
503721
- constructor(options) {
503722
- this.config = options.config ?? resolveTurnWatchdogConfig();
503723
- this.now = options.now ?? Date.now;
503724
- this.setTimer = options.setTimer ?? setTimeout;
503725
- this.clearTimer = options.clearTimer ?? clearTimeout;
503726
- this.onIdle = options.onIdle;
503727
- this.onAbort = options.onAbort;
503728
- }
503729
- start() {
503730
- this.stop();
503731
- const now = this.now();
503732
- this.active = true;
503733
- this.startedAtMs = now;
503734
- this.lastProgressAtMs = now;
503735
- this.lastToolName = "none";
503736
- this.lastFailedKey = void 0;
503737
- this.failedRepetitions = 0;
503738
- this.idleReportedForProgressAtMs = void 0;
503739
- this.scheduleIdleCheck();
503740
- }
503741
- stop() {
503742
- this.active = false;
503743
- this.toolCalls.clear();
503744
- if (this.timer !== void 0) {
503745
- this.clearTimer(this.timer);
503746
- this.timer = void 0;
503747
- }
503748
- }
503749
- recordToolCall(toolCallId, name, args) {
503750
- if (!this.active) return;
503751
- this.lastToolName = name;
503752
- this.toolCalls.set(toolCallId, {
503753
- name,
503754
- key: `${name}\0${canonicalJson(args)}`
503755
- });
503756
- }
503757
- recordToolResult(toolCallId, isError) {
503758
- if (!this.active) return;
503759
- const toolCall = this.toolCalls.get(toolCallId);
503760
- this.toolCalls.delete(toolCallId);
503761
- if (toolCall !== void 0) this.lastToolName = toolCall.name;
503762
- this.lastProgressAtMs = this.now();
503763
- this.idleReportedForProgressAtMs = void 0;
503764
- this.scheduleIdleCheck();
503765
- if (!isError || toolCall === void 0) {
503766
- this.lastFailedKey = void 0;
503767
- this.failedRepetitions = 0;
503768
- return;
503769
- }
503770
- if (toolCall.key === this.lastFailedKey) this.failedRepetitions += 1;
503771
- else {
503772
- this.lastFailedKey = toolCall.key;
503773
- this.failedRepetitions = 1;
503774
- }
503775
- if (this.failedRepetitions < this.config.maxFailedRepetitions) return;
503776
- const snapshot = this.snapshot();
503777
- this.stop();
503778
- this.onAbort(snapshot);
503779
- }
503780
- scheduleIdleCheck() {
503781
- if (!this.active) return;
503782
- if (this.timer !== void 0) this.clearTimer(this.timer);
503783
- const remaining = Math.max(0, this.config.idleMs - (this.now() - this.lastProgressAtMs));
503784
- this.timer = this.setTimer(() => {
503785
- this.timer = void 0;
503786
- this.checkIdle();
503787
- }, remaining);
503788
- }
503789
- checkIdle() {
503790
- if (!this.active) return;
503791
- if (this.now() - this.lastProgressAtMs >= this.config.idleMs && this.idleReportedForProgressAtMs !== this.lastProgressAtMs) {
503792
- this.idleReportedForProgressAtMs = this.lastProgressAtMs;
503793
- this.onIdle(this.snapshot());
503794
- return;
503795
- }
503796
- this.scheduleIdleCheck();
503797
- }
503798
- snapshot() {
503799
- return {
503800
- elapsedMinutes: Math.max(1, Math.floor((this.now() - this.startedAtMs) / 6e4)),
503801
- lastToolName: this.lastToolName,
503802
- failedRepetitions: this.failedRepetitions
503803
- };
503804
- }
503805
- };
503806
- function parseBoundedInteger(raw, fallback, minimum, maximum) {
503807
- if (raw === void 0 || raw.trim() === "") return fallback;
503808
- const value = Number(raw);
503809
- return Number.isSafeInteger(value) && value >= minimum && value <= maximum ? value : fallback;
503810
- }
503811
- function canonicalJson(value) {
503812
- const normalized = normalizeJson(value);
503813
- return JSON.stringify(normalized) ?? "undefined";
503814
- }
503815
- function normalizeJson(value) {
503816
- if (Array.isArray(value)) return value.map(normalizeJson);
503817
- if (value === null || typeof value !== "object") return value;
503818
- const record = value;
503819
- return Object.fromEntries(Object.keys(record).toSorted().map((key) => [key, normalizeJson(record[key])]));
503820
- }
503821
- //#endregion
503822
503673
  //#region src/tui/controllers/session-event-handler.ts
503823
503674
  const MANAGED_TELEGRAM_MCP_SERVER = "plugin-telegram:telegram";
503824
503675
  function isManagedTelegramMissingTokenFailure(server) {
@@ -503827,7 +503678,6 @@ function isManagedTelegramMissingTokenFailure(server) {
503827
503678
  var SessionEventHandler = class {
503828
503679
  host;
503829
503680
  subAgentEventHandler;
503830
- turnWatchdog;
503831
503681
  constructor(host) {
503832
503682
  this.host = host;
503833
503683
  this.subAgentEventHandler = new SubAgentEventHandler(host, {
@@ -503837,10 +503687,6 @@ var SessionEventHandler = class {
503837
503687
  this.syncBackgroundTaskBadge();
503838
503688
  }
503839
503689
  });
503840
- this.turnWatchdog = new TurnWatchdogController({
503841
- onIdle: (snapshot) => this.reportWatchdogIdle(snapshot),
503842
- onAbort: (snapshot) => this.abortWatchdogLoop(snapshot)
503843
- });
503844
503690
  }
503845
503691
  backgroundTasks = /* @__PURE__ */ new Map();
503846
503692
  backgroundTaskTranscriptedTerminal = /* @__PURE__ */ new Set();
@@ -503860,7 +503706,6 @@ var SessionEventHandler = class {
503860
503706
  queuedGoalPromotionTimer;
503861
503707
  lastCompactionInstruction;
503862
503708
  resetRuntimeState() {
503863
- this.turnWatchdog.stop();
503864
503709
  this.backgroundTasks.clear();
503865
503710
  this.backgroundTaskTranscriptedTerminal.clear();
503866
503711
  this.subAgentEventHandler.resetRuntimeState();
@@ -504046,7 +503891,6 @@ var SessionEventHandler = class {
504046
503891
  this.mcpServerStatusSpinners.clear();
504047
503892
  }
504048
503893
  handleTurnBegin(event) {
504049
- this.turnWatchdog.start();
504050
503894
  const sessionId = this.host.session?.id;
504051
503895
  if (sessionId !== void 0) bindPersonalMemoryRememberIntentTurn(sessionId, event.turnId);
504052
503896
  this.currentTurnHasAssistantText = false;
@@ -504085,7 +503929,6 @@ var SessionEventHandler = class {
504085
503929
  });
504086
503930
  }
504087
503931
  handleTurnEnd(event, sendQueued) {
504088
- this.turnWatchdog.stop();
504089
503932
  this.host.restoreQueuedSteerAtTurnEnd(event.turnId);
504090
503933
  const sessionId = this.host.session?.id;
504091
503934
  if (sessionId !== void 0) finishPersonalMemoryRememberIntentTurn(sessionId, event.turnId);
@@ -504230,7 +504073,6 @@ var SessionEventHandler = class {
504230
504073
  });
504231
504074
  }
504232
504075
  handleToolCall(event) {
504233
- this.turnWatchdog.recordToolCall(event.toolCallId, event.name, event.args);
504234
504076
  const { streamingUI } = this.host;
504235
504077
  streamingUI.flushNow();
504236
504078
  const { turnId, step } = streamingUI.getTurnContext();
@@ -504280,7 +504122,6 @@ var SessionEventHandler = class {
504280
504122
  if (event.update.kind === "stdout" || event.update.kind === "stderr") tc.appendLiveOutput(text);
504281
504123
  }
504282
504124
  handleToolResult(event) {
504283
- this.turnWatchdog.recordToolResult(event.toolCallId, event.isError === true);
504284
504125
  const { streamingUI } = this.host;
504285
504126
  streamingUI.flushNow();
504286
504127
  const resultData = {
@@ -504304,26 +504145,6 @@ var SessionEventHandler = class {
504304
504145
  }
504305
504146
  this.host.patchLivePane({ mode: "waiting" });
504306
504147
  }
504307
- reportWatchdogIdle(snapshot) {
504308
- const message = uiText("sessionEvent.watchdog.idle", {
504309
- minutes: snapshot.elapsedMinutes,
504310
- tool: snapshot.lastToolName,
504311
- repetitions: snapshot.failedRepetitions
504312
- });
504313
- this.host.showStatus(message, "warning");
504314
- this.host.sendChannelTurnStatus?.(message);
504315
- }
504316
- abortWatchdogLoop(snapshot) {
504317
- const message = uiText("sessionEvent.watchdog.aborted", {
504318
- tool: snapshot.lastToolName,
504319
- repetitions: snapshot.failedRepetitions
504320
- });
504321
- this.host.showError(message);
504322
- this.host.sendChannelTurnStatus?.(message);
504323
- this.host.session?.cancel().catch((error) => {
504324
- this.host.showError(formatErrorMessage$2(error));
504325
- });
504326
- }
504327
504148
  handleStatusUpdate(event) {
504328
504149
  const shouldRenderSwarmEnded = event.swarmMode === false && this.host.state.appState.swarmMode && this.host.state.appState.swarmModeEntry === "task";
504329
504150
  const patch = {};
@@ -513006,13 +512827,6 @@ var BlunTUI = class {
513006
512827
  this.showError(uiText("blunTui.session.sendFailed", { error: "Telegram media" }));
513007
512828
  });
513008
512829
  }
513009
- sendChannelTurnStatus(message) {
513010
- const guard = this.pendingChannelReplyGuard;
513011
- if (guard === void 0) return;
513012
- sendReplyFallback(guard.chatId, message, guard.contextOnly).then((sent) => {
513013
- if (sent && this.pendingChannelReplyGuard === guard) guard.outboxMarker = outboxMarker();
513014
- });
513015
- }
513016
512830
  runChannelReplyFallback(reason) {
513017
512831
  const guard = this.pendingChannelReplyGuard;
513018
512832
  if (guard === void 0) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.40",
3
+ "version": "9.1.41",
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": {