blun-king-cli 9.1.176 → 9.1.178

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.
@@ -14,6 +14,22 @@ const SYNTHETIC_TOOL_ARGUMENT_MARKER = JSON.stringify({
14
14
  const TELEGRAM_REPLY_TOOL_RE = /^mcp__[^\s]*telegram[^\s]*__reply$/iu;
15
15
  const SYNTHETIC_TOOL_ARGUMENT_SUMMARY_MARKER = '[Historical tool arguments unavailable]';
16
16
 
17
+ function isSyntheticToolArguments(value) {
18
+ let parsed = value;
19
+ if (typeof value === 'string') {
20
+ try {
21
+ parsed = JSON.parse(value);
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return false;
27
+ const keys = Object.keys(parsed);
28
+ return keys.length === 1
29
+ && keys[0] === '_blun_compacted'
30
+ && parsed._blun_compacted === '[Old tool call arguments cleared]';
31
+ }
32
+
17
33
  function shouldOffloadHistoricalAssistantMessage(options = {}) {
18
34
  const historyIndex = Number(options.historyIndex);
19
35
  const historyLength = Number(options.historyLength);
@@ -134,7 +150,7 @@ function removeSyntheticToolArgumentFailures(messages) {
134
150
  const syntheticCallIds = new Set(scrubbedMessages.flatMap((message) => (
135
151
  message?.role === 'assistant' && Array.isArray(message.toolCalls)
136
152
  ? message.toolCalls
137
- .filter((call) => call?.arguments === SYNTHETIC_TOOL_ARGUMENT_MARKER)
153
+ .filter((call) => isSyntheticToolArguments(call?.arguments))
138
154
  .map((call) => call?.id)
139
155
  : []
140
156
  )).filter((id) => typeof id === 'string' && id.length > 0));
@@ -165,6 +181,7 @@ module.exports = {
165
181
  ASSISTANT_POST_TELEGRAM_REPLY_MARKER,
166
182
  compactHistoricalPostTelegramReplyNarration,
167
183
  createAssistantMessagePreview,
184
+ isSyntheticToolArguments,
168
185
  removeSyntheticToolArgumentFailures,
169
186
  shouldCompactHistoricalAssistantToolNarration,
170
187
  shouldOffloadHistoricalAssistantMessage,
@@ -60,6 +60,7 @@ const CORE_LOAD_TIMEOUT_MS = 30_000;
60
60
  const RUNTIME_READY_TIMEOUT_MS = 60_000;
61
61
  const RUNNING_UPDATE_RECHECK_MS = 60_000;
62
62
  const RUNNING_UPDATE_RECHECK_JITTER_MS = 30_000;
63
+ const RUNNING_UPDATE_HANDOFF_NOTICE = 'Ein Update wird geladen. Die TUI wird anschließend neu gestartet.';
63
64
 
64
65
  function runningUpdateRecheckDelay(randomValue = Math.random()) {
65
66
  const normalized = Number.isFinite(randomValue)
@@ -78,6 +79,10 @@ function scheduleRunningUpdateRecheck(callback, options = {}) {
78
79
  return timer;
79
80
  }
80
81
 
82
+ function writeRunningUpdateHandoffNotice(output = process.stdout) {
83
+ output.write(`\n${RUNNING_UPDATE_HANDOFF_NOTICE}\n`);
84
+ }
85
+
81
86
  function normalizeWindowsPath(value) {
82
87
  return path.win32.normalize(value).replace(/\\+$/u, '').toLowerCase();
83
88
  }
@@ -255,6 +260,14 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
255
260
  let runningUpdateMode = readRunningUpdateMode(env.BLUN_HOME);
256
261
  const automaticMode = () => runningUpdateMode === RUNNING_UPDATE_MODES.RESUME
257
262
  || runningUpdateMode === RUNNING_UPDATE_MODES.NEW;
263
+ const refreshRunningUpdateMode = () => {
264
+ const persistedMode = readRunningUpdateMode(env.BLUN_HOME);
265
+ if (persistedMode !== runningUpdateMode) {
266
+ runningUpdateMode = persistedMode;
267
+ handoffSessionId = undefined;
268
+ handoffMode = undefined;
269
+ }
270
+ };
258
271
  const clearRunningUpdatePoll = () => {
259
272
  if (runningUpdatePollTimer === undefined) return;
260
273
  (options.clearTimeoutImpl || clearTimeout)(runningUpdatePollTimer);
@@ -262,10 +275,12 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
262
275
  };
263
276
  const scheduleNextPreparation = (child) => {
264
277
  clearRunningUpdatePoll();
265
- if (preparedTarget !== undefined || updateStarted || !automaticMode()) return;
278
+ if (preparedTarget !== undefined || updateStarted) return;
266
279
  runningUpdatePollTimer = (options.scheduleRunningUpdateRecheck || scheduleRunningUpdateRecheck)(() => {
267
280
  runningUpdatePollTimer = undefined;
268
- startPreparation(child);
281
+ refreshRunningUpdateMode();
282
+ if (automaticMode()) startPreparation(child);
283
+ else scheduleNextPreparation(child);
269
284
  });
270
285
  };
271
286
  const announcePrepared = (child) => {
@@ -309,7 +324,9 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
309
324
  onMessage(message, child) {
310
325
  if (message?.type === RUNTIME_READY_MESSAGE) {
311
326
  runtimeReady = true;
312
- startPreparation(child);
327
+ refreshRunningUpdateMode();
328
+ if (automaticMode()) startPreparation(child);
329
+ else scheduleNextPreparation(child);
313
330
  }
314
331
  if (message?.type === RUNNING_UPDATE_MODE_MESSAGE && typeof message.mode === 'string') {
315
332
  runningUpdateMode = normalizeRunningUpdateMode(message.mode);
@@ -322,7 +339,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
322
339
  updateStarted = false;
323
340
  startPreparation(child);
324
341
  }
325
- }
342
+ } else if (runtimeReady) scheduleNextPreparation(child);
326
343
  }
327
344
  if (message?.type === RUNNING_UPDATE_HANDOFF_MESSAGE
328
345
  && typeof message.sessionId === 'string'
@@ -343,6 +360,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
343
360
  && preparedTarget !== undefined
344
361
  && handoffSessionId !== undefined
345
362
  && handoffMode !== undefined) {
363
+ writeRunningUpdateHandoffNotice(options.runningUpdateNoticeOutput || process.stdout);
346
364
  const handoff = await handoffRuntime({
347
365
  target: preparedTarget,
348
366
  previous: { packageRoot, version: readPackageVersion() },
@@ -705,4 +723,5 @@ module.exports = {
705
723
  shouldDetachProtectedCore,
706
724
  spawnManagedLauncher,
707
725
  superviseProtectedCore,
726
+ writeRunningUpdateHandoffNotice,
708
727
  };
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+
3
+ function textWidth(value) {
4
+ return [...String(value ?? '')].length;
5
+ }
6
+
7
+ function wrapMediaActivityChainItems(items, width, options = {}) {
8
+ const safeItems = Array.isArray(items) ? items : [];
9
+ const safeWidth = Math.max(1, Math.floor(Number(width) || 1));
10
+ const measure = typeof options.measure === 'function' ? options.measure : textWidth;
11
+ const firstPrefixWidth = Math.max(0, Number(options.firstPrefixWidth) || 0);
12
+ const continuationPrefixWidth = Math.max(0, Number(options.continuationPrefixWidth) || 0);
13
+ const separatorWidth = Math.max(0, Number(options.separatorWidth) || 0);
14
+ const rows = [];
15
+ let row = [];
16
+ let rowWidth = firstPrefixWidth;
17
+
18
+ for (const item of safeItems) {
19
+ const itemWidth = Math.max(0, measure(item));
20
+ const candidateWidth = rowWidth + (row.length > 0 ? separatorWidth : 0) + itemWidth;
21
+ if (row.length > 0 && candidateWidth > safeWidth) {
22
+ rows.push(row);
23
+ row = [];
24
+ rowWidth = continuationPrefixWidth;
25
+ }
26
+ row.push(item);
27
+ rowWidth += (row.length > 1 ? separatorWidth : 0) + itemWidth;
28
+ }
29
+
30
+ if (row.length > 0) rows.push(row);
31
+ return rows;
32
+ }
33
+
34
+ module.exports = { wrapMediaActivityChainItems };
@@ -73,6 +73,20 @@ function searchDeferredTools(tools, query) {
73
73
  const tokens = normalized.split(/\s+/).filter(Boolean);
74
74
  const requiredNameTokens = tokens.filter((token) => token.startsWith('+')).map((token) => token.slice(1)).filter(Boolean);
75
75
  const searchTokens = tokens.filter((token) => !token.startsWith('+'));
76
+ const eligibleTools = tools.filter((tool) => {
77
+ const name = String(tool?.name || '').toLowerCase();
78
+ return requiredNameTokens.every((token) => name.includes(token));
79
+ });
80
+ const firstSelector = searchTokens[0];
81
+ if (firstSelector) {
82
+ const exactNameMatches = eligibleTools.filter((tool) => String(tool?.name || '').toLowerCase() === firstSelector);
83
+ if (exactNameMatches.length === 1) return exactNameMatches;
84
+ const exactLeafMatches = eligibleTools.filter((tool) => {
85
+ const name = String(tool?.name || '').toLowerCase();
86
+ return name.split(/__|:/).at(-1) === firstSelector;
87
+ });
88
+ if (exactLeafMatches.length === 1) return exactLeafMatches;
89
+ }
76
90
  return tools.map((tool) => {
77
91
  const name = String(tool?.name || '').toLowerCase();
78
92
  const description = String(tool?.description || '').toLowerCase();
package/blun.mjs CHANGED
@@ -500173,6 +500173,8 @@ registerUiCatalogFragment({
500173
500173
  "media.phase.analyzing": "Wird analysiert"
500174
500174
  }
500175
500175
  });
500176
+ var wrapMediaActivityChainItems;
500177
+ ({ wrapMediaActivityChainItems } = createRequire(import.meta.url)("./bin/media-activity-layout-policy.cjs"));
500176
500178
  function mediaActivityStatusKey(value) {
500177
500179
  return String(value ?? "processing").trim().toLowerCase().replaceAll(/[^a-z0-9]+/g, "-");
500178
500180
  }
@@ -500392,16 +500394,24 @@ var MediaActivityComponent = class {
500392
500394
  const line = `${currentTheme.boldFg("primary", "●")} ${currentTheme.boldFg("primary", kind)} · ${phase}${details.length === 0 ? "" : ` · ${details.join(" · ")}`}${progress}`;
500393
500395
  return truncateToWidth(line, Math.max(1, width), "…");
500394
500396
  }
500395
- chainLine(job, width) {
500397
+ chainLines(job, width) {
500398
+ const separator = currentTheme.fg("textDim", " · ");
500399
+ const prefix = ` ${currentTheme.fg("textDim", mediaUiText("media.activity.chain"))} · `;
500400
+ const continuationPrefix = " ";
500396
500401
  const chain = mediaActivityChainStates(job).map(({ phase, state }) => {
500397
500402
  const symbol = state === "done" ? "■" : state === "active" ? "▶" : "□";
500398
500403
  const label = mediaActivityLabel("media.phase", phase, phase);
500399
500404
  const text = `${symbol} ${label}`;
500400
- if (state === "done") return currentTheme.fg("success", text);
500401
- if (state === "active") return currentTheme.boldFg("primary", text);
500402
- return currentTheme.fg("textDim", text);
500405
+ if (state === "done") return { plain: text, styled: currentTheme.fg("success", text) };
500406
+ if (state === "active") return { plain: text, styled: currentTheme.boldFg("primary", text) };
500407
+ return { plain: text, styled: currentTheme.fg("textDim", text) };
500403
500408
  });
500404
- return truncateToWidth(` ${currentTheme.fg("textDim", mediaUiText("media.activity.chain"))} · ${chain.join(currentTheme.fg("textDim", " · "))}`, Math.max(1, width), "…");
500409
+ return wrapMediaActivityChainItems(chain, Math.max(1, width), {
500410
+ measure: (item) => visibleWidth(item.plain),
500411
+ firstPrefixWidth: visibleWidth(prefix),
500412
+ continuationPrefixWidth: visibleWidth(continuationPrefix),
500413
+ separatorWidth: visibleWidth(" · ")
500414
+ }).map((row, index) => truncateToWidth(`${index === 0 ? prefix : continuationPrefix}${row.map((item) => item.styled).join(separator)}`, Math.max(1, width), "…"));
500405
500415
  }
500406
500416
  previewImage(job) {
500407
500417
  let previewDataBase64 = typeof job.previewDataBase64 === "string" ? job.previewDataBase64 : "";
@@ -500434,7 +500444,7 @@ var MediaActivityComponent = class {
500434
500444
  return image;
500435
500445
  }
500436
500446
  extraLines(job, width) {
500437
- const lines = [this.chainLine(job, width)];
500447
+ const lines = [...this.chainLines(job, width)];
500438
500448
  if (Array.isArray(job.waveform) && job.waveform.length > 0) {
500439
500449
  const label = `${mediaUiText("media.detail.waveform")} · `;
500440
500450
  const waveform = renderMediaWaveform(job.waveform, Math.max(1, width - visibleWidth(label) - 2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.176",
3
+ "version": "9.1.178",
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": {