blun-king-cli 9.1.34 → 9.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LIESMICH.txt 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.1
12
+ npm install -g blun-king-cli@9.1.36
13
13
 
14
14
  Start
15
15
  -----
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.34
12
+ npm install -g blun-king-cli@9.1.36
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
package/blun.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:ec5eb56eb8addc29b2ddab22ca4987f2156e16b88a8f468ce3248d312afa717f
2
+ // BLUN_BUILD_INPUT_SHA256:0a9b399298f68e4bffadcc1ead801f14012d39becc3a208a737071e6bb201f97
3
3
  import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
4
4
  import { dirname as __cjsShimDirname } from 'node:path';
5
5
  const __filename = __cjsShimFileURLToPath(import.meta.url);
@@ -30089,6 +30089,74 @@ var init_abort = __esmMin((() => {
30089
30089
  };
30090
30090
  }));
30091
30091
  //#endregion
30092
+ //#region ../../packages/agent-core/src/utils/completion-budget.ts
30093
+ /**
30094
+ * Resolve configured completion budget. Env values are explicit hard caps;
30095
+ * non-positive env values disable clamping.
30096
+ */
30097
+ function resolveCompletionBudget(args) {
30098
+ const env = args.env ?? process.env;
30099
+ const fromNew = parseEnvBudget(env["BLUN_MODEL_MAX_COMPLETION_TOKENS"]);
30100
+ if (fromNew !== "absent") return fromNew === "disabled" ? void 0 : { hardCap: fromNew };
30101
+ const fromLegacy = parseEnvBudget(env["BLUN_MODEL_MAX_TOKENS"]);
30102
+ if (fromLegacy !== "absent") return fromLegacy === "disabled" ? void 0 : { hardCap: fromLegacy };
30103
+ if (args.maxOutputSize !== void 0 && args.maxOutputSize > 0) return { hardCap: args.maxOutputSize };
30104
+ if (args.reservedContextSize !== void 0 && args.reservedContextSize > 0) return { fallback: args.reservedContextSize };
30105
+ return { fallback: DEFAULT_UNKNOWN_CONTEXT_FALLBACK };
30106
+ }
30107
+ function parseEnvBudget(raw) {
30108
+ if (raw === void 0 || raw === "") return "absent";
30109
+ const n = Number(raw);
30110
+ if (!Number.isFinite(n) || !Number.isInteger(n)) return "absent";
30111
+ if (n <= 0) return "disabled";
30112
+ return n;
30113
+ }
30114
+ /**
30115
+ * Compute the effective `max_completion_tokens` cap.
30116
+ */
30117
+ function computeCompletionBudgetCap(args) {
30118
+ const maxCtx = args.capability?.max_context_tokens ?? 0;
30119
+ const cap = args.budget.hardCap ?? (maxCtx > 0 ? maxCtx : args.budget.fallback ?? DEFAULT_UNKNOWN_CONTEXT_FALLBACK);
30120
+ return Math.max(MIN_FLOOR, cap);
30121
+ }
30122
+ /**
30123
+ * Apply a completion budget to a provider via its optional
30124
+ * `withMaxCompletionTokens` capability. Returns the original provider
30125
+ * unchanged when no budget is configured or the provider opts out.
30126
+ *
30127
+ * The returned provider is intentionally a shallow clone that shares the
30128
+ * original's HTTP client. Callers MUST treat it as a single-step value
30129
+ * and NOT persist it back to durable agent state — see the F3 discussion
30130
+ * in `BlunChatProvider._clone()`.
30131
+ */
30132
+ function applyCompletionBudget(args) {
30133
+ return applyCompletionBudgetWithDetails(args).provider;
30134
+ }
30135
+ function applyCompletionBudgetWithDetails(args) {
30136
+ if (args.budget === void 0) return { provider: args.provider };
30137
+ if (args.provider.withMaxCompletionTokens === void 0) return { provider: args.provider };
30138
+ let cap = computeCompletionBudgetCap({
30139
+ budget: args.budget,
30140
+ capability: args.capability
30141
+ });
30142
+ if (args.retry !== void 0) cap = Math.max(args.retry.minimumCompletionTokens, Math.ceil(cap * args.retry.multiplier));
30143
+ const maxContextTokens = args.capability?.max_context_tokens;
30144
+ if (args.usedContextTokens !== void 0 && maxContextTokens !== void 0 && maxContextTokens > 0) cap = Math.max(MIN_FLOOR, Math.min(cap, maxContextTokens - args.usedContextTokens));
30145
+ return {
30146
+ provider: args.provider.withMaxCompletionTokens(cap, {
30147
+ usedContextTokens: args.usedContextTokens,
30148
+ maxContextTokens
30149
+ }),
30150
+ maxCompletionTokens: cap
30151
+ };
30152
+ }
30153
+ var MIN_FLOOR, DEFAULT_UNKNOWN_CONTEXT_FALLBACK, MIN_THINKING_COMPLETION_TOKENS;
30154
+ var init_completion_budget = __esmMin((() => {
30155
+ MIN_FLOOR = 1;
30156
+ DEFAULT_UNKNOWN_CONTEXT_FALLBACK = 32e3;
30157
+ MIN_THINKING_COMPLETION_TOKENS = 1024;
30158
+ }));
30159
+ //#endregion
30092
30160
  //#region ../../packages/agent-core/src/loop/retry.ts
30093
30161
  async function chatWithRetry(input) {
30094
30162
  const maxAttempts = input.maxAttempts ?? 3;
@@ -30103,23 +30171,22 @@ async function chatWithRetry(input) {
30103
30171
  }
30104
30172
  const delays = retryBackoffDelays(maxAttempts);
30105
30173
  let completionBudgetRetry;
30106
- let emptyRetryStarted = false;
30174
+ let emptyRetryKind;
30107
30175
  for (let attempt = 1;; attempt += 1) try {
30108
30176
  return await input.llm.chat(paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry));
30109
30177
  } catch (error) {
30110
- if (error instanceof APIEmptyResponseError && (emptyRetryStarted || error.emptyResponseKind === "length" || error.emptyResponseKind === "stop")) {
30111
- const emptyAttemptLimit = Math.min(maxAttempts, 2);
30178
+ if (error instanceof APIEmptyResponseError && (emptyRetryKind !== void 0 || error.emptyResponseKind === "length" || error.emptyResponseKind === "stop")) {
30112
30179
  logEmptyResponse(input, error, attempt);
30113
- if (attempt >= emptyAttemptLimit) {
30114
- const terminal = error.withMetadata({ attempts: attempt });
30115
- logRequestFailure(input, terminal, attempt, emptyAttemptLimit);
30180
+ if (emptyRetryKind !== void 0 || attempt >= maxAttempts) {
30181
+ const terminal = error.withMetadata({ attempts: emptyRetryKind === error.emptyResponseKind ? 2 : 1 });
30182
+ logRequestFailure(input, terminal, attempt, maxAttempts);
30116
30183
  throw terminal;
30117
30184
  }
30118
30185
  completionBudgetRetry = error.emptyResponseKind === "length" ? {
30119
- minimumCompletionTokens: 1024,
30186
+ minimumCompletionTokens: MIN_THINKING_COMPLETION_TOKENS,
30120
30187
  multiplier: 2
30121
30188
  } : void 0;
30122
- emptyRetryStarted = true;
30189
+ emptyRetryKind = error.emptyResponseKind;
30123
30190
  input.params.signal.throwIfAborted();
30124
30191
  input.dispatchEvent({
30125
30192
  type: "step.retrying",
@@ -30128,7 +30195,7 @@ async function chatWithRetry(input) {
30128
30195
  stepUuid: input.stepUuid,
30129
30196
  failedAttempt: attempt,
30130
30197
  nextAttempt: attempt + 1,
30131
- maxAttempts: emptyAttemptLimit,
30198
+ maxAttempts,
30132
30199
  delayMs: 0,
30133
30200
  ...retryErrorFields(error)
30134
30201
  });
@@ -30214,6 +30281,7 @@ var init_retry = __esmMin((() => {
30214
30281
  init_src$4();
30215
30282
  import_retry$1 = /* @__PURE__ */ __toESM(require_retry$1(), 1);
30216
30283
  init_abort();
30284
+ init_completion_budget();
30217
30285
  init_errors$4();
30218
30286
  RETRY_MIN_TIMEOUT_MS = 300;
30219
30287
  RETRY_MAX_TIMEOUT_MS = 5e3;
@@ -30832,73 +30900,6 @@ var init_tokens = __esmMin((() => {
30832
30900
  MAX_IMAGE_HEADER_BYTES = 1024 * 1024;
30833
30901
  }));
30834
30902
  //#endregion
30835
- //#region ../../packages/agent-core/src/utils/completion-budget.ts
30836
- /**
30837
- * Resolve configured completion budget. Env values are explicit hard caps;
30838
- * non-positive env values disable clamping.
30839
- */
30840
- function resolveCompletionBudget(args) {
30841
- const env = args.env ?? process.env;
30842
- const fromNew = parseEnvBudget(env["BLUN_MODEL_MAX_COMPLETION_TOKENS"]);
30843
- if (fromNew !== "absent") return fromNew === "disabled" ? void 0 : { hardCap: fromNew };
30844
- const fromLegacy = parseEnvBudget(env["BLUN_MODEL_MAX_TOKENS"]);
30845
- if (fromLegacy !== "absent") return fromLegacy === "disabled" ? void 0 : { hardCap: fromLegacy };
30846
- if (args.maxOutputSize !== void 0 && args.maxOutputSize > 0) return { hardCap: args.maxOutputSize };
30847
- if (args.reservedContextSize !== void 0 && args.reservedContextSize > 0) return { fallback: args.reservedContextSize };
30848
- return { fallback: DEFAULT_UNKNOWN_CONTEXT_FALLBACK };
30849
- }
30850
- function parseEnvBudget(raw) {
30851
- if (raw === void 0 || raw === "") return "absent";
30852
- const n = Number(raw);
30853
- if (!Number.isFinite(n) || !Number.isInteger(n)) return "absent";
30854
- if (n <= 0) return "disabled";
30855
- return n;
30856
- }
30857
- /**
30858
- * Compute the effective `max_completion_tokens` cap.
30859
- */
30860
- function computeCompletionBudgetCap(args) {
30861
- const maxCtx = args.capability?.max_context_tokens ?? 0;
30862
- const cap = args.budget.hardCap ?? (maxCtx > 0 ? maxCtx : args.budget.fallback ?? DEFAULT_UNKNOWN_CONTEXT_FALLBACK);
30863
- return Math.max(MIN_FLOOR, cap);
30864
- }
30865
- /**
30866
- * Apply a completion budget to a provider via its optional
30867
- * `withMaxCompletionTokens` capability. Returns the original provider
30868
- * unchanged when no budget is configured or the provider opts out.
30869
- *
30870
- * The returned provider is intentionally a shallow clone that shares the
30871
- * original's HTTP client. Callers MUST treat it as a single-step value
30872
- * and NOT persist it back to durable agent state — see the F3 discussion
30873
- * in `BlunChatProvider._clone()`.
30874
- */
30875
- function applyCompletionBudget(args) {
30876
- return applyCompletionBudgetWithDetails(args).provider;
30877
- }
30878
- function applyCompletionBudgetWithDetails(args) {
30879
- if (args.budget === void 0) return { provider: args.provider };
30880
- if (args.provider.withMaxCompletionTokens === void 0) return { provider: args.provider };
30881
- let cap = computeCompletionBudgetCap({
30882
- budget: args.budget,
30883
- capability: args.capability
30884
- });
30885
- if (args.retry !== void 0) cap = Math.max(args.retry.minimumCompletionTokens, Math.ceil(cap * args.retry.multiplier));
30886
- const maxContextTokens = args.capability?.max_context_tokens;
30887
- if (args.usedContextTokens !== void 0 && maxContextTokens !== void 0 && maxContextTokens > 0) cap = Math.max(MIN_FLOOR, Math.min(cap, maxContextTokens - args.usedContextTokens));
30888
- return {
30889
- provider: args.provider.withMaxCompletionTokens(cap, {
30890
- usedContextTokens: args.usedContextTokens,
30891
- maxContextTokens
30892
- }),
30893
- maxCompletionTokens: cap
30894
- };
30895
- }
30896
- var MIN_FLOOR, DEFAULT_UNKNOWN_CONTEXT_FALLBACK;
30897
- var init_completion_budget = __esmMin((() => {
30898
- MIN_FLOOR = 1;
30899
- DEFAULT_UNKNOWN_CONTEXT_FALLBACK = 32e3;
30900
- }));
30901
- //#endregion
30902
30903
  //#region ../../node_modules/.pnpm/bmp-ts@1.0.9/node_modules/bmp-ts/dist/esm/header-types.js
30903
30904
  var HeaderTypes, header_types_default;
30904
30905
  var init_header_types = __esmMin((() => {
@@ -74369,6 +74370,9 @@ var init_vision_reader = __esmMin((() => {
74369
74370
  }));
74370
74371
  //#endregion
74371
74372
  //#region ../../packages/agent-core/src/agent/turn/kosong-llm.ts
74373
+ function thinkingEnabled(effort) {
74374
+ return effort !== null && effort !== "off" && effort !== "none";
74375
+ }
74372
74376
  function buildStreamTiming(requestStartedAt, requestSentAt, firstChunkAt, streamEndedAt, decodeStats) {
74373
74377
  const outputEndedAt = streamEndedAt ?? Date.now();
74374
74378
  const timing = {
@@ -74611,7 +74615,10 @@ var init_kosong_llm = __esmMin((() => {
74611
74615
  budget: this.completionBudgetConfig,
74612
74616
  capability: this.capability,
74613
74617
  usedContextTokens,
74614
- retry: params.completionBudgetRetry
74618
+ retry: params.completionBudgetRetry ?? (thinkingEnabled(this.provider.thinkingEffort) ? {
74619
+ minimumCompletionTokens: 1024,
74620
+ multiplier: 1
74621
+ } : void 0)
74615
74622
  });
74616
74623
  result = await this.generate(completionBudget.provider, this.systemPrompt, tools, outgoingMessages, callbacks, options);
74617
74624
  } catch (error) {
@@ -75019,10 +75026,17 @@ function isModelFallbackStatus(error) {
75019
75026
  function compactionTimingKey(provider) {
75020
75027
  return `${provider.name}\u0000${provider.modelName}`;
75021
75028
  }
75022
- function estimateCompactionProgressPercent(initialInputTokens, currentInputTokens) {
75023
- if (initialInputTokens <= 0) return 0;
75024
- const reducedTokens = Math.max(0, initialInputTokens - currentInputTokens);
75025
- return Math.min(99, Math.floor(reducedTokens / initialInputTokens * 100));
75029
+ function estimateCompactionStageCount(initialInputTokens, safeRequestLimitTokens, currentStage) {
75030
+ if (safeRequestLimitTokens <= 0) return currentStage;
75031
+ return Math.max(currentStage, Math.ceil(initialInputTokens / safeRequestLimitTokens));
75032
+ }
75033
+ function estimateCompactionProgressPercent(stage, estimatedStageCount) {
75034
+ if (estimatedStageCount <= 0) return 0;
75035
+ return Math.min(99, Math.floor(stage / estimatedStageCount * 100));
75036
+ }
75037
+ function estimateCompactionWindowUsagePercent(requestTokens, maxContextTokens) {
75038
+ if (maxContextTokens <= 0) return void 0;
75039
+ return Math.min(100, Math.max(0, Math.ceil(requestTokens / maxContextTokens * 100)));
75026
75040
  }
75027
75041
  function selectHierarchicalCompactionChunk(history, targetRequestTokens, hardRequestLimit, build) {
75028
75042
  const safeEnds = [];
@@ -75502,12 +75516,17 @@ var init_full = __esmMin((() => {
75502
75516
  provider = buildCompactionProvider(estimatedCompactionRequestTokens);
75503
75517
  attemptCount += 1;
75504
75518
  charsReceived = 0;
75505
- const estimatedProgressPercent = estimateCompactionProgressPercent(initialCompactionRequestTokens, estimatedCompactionRequestTokens);
75519
+ const stage = hierarchicalPassCount + 1;
75520
+ const estimatedStageCount = estimateCompactionStageCount(initialCompactionRequestTokens, safeCompactionRequestLimit, stage);
75521
+ const estimatedProgressPercent = estimateCompactionProgressPercent(stage, estimatedStageCount);
75522
+ const windowUsagePercent = estimateCompactionWindowUsagePercent(estimatedCompactionRequestTokens, compactionRequestLimit);
75506
75523
  this.agent.log.info("compaction stage request", {
75507
75524
  source: data.source,
75508
- stage: hierarchicalPassCount + 1,
75525
+ stage,
75526
+ estimatedStageCount,
75509
75527
  activeContextTokens: this.estimateProjectedRequestTokens(),
75510
75528
  estimatedInputTokens: estimatedCompactionRequestTokens,
75529
+ windowUsagePercent,
75511
75530
  safeInputLimitTokens: safeCompactionRequestLimit,
75512
75531
  maxContextTokens: compactionRequestLimit
75513
75532
  });
@@ -75517,9 +75536,11 @@ var init_full = __esmMin((() => {
75517
75536
  lastProgressEmitAt = now;
75518
75537
  this.agent.emitEvent({
75519
75538
  type: "compaction.progress",
75520
- stage: hierarchicalPassCount + 1,
75539
+ stage,
75540
+ estimatedStageCount,
75521
75541
  estimatedInputTokens: estimatedCompactionRequestTokens,
75522
75542
  estimatedProgressPercent,
75543
+ ...windowUsagePercent === void 0 ? {} : { windowUsagePercent },
75523
75544
  charsReceived,
75524
75545
  attempt: attemptCount,
75525
75546
  ...typicalDurationMs !== void 0 ? { typicalDurationMs } : {}
@@ -245396,7 +245417,9 @@ var init_events$1 = __esmMin((() => {
245396
245417
  compactionProgressEventSchema = object({
245397
245418
  type: literal("compaction.progress"),
245398
245419
  stage: number$1().int().positive().optional(),
245420
+ estimatedStageCount: number$1().int().positive().optional(),
245399
245421
  estimatedProgressPercent: number$1().int().min(0).max(99).optional(),
245422
+ windowUsagePercent: number$1().int().min(0).max(100).optional(),
245400
245423
  estimatedInputTokens: number$1().optional(),
245401
245424
  charsReceived: number$1(),
245402
245425
  attempt: number$1(),
@@ -259389,6 +259412,10 @@ function blunThinkingIntentInput(input) {
259389
259412
  text: channelText
259390
259413
  }];
259391
259414
  }
259415
+ function blunToolsForOrigin(tools, origin) {
259416
+ if (origin.kind !== "system_trigger" && origin.kind !== "injection") return tools;
259417
+ return tools.filter((tool) => !BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name));
259418
+ }
259392
259419
  /**
259393
259420
  * Choose the tool set for a task turn. Returns the full set unless the model
259394
259421
  * window is small enough that the schemas alone blow the context budget, in
@@ -259620,7 +259647,7 @@ function toolResultText(result) {
259620
259647
  function abandonedToolResultOutput(ended) {
259621
259648
  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.`;
259622
259649
  }
259623
- var BLUN_LEAN_TOOL_NAMES, BLUN_LEAN_KEEP_RE, BLUN_TOOL_BUDGET_RATIO, 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;
259650
+ var BLUN_LEAN_TOOL_NAMES, BLUN_LEAN_KEEP_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TOOL_BUDGET_RATIO, 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;
259624
259651
  var init_turn = __esmMin((() => {
259625
259652
  init_dist$4();
259626
259653
  init_src$4();
@@ -259646,6 +259673,7 @@ var init_turn = __esmMin((() => {
259646
259673
  "MistakeRecord"
259647
259674
  ]);
259648
259675
  BLUN_LEAN_KEEP_RE = /(^|__|:)(reply|react|edit_message|download_attachment|memory_(?:status|settings_update|remember|list|threads_list|recall))$/i;
259676
+ BLUN_TELEGRAM_OUTBOUND_TOOL_RE = /^mcp__[^\s]*telegram[^\s]*__(?:reply|react|edit_message)$/i;
259649
259677
  BLUN_TOOL_BUDGET_RATIO = .25;
259650
259678
  LLM_NOT_SET_MESSAGE = "LLM not set, send \"/login\" to login";
259651
259679
  GOAL_CONTINUATION_ORIGIN = {
@@ -260213,7 +260241,7 @@ var init_turn = __esmMin((() => {
260213
260241
  const loopControl = this.agent.blunConfig?.loopControl;
260214
260242
  let stopForGoalBudget = false;
260215
260243
  try {
260216
- const eligibleTools = this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools);
260244
+ const eligibleTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools), origin);
260217
260245
  const selectedTools = turnNeedsTools ? blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens) : [];
260218
260246
  return (await runTurn({
260219
260247
  turnId: String(turnId),
@@ -425706,6 +425734,14 @@ function formatCompactCount(n) {
425706
425734
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
425707
425735
  return String(n);
425708
425736
  }
425737
+ function formatCompactionStageText(progress) {
425738
+ const stage = progress.stage;
425739
+ const total = progress.estimatedStageCount;
425740
+ const parts = [];
425741
+ if (stage !== void 0 && total !== void 0) parts.push(`${String(stage)}/~${String(total)}`);
425742
+ if (progress.windowUsagePercent !== void 0) parts.push(`${String(progress.windowUsagePercent)} %`);
425743
+ return parts.join(" · ");
425744
+ }
425709
425745
  function formatCompactionRunningText(inputTokens) {
425710
425746
  return inputTokens === void 0 ? uiText("compaction.running") : uiText("compaction.runningWithSize", { tokens: formatCompactCount(inputTokens) });
425711
425747
  }
@@ -425747,8 +425783,10 @@ var CompactionComponent = class extends Container {
425747
425783
  estimatedInputTokens;
425748
425784
  attempt = 1;
425749
425785
  stage = 1;
425786
+ estimatedStageCount;
425750
425787
  stageCount;
425751
425788
  estimatedProgressPercent;
425789
+ windowUsagePercent;
425752
425790
  constructor(ui, instruction, tip, showRunning = true) {
425753
425791
  super();
425754
425792
  this.showRunning = showRunning;
@@ -425803,7 +425841,9 @@ var CompactionComponent = class extends Container {
425803
425841
  if (progress.attempt !== this.attempt) this.attemptStartedAtMs = Date.now();
425804
425842
  this.attempt = progress.attempt;
425805
425843
  this.stage = progress.stage ?? this.stage;
425844
+ this.estimatedStageCount = progress.estimatedStageCount;
425806
425845
  this.estimatedProgressPercent = progress.estimatedProgressPercent;
425846
+ this.windowUsagePercent = progress.windowUsagePercent;
425807
425847
  this.statusText.setText(this.buildStatusLine());
425808
425848
  if (this.showRunning) this.ui?.requestRender();
425809
425849
  }
@@ -425828,8 +425868,17 @@ var CompactionComponent = class extends Container {
425828
425868
  const percent = this.estimatedProgressPercent ?? estimateCompactionPercent(elapsedMs, this.estimatedInputTokens);
425829
425869
  const filled = Math.round(percent / 100 * BAR_WIDTH);
425830
425870
  const bar = `[${"█".repeat(filled)}${"░".repeat(BAR_WIDTH - filled)}]`;
425831
- const runningText = `${formatCompactionRunningText(this.estimatedInputTokens)} · ${String(this.stage)}/?`;
425832
- return `${currentTheme.fg("primary", bar)} ${currentTheme.boldFg("primary", runningText)}${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}`) : ""}`;
425871
+ const stageText = formatCompactionStageText({
425872
+ stage: this.stage,
425873
+ estimatedStageCount: this.estimatedStageCount,
425874
+ estimatedProgressPercent: this.estimatedProgressPercent,
425875
+ windowUsagePercent: this.windowUsagePercent,
425876
+ estimatedInputTokens: this.estimatedInputTokens,
425877
+ charsReceived: 0,
425878
+ attempt: this.attempt
425879
+ });
425880
+ const runningText = `${formatCompactionRunningText(this.estimatedInputTokens)}${stageText.length === 0 ? "" : ` · ${stageText}`}`;
425881
+ 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}`) : ""}`;
425833
425882
  }
425834
425883
  startTicking() {
425835
425884
  this.timer = setInterval(() => {
@@ -506143,17 +506192,21 @@ function formatContextStatus(usage, tokens, maxTokens, colors, width, now = /* @
506143
506192
  for (const variant of variants) if (visibleWidth(variant) <= available) return variant;
506144
506193
  return truncateToWidth(current, available, "…");
506145
506194
  }
506146
- function formatCompactionStatus(elapsedMs, estimatedInputTokens, colors, width, now = /* @__PURE__ */ new Date()) {
506147
- const percent = estimateCompactionPercent(elapsedMs, estimatedInputTokens);
506195
+ function formatCompactionStatus(elapsedMs, estimatedInputTokens, progress, colors, width, now = /* @__PURE__ */ new Date()) {
506196
+ const percent = progress?.estimatedProgressPercent ?? estimateCompactionPercent(elapsedMs, estimatedInputTokens);
506148
506197
  const filled = Math.max(1, Math.ceil((1 - percent / 100) * CONTEXT_BAR_WIDTH));
506149
506198
  const bar = chalk.hex(colors.primary)(`${"█".repeat(filled)}${"░".repeat(CONTEXT_BAR_WIDTH - filled)}`);
506150
506199
  const label = formatCompactionRunningText(estimatedInputTokens);
506151
- const estimate = `~${String(percent)} %`;
506200
+ const stageText = progress === void 0 ? "" : formatCompactionStageText(progress);
506201
+ const compactStageText = progress?.stage === void 0 || progress.estimatedStageCount === void 0 ? "" : `${String(progress.stage)}/~${String(progress.estimatedStageCount)}${progress.windowUsagePercent === void 0 ? "" : ` · ${String(progress.windowUsagePercent)}%`}`;
506202
+ const estimate = progress?.windowUsagePercent === void 0 ? `~${String(percent)} %` : "";
506203
+ const clock = chalk.hex(colors.textDim)(` · ${clockHhmm(now)}`);
506152
506204
  const variants = [
506153
- `${label} ${bar} ${estimate}${chalk.hex(colors.textDim)(` · ${clockHhmm(now)}`)}`,
506154
- `${label} ${bar} ${estimate}`,
506155
- `${bar} ${estimate}`,
506156
- estimate
506205
+ `${label}${stageText.length === 0 ? "" : ` · ${stageText}`} ${bar}${estimate.length === 0 ? "" : ` ${estimate}`}${clock}`,
506206
+ `${label}${stageText.length === 0 ? "" : ` · ${stageText}`}`,
506207
+ compactStageText,
506208
+ `${bar}${estimate.length === 0 ? "" : ` ${estimate}`}`,
506209
+ stageText.length === 0 ? estimate : stageText
506157
506210
  ];
506158
506211
  const available = Math.max(0, width);
506159
506212
  for (const variant of variants) if (visibleWidth(variant) <= available) return variant;
@@ -506188,6 +506241,7 @@ var FooterComponent = class {
506188
506241
  goalTimer = null;
506189
506242
  compactionAttemptStartedAtMs = null;
506190
506243
  compactionEstimatedInputTokens;
506244
+ compactionProgress;
506191
506245
  compactionAttempt = 1;
506192
506246
  compactionTimer = null;
506193
506247
  /**
@@ -506222,6 +506276,7 @@ var FooterComponent = class {
506222
506276
  startCompaction() {
506223
506277
  this.compactionAttemptStartedAtMs = Date.now();
506224
506278
  this.compactionEstimatedInputTokens = void 0;
506279
+ this.compactionProgress = void 0;
506225
506280
  this.compactionAttempt = 1;
506226
506281
  if (this.compactionTimer === null) {
506227
506282
  this.compactionTimer = setInterval(() => {
@@ -506235,11 +506290,13 @@ var FooterComponent = class {
506235
506290
  if (progress.estimatedInputTokens !== void 0) this.compactionEstimatedInputTokens = progress.estimatedInputTokens;
506236
506291
  if (progress.attempt !== this.compactionAttempt) this.compactionAttemptStartedAtMs = Date.now();
506237
506292
  this.compactionAttempt = progress.attempt;
506293
+ this.compactionProgress = progress;
506238
506294
  this.onRefresh();
506239
506295
  }
506240
506296
  finishCompaction() {
506241
506297
  this.compactionAttemptStartedAtMs = null;
506242
506298
  this.compactionEstimatedInputTokens = void 0;
506299
+ this.compactionProgress = void 0;
506243
506300
  this.compactionAttempt = 1;
506244
506301
  if (this.compactionTimer !== null) {
506245
506302
  clearInterval(this.compactionTimer);
@@ -506306,7 +506363,7 @@ var FooterComponent = class {
506306
506363
  const leftLine = left.join(" ");
506307
506364
  const leftWidth = visibleWidth(leftLine);
506308
506365
  const context = contextMetrics(state);
506309
- const contextText = this.compactionAttemptStartedAtMs === null ? formatContextStatus(context.usage, context.tokens, context.maxTokens, colors, width) : formatCompactionStatus(Math.max(0, Date.now() - this.compactionAttemptStartedAtMs), this.compactionEstimatedInputTokens, colors, width);
506366
+ const contextText = this.compactionAttemptStartedAtMs === null ? formatContextStatus(context.usage, context.tokens, context.maxTokens, colors, width) : formatCompactionStatus(Math.max(0, Date.now() - this.compactionAttemptStartedAtMs), this.compactionEstimatedInputTokens, this.compactionProgress, colors, width);
506310
506367
  const right = this.transientHint && this.compactionAttemptStartedAtMs === null ? chalk.hex(colors.warning).bold(this.transientHint) : chalk.hex(colors.text)(contextText);
506311
506368
  const rightWidth = visibleWidth(right);
506312
506369
  let line1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.34",
3
+ "version": "9.1.36",
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": {