blun-king-cli 9.1.193 → 9.1.195
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/bin/launcher-runtime.js +18 -2
- package/blun.mjs +47 -9
- package/package.json +1 -1
package/bin/launcher-runtime.js
CHANGED
|
@@ -256,11 +256,23 @@ async function waitForRuntimeReady(core, timeoutMs = RUNTIME_READY_TIMEOUT_MS) {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
function resolveHandoffCwd(candidate, fallback) {
|
|
260
|
+
if (typeof candidate !== 'string' || candidate.trim().length === 0 || !path.isAbsolute(candidate)) {
|
|
261
|
+
return fallback;
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
return fs.statSync(candidate).isDirectory() ? path.resolve(candidate) : fallback;
|
|
265
|
+
} catch {
|
|
266
|
+
return fallback;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
259
270
|
async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {}) {
|
|
260
271
|
const packageRoot = path.resolve(options.packageRoot || PKG);
|
|
261
272
|
let preparedTarget;
|
|
262
273
|
let handoffSessionId;
|
|
263
274
|
let handoffMode;
|
|
275
|
+
let handoffCwd = cwd;
|
|
264
276
|
let updateStarted = false;
|
|
265
277
|
let runtimeReady = false;
|
|
266
278
|
let runningUpdatePollTimer;
|
|
@@ -273,6 +285,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
273
285
|
runningUpdateMode = persistedMode;
|
|
274
286
|
handoffSessionId = undefined;
|
|
275
287
|
handoffMode = undefined;
|
|
288
|
+
handoffCwd = cwd;
|
|
276
289
|
}
|
|
277
290
|
};
|
|
278
291
|
const clearRunningUpdatePoll = () => {
|
|
@@ -337,6 +350,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
337
350
|
runningUpdateMode = normalizeRunningUpdateMode(message.mode);
|
|
338
351
|
handoffSessionId = undefined;
|
|
339
352
|
handoffMode = undefined;
|
|
353
|
+
handoffCwd = cwd;
|
|
340
354
|
clearRunningUpdatePoll();
|
|
341
355
|
if (automaticMode()) {
|
|
342
356
|
if (preparedTarget !== undefined) announcePrepared(child);
|
|
@@ -353,6 +367,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
353
367
|
&& automaticMode()) {
|
|
354
368
|
handoffSessionId = message.sessionId;
|
|
355
369
|
handoffMode = runningUpdateMode;
|
|
370
|
+
handoffCwd = resolveHandoffCwd(message.cwd, cwd);
|
|
356
371
|
}
|
|
357
372
|
};
|
|
358
373
|
const spawnCore = options.spawnProtectedCore || spawnProtectedCore;
|
|
@@ -394,7 +409,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
394
409
|
probeTarget: options.probeRunningUpdate || (() => true),
|
|
395
410
|
stopOld: async () => {},
|
|
396
411
|
startCore: async ({ packageRoot: nextRoot, args: nextArgs }) => {
|
|
397
|
-
const nextCore = spawnCore(nextArgs, env,
|
|
412
|
+
const nextCore = spawnCore(nextArgs, env, handoffCwd, { packageRoot: nextRoot });
|
|
398
413
|
const nextLoaded = await nextCore.loaded;
|
|
399
414
|
const ready = nextLoaded && await waitForRuntimeReady(nextCore, options.readyTimeoutMs);
|
|
400
415
|
if (!ready) {
|
|
@@ -408,7 +423,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
408
423
|
const resumed = handoff.core;
|
|
409
424
|
if (resumed === undefined || resumed.ready !== true) return 1;
|
|
410
425
|
const resumedArgs = handoffArgsForMode(args, handoffMode, handoffSessionId);
|
|
411
|
-
return superviseProtectedCore(resumedArgs, env,
|
|
426
|
+
return superviseProtectedCore(resumedArgs, env, handoffCwd, async () => {}, {
|
|
412
427
|
...options,
|
|
413
428
|
existingCore: resumed,
|
|
414
429
|
packageRoot: handoff.runtime.packageRoot,
|
|
@@ -745,6 +760,7 @@ module.exports = {
|
|
|
745
760
|
RUNNING_UPDATE_RECHECK_MS,
|
|
746
761
|
createManagedNodeEnvironment,
|
|
747
762
|
resolveLauncherPrivatePaths,
|
|
763
|
+
resolveHandoffCwd,
|
|
748
764
|
runningUpdateRecheckDelay,
|
|
749
765
|
runLauncher,
|
|
750
766
|
scheduleRunningUpdateRecheck,
|
package/blun.mjs
CHANGED
|
@@ -505310,6 +505310,7 @@ registerUiCatalogFragment({
|
|
|
505310
505310
|
"sessionEvent.mcp.connecting": "MCP server \"{name}\" connecting…",
|
|
505311
505311
|
"sessionEvent.skill.activated": "Activated skill: {skillName}",
|
|
505312
505312
|
"sessionEvent.watchdog.idle": "Turn running for {minutes} min; last tool: {tool}; repeated failures: {repetitions}.",
|
|
505313
|
+
"sessionEvent.watchdog.timeout": "Turn stopped after {minutes} min without progress; last tool: {tool}.",
|
|
505313
505314
|
"sessionEvent.watchdog.aborted": "Turn stopped after {repetitions} repeated failed calls to {tool}."
|
|
505314
505315
|
},
|
|
505315
505316
|
de: {
|
|
@@ -505339,6 +505340,7 @@ registerUiCatalogFragment({
|
|
|
505339
505340
|
"sessionEvent.mcp.connecting": "MCP-Server „{name}“ wird verbunden…",
|
|
505340
505341
|
"sessionEvent.skill.activated": "Skill aktiviert: {skillName}",
|
|
505341
505342
|
"sessionEvent.watchdog.idle": "Zug läuft seit {minutes} Min.; letztes Werkzeug: {tool}; wiederholte Fehler: {repetitions}.",
|
|
505343
|
+
"sessionEvent.watchdog.timeout": "Zug nach {minutes} Min. ohne Fortschritt beendet; letztes Werkzeug: {tool}.",
|
|
505342
505344
|
"sessionEvent.watchdog.aborted": "Zug nach {repetitions} wiederholten fehlgeschlagenen Aufrufen von {tool} beendet."
|
|
505343
505345
|
},
|
|
505344
505346
|
es: {
|
|
@@ -505368,6 +505370,7 @@ registerUiCatalogFragment({
|
|
|
505368
505370
|
"sessionEvent.mcp.connecting": "Conectando el servidor MCP «{name}»…",
|
|
505369
505371
|
"sessionEvent.skill.activated": "Skill activado: {skillName}",
|
|
505370
505372
|
"sessionEvent.watchdog.idle": "El turno lleva {minutes} min en curso; última herramienta: {tool}; fallos repetidos: {repetitions}.",
|
|
505373
|
+
"sessionEvent.watchdog.timeout": "Turno detenido tras {minutes} min sin progreso; última herramienta: {tool}.",
|
|
505371
505374
|
"sessionEvent.watchdog.aborted": "Turno detenido tras {repetitions} llamadas fallidas repetidas a {tool}."
|
|
505372
505375
|
},
|
|
505373
505376
|
fr: {
|
|
@@ -505397,6 +505400,7 @@ registerUiCatalogFragment({
|
|
|
505397
505400
|
"sessionEvent.mcp.connecting": "Connexion du serveur MCP « {name} »…",
|
|
505398
505401
|
"sessionEvent.skill.activated": "Skill activé : {skillName}",
|
|
505399
505402
|
"sessionEvent.watchdog.idle": "Tour en cours depuis {minutes} min ; dernier outil : {tool} ; échecs répétés : {repetitions}.",
|
|
505403
|
+
"sessionEvent.watchdog.timeout": "Tour arrêté après {minutes} min sans progression ; dernier outil : {tool}.",
|
|
505400
505404
|
"sessionEvent.watchdog.aborted": "Tour arrêté après {repetitions} appels répétés ayant échoué pour l'outil {tool}."
|
|
505401
505405
|
},
|
|
505402
505406
|
sv: {
|
|
@@ -505426,6 +505430,7 @@ registerUiCatalogFragment({
|
|
|
505426
505430
|
"sessionEvent.mcp.connecting": "Ansluter MCP-servern ”{name}”…",
|
|
505427
505431
|
"sessionEvent.skill.activated": "Skill aktiverad: {skillName}",
|
|
505428
505432
|
"sessionEvent.watchdog.idle": "Körningen har pågått i {minutes} min. Senaste verktyg: {tool}. Upprepade fel: {repetitions}.",
|
|
505433
|
+
"sessionEvent.watchdog.timeout": "Körningen stoppades efter {minutes} min utan framsteg. Senaste verktyg: {tool}.",
|
|
505429
505434
|
"sessionEvent.watchdog.aborted": "Körningen stoppades efter {repetitions} upprepade misslyckade anrop till {tool}."
|
|
505430
505435
|
},
|
|
505431
505436
|
cs: {
|
|
@@ -505455,6 +505460,7 @@ registerUiCatalogFragment({
|
|
|
505455
505460
|
"sessionEvent.mcp.connecting": "Server MCP \"{name}\" se připojuje…",
|
|
505456
505461
|
"sessionEvent.skill.activated": "Aktivována dovednost: {skillName}",
|
|
505457
505462
|
"sessionEvent.watchdog.idle": "Kolo běží {minutes} min; poslední nástroj: {tool}; opakovaná selhání: {repetitions}.",
|
|
505463
|
+
"sessionEvent.watchdog.timeout": "Kolo bylo zastaveno po {minutes} min bez pokroku; poslední nástroj: {tool}.",
|
|
505458
505464
|
"sessionEvent.watchdog.aborted": "Kolo bylo zastaveno po {repetitions} opakovaných neúspěšných voláních nástroje {tool}."
|
|
505459
505465
|
}
|
|
505460
505466
|
});
|
|
@@ -506606,18 +506612,22 @@ function isUserCancelledSubagentError(error) {
|
|
|
506606
506612
|
//#endregion
|
|
506607
506613
|
//#region src/tui/controllers/turn-watchdog.ts
|
|
506608
506614
|
const DEFAULT_IDLE_MINUTES = 20;
|
|
506615
|
+
const DEFAULT_HARD_IDLE_MINUTES = 30;
|
|
506609
506616
|
const DEFAULT_MAX_FAILED_REPETITIONS = 5;
|
|
506610
506617
|
const MIN_IDLE_MINUTES = 1;
|
|
506611
506618
|
const MAX_IDLE_MINUTES = 1440;
|
|
506612
506619
|
const MIN_FAILED_REPETITIONS = 2;
|
|
506613
506620
|
const MAX_FAILED_REPETITIONS = 100;
|
|
506614
506621
|
const TURN_WATCHDOG_IDLE_MINUTES_ENV = "BLUN_TURN_WATCHDOG_IDLE_MINUTES";
|
|
506622
|
+
const TURN_WATCHDOG_HARD_IDLE_MINUTES_ENV = "BLUN_TURN_WATCHDOG_HARD_IDLE_MINUTES";
|
|
506615
506623
|
const TURN_WATCHDOG_MAX_FAILED_REPETITIONS_ENV = "BLUN_TURN_WATCHDOG_MAX_FAILED_REPETITIONS";
|
|
506616
506624
|
function resolveTurnWatchdogConfig(env = process.env) {
|
|
506617
506625
|
const idleMinutes = parseBoundedInteger(env[TURN_WATCHDOG_IDLE_MINUTES_ENV], DEFAULT_IDLE_MINUTES, MIN_IDLE_MINUTES, MAX_IDLE_MINUTES);
|
|
506626
|
+
const hardIdleMinutes = parseBoundedInteger(env[TURN_WATCHDOG_HARD_IDLE_MINUTES_ENV], DEFAULT_HARD_IDLE_MINUTES, MIN_IDLE_MINUTES, MAX_IDLE_MINUTES);
|
|
506618
506627
|
const maxFailedRepetitions = parseBoundedInteger(env[TURN_WATCHDOG_MAX_FAILED_REPETITIONS_ENV], DEFAULT_MAX_FAILED_REPETITIONS, MIN_FAILED_REPETITIONS, MAX_FAILED_REPETITIONS);
|
|
506619
506628
|
return {
|
|
506620
506629
|
idleMs: idleMinutes * 6e4,
|
|
506630
|
+
hardIdleMs: hardIdleMinutes * 6e4,
|
|
506621
506631
|
maxFailedRepetitions
|
|
506622
506632
|
};
|
|
506623
506633
|
}
|
|
@@ -506667,6 +506677,7 @@ var TurnWatchdogController = class {
|
|
|
506667
506677
|
}
|
|
506668
506678
|
recordToolCall(toolCallId, name, args) {
|
|
506669
506679
|
if (!this.active) return;
|
|
506680
|
+
this.recordProgress();
|
|
506670
506681
|
this.lastToolName = name;
|
|
506671
506682
|
this.toolCalls.set(toolCallId, {
|
|
506672
506683
|
name,
|
|
@@ -506678,9 +506689,7 @@ var TurnWatchdogController = class {
|
|
|
506678
506689
|
const toolCall = this.toolCalls.get(toolCallId);
|
|
506679
506690
|
this.toolCalls.delete(toolCallId);
|
|
506680
506691
|
if (toolCall !== void 0) this.lastToolName = toolCall.name;
|
|
506681
|
-
this.
|
|
506682
|
-
this.idleReportedForProgressAtMs = void 0;
|
|
506683
|
-
this.scheduleIdleCheck();
|
|
506692
|
+
this.recordProgress();
|
|
506684
506693
|
if (!isError || toolCall === void 0) {
|
|
506685
506694
|
this.lastFailedKey = void 0;
|
|
506686
506695
|
this.failedRepetitions = 0;
|
|
@@ -506692,14 +506701,26 @@ var TurnWatchdogController = class {
|
|
|
506692
506701
|
this.failedRepetitions = 1;
|
|
506693
506702
|
}
|
|
506694
506703
|
if (this.failedRepetitions < this.config.maxFailedRepetitions) return;
|
|
506695
|
-
const snapshot =
|
|
506704
|
+
const snapshot = {
|
|
506705
|
+
...this.snapshot(),
|
|
506706
|
+
reason: "repeated_failures"
|
|
506707
|
+
};
|
|
506696
506708
|
this.stop();
|
|
506697
506709
|
this.onAbort(snapshot);
|
|
506698
506710
|
}
|
|
506711
|
+
recordProgress() {
|
|
506712
|
+
if (!this.active) return;
|
|
506713
|
+
this.lastProgressAtMs = this.now();
|
|
506714
|
+
this.idleReportedForProgressAtMs = void 0;
|
|
506715
|
+
this.scheduleIdleCheck();
|
|
506716
|
+
}
|
|
506699
506717
|
scheduleIdleCheck() {
|
|
506700
506718
|
if (!this.active) return;
|
|
506701
506719
|
if (this.timer !== void 0) this.clearTimer(this.timer);
|
|
506702
|
-
const
|
|
506720
|
+
const idleForMs = this.now() - this.lastProgressAtMs;
|
|
506721
|
+
const warningRemaining = this.idleReportedForProgressAtMs === this.lastProgressAtMs ? Number.POSITIVE_INFINITY : this.config.idleMs - idleForMs;
|
|
506722
|
+
const hardRemaining = this.config.hardIdleMs - idleForMs;
|
|
506723
|
+
const remaining = Math.max(0, Math.min(warningRemaining, hardRemaining));
|
|
506703
506724
|
this.timer = this.setTimer(() => {
|
|
506704
506725
|
this.timer = void 0;
|
|
506705
506726
|
this.checkIdle();
|
|
@@ -506707,16 +506728,26 @@ var TurnWatchdogController = class {
|
|
|
506707
506728
|
}
|
|
506708
506729
|
checkIdle() {
|
|
506709
506730
|
if (!this.active) return;
|
|
506710
|
-
|
|
506731
|
+
const idleForMs = this.now() - this.lastProgressAtMs;
|
|
506732
|
+
if (idleForMs >= this.config.hardIdleMs) {
|
|
506733
|
+
const snapshot = {
|
|
506734
|
+
...this.snapshot(),
|
|
506735
|
+
reason: "idle_timeout"
|
|
506736
|
+
};
|
|
506737
|
+
this.stop();
|
|
506738
|
+
this.onAbort(snapshot);
|
|
506739
|
+
return;
|
|
506740
|
+
}
|
|
506741
|
+
if (idleForMs >= this.config.idleMs && this.idleReportedForProgressAtMs !== this.lastProgressAtMs) {
|
|
506711
506742
|
this.idleReportedForProgressAtMs = this.lastProgressAtMs;
|
|
506712
506743
|
this.onIdle(this.snapshot());
|
|
506713
|
-
return;
|
|
506714
506744
|
}
|
|
506715
506745
|
this.scheduleIdleCheck();
|
|
506716
506746
|
}
|
|
506717
506747
|
snapshot() {
|
|
506718
506748
|
return {
|
|
506719
506749
|
elapsedMinutes: Math.max(1, Math.floor((this.now() - this.startedAtMs) / 6e4)),
|
|
506750
|
+
idleMinutes: Math.max(1, Math.floor((this.now() - this.lastProgressAtMs) / 6e4)),
|
|
506720
506751
|
lastToolName: this.lastToolName,
|
|
506721
506752
|
failedRepetitions: this.failedRepetitions
|
|
506722
506753
|
};
|
|
@@ -507035,6 +507066,7 @@ var SessionEventHandler = class {
|
|
|
507035
507066
|
requestRunningUpdateAtSafeBoundary(this.host);
|
|
507036
507067
|
}
|
|
507037
507068
|
handleStepBegin(event) {
|
|
507069
|
+
this.turnWatchdog.recordProgress();
|
|
507038
507070
|
this.host.commitQueuedSteerAtStepStart(event.turnId);
|
|
507039
507071
|
this.host.streamingUI.flushNow();
|
|
507040
507072
|
this.host.streamingUI.setStep(event.step);
|
|
@@ -507108,6 +507140,7 @@ var SessionEventHandler = class {
|
|
|
507108
507140
|
handleThinkingDelta(event) {
|
|
507109
507141
|
const { state, streamingUI } = this.host;
|
|
507110
507142
|
if (event.delta.length === 0 && !streamingUI.hasThinkingDraft()) return;
|
|
507143
|
+
if (event.delta.length > 0) this.turnWatchdog.recordProgress();
|
|
507111
507144
|
streamingUI.appendThinkingDelta(event.delta);
|
|
507112
507145
|
this.host.patchLivePane({ mode: "idle" });
|
|
507113
507146
|
if (state.appState.streamingPhase !== "thinking") this.host.setAppState({
|
|
@@ -507120,6 +507153,7 @@ var SessionEventHandler = class {
|
|
|
507120
507153
|
const { state, streamingUI } = this.host;
|
|
507121
507154
|
if (streamingUI.hasThinkingDraft()) streamingUI.flushThinkingToTranscript("idle");
|
|
507122
507155
|
if (event.delta.trim().length > 0) {
|
|
507156
|
+
this.turnWatchdog.recordProgress();
|
|
507123
507157
|
this.currentTurnHasAssistantText = true;
|
|
507124
507158
|
this.pendingModelBlockedFallback = void 0;
|
|
507125
507159
|
}
|
|
@@ -507180,6 +507214,7 @@ var SessionEventHandler = class {
|
|
|
507180
507214
|
}
|
|
507181
507215
|
handleToolCallDelta(event) {
|
|
507182
507216
|
if (event.toolCallId.length === 0) return;
|
|
507217
|
+
if (event.argumentsPart.length > 0) this.turnWatchdog.recordProgress();
|
|
507183
507218
|
const { state, streamingUI } = this.host;
|
|
507184
507219
|
streamingUI.accumulateToolCallDelta(event.toolCallId, event.name, event.argumentsPart);
|
|
507185
507220
|
const preview = streamingUI.getStreamingToolCallPreview(event.toolCallId);
|
|
@@ -507196,6 +507231,7 @@ var SessionEventHandler = class {
|
|
|
507196
507231
|
streamingUI.scheduleFlush();
|
|
507197
507232
|
}
|
|
507198
507233
|
handleToolProgress(event) {
|
|
507234
|
+
this.turnWatchdog.recordProgress();
|
|
507199
507235
|
if (event.update.kind === "custom" && event.update.customKind === MEDIA_PROGRESS_CUSTOM_KIND) {
|
|
507200
507236
|
this.host.updateMediaActivity(event.toolCallId, event.update.customData);
|
|
507201
507237
|
return;
|
|
@@ -507251,7 +507287,8 @@ var SessionEventHandler = class {
|
|
|
507251
507287
|
this.host.sendChannelTurnStatus?.(message);
|
|
507252
507288
|
}
|
|
507253
507289
|
abortWatchdogLoop(snapshot) {
|
|
507254
|
-
const message = uiText("sessionEvent.watchdog.aborted", {
|
|
507290
|
+
const message = uiText(snapshot.reason === "idle_timeout" ? "sessionEvent.watchdog.timeout" : "sessionEvent.watchdog.aborted", {
|
|
507291
|
+
minutes: snapshot.idleMinutes,
|
|
507255
507292
|
tool: snapshot.lastToolName,
|
|
507256
507293
|
repetitions: snapshot.failedRepetitions
|
|
507257
507294
|
});
|
|
@@ -514970,7 +515007,8 @@ function requestRunningUpdateAtSafeBoundary(tui) {
|
|
|
514970
515007
|
type: RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
514971
515008
|
sessionId,
|
|
514972
515009
|
version: tui.runningUpdatePreparedVersion,
|
|
514973
|
-
mode: tui.runningUpdatePreparedMode
|
|
515010
|
+
mode: tui.runningUpdatePreparedMode,
|
|
515011
|
+
cwd: tui.state.appState.workDir
|
|
514974
515012
|
}, (error) => {
|
|
514975
515013
|
if (error || !isSafeRuntimeBoundary(boundaryState())) {
|
|
514976
515014
|
tui.runningUpdateHandoffStarted = false;
|