blun-king-cli 9.1.46 → 9.1.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LIESMICH.txt +11 -1
  2. package/README.md +12 -1
  3. package/blun.mjs +409 -64
  4. package/package.json +1 -1
package/LIESMICH.txt CHANGED
@@ -9,7 +9,7 @@ Installation
9
9
  ------------
10
10
  Die geprüfte Version exakt global installieren:
11
11
 
12
- npm install -g blun-king-cli@9.1.46
12
+ npm install -g blun-king-cli@9.1.48
13
13
 
14
14
  Start
15
15
  -----
@@ -31,6 +31,16 @@ Die Grenzwerte lassen sich vor dem Start über diese Umgebungsvariablen ändern:
31
31
  BLUN_TURN_WATCHDOG_IDLE_MINUTES
32
32
  BLUN_TURN_WATCHDOG_MAX_FAILED_REPETITIONS
33
33
 
34
+ Befehle und Loops während eines laufenden Zugs
35
+ ------------------------------------------------
36
+ Slash-Befehle, die einen freien Agenten benötigen, werden während eines
37
+ laufenden Zugs in ihrer Eingabereihenfolge vorgemerkt und danach ausgeführt.
38
+ Status-, Stopp- und andere sichere Steuerbefehle bleiben sofort verfügbar.
39
+
40
+ Ein neuer /loop ersetzt den bisherigen Loop derselben Sitzung. Dabei bleibt
41
+ genau ein gespeicherter Loop aktiv. /loop stop, /loop pause und /loop status
42
+ wirken auch dann sofort, wenn der Agent gerade arbeitet.
43
+
34
44
  Nachweisbare Arbeitsabläufe
35
45
  ---------------------------
36
46
 
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.46
12
+ npm install -g blun-king-cli@9.1.48
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
@@ -45,6 +45,17 @@ Die Grenzwerte lassen sich vor dem Start mit
45
45
  `BLUN_TURN_WATCHDOG_IDLE_MINUTES` und
46
46
  `BLUN_TURN_WATCHDOG_MAX_FAILED_REPETITIONS` ändern.
47
47
 
48
+ ## Befehle und Loops während eines laufenden Zugs
49
+
50
+ Slash-Befehle, die einen freien Agenten benötigen, werden während eines
51
+ laufenden Zugs in ihrer Eingabereihenfolge vorgemerkt und danach ausgeführt.
52
+ Status-, Stopp- und andere sichere Steuerbefehle bleiben sofort verfügbar.
53
+
54
+ Ein neuer `/loop` ersetzt den bisherigen Loop derselben Sitzung. Dabei bleibt
55
+ genau ein gespeicherter Loop aktiv; der neue Auftrag, das neue Intervall und
56
+ der neue Startzeitpunkt gelten vollständig. `/loop stop`, `/loop pause` und
57
+ `/loop status` wirken auch dann sofort, wenn der Agent gerade arbeitet.
58
+
48
59
  Beim ersten Start werden das Telegram-Plugin und die mitgelieferten Skills
49
60
  eingerichtet. Die Anmeldung erfolgt anschließend in der
50
61
  Konsole mit `/login` über den BLUN-OAuth-Server. Das Paket erzeugt keine
package/blun.mjs CHANGED
@@ -75066,10 +75066,6 @@ function estimateCompactionStageCount(initialInputTokens, safeRequestLimitTokens
75066
75066
  if (safeRequestLimitTokens <= 0) return currentStage;
75067
75067
  return Math.max(currentStage, Math.ceil(initialInputTokens / safeRequestLimitTokens));
75068
75068
  }
75069
- function estimateCompactionProgressPercent(stage, estimatedStageCount) {
75070
- if (estimatedStageCount <= 0) return 0;
75071
- return Math.min(99, Math.floor(stage / estimatedStageCount * 100));
75072
- }
75073
75069
  function estimateCompactionWindowUsagePercent(requestTokens, maxContextTokens) {
75074
75070
  if (maxContextTokens <= 0) return void 0;
75075
75071
  return Math.min(100, Math.max(0, Math.ceil(requestTokens / maxContextTokens * 100)));
@@ -75554,9 +75550,11 @@ var init_full = __esmMin((() => {
75554
75550
  charsReceived = 0;
75555
75551
  const stage = hierarchicalPassCount + 1;
75556
75552
  const estimatedStageCount = estimateCompactionStageCount(initialCompactionRequestTokens, safeCompactionRequestLimit, stage);
75557
- const estimatedProgressPercent = estimateCompactionProgressPercent(stage, estimatedStageCount);
75558
75553
  const windowUsagePercent = estimateCompactionWindowUsagePercent(estimatedCompactionRequestTokens, compactionRequestLimit);
75559
75554
  this.agent.log.info("compaction stage request", {
75555
+ requestPurpose: "compaction",
75556
+ toolSuppressionReason: "compaction_summary",
75557
+ selectedToolCount: compactionTools.length,
75560
75558
  source: data.source,
75561
75559
  stage,
75562
75560
  estimatedStageCount,
@@ -75575,7 +75573,6 @@ var init_full = __esmMin((() => {
75575
75573
  stage,
75576
75574
  estimatedStageCount,
75577
75575
  estimatedInputTokens: estimatedCompactionRequestTokens,
75578
- estimatedProgressPercent,
75579
75576
  ...windowUsagePercent === void 0 ? {} : { windowUsagePercent },
75580
75577
  charsReceived,
75581
75578
  attempt: attemptCount,
@@ -77685,12 +77682,29 @@ var init_session_loop = __esmMin((() => {
77685
77682
  }
77686
77683
  createLoop(input) {
77687
77684
  if (process.env["BLUN_DISABLE_CRON"] === "1") throw new BlunError(ErrorCodes.LOOP_DISABLED, "Recurring loops are disabled");
77688
- if (this.currentTask() !== void 0) throw new BlunError(ErrorCodes.LOOP_ALREADY_EXISTS, "A recurring loop already exists");
77689
- if (this.cron.store.list().length >= 50) throw new BlunError(ErrorCodes.LOOP_LIMIT_REACHED, "Session cron task limit reached");
77685
+ const existing = this.currentTask();
77686
+ if (existing === void 0 && this.cron.store.list().length >= 50) throw new BlunError(ErrorCodes.LOOP_LIMIT_REACHED, "Session cron task limit reached");
77690
77687
  const parsed = parseLoopInterval(input.interval);
77691
77688
  const prompt = input.prompt.trim();
77692
77689
  if (prompt.length === 0) throw new BlunError(ErrorCodes.LOOP_PROMPT_EMPTY, "Loop prompt cannot be empty");
77693
77690
  if (Buffer.byteLength(prompt, "utf8") > MAX_LOOP_PROMPT_BYTES) throw new BlunError(ErrorCodes.LOOP_PROMPT_TOO_LONG, `Loop prompt cannot exceed ${String(MAX_LOOP_PROMPT_BYTES)} UTF-8 bytes`);
77691
+ if (existing !== void 0) {
77692
+ const now = this.cron.clocks.wallNow();
77693
+ const task = this.requireUpdatedTask(existing.id, {
77694
+ cron: parsed.cron,
77695
+ prompt,
77696
+ recurring: true,
77697
+ owner: "session-loop",
77698
+ loopInterval: parsed.interval,
77699
+ paused: false,
77700
+ autoExpire: false,
77701
+ createdAt: now,
77702
+ scheduleFromAt: now,
77703
+ lastFiredAt: void 0
77704
+ });
77705
+ this.cron.emitScheduled(task);
77706
+ return this.snapshot(task);
77707
+ }
77694
77708
  const task = this.cron.addTask({
77695
77709
  cron: parsed.cron,
77696
77710
  prompt,
@@ -259752,6 +259766,12 @@ function blunSelectTurnTools(tools, maxContextTokens) {
259752
259766
  const lean = tools.filter((tool) => BLUN_LEAN_TOOL_NAMES.has(tool.name) || BLUN_LEAN_KEEP_RE.test(tool.name));
259753
259767
  return lean.length > 0 ? lean : tools;
259754
259768
  }
259769
+ function blunToolSuppressionReason(turnNeedsTools, eligibleTools, selectedTools) {
259770
+ if (!turnNeedsTools) return "greeting_optimization";
259771
+ if (eligibleTools.length === 0) return "no_eligible_tools";
259772
+ if (selectedTools.length < eligibleTools.length) return "context_budget_lean_set";
259773
+ return "none";
259774
+ }
259755
259775
  function isGoalOutcomeReminderOrigin(origin) {
259756
259776
  return origin?.kind === "system_trigger" && (origin.name === "goal_completion" || origin.name === "goal_blocked");
259757
259777
  }
@@ -260566,6 +260586,13 @@ var init_turn = __esmMin((() => {
260566
260586
  try {
260567
260587
  const eligibleTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools), origin);
260568
260588
  const selectedTools = turnNeedsTools ? blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens) : [];
260589
+ const toolSuppressionReason = blunToolSuppressionReason(turnNeedsTools, eligibleTools, selectedTools);
260590
+ this.agent.log.info("turn request tools", {
260591
+ requestPurpose: "conversation",
260592
+ toolSuppressionReason,
260593
+ eligibleToolCount: eligibleTools.length,
260594
+ selectedToolCount: selectedTools.length
260595
+ });
260569
260596
  return (await runTurn({
260570
260597
  turnId: String(turnId),
260571
260598
  signal,
@@ -261917,6 +261944,45 @@ function contentPartFor(mimeType, url) {
261917
261944
  function errorMessage$10(error) {
261918
261945
  return error instanceof Error ? error.message : String(error);
261919
261946
  }
261947
+ const MEDIA_PROGRESS_CUSTOM_KIND = "blun.media.progress";
261948
+ function mediaKindForToolName(name) {
261949
+ switch (name) {
261950
+ case "GenerateImage": return "image";
261951
+ case "GenerateVideo": return "video";
261952
+ case "GenerateSpeech": return "voice";
261953
+ case "UnderstandImage": return "image-analysis";
261954
+ case "UnderstandVideo": return "video-analysis";
261955
+ case "DubVideo": return "dubbing";
261956
+ case "LipSyncMedia": return "lipsync";
261957
+ case "GetMedia": return "media";
261958
+ default: return "media";
261959
+ }
261960
+ }
261961
+ function isMediaToolName(name) {
261962
+ return [
261963
+ "GenerateImage",
261964
+ "GenerateVideo",
261965
+ "GenerateSpeech",
261966
+ "UnderstandImage",
261967
+ "UnderstandVideo",
261968
+ "DubVideo",
261969
+ "LipSyncMedia",
261970
+ "GetMedia"
261971
+ ].includes(name);
261972
+ }
261973
+ function emitMediaProgress(ctx, toolName, phase, data = {}) {
261974
+ ctx.onUpdate({
261975
+ kind: "custom",
261976
+ customKind: MEDIA_PROGRESS_CUSTOM_KIND,
261977
+ customData: {
261978
+ toolName,
261979
+ mediaKind: data.mediaKind ?? mediaKindForToolName(toolName),
261980
+ phase,
261981
+ observedAt: Date.now(),
261982
+ ...data
261983
+ }
261984
+ });
261985
+ }
261920
261986
  var PromptSchema, MediaIdSchema, GenerateImageInputSchema, GenerateVideoInputSchema, GenerateSpeechInputSchema, GetMediaInputSchema, UnderstandImageInputSchema, UnderstandVideoInputSchema, DubVideoInputSchema, LipSyncMediaInputSchema, REQUEST_NOTE, LIPSYNC_REQUEST_NOTE, MediaGenerationTool, GenerateImageTool, GenerateVideoTool, GenerateSpeechTool, UnderstandImageTool, UnderstandVideoTool, DubVideoTool, LipSyncMediaTool, GetMediaTool;
261921
261987
  var init_blun_media$1 = __esmMin((() => {
261922
261988
  init_zod$1();
@@ -261968,16 +262034,22 @@ var init_blun_media$1 = __esmMin((() => {
261968
262034
  };
261969
262035
  }
261970
262036
  async execution(args, ctx) {
262037
+ emitMediaProgress(ctx, this.name, "submitting");
261971
262038
  try {
261972
262039
  const job = await this.submit(args, {
261973
262040
  signal: ctx.signal,
261974
262041
  toolCallId: ctx.toolCallId
261975
262042
  });
262043
+ emitMediaProgress(ctx, this.name, job.status, {
262044
+ id: job.id,
262045
+ ...job.progress
262046
+ });
261976
262047
  return {
261977
262048
  output: `Media job ${job.id} accepted with status ${job.status}. ${this.requestNote}`,
261978
262049
  isError: false
261979
262050
  };
261980
262051
  } catch (error) {
262052
+ emitMediaProgress(ctx, this.name, "failed", { error: errorMessage$10(error) });
261981
262053
  return {
261982
262054
  isError: true,
261983
262055
  output: `Media request failed: ${errorMessage$10(error)}`
@@ -262054,6 +262126,7 @@ var init_blun_media$1 = __esmMin((() => {
262054
262126
  };
262055
262127
  }
262056
262128
  async execution(args, safePath, ctx) {
262129
+ emitMediaProgress(ctx, "UnderstandImage", "uploading");
262057
262130
  try {
262058
262131
  const fileType = detectFileType(safePath, await this.kaos.readBytes(safePath, 512), "media");
262059
262132
  if (fileType.mimeType !== "image/png" && fileType.mimeType !== "image/jpeg") return {
@@ -262070,12 +262143,18 @@ var init_blun_media$1 = __esmMin((() => {
262070
262143
  toolCallId: ctx.toolCallId
262071
262144
  };
262072
262145
  const upload = await this.provider.uploadMedia(data, fileType.mimeType, options);
262146
+ emitMediaProgress(ctx, "UnderstandImage", "processing");
262073
262147
  const job = await this.provider.understandImage(upload.id, args.prompt, options);
262148
+ emitMediaProgress(ctx, "UnderstandImage", job.status, {
262149
+ id: job.id,
262150
+ ...job.progress
262151
+ });
262074
262152
  return {
262075
262153
  output: `Media job ${job.id} accepted with status ${job.status}. ${REQUEST_NOTE}`,
262076
262154
  isError: false
262077
262155
  };
262078
262156
  } catch (error) {
262157
+ emitMediaProgress(ctx, "UnderstandImage", "failed", { error: errorMessage$10(error) });
262079
262158
  return {
262080
262159
  isError: true,
262081
262160
  output: `Image understanding failed: ${errorMessage$10(error)}`
@@ -262137,6 +262216,7 @@ var init_blun_media$1 = __esmMin((() => {
262137
262216
  };
262138
262217
  }
262139
262218
  async execution(args, ctx) {
262219
+ emitMediaProgress(ctx, "GetMedia", "checking", { id: args.id });
262140
262220
  try {
262141
262221
  const result = await this.provider.getMedia(args.id, {
262142
262222
  signal: ctx.signal,
@@ -262150,15 +262230,22 @@ var init_blun_media$1 = __esmMin((() => {
262150
262230
  ].includes(result.status.trim().toLowerCase());
262151
262231
  const source = result.sourceId === void 0 ? "" : ` Source job ${result.sourceId}${result.sourceStatus === void 0 ? "" : ` status: ${result.sourceStatus}`}.`;
262152
262232
  const retryable = result.retryable === void 0 ? "" : ` Retryable: ${result.retryable ? "yes" : "no"}.`;
262233
+ emitMediaProgress(ctx, "GetMedia", result.status, {
262234
+ id: result.id,
262235
+ ...result.progress
262236
+ });
262153
262237
  return {
262154
262238
  output: `Media job ${result.id} status: ${result.status}.${source}${retryable}`,
262155
262239
  isError: terminalError
262156
262240
  };
262157
262241
  }
262158
- if (result.kind === "text") return {
262159
- output: result.text,
262160
- isError: false
262161
- };
262242
+ if (result.kind === "text") {
262243
+ emitMediaProgress(ctx, "GetMedia", "complete", { id: result.id });
262244
+ return {
262245
+ output: result.text,
262246
+ isError: false
262247
+ };
262248
+ }
262162
262249
  const url = `data:${result.mimeType};base64,${Buffer.from(result.data).toString("base64")}`;
262163
262250
  const mediaPart = contentPartFor(result.mimeType, url);
262164
262251
  if (mediaPart === void 0) return {
@@ -262171,6 +262258,11 @@ var init_blun_media$1 = __esmMin((() => {
262171
262258
  });
262172
262259
  const localPath = join(this.outputDir, `${safeMediaId(result.id)}.${extensionForMediaType(result.mimeType)}`);
262173
262260
  await writeFile(localPath, result.data, { mode: 384 });
262261
+ emitMediaProgress(ctx, "GetMedia", "complete", {
262262
+ id: result.id,
262263
+ mimeType: result.mimeType,
262264
+ localPath
262265
+ });
262174
262266
  return {
262175
262267
  output: [{
262176
262268
  type: "text",
@@ -262179,6 +262271,10 @@ var init_blun_media$1 = __esmMin((() => {
262179
262271
  isError: false
262180
262272
  };
262181
262273
  } catch (error) {
262274
+ emitMediaProgress(ctx, "GetMedia", "failed", {
262275
+ id: args.id,
262276
+ error: errorMessage$10(error)
262277
+ });
262182
262278
  return {
262183
262279
  isError: true,
262184
262280
  output: `Media lookup failed: ${errorMessage$10(error)}`
@@ -310705,13 +310801,47 @@ async function parseBlockedStatus(response, id) {
310705
310801
  ...typeof retryable === "boolean" ? { retryable } : {}
310706
310802
  };
310707
310803
  }
310804
+ function mediaPayloadNumber(payload, keys) {
310805
+ for (const key of keys) {
310806
+ const value = payload[key];
310807
+ const parsed = typeof value === "number" ? value : typeof value === "string" && value.trim() !== "" ? Number(value) : NaN;
310808
+ if (Number.isFinite(parsed) && parsed >= 0) return parsed;
310809
+ }
310810
+ }
310811
+ function mediaPayloadText(payload, keys) {
310812
+ for (const key of keys) {
310813
+ const value = payload[key];
310814
+ if (typeof value === "string" && value.trim() !== "") return value.trim();
310815
+ }
310816
+ }
310817
+ function mediaProgressFromPayload(payload) {
310818
+ const rawPercent = mediaPayloadNumber(payload, ["percent", "progress_percent", "progressPercent", "progress"]);
310819
+ const percent = rawPercent === void 0 ? void 0 : rawPercent <= 1 ? rawPercent * 100 : rawPercent;
310820
+ const progress = {
310821
+ phaseLabel: mediaPayloadText(payload, ["phase", "stage", "step_name", "stepName"]),
310822
+ percent: percent === void 0 ? void 0 : Math.min(100, Math.max(0, percent)),
310823
+ currentFrame: mediaPayloadNumber(payload, ["current_frame", "currentFrame", "frames_completed", "framesCompleted"]),
310824
+ totalFrames: mediaPayloadNumber(payload, ["total_frames", "totalFrames", "frame_count", "frameCount"]),
310825
+ fps: mediaPayloadNumber(payload, ["fps", "frames_per_second", "framesPerSecond"]),
310826
+ currentStep: mediaPayloadNumber(payload, ["current_step", "currentStep", "step"]),
310827
+ totalSteps: mediaPayloadNumber(payload, ["total_steps", "totalSteps", "steps"]),
310828
+ currentSegment: mediaPayloadNumber(payload, ["current_segment", "currentSegment", "segment"]),
310829
+ totalSegments: mediaPayloadNumber(payload, ["total_segments", "totalSegments", "segments"]),
310830
+ generatedSeconds: mediaPayloadNumber(payload, ["generated_seconds", "generatedSeconds", "audio_seconds", "audioSeconds"]),
310831
+ queuePosition: mediaPayloadNumber(payload, ["queue_position", "queuePosition"]),
310832
+ elapsedSeconds: mediaPayloadNumber(payload, ["elapsed_seconds", "elapsedSeconds"]),
310833
+ remainingSeconds: mediaPayloadNumber(payload, ["remaining_seconds", "remainingSeconds", "eta_seconds", "etaSeconds"])
310834
+ };
310835
+ return Object.fromEntries(Object.entries(progress).filter(([, value]) => value !== void 0));
310836
+ }
310708
310837
  function parseJob(payload) {
310709
310838
  const id = payload["id"];
310710
310839
  const status = payload["status"];
310711
310840
  if (typeof id !== "string" || id.length === 0 || typeof status !== "string" || status.length === 0) throw new Error("Media request returned an invalid job response.");
310712
310841
  return {
310713
310842
  id,
310714
- status
310843
+ status,
310844
+ progress: mediaProgressFromPayload(payload)
310715
310845
  };
310716
310846
  }
310717
310847
  function parseStatus(payload, expectedId) {
@@ -310721,7 +310851,8 @@ function parseStatus(payload, expectedId) {
310721
310851
  return {
310722
310852
  kind: "status",
310723
310853
  id,
310724
- status
310854
+ status,
310855
+ progress: mediaProgressFromPayload(payload)
310725
310856
  };
310726
310857
  }
310727
310858
  async function assertSuccess(response, operation) {
@@ -401433,6 +401564,16 @@ function slashCommandBusyReason(options) {
401433
401564
  if (options.isStreaming) return "streaming";
401434
401565
  if (options.isCompacting) return "compacting";
401435
401566
  }
401567
+ function shouldQueueBusySlashCommand(input, options) {
401568
+ const parsed = parseSlashInput(input);
401569
+ if (parsed === null) return false;
401570
+ if (slashCommandBusyReason(options) === void 0) return false;
401571
+ const normalizedName = normalizeLegacyEffortCommandName(parsed.name);
401572
+ const command = findBuiltInSlashCommand(normalizedName);
401573
+ if (command === void 0) return true;
401574
+ if (!isExperimentalFlagEnabled(command.experimentalFlag)) return false;
401575
+ return resolveSlashCommandAvailability(command, parsed.args) === "idle-only";
401576
+ }
401436
401577
  function slashBusyMessage(commandName, reason) {
401437
401578
  if (reason === "streaming") return uiText("resolve.busy.streaming", { command: commandName });
401438
401579
  return uiText("resolve.busy.compacting", { command: commandName });
@@ -426133,27 +426274,7 @@ registerUiCatalogFragment({
426133
426274
  }
426134
426275
  });
426135
426276
  const TICK_INTERVAL = 200;
426136
- const COMPACTION_TOKENS_PER_SECOND = 4250;
426137
- const MIN_ESTIMATED_DURATION_MS = 1e3;
426138
- const ACTIVE_PERCENT_LIMIT = 97;
426139
426277
  const BAR_WIDTH = 12;
426140
- const LOAD_PHASE_SHARE = .72;
426141
- const TAIL_PHASE_SHARE = .25;
426142
- function estimateCompactionDurationMs(inputTokens) {
426143
- if (inputTokens === void 0 || !Number.isFinite(inputTokens) || inputTokens <= 0) return;
426144
- return Math.max(MIN_ESTIMATED_DURATION_MS, Math.round(inputTokens / COMPACTION_TOKENS_PER_SECOND * 1e3));
426145
- }
426146
- function estimateCompactionPercent(elapsedMs, inputTokens) {
426147
- const durationMs = estimateCompactionDurationMs(inputTokens);
426148
- if (durationMs === void 0) return 0;
426149
- const safeElapsedMs = Math.max(0, elapsedMs);
426150
- let estimate = Math.min(1, safeElapsedMs / durationMs) * LOAD_PHASE_SHARE;
426151
- if (safeElapsedMs > durationMs) {
426152
- const tailFraction = 1 - Math.exp(-(safeElapsedMs - durationMs) / durationMs);
426153
- estimate += tailFraction * TAIL_PHASE_SHARE;
426154
- }
426155
- return Math.min(ACTIVE_PERCENT_LIMIT, Math.max(0, Math.round(estimate * 100)));
426156
- }
426157
426278
  var SingleLineText = class {
426158
426279
  text;
426159
426280
  constructor(text) {
@@ -426224,7 +426345,6 @@ var CompactionComponent = class extends Container {
426224
426345
  stage = 1;
426225
426346
  estimatedStageCount;
426226
426347
  stageCount;
426227
- estimatedProgressPercent;
426228
426348
  windowUsagePercent;
426229
426349
  constructor(ui, instruction, tip, showRunning = true) {
426230
426350
  super();
@@ -426281,7 +426401,6 @@ var CompactionComponent = class extends Container {
426281
426401
  this.attempt = progress.attempt;
426282
426402
  this.stage = progress.stage ?? this.stage;
426283
426403
  this.estimatedStageCount = progress.estimatedStageCount;
426284
- this.estimatedProgressPercent = progress.estimatedProgressPercent;
426285
426404
  this.windowUsagePercent = progress.windowUsagePercent;
426286
426405
  this.statusText.setText(this.buildStatusLine());
426287
426406
  if (this.showRunning) this.ui?.requestRender();
@@ -426303,21 +426422,16 @@ var CompactionComponent = class extends Container {
426303
426422
  }
426304
426423
  if (this.failed) return `${currentTheme.fg("error", STATUS_BULLET)}${currentTheme.boldFg("error", this.failureTitle ?? uiText("compaction.failed"))}${currentTheme.fg("textDim", ` · ${this.failureDetail ?? uiText("compaction.failureDetail")}`)}`;
426305
426424
  if (this.canceled) return `${currentTheme.fg("warning", STATUS_BULLET)}${currentTheme.boldFg("warning", uiText("compaction.canceled"))}`;
426306
- const elapsedMs = Math.max(0, Date.now() - this.attemptStartedAtMs);
426307
- const percent = this.estimatedProgressPercent ?? estimateCompactionPercent(elapsedMs, this.estimatedInputTokens);
426308
- const filled = Math.round(percent / 100 * BAR_WIDTH);
426309
- const bar = `[${"█".repeat(filled)}${"░".repeat(BAR_WIDTH - filled)}]`;
426310
426425
  const stageText = formatCompactionStageText({
426311
426426
  stage: this.stage,
426312
426427
  estimatedStageCount: this.estimatedStageCount,
426313
- estimatedProgressPercent: this.estimatedProgressPercent,
426314
426428
  windowUsagePercent: this.windowUsagePercent,
426315
426429
  estimatedInputTokens: this.estimatedInputTokens,
426316
426430
  charsReceived: 0,
426317
426431
  attempt: this.attempt
426318
426432
  });
426319
426433
  const runningText = `${formatCompactionRunningText(this.estimatedInputTokens)}${stageText.length === 0 ? "" : ` · ${stageText}`}`;
426320
- return `${currentTheme.fg("primary", bar)} ${currentTheme.boldFg("primary", runningText)}${this.windowUsagePercent === void 0 ? currentTheme.fg("textDim", ` ~${String(percent)} %`) : ""}${currentTheme.fg("textDim", ` · ${String(this.elapsedSeconds())}s`)}${this.attempt > 1 ? currentTheme.fg("textDim", uiText("compaction.attempt", { attempt: this.attempt })) : ""}${currentTheme.fg("textDim", ` · ${uiText("compaction.cancelHint")}`)}${this.instruction ? currentTheme.fg("textDim", ` · ${this.instruction}`) : ""}${this.tip ? currentTheme.fg("textDim", ` · ${this.tip}`) : ""}`;
426434
+ return `${currentTheme.fg("primary", STATUS_BULLET)}${currentTheme.boldFg("primary", runningText)}${currentTheme.fg("textDim", ` · ${String(this.elapsedSeconds())}s`)}${this.attempt > 1 ? currentTheme.fg("textDim", uiText("compaction.attempt", { attempt: this.attempt })) : ""}${currentTheme.fg("textDim", ` · ${uiText("compaction.cancelHint")}`)}${this.instruction ? currentTheme.fg("textDim", ` · ${this.instruction}`) : ""}${this.tip ? currentTheme.fg("textDim", ` · ${this.tip}`) : ""}`;
426321
426435
  }
426322
426436
  startTicking() {
426323
426437
  this.timer = setInterval(() => {
@@ -427826,24 +427940,12 @@ var AgentSwarmProgressComponent = class {
427826
427940
  if (snapshot.phase === "cancelled" && snapshot.ticks <= 0) return renderCancelledUnstartedCell(member, width, this.colors);
427827
427941
  if (!layout.renderText) return this.renderCompactCell(member, snapshot, layout.barCells, nowMs);
427828
427942
  if (snapshot.phase === "queued" && snapshot.ticks <= 0) return renderQueuedCell(member, width, this.colors);
427829
- const estimate = this.progressEstimator.estimate({
427830
- memberKey: member.id,
427831
- phase: snapshot.phase,
427832
- capacityTicks: layout.barCells * PROGRESS_LEVELS.length,
427833
- nowMs
427834
- });
427835
- const prefix = `${chalk.hex(this.colors.primary)(member.id)} ${progressBar(estimate.displayTicks, snapshot.phase, layout.barCells, this.colors, snapshot.phaseElapsedMs, cancelledProgressColor(member, snapshot.phase, this.colors))} `;
427943
+ const prefix = `${chalk.hex(this.colors.primary)(member.id)} ${chalk.hex(phaseColor(snapshot.phase, this.colors))(phaseLabel(snapshot.phase))} · `;
427836
427944
  return prefix + renderCellLabel(member, snapshot, Math.max(1, width - visibleWidth(prefix)), this.colors);
427837
427945
  }
427838
427946
  renderCompactCell(member, snapshot, barCells, nowMs) {
427839
427947
  const estimatePhase = snapshot.phase === "pending" ? "queued" : snapshot.phase;
427840
- const estimate = this.progressEstimator.estimate({
427841
- memberKey: member.id,
427842
- phase: estimatePhase,
427843
- capacityTicks: barCells * PROGRESS_LEVELS.length,
427844
- nowMs
427845
- });
427846
- return `${chalk.hex(this.colors.primary)(member.id)} ${progressBar(estimate.displayTicks, estimatePhase, barCells, this.colors, snapshot.phaseElapsedMs, cancelledProgressColor(member, snapshot.phase, this.colors))}${compactTerminalMark(member, snapshot.phase, this.colors)}`;
427948
+ return `${chalk.hex(this.colors.primary)(member.id)} ${chalk.hex(phaseColor(estimatePhase, this.colors))(phaseLabel(estimatePhase))}${compactTerminalMark(member, snapshot.phase, this.colors)}`;
427847
427949
  }
427848
427950
  findMemberForSubagent(agentId, swarmIndex) {
427849
427951
  const existing = this.findMemberByAgentId(agentId);
@@ -497899,6 +498001,208 @@ var ActivityPaneComponent = class extends Container {
497899
498001
  return lines;
497900
498002
  }
497901
498003
  };
498004
+ registerUiCatalogFragment({
498005
+ en: {
498006
+ "media.activity.jobs": "{count} media jobs active",
498007
+ "media.detail.queue": "Position {position}",
498008
+ "media.detail.segment": "Segment {current}/{total}",
498009
+ "media.detail.audio": "{seconds}s audio",
498010
+ "media.detail.remaining": "about {duration} remaining",
498011
+ "media.kind.media": "Media",
498012
+ "media.kind.image": "Image",
498013
+ "media.kind.video": "Video",
498014
+ "media.kind.voice": "Voice",
498015
+ "media.kind.image-analysis": "Image analysis",
498016
+ "media.kind.video-analysis": "Video analysis",
498017
+ "media.kind.dubbing": "Dubbing",
498018
+ "media.kind.lipsync": "Lip sync",
498019
+ "media.phase.submitting": "Sending request",
498020
+ "media.phase.uploading": "Sending request",
498021
+ "media.phase.accepted": "Queued",
498022
+ "media.phase.pending": "Queued",
498023
+ "media.phase.queued": "Queued",
498024
+ "media.phase.running": "Processing",
498025
+ "media.phase.in-progress": "Processing",
498026
+ "media.phase.generating": "Generating",
498027
+ "media.phase.rendering": "Rendering",
498028
+ "media.phase.processing": "Processing",
498029
+ "media.phase.checking": "Checking status",
498030
+ "media.phase.audio-analysis": "Audio analysis",
498031
+ "media.phase.face-detection": "Face detection",
498032
+ "media.phase.face-tracking": "Face tracking",
498033
+ "media.phase.lip-sync-running": "Lip sync running",
498034
+ "media.phase.exporting": "Exporting",
498035
+ "media.phase.saving": "Saving",
498036
+ "media.phase.upscaling": "Upscaling",
498037
+ "media.phase.analyzing": "Analyzing"
498038
+ },
498039
+ de: {
498040
+ "media.activity.jobs": "{count} Medienaufträge aktiv",
498041
+ "media.detail.queue": "Platz {position}",
498042
+ "media.detail.segment": "Abschnitt {current}/{total}",
498043
+ "media.detail.audio": "{seconds}s Audio",
498044
+ "media.detail.remaining": "noch etwa {duration}",
498045
+ "media.kind.media": "Medien",
498046
+ "media.kind.image": "Bild",
498047
+ "media.kind.video": "Video",
498048
+ "media.kind.voice": "Stimme",
498049
+ "media.kind.image-analysis": "Bildanalyse",
498050
+ "media.kind.video-analysis": "Videoanalyse",
498051
+ "media.kind.dubbing": "Vertonung",
498052
+ "media.kind.lipsync": "Lip-Sync",
498053
+ "media.phase.submitting": "Auftrag wird gesendet",
498054
+ "media.phase.uploading": "Auftrag wird gesendet",
498055
+ "media.phase.accepted": "Eingereiht",
498056
+ "media.phase.pending": "Eingereiht",
498057
+ "media.phase.queued": "Eingereiht",
498058
+ "media.phase.running": "Wird verarbeitet",
498059
+ "media.phase.in-progress": "Wird verarbeitet",
498060
+ "media.phase.generating": "Wird erzeugt",
498061
+ "media.phase.rendering": "Wird gerendert",
498062
+ "media.phase.processing": "Wird verarbeitet",
498063
+ "media.phase.checking": "Status wird geprüft",
498064
+ "media.phase.audio-analysis": "Audioanalyse",
498065
+ "media.phase.face-detection": "Gesichtserkennung",
498066
+ "media.phase.face-tracking": "Gesicht wird verfolgt",
498067
+ "media.phase.lip-sync-running": "Lip-Sync läuft",
498068
+ "media.phase.exporting": "Wird exportiert",
498069
+ "media.phase.saving": "Wird gespeichert",
498070
+ "media.phase.upscaling": "Wird hochskaliert",
498071
+ "media.phase.analyzing": "Wird analysiert"
498072
+ }
498073
+ });
498074
+ function mediaActivityStatusKey(value) {
498075
+ return String(value ?? "processing").trim().toLowerCase().replaceAll(/[^a-z0-9]+/g, "-");
498076
+ }
498077
+ function mediaActivityIsTerminal(value) {
498078
+ return [
498079
+ "complete",
498080
+ "completed",
498081
+ "ready",
498082
+ "failed",
498083
+ "expired",
498084
+ "blocked"
498085
+ ].includes(mediaActivityStatusKey(value));
498086
+ }
498087
+ const MEDIA_ACTIVITY_LABELS = {
498088
+ "media.kind": /* @__PURE__ */ new Set([
498089
+ "media",
498090
+ "image",
498091
+ "video",
498092
+ "voice",
498093
+ "image-analysis",
498094
+ "video-analysis",
498095
+ "dubbing",
498096
+ "lipsync"
498097
+ ]),
498098
+ "media.phase": /* @__PURE__ */ new Set([
498099
+ "submitting",
498100
+ "uploading",
498101
+ "accepted",
498102
+ "pending",
498103
+ "queued",
498104
+ "running",
498105
+ "in-progress",
498106
+ "generating",
498107
+ "rendering",
498108
+ "processing",
498109
+ "checking",
498110
+ "audio-analysis",
498111
+ "face-detection",
498112
+ "face-tracking",
498113
+ "lip-sync-running",
498114
+ "exporting",
498115
+ "saving",
498116
+ "upscaling",
498117
+ "analyzing"
498118
+ ])
498119
+ };
498120
+ function mediaUiText(key, params = {}) {
498121
+ return uiTextFor(getCurrentUiLocale() === "de" ? "de" : "en", key, params);
498122
+ }
498123
+ function mediaActivityLabel(prefix, value, fallback) {
498124
+ const normalized = mediaActivityStatusKey(value);
498125
+ if (!MEDIA_ACTIVITY_LABELS[prefix]?.has(normalized)) return fallback;
498126
+ return mediaUiText(`${prefix}.${normalized}`);
498127
+ }
498128
+ function formatMediaDuration(seconds) {
498129
+ if (!Number.isFinite(seconds) || seconds < 0) return;
498130
+ const whole = Math.round(seconds);
498131
+ const minutes = Math.floor(whole / 60);
498132
+ const rest = whole % 60;
498133
+ return minutes > 0 ? `${String(minutes)}:${String(rest).padStart(2, "0")}` : `${String(rest)}s`;
498134
+ }
498135
+ var MediaActivityStore = class {
498136
+ jobs = /* @__PURE__ */ new Map();
498137
+ update(toolCallId, event) {
498138
+ if (event === null || typeof event !== "object") return;
498139
+ const id = typeof event.id === "string" && event.id.length > 0 ? event.id : void 0;
498140
+ let existingKey = id;
498141
+ if (existingKey === void 0 || !this.jobs.has(existingKey)) for (const [key, job] of this.jobs) if (job.toolCallId === toolCallId || id !== void 0 && job.id === id) {
498142
+ existingKey = key;
498143
+ break;
498144
+ }
498145
+ const key = id ?? existingKey ?? toolCallId;
498146
+ const previous = existingKey === void 0 ? void 0 : this.jobs.get(existingKey);
498147
+ if (existingKey !== void 0 && existingKey !== key) this.jobs.delete(existingKey);
498148
+ if (mediaActivityIsTerminal(event.phase)) {
498149
+ this.jobs.delete(key);
498150
+ return;
498151
+ }
498152
+ const mediaKind = event.mediaKind === "media" && previous?.mediaKind !== void 0 ? previous.mediaKind : event.mediaKind ?? previous?.mediaKind ?? "media";
498153
+ this.jobs.set(key, {
498154
+ ...previous,
498155
+ ...event,
498156
+ id: id ?? previous?.id,
498157
+ mediaKind,
498158
+ toolCallId,
498159
+ startedAt: previous?.startedAt ?? Date.now(),
498160
+ updatedAt: Date.now()
498161
+ });
498162
+ }
498163
+ active() {
498164
+ return [...this.jobs.values()].filter((job) => !mediaActivityIsTerminal(job.phase)).sort((a, b) => a.startedAt - b.startedAt);
498165
+ }
498166
+ clear() {
498167
+ this.jobs.clear();
498168
+ }
498169
+ };
498170
+ var MediaActivityComponent = class {
498171
+ jobs;
498172
+ constructor(jobs) {
498173
+ this.jobs = jobs;
498174
+ }
498175
+ invalidate() {}
498176
+ render(width) {
498177
+ if (this.jobs.length === 0) return [];
498178
+ const job = this.jobs[0];
498179
+ const kind = mediaActivityLabel("media.kind", job.mediaKind, String(job.mediaKind ?? "Media"));
498180
+ const rawPhase = job.phaseLabel ?? job.phase ?? "processing";
498181
+ const phase = sanitizeTerminalText(mediaActivityLabel("media.phase", rawPhase, String(rawPhase)));
498182
+ const details = [];
498183
+ if (job.queuePosition !== void 0) details.push(mediaUiText("media.detail.queue", { position: job.queuePosition }));
498184
+ if (job.currentStep !== void 0 && job.totalSteps !== void 0) details.push(`${String(job.currentStep)}/${String(job.totalSteps)}`);
498185
+ if (job.currentSegment !== void 0 && job.totalSegments !== void 0) details.push(mediaUiText("media.detail.segment", {
498186
+ current: job.currentSegment,
498187
+ total: job.totalSegments
498188
+ }));
498189
+ if (job.currentFrame !== void 0 && job.totalFrames !== void 0) details.push(`Frame ${String(job.currentFrame)}/${String(job.totalFrames)}`);
498190
+ if (job.fps !== void 0) details.push(`${String(Math.round(job.fps * 10) / 10)} FPS`);
498191
+ if (job.generatedSeconds !== void 0) details.push(mediaUiText("media.detail.audio", { seconds: Math.round(job.generatedSeconds) }));
498192
+ const elapsed = job.elapsedSeconds ?? (Date.now() - job.startedAt) / 1e3;
498193
+ const elapsedText = formatMediaDuration(elapsed);
498194
+ if (elapsedText !== void 0) details.push(elapsedText);
498195
+ if (job.remainingSeconds !== void 0) details.push(mediaUiText("media.detail.remaining", { duration: formatMediaDuration(job.remainingSeconds) }));
498196
+ let progress = "";
498197
+ if (job.percent !== void 0 && Number.isFinite(job.percent)) {
498198
+ const percent = Math.min(100, Math.max(0, job.percent));
498199
+ progress = ` · ${renderProgressBar(percent / 100, 12)} · ${String(Math.round(percent))} %`;
498200
+ }
498201
+ const summary = this.jobs.length > 1 ? ` · ${mediaUiText("media.activity.jobs", { count: this.jobs.length })}` : "";
498202
+ const line = `${currentTheme.boldFg("primary", kind)} · ${phase}${details.length === 0 ? "" : ` · ${details.join(" · ")}`}${progress}${summary}`;
498203
+ return [truncateToWidth(line, Math.max(1, width), "…")];
498204
+ }
498205
+ };
497902
498206
  //#endregion
497903
498207
  //#region src/tui/components/panes/queue-pane.copy.ts
497904
498208
  registerUiCatalogFragment({
@@ -504425,6 +504729,10 @@ var SessionEventHandler = class {
504425
504729
  streamingUI.scheduleFlush();
504426
504730
  }
504427
504731
  handleToolProgress(event) {
504732
+ if (event.update.kind === "custom" && event.update.customKind === MEDIA_PROGRESS_CUSTOM_KIND) {
504733
+ this.host.updateMediaActivity(event.toolCallId, event.update.customData);
504734
+ return;
504735
+ }
504428
504736
  const text = event.update.text;
504429
504737
  if (text === void 0 || text.length === 0) return;
504430
504738
  const tc = this.host.streamingUI.getToolComponent(event.toolCallId);
@@ -504446,6 +504754,10 @@ var SessionEventHandler = class {
504446
504754
  synthetic: event.synthetic
504447
504755
  };
504448
504756
  const matchedCall = streamingUI.completeToolResult(event.toolCallId, resultData);
504757
+ if (matchedCall !== void 0 && isMediaToolName(matchedCall.name) && event.isError === true) this.host.updateMediaActivity(event.toolCallId, {
504758
+ mediaKind: mediaKindForToolName(matchedCall.name),
504759
+ phase: "failed"
504760
+ });
504449
504761
  if (matchedCall?.name === "GetMedia" && event.isError !== true) this.host.runChannelMediaFallback(event.output);
504450
504762
  this.subAgentEventHandler.handleAgentSwarmToolResult(event.toolCallId, resultData, event.isError === true);
504451
504763
  if (matchedCall !== void 0 && matchedCall.name === "TodoList" && !event.isError) {
@@ -506811,24 +507123,21 @@ function formatContextStatus(usage, tokens, maxTokens, colors, width, now = /* @
506811
507123
  return truncateToWidth(current, available, "…");
506812
507124
  }
506813
507125
  function formatCompactionStatus(elapsedMs, estimatedInputTokens, progress, colors, width, now = /* @__PURE__ */ new Date()) {
506814
- const percent = progress?.estimatedProgressPercent ?? estimateCompactionPercent(elapsedMs, estimatedInputTokens);
506815
- const filled = Math.max(1, Math.ceil((1 - percent / 100) * CONTEXT_BAR_WIDTH));
506816
- const bar = chalk.hex(colors.primary)(`${"█".repeat(filled)}${"░".repeat(CONTEXT_BAR_WIDTH - filled)}`);
506817
507126
  const label = formatCompactionRunningText(estimatedInputTokens);
506818
507127
  const stageText = progress === void 0 ? "" : formatCompactionStageText(progress);
506819
507128
  const compactStageText = progress?.stage === void 0 || progress.estimatedStageCount === void 0 ? "" : `${String(progress.stage)}/~${String(progress.estimatedStageCount)}${progress.windowUsagePercent === void 0 ? "" : ` · ${String(progress.windowUsagePercent)}%`}`;
506820
- const estimate = progress?.windowUsagePercent === void 0 ? `~${String(percent)} %` : "";
507129
+ const elapsed = `${String(Math.max(0, Math.round(elapsedMs / 1e3)))}s`;
506821
507130
  const clock = chalk.hex(colors.textDim)(` · ${clockHhmm(now)}`);
506822
507131
  const variants = [
506823
- `${label}${stageText.length === 0 ? "" : ` · ${stageText}`} ${bar}${estimate.length === 0 ? "" : ` ${estimate}`}${clock}`,
507132
+ `${label}${stageText.length === 0 ? "" : ` · ${stageText}`} · ${elapsed}${clock}`,
506824
507133
  `${label}${stageText.length === 0 ? "" : ` · ${stageText}`}`,
506825
507134
  compactStageText,
506826
- `${bar}${estimate.length === 0 ? "" : ` ${estimate}`}`,
506827
- stageText.length === 0 ? estimate : stageText
507135
+ elapsed,
507136
+ stageText
506828
507137
  ];
506829
507138
  const available = Math.max(0, width);
506830
507139
  for (const variant of variants) if (visibleWidth(variant) <= available) return variant;
506831
- return truncateToWidth(estimate, available, "…");
507140
+ return truncateToWidth(elapsed, available, "…");
506832
507141
  }
506833
507142
  function contextMetrics(state) {
506834
507143
  const tokens = Number.isFinite(state.contextTokens) ? Math.max(0, state.contextTokens) : 0;
@@ -512067,6 +512376,8 @@ var BlunTUI = class {
512067
512376
  startupGoalPromptedSessionId;
512068
512377
  lastActivityMode;
512069
512378
  currentLoadingTip = void 0;
512379
+ mediaActivityStore = new MediaActivityStore();
512380
+ mediaActivityTickTimer;
512070
512381
  lastHistoryContent;
512071
512382
  shellOutputStreams = /* @__PURE__ */ new Map();
512072
512383
  streamingUI;
@@ -512578,6 +512889,7 @@ var BlunTUI = class {
512578
512889
  this.tasksBrowserController.close();
512579
512890
  this.btwPanelController.clear();
512580
512891
  this.stopActivitySpinner();
512892
+ this.stopMediaActivityTicking();
512581
512893
  this.disposeEditorReplacement();
512582
512894
  this.streamingUI.disposeActiveCompactionBlock();
512583
512895
  this.streamingUI.resetToolUi();
@@ -512726,6 +513038,13 @@ var BlunTUI = class {
512726
513038
  return;
512727
513039
  }
512728
513040
  if (text.trimStart().startsWith("/")) {
513041
+ if (shouldQueueBusySlashCommand(text, {
513042
+ isStreaming: this.state.appState.streamingPhase !== "idle",
513043
+ isCompacting: this.state.appState.isCompacting
513044
+ })) {
513045
+ this.enqueueSlashCommand(text);
513046
+ return;
513047
+ }
512729
513048
  this.runSlashCommand(text);
512730
513049
  return;
512731
513050
  }
@@ -513733,6 +514052,8 @@ var BlunTUI = class {
513733
514052
  this.setAppState({ mcpServersSummary: null });
513734
514053
  this.streamingUI.setStep(0);
513735
514054
  this.streamingUI.resetLiveText();
514055
+ this.mediaActivityStore.clear();
514056
+ this.stopMediaActivityTicking();
513736
514057
  this.updateQueueDisplay();
513737
514058
  }
513738
514059
  async showResumeOtherWorkDirHint(session) {
@@ -514184,8 +514505,32 @@ var BlunTUI = class {
514184
514505
  this.state.ui.requestRender();
514185
514506
  return this.showLoginProgressSpinner(uiText("blunTui.login.waiting"));
514186
514507
  }
514508
+ updateMediaActivity(toolCallId, event) {
514509
+ this.mediaActivityStore.update(toolCallId, event);
514510
+ if (this.mediaActivityStore.active().length > 0) {
514511
+ if (this.mediaActivityTickTimer === void 0) this.mediaActivityTickTimer = setInterval(() => this.state.ui.requestRender(), 1e3);
514512
+ } else this.stopMediaActivityTicking();
514513
+ this.lastActivityMode = void 0;
514514
+ this.updateActivityPane();
514515
+ }
514516
+ stopMediaActivityTicking() {
514517
+ if (this.mediaActivityTickTimer === void 0) return;
514518
+ clearInterval(this.mediaActivityTickTimer);
514519
+ this.mediaActivityTickTimer = void 0;
514520
+ }
514187
514521
  updateActivityPane() {
514188
514522
  const effectiveMode = this.resolveActivityPaneMode();
514523
+ const mediaActivities = effectiveMode === "hidden" ? [] : this.mediaActivityStore.active();
514524
+ if (mediaActivities.length > 0) {
514525
+ this.stopActivitySpinner();
514526
+ this.syncAgentSwarmActivitySpinner(void 0);
514527
+ this.lastActivityMode = `media:${mediaActivities.map((job) => `${job.id ?? job.toolCallId}:${job.updatedAt}`).join(",")}`;
514528
+ this.state.activityContainer.clear();
514529
+ this.state.activityContainer.addChild(new Spacer(1));
514530
+ this.state.activityContainer.addChild(new MediaActivityComponent(mediaActivities));
514531
+ this.state.ui.requestRender();
514532
+ return;
514533
+ }
514189
514534
  const tipKind = loadingTipKind(effectiveMode);
514190
514535
  if (effectiveMode === "idle" || effectiveMode === "session" || effectiveMode === "hidden") this.currentLoadingTip = void 0;
514191
514536
  else if (tipKind !== void 0 && (this.currentLoadingTip === void 0 || this.currentLoadingTip.kind !== tipKind)) this.currentLoadingTip = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.46",
3
+ "version": "9.1.48",
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": {