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.
- package/LIESMICH.txt +1 -12
- package/README.md +1 -11
- package/blun.mjs +96 -282
- 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.
|
|
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.
|
|
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:
|
|
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
|
|
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
|
|
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,
|
|
1978
|
-
const maxRetries = normalizeMaxRetries(
|
|
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)
|
|
1981
|
-
const
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
const
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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 >
|
|
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 ${
|
|
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)}
|
|
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 >
|
|
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 ${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 ||
|
|
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é
|
|
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;
|