blun-king-cli 9.1.183 → 9.1.185

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.
@@ -34,6 +34,7 @@ const {
34
34
  RUNNING_UPDATE_MODE_MESSAGE,
35
35
  RUNNING_UPDATE_PREPARED_MESSAGE,
36
36
  activateRuntime,
37
+ handoffArgsForMode,
37
38
  handoffRuntime,
38
39
  prepareRunningUpdate,
39
40
  readActiveRuntime,
@@ -156,14 +157,18 @@ function resolveLauncherPrivatePaths(options = {}) {
156
157
  };
157
158
  }
158
159
 
159
- function readPackageVersion() {
160
- const { version } = JSON.parse(fs.readFileSync(path.join(PKG, 'package.json'), 'utf8'));
160
+ function readPackageVersionAt(packageRoot = PKG) {
161
+ const { version } = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
161
162
  if (typeof version !== 'string' || version.length === 0) {
162
163
  throw new Error('Ungueltige Paketversion in package.json');
163
164
  }
164
165
  return version;
165
166
  }
166
167
 
168
+ function readPackageVersion() {
169
+ return readPackageVersionAt(PKG);
170
+ }
171
+
167
172
  function shouldDetachProtectedCore(options = {}) {
168
173
  const platform = options.platform || process.platform;
169
174
  const stdinIsTTY = Object.hasOwn(options, 'stdinIsTTY')
@@ -321,38 +326,45 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
321
326
  scheduleNextPreparation(child);
322
327
  });
323
328
  };
324
- const core = (options.spawnProtectedCore || spawnProtectedCore)(args, env, cwd, {
329
+ const handleCoreMessage = (message, child) => {
330
+ if (message?.type === RUNTIME_READY_MESSAGE) {
331
+ runtimeReady = true;
332
+ refreshRunningUpdateMode();
333
+ if (automaticMode()) startPreparation(child);
334
+ else scheduleNextPreparation(child);
335
+ }
336
+ if (message?.type === RUNNING_UPDATE_MODE_MESSAGE && typeof message.mode === 'string') {
337
+ runningUpdateMode = normalizeRunningUpdateMode(message.mode);
338
+ handoffSessionId = undefined;
339
+ handoffMode = undefined;
340
+ clearRunningUpdatePoll();
341
+ if (automaticMode()) {
342
+ if (preparedTarget !== undefined) announcePrepared(child);
343
+ else if (runtimeReady) {
344
+ updateStarted = false;
345
+ startPreparation(child);
346
+ }
347
+ } else if (runtimeReady) scheduleNextPreparation(child);
348
+ }
349
+ if (message?.type === RUNNING_UPDATE_HANDOFF_MESSAGE
350
+ && typeof message.sessionId === 'string'
351
+ && message.sessionId.length > 0
352
+ && message.mode === runningUpdateMode
353
+ && automaticMode()) {
354
+ handoffSessionId = message.sessionId;
355
+ handoffMode = runningUpdateMode;
356
+ }
357
+ };
358
+ const spawnCore = options.spawnProtectedCore || spawnProtectedCore;
359
+ const core = options.existingCore || spawnCore(args, env, cwd, {
325
360
  packageRoot,
326
- onMessage(message, child) {
327
- if (message?.type === RUNTIME_READY_MESSAGE) {
328
- runtimeReady = true;
329
- refreshRunningUpdateMode();
330
- if (automaticMode()) startPreparation(child);
331
- else scheduleNextPreparation(child);
332
- }
333
- if (message?.type === RUNNING_UPDATE_MODE_MESSAGE && typeof message.mode === 'string') {
334
- runningUpdateMode = normalizeRunningUpdateMode(message.mode);
335
- handoffSessionId = undefined;
336
- handoffMode = undefined;
337
- clearRunningUpdatePoll();
338
- if (automaticMode()) {
339
- if (preparedTarget !== undefined) announcePrepared(child);
340
- else if (runtimeReady) {
341
- updateStarted = false;
342
- startPreparation(child);
343
- }
344
- } else if (runtimeReady) scheduleNextPreparation(child);
345
- }
346
- if (message?.type === RUNNING_UPDATE_HANDOFF_MESSAGE
347
- && typeof message.sessionId === 'string'
348
- && message.sessionId.length > 0
349
- && message.mode === runningUpdateMode
350
- && automaticMode()) {
351
- handoffSessionId = message.sessionId;
352
- handoffMode = runningUpdateMode;
353
- }
354
- },
361
+ onMessage: handleCoreMessage,
355
362
  });
363
+ let existingMessageHandler;
364
+ if (options.existingCore) {
365
+ existingMessageHandler = (message) => handleCoreMessage(message, core.child);
366
+ core.child.on('message', existingMessageHandler);
367
+ }
356
368
  const loaded = await core.loaded;
357
369
  if (loaded && !runtimeReady) {
358
370
  // Core load is an independent readiness signal. Start the download even
@@ -366,6 +378,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
366
378
  await releaseNotice();
367
379
  const result = await core.completed;
368
380
  clearRunningUpdatePoll();
381
+ if (existingMessageHandler) core.child.off('message', existingMessageHandler);
369
382
  if (result.error) throw result.error;
370
383
  if (result.code === RUNNING_UPDATE_HANDOFF_EXIT_CODE
371
384
  && preparedTarget !== undefined
@@ -374,14 +387,14 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
374
387
  writeRunningUpdateHandoffNotice(options.runningUpdateNoticeOutput || process.stdout);
375
388
  const handoff = await handoffRuntime({
376
389
  target: preparedTarget,
377
- previous: { packageRoot, version: readPackageVersion() },
390
+ previous: { packageRoot, version: readPackageVersionAt(packageRoot) },
378
391
  sessionId: handoffSessionId,
379
392
  mode: handoffMode,
380
393
  args,
381
394
  probeTarget: options.probeRunningUpdate || (() => true),
382
395
  stopOld: async () => {},
383
396
  startCore: async ({ packageRoot: nextRoot, args: nextArgs }) => {
384
- const nextCore = spawnProtectedCore(nextArgs, env, cwd, { packageRoot: nextRoot });
397
+ const nextCore = spawnCore(nextArgs, env, cwd, { packageRoot: nextRoot });
385
398
  const nextLoaded = await nextCore.loaded;
386
399
  const ready = nextLoaded && await waitForRuntimeReady(nextCore, options.readyTimeoutMs);
387
400
  if (!ready) {
@@ -394,9 +407,12 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
394
407
  });
395
408
  const resumed = handoff.core;
396
409
  if (resumed === undefined || resumed.ready !== true) return 1;
397
- const resumedResult = await resumed.completed;
398
- if (resumedResult.error) throw resumedResult.error;
399
- return exitCodeForChild(resumedResult, true);
410
+ const resumedArgs = handoffArgsForMode(args, handoffMode, handoffSessionId);
411
+ return superviseProtectedCore(resumedArgs, env, cwd, async () => {}, {
412
+ ...options,
413
+ existingCore: resumed,
414
+ packageRoot: handoff.runtime.packageRoot,
415
+ });
400
416
  }
401
417
  return exitCodeForChild(result, loaded);
402
418
  }
@@ -29,11 +29,37 @@ const CORE_TOOL_NAMES = Object.freeze([
29
29
  'Grep',
30
30
  'Write',
31
31
  'Glob',
32
- 'GenerateImage',
33
- 'GenerateVideo',
34
32
  'mcp__plugin-telegram_telegram__reply',
35
33
  ]);
36
34
 
35
+ const IMAGE_MEDIA_TERM_RE = /(?:^|[^\p{L}])(?:bild(?:er)?|foto(?:s)?|grafik(?:en)?|illustration(?:en)?|logo(?:s)?|image|images|photo|photos|picture|pictures|illustration|illustrations|visual|visuals)(?=$|[^\p{L}])/u;
36
+ const VIDEO_MEDIA_TERM_RE = /(?:^|[^\p{L}])(?:video(?:s)?|clip(?:s)?|film(?:e)?|animation(?:en)?|movie|movies)(?=$|[^\p{L}])/u;
37
+ const ANIMATE_ACTION_RE = /(?:^|[^\p{L}])(?:animier(?:e|en|t)?|animate|animated|animating)(?=$|[^\p{L}])/u;
38
+ const CREATE_ACTION_RE = /(?:^|[^\p{L}])(?:erstell(?:e|en|t)?|generier(?:e|en|t)?|erzeug(?:e|en|t)?|produzier(?:e|en|t)?|zeichn(?:e|en|et)?|mal(?:e|en|t)?|render(?:e|n|t)?|mach(?:e|en|t)?|create|creates|creating|generate|generates|generating|make|makes|making|draw|draws|drawing|paint|paints|painting|render|renders|rendering|produce|produces|producing)(?=$|[^\p{L}])/u;
39
+ const REQUEST_PREFIX_RE = /^(?:bitte\s+|please\s+)?(?:erstell|generier|erzeug|produzier|zeichn|mal|render|mach|animier|create|generate|make|draw|paint|render|produce|animate)/u;
40
+ const REQUEST_PHRASE_RE = /(?:^|[^\p{L}])(?:bitte|kannst du|könntest du|ich möchte|ich will|ich brauche|please|can you|could you|i want|i need)(?=$|[^\p{L}])/u;
41
+
42
+ function mediaGenerationToolNamesForText(value) {
43
+ const text = String(value || '').normalize('NFKC').trim().toLowerCase();
44
+ const selected = new Set();
45
+ if (!text) return selected;
46
+ if (/(?:^|[^a-z])generateimage(?=$|[^a-z])/u.test(text)) selected.add('GenerateImage');
47
+ if (/(?:^|[^a-z])generatevideo(?=$|[^a-z])/u.test(text)) selected.add('GenerateVideo');
48
+ if (selected.size > 0) return selected;
49
+
50
+ const animate = ANIMATE_ACTION_RE.test(text);
51
+ const create = CREATE_ACTION_RE.test(text);
52
+ const explicitRequest = REQUEST_PREFIX_RE.test(text) || REQUEST_PHRASE_RE.test(text);
53
+ if (!explicitRequest || (!create && !animate)) return selected;
54
+ if (animate && (IMAGE_MEDIA_TERM_RE.test(text) || VIDEO_MEDIA_TERM_RE.test(text))) {
55
+ selected.add('GenerateVideo');
56
+ return selected;
57
+ }
58
+ if (IMAGE_MEDIA_TERM_RE.test(text)) selected.add('GenerateImage');
59
+ if (VIDEO_MEDIA_TERM_RE.test(text)) selected.add('GenerateVideo');
60
+ return selected;
61
+ }
62
+
37
63
  function toolSchemaBudgetTokens(maxContextTokens) {
38
64
  const context = Number(maxContextTokens);
39
65
  if (!Number.isFinite(context) || context <= 0) return TOOL_SCHEMA_MAX_TOKENS;
@@ -247,5 +273,6 @@ module.exports = {
247
273
  createDeferredToolLoader,
248
274
  deferredToolCatalog,
249
275
  deferredToolNames,
276
+ mediaGenerationToolNamesForText,
250
277
  toolSchemaBudgetTokens,
251
278
  };
package/blun.mjs CHANGED
@@ -260959,10 +260959,10 @@ function blunPendingMediaSystemPrompt(systemPrompt, pendingMediaJobIds) {
260959
260959
  if (pendingMediaJobIds.length === 0) return systemPrompt;
260960
260960
  return `${systemPrompt}\n\n## Pending BLUN media\n\nThe following media jobs were already accepted and are still pending: ${pendingMediaJobIds.join(", ")}. Call GetMedia exactly once for each listed id before replying. If a job is still processing, report that status truthfully and wait for a later turn; do not claim that media tools are unavailable.`;
260961
260961
  }
260962
- function blunFastConversationTools(tools, input, pendingMediaJobIds = []) {
260962
+ function blunFastConversationTools(tools, input, pendingMediaJobIds = [], requiredToolNames = /* @__PURE__ */ new Set()) {
260963
260963
  const telegramTurn = BLUN_TELEGRAM_CHANNEL_RE.test(blunExtractText(input));
260964
260964
  const mediaPending = pendingMediaJobIds.length > 0;
260965
- return tools.filter((tool) => telegramTurn && BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name) || mediaPending && tool.name === "GetMedia");
260965
+ return tools.filter((tool) => telegramTurn && BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name) || mediaPending && tool.name === "GetMedia" || requiredToolNames.has(tool.name));
260966
260966
  }
260967
260967
  /**
260968
260968
  * Keep frequently used native tools resident and expose every other tool by
@@ -261208,7 +261208,7 @@ function toolResultText(result) {
261208
261208
  function abandonedToolResultOutput(ended) {
261209
261209
  return `Tool call did not complete: ${ended.reason === "cancelled" ? "the turn was cancelled" : ended.reason === "failed" ? `the turn failed${ended.error !== void 0 ? ` (${ended.error.message})` : ""}` : "the turn ended"} before its result was recorded. Do not assume the tool completed successfully.`;
261210
261210
  }
261211
- var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, toolSchemaBudgetTokens, projectRecurringCronHistory, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
261211
+ var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, mediaGenerationToolNamesForText, toolSchemaBudgetTokens, projectRecurringCronHistory, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
261212
261212
  var init_turn = __esmMin((() => {
261213
261213
  init_dist$4();
261214
261214
  init_src$4();
@@ -261225,7 +261225,7 @@ var init_turn = __esmMin((() => {
261225
261225
  init_tool_result_budget();
261226
261226
  init_user_message_offload();
261227
261227
  init_assistant_message_offload();
261228
- ({ CORE_TOOL_NAMES: BLUN_CORE_TOOL_NAMES, createDeferredToolLoader, toolSchemaBudgetTokens } = createRequire(import.meta.url)("./bin/turn-tool-performance-policy.cjs"));
261228
+ ({ CORE_TOOL_NAMES: BLUN_CORE_TOOL_NAMES, createDeferredToolLoader, mediaGenerationToolNamesForText, toolSchemaBudgetTokens } = createRequire(import.meta.url)("./bin/turn-tool-performance-policy.cjs"));
261229
261229
  ({ projectRecurringCronHistory } = createRequire(import.meta.url)("./bin/recurring-cron-history-policy.cjs"));
261230
261230
  BLUN_LEAN_TOOL_NAMES = new Set(BLUN_CORE_TOOL_NAMES);
261231
261231
  BLUN_ATTACHMENT_MARKER_RE = /\b(?:attachment_file_id|telegram-anhang|telegram attachment)\b/i;
@@ -261800,6 +261800,8 @@ var init_turn = __esmMin((() => {
261800
261800
  const turnThinkingEffort = turnHasAttachment ? void 0 : selectThinkingEffortForTurn(blunExtractText(blunThinkingIntentInput(input)), origin.kind);
261801
261801
  const fastConversation = turnThinkingEffort === "off" || turnThinkingEffort === "low";
261802
261802
  const pendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
261803
+ const requiredToolNames = mediaGenerationToolNamesForText(blunExtractText(blunThinkingIntentInput(input)));
261804
+ if (turnHasAttachment) requiredToolNames.add("mcp__plugin-telegram_telegram__download_attachment");
261803
261805
  const turnSystemPrompt = pendingMediaJobIds.length > 0 ? blunPendingMediaSystemPrompt(fastConversation ? this.agent.fastConversationSystemPrompt : this.agent.effectiveSystemPrompt, pendingMediaJobIds) : fastConversation ? this.agent.fastConversationSystemPrompt : void 0;
261804
261806
  const turnLLM = this.agent.llmForTurn(turnThinkingEffort, turnSystemPrompt);
261805
261807
  let previousStepToolOutcome = "initial";
@@ -261815,9 +261817,9 @@ var init_turn = __esmMin((() => {
261815
261817
  const compactConversationTool = originTools.find((tool) => tool.name === "CompactConversation");
261816
261818
  const eligibleTools = originTools.filter((tool) => tool.name !== "CompactConversation" || this.agent.fullCompaction.isProactiveCompactionEligible());
261817
261819
  const toolSelection = fastConversation ? {
261818
- tools: [...blunFastConversationTools(eligibleTools, input, pendingMediaJobIds)],
261820
+ tools: [...blunFastConversationTools(eligibleTools, input, pendingMediaJobIds, requiredToolNames)],
261819
261821
  deferredToolCount: 0
261820
- } : turnNeedsTools ? blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames, turnHasAttachment ? new Set(["mcp__plugin-telegram_telegram__download_attachment"]) : void 0) : {
261822
+ } : turnNeedsTools ? blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames, requiredToolNames) : {
261821
261823
  tools: [],
261822
261824
  deferredToolCount: 0
261823
261825
  };
@@ -261884,7 +261886,8 @@ var init_turn = __esmMin((() => {
261884
261886
  const steerThinkingEffort = "low";
261885
261887
  const steerPendingMediaJobIds = this.agent.toolServices?.media?.pendingMediaJobIds?.() ?? [];
261886
261888
  const steerLLM = this.agent.llmForTurn(steerThinkingEffort, blunPendingMediaSystemPrompt(this.agent.fastConversationSystemPrompt, steerPendingMediaJobIds));
261887
- const steerTools = [...blunFastConversationTools(eligibleTools, steerInput, steerPendingMediaJobIds)];
261889
+ const steerRequiredToolNames = mediaGenerationToolNamesForText(blunExtractText(blunThinkingIntentInput(steerInput)));
261890
+ const steerTools = [...blunFastConversationTools(eligibleTools, steerInput, steerPendingMediaJobIds, steerRequiredToolNames)];
261888
261891
  const steerHistory = () => blunFastConversationHistory(this.agent.context.history);
261889
261892
  const buildSteerMessages = () => this.agent.context.project(steerHistory(), { dropOrphanResults: true });
261890
261893
  const buildSteerMessagesStrict = () => this.agent.context.project(steerHistory(), {
@@ -514883,7 +514886,7 @@ function notifyRunningRuntimeReady(tui) {
514883
514886
  }
514884
514887
  function requestRunningUpdateAtSafeBoundary(tui) {
514885
514888
  if (tui.runningUpdatePreparedVersion === void 0 || tui.runningUpdatePreparedMode === void 0 || tui.runningUpdateHandoffStarted || !process.connected) return false;
514886
- if (!isSafeRuntimeBoundary({
514889
+ const boundaryState = () => ({
514887
514890
  isShuttingDown: tui.isShuttingDown,
514888
514891
  streamingPhase: tui.state.appState.streamingPhase,
514889
514892
  isCompacting: tui.state.appState.isCompacting,
@@ -514891,7 +514894,8 @@ function requestRunningUpdateAtSafeBoundary(tui) {
514891
514894
  activeToolCalls: tui.streamingUI.hasActiveToolCalls() ? 1 : 0,
514892
514895
  shellCommands: tui.shellOutputStreams.size,
514893
514896
  queueCommandRunning: tui.queueCommandRunning
514894
- })) return false;
514897
+ });
514898
+ if (!isSafeRuntimeBoundary(boundaryState())) return false;
514895
514899
  const sessionId = tui.getCurrentSessionId();
514896
514900
  if (sessionId.length === 0) return false;
514897
514901
  tui.runningUpdateHandoffStarted = true;
@@ -514901,12 +514905,17 @@ function requestRunningUpdateAtSafeBoundary(tui) {
514901
514905
  sessionId,
514902
514906
  version: tui.runningUpdatePreparedVersion,
514903
514907
  mode: tui.runningUpdatePreparedMode
514908
+ }, (error) => {
514909
+ if (error || !isSafeRuntimeBoundary(boundaryState())) {
514910
+ tui.runningUpdateHandoffStarted = false;
514911
+ return;
514912
+ }
514913
+ void tui.stop(RUNNING_UPDATE_HANDOFF_EXIT_CODE);
514904
514914
  });
514905
514915
  } catch {
514906
514916
  tui.runningUpdateHandoffStarted = false;
514907
514917
  return false;
514908
514918
  }
514909
- void tui.stop(RUNNING_UPDATE_HANDOFF_EXIT_CODE);
514910
514919
  return true;
514911
514920
  }
514912
514921
  function installRunningUpdateListener(tui) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.183",
3
+ "version": "9.1.185",
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": {