blun-king-cli 9.1.105 → 9.1.107

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.105
12
+ npm install -g blun-king-cli@9.1.106
13
13
 
14
14
  Start
15
15
  -----
@@ -107,6 +107,8 @@ Reguläre `Agent`-Teilaufgaben verwenden eine eigene `ContextMemory` und eine ei
107
107
 
108
108
  Version 9.1.105 ergänzt `TaskUpdate` für laufende Hintergrundagenten. King übergibt zusätzliche Anweisungen am nächsten sicheren Modellschritt an denselben aktiven Agenten, ohne ihn zu stoppen oder einen weiteren Agenten zu starten. Unbekannte und bereits beendete Aufgaben, Shell-Aufgaben sowie Agenten, die keine Aktualisierung mehr annehmen, werden unverändert abgewiesen.
109
109
 
110
+ Version 9.1.106 erlaubt Agentenprofilen, Werkzeuge namentlich auszuschließen. King wendet diese Ausschlüsse erst an, nachdem dauerhaft geladene, dynamisch nachgeladene und MCP-Werkzeuge zusammengestellt wurden. Die Standardprofile `coder`, `explore` und `plan` können über Telegram weder antworten noch reagieren, Nachrichten bearbeiten oder Anhänge herunterladen; der Hauptagent bleibt unverändert. So senden delegierte Agenten keine Nachrichten am Hauptagenten vorbei, und ihre Modellanfragen enthalten weniger Werkzeugschemas. Nicht gefundene, namentlich angegebene Werkzeuge werden sichtbar gemeldet.
111
+
110
112
  Verliert ein delegierter Einzelagent oder ein Mitglied eines Agentenschwarms die Provider-Verbindung, erhält es eine leere Provider-Antwort, bricht sein Stream wegen Leerlaufs ab oder meldet der Server HTTP 408/500/502/503/504, setzt BLUN King denselben Agenten anhand seines dauerhaften Verlaufs fort. Bei Einzelagenten sowie bei Schwarm-Unterbrechungen außerhalb von HTTP 429 wartet die erste Fortsetzung zwei Sekunden und die zweite fünf Sekunden; danach bleibt der ursprüngliche Fehler sichtbar. HTTP 429 behält im Schwarm seine getrennte, längere Überlastungsregel. Authentifizierungs-, Zahlungs- oder Kontingent-, Richtlinien-, Kontext-, Werkzeug- und Codefehler sowie manuelle Abbrüche lösen keine automatische Fortsetzung aus. Jeder Fortsetzungsversuch verwendet die bestehende Agenten-ID, damit bereits abgeschlossene Arbeit nicht wiederholt wird.
111
113
 
112
114
  Rein lesende Sitzungsdiagnose
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.105
12
+ npm install -g blun-king-cli@9.1.106
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
@@ -115,6 +115,8 @@ Version 9.1.104 lässt Shell-Befehle im Vordergrund auch bei sehr großen Ausgab
115
115
 
116
116
  Version 9.1.105 ergänzt `TaskUpdate` für laufende Hintergrundagenten. King übergibt zusätzliche Anweisungen am nächsten sicheren Modellschritt an denselben aktiven Agenten, ohne ihn zu stoppen oder einen weiteren Agenten zu starten. Unbekannte und bereits beendete Aufgaben, Shell-Aufgaben sowie Agenten, die keine Aktualisierung mehr annehmen, werden unverändert abgewiesen.
117
117
 
118
+ Version 9.1.106 erlaubt Agentenprofilen, Werkzeuge namentlich auszuschließen. King wendet diese Ausschlüsse erst an, nachdem dauerhaft geladene, dynamisch nachgeladene und MCP-Werkzeuge zusammengestellt wurden. Die Standardprofile `coder`, `explore` und `plan` können über Telegram weder antworten noch reagieren, Nachrichten bearbeiten oder Anhänge herunterladen; der Hauptagent bleibt unverändert. So senden delegierte Agenten keine Nachrichten am Hauptagenten vorbei, und ihre Modellanfragen enthalten weniger Werkzeugschemas. Nicht gefundene, namentlich angegebene Werkzeuge werden sichtbar gemeldet.
119
+
118
120
  Ab BLUN King 9.1.99 werden auch direkt aufeinanderfolgende reine Textergebnisse als Stapel betrachtet. Enthalten sie zusammen mehr als 12.000 Zeichen, obwohl kein einzelnes Ergebnis diese Grenze überschreitet, speichert King so viele der größten geeigneten Ergebnisse wie nötig in privaten Dateien. In der Modellprojektion verbleiben lesbare Verweise. Der unveränderte Sitzungsrohverlauf bleibt vollständig erhalten. Gemischte Medienergebnisse, einzelne Ergebnisse unter 3.000 Zeichen und Stapel bis einschließlich 12.000 Zeichen bleiben unverändert. Beispiel: Bei zwei Suchergebnissen mit 7.000 und 6.000 Zeichen wird das größere Ergebnis privat gespeichert; Anfang, Ende, ausgelassene Zeichenzahl und `output_path` bleiben für den Agenten sichtbar.
119
121
 
120
122
  Ab BLUN King 9.1.100 beendet eine begrenzte Grep-Inhaltssuche ripgrep, sobald der Versatz, die angeforderten Zeilen und eine zusätzliche Vorschauzeile vollständig vorliegen. Die Vorschauzeile belegt, ob eine weitere Seite existiert, ohne vorher bis zu 10 MB einzulesen. Unbegrenzte Suchen, Trefferzählungen und nach Änderungszeit sortierte Dateilisten laufen weiterhin vollständig durch.
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ function normalizedExcludedToolNames(excludedNames) {
4
+ if (!Array.isArray(excludedNames)) return [];
5
+ return [...new Set(excludedNames
6
+ .map((name) => String(name || '').trim())
7
+ .filter(Boolean))];
8
+ }
9
+
10
+ function applyProfileToolExclusions(tools, excludedNames) {
11
+ const excluded = normalizedExcludedToolNames(excludedNames);
12
+ if (excluded.length === 0) return { tools, matched: [], unmatched: [] };
13
+
14
+ const excludedSet = new Set(excluded);
15
+ const matchedSet = new Set();
16
+ const filtered = [];
17
+ for (const tool of Array.isArray(tools) ? tools : []) {
18
+ const name = String(tool?.name || '');
19
+ if (excludedSet.has(name)) {
20
+ matchedSet.add(name);
21
+ continue;
22
+ }
23
+ filtered.push(tool);
24
+ }
25
+
26
+ return {
27
+ tools: filtered,
28
+ matched: excluded.filter((name) => matchedSet.has(name)),
29
+ unmatched: excluded.filter((name) => !matchedSet.has(name)),
30
+ };
31
+ }
32
+
33
+ module.exports = {
34
+ applyProfileToolExclusions,
35
+ normalizedExcludedToolNames,
36
+ };
37
+
package/blun.mjs CHANGED
@@ -21349,6 +21349,7 @@ var init_types$13 = __esmMin((() => {
21349
21349
  systemPromptTemplate: string().optional(),
21350
21350
  promptVars: record(string(), string()).optional(),
21351
21351
  tools: array(string()).optional(),
21352
+ excludedTools: array(string()).optional(),
21352
21353
  whenToUse: string().optional(),
21353
21354
  subagents: record(string(), RawSubagentProfileSchema).optional()
21354
21355
  });
@@ -28341,6 +28342,7 @@ function resolveMergedProfile(name, profileMap, cache, stack) {
28341
28342
  ...profile.promptVars
28342
28343
  },
28343
28344
  tools: profile.tools !== void 0 ? [...profile.tools] : [...parent?.tools ?? []],
28345
+ excludedTools: profile.excludedTools !== void 0 ? [...profile.excludedTools] : [...parent?.excludedTools ?? []],
28344
28346
  whenToUse: profile.whenToUse ?? parent?.whenToUse,
28345
28347
  subagents: cloneSubagents(profile.subagents)
28346
28348
  };
@@ -28353,6 +28355,7 @@ function toResolvedProfile(merged) {
28353
28355
  description: merged.description,
28354
28356
  systemPrompt: createSystemPromptRenderer(merged),
28355
28357
  tools: [...merged.tools],
28358
+ excludedTools: [...merged.excludedTools],
28356
28359
  whenToUse: merged.whenToUse
28357
28360
  };
28358
28361
  }
@@ -28524,9 +28527,12 @@ var PROFILE_SOURCES, DEFAULT_INIT_PROMPT, DEFAULT_AGENT_PROFILES;
28524
28527
  var init_default$1 = __esmMin((() => {
28525
28528
  init_agent$3();
28526
28529
  init_coder();
28530
+ coder_default = coder_default.replace("\nwhenToUse:", "\nexcludedTools:\n - mcp__plugin-telegram_telegram__reply\n - mcp__plugin-telegram_telegram__react\n - mcp__plugin-telegram_telegram__edit_message\n - mcp__plugin-telegram_telegram__download_attachment\n\nwhenToUse:");
28527
28531
  init_explore();
28532
+ explore_default = explore_default.replace("\nwhenToUse:", "\nexcludedTools:\n - mcp__plugin-telegram_telegram__reply\n - mcp__plugin-telegram_telegram__react\n - mcp__plugin-telegram_telegram__edit_message\n - mcp__plugin-telegram_telegram__download_attachment\n\nwhenToUse:");
28528
28533
  init_init();
28529
28534
  init_plan$1();
28535
+ plan_default = plan_default.replace("\nwhenToUse:", "\nexcludedTools:\n - mcp__plugin-telegram_telegram__reply\n - mcp__plugin-telegram_telegram__react\n - mcp__plugin-telegram_telegram__edit_message\n - mcp__plugin-telegram_telegram__download_attachment\n\nwhenToUse:");
28530
28536
  init_system();
28531
28537
  init_load();
28532
28538
  PROFILE_SOURCES = {
@@ -263333,7 +263339,7 @@ var init_builtin = __esmMin((() => {
263333
263339
  var init_types$3 = __esmMin((() => {}));
263334
263340
  //#endregion
263335
263341
  //#region ../../packages/agent-core/src/agent/tool/index.ts
263336
- var import_picomatch, SHELL_FOREGROUND_TIMEOUT_S, ToolManager;
263342
+ var import_picomatch, profileToolExclusionPolicy, applyProfileToolExclusions, SHELL_FOREGROUND_TIMEOUT_S, ToolManager;
263337
263343
  var init_tool$1 = __esmMin((() => {
263338
263344
  init_dist$4();
263339
263345
  import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
@@ -263346,6 +263352,8 @@ var init_tool$1 = __esmMin((() => {
263346
263352
  init_builtin();
263347
263353
  init_compact_conversation_tool();
263348
263354
  init_types$3();
263355
+ profileToolExclusionPolicy = createRequire(import.meta.url)("./bin/profile-tool-exclusion-policy.cjs");
263356
+ applyProfileToolExclusions = profileToolExclusionPolicy.applyProfileToolExclusions;
263349
263357
  SHELL_FOREGROUND_TIMEOUT_S = 120;
263350
263358
  ToolManager = class {
263351
263359
  agent;
@@ -263361,6 +263369,8 @@ var init_tool$1 = __esmMin((() => {
263361
263369
  store = {};
263362
263370
  mcpToolStatusUnsubscribe;
263363
263371
  allowedTools;
263372
+ excludedTools = [];
263373
+ reportedUnmatchedExclusions = /* @__PURE__ */ new Set();
263364
263374
  /** Abort controllers for in-flight `!` shell commands, keyed by commandId so
263365
263375
  * the TUI can cancel (Esc / Ctrl+C) a running command. */
263366
263376
  shellCommandControllers = /* @__PURE__ */ new Map();
@@ -263681,6 +263691,14 @@ var init_tool$1 = __esmMin((() => {
263681
263691
  setAllowedTools(tools) {
263682
263692
  this.allowedTools = tools !== void 0 && tools.length > 0 ? [...tools] : void 0;
263683
263693
  }
263694
+ setExcludedTools(names) {
263695
+ this.excludedTools = [...new Set((Array.isArray(names) ? names : []).map((name) => String(name || "").trim()).filter(Boolean))];
263696
+ this.reportedUnmatchedExclusions.clear();
263697
+ this.agent.records.logRecord({
263698
+ type: "tools.set_excluded_tools",
263699
+ names: this.excludedTools
263700
+ });
263701
+ }
263684
263702
  copyLoopToolsFrom(source) {
263685
263703
  this.loopToolsOverride = source.loopTools;
263686
263704
  }
@@ -263821,12 +263839,22 @@ var init_tool$1 = __esmMin((() => {
263821
263839
  }
263822
263840
  }
263823
263841
  get loopTools() {
263824
- if (this.loopToolsOverride !== void 0) return this.loopToolsOverride;
263825
- const mcpNames = [...this.mcpTools.keys()].filter((name) => this.isMcpToolEnabled(name));
263826
- const hideGoalMutationTools = this.agent.goal.getGoal().goal === null;
263827
- const allowedTools = this.allowedTools;
263828
- const names = uniq([...this.enabledTools, ...mcpNames]).toSorted((a, b) => a.localeCompare(b)).filter((name) => !(hideGoalMutationTools && (name === "SetGoalBudget" || name === "UpdateGoal")));
263829
- return (allowedTools !== void 0 && allowedTools.length > 0 ? names.filter((name) => allowedTools.includes(name)) : names).map((name) => this.userTools.get(name) ?? this.mcpTools.get(name)?.tool ?? this.builtinTools.get(name)).filter((tool) => !!tool);
263842
+ let selectedTools;
263843
+ if (this.loopToolsOverride !== void 0) selectedTools = this.loopToolsOverride;
263844
+ else {
263845
+ const mcpNames = [...this.mcpTools.keys()].filter((name) => this.isMcpToolEnabled(name));
263846
+ const hideGoalMutationTools = this.agent.goal.getGoal().goal === null;
263847
+ const allowedTools = this.allowedTools;
263848
+ const names = uniq([...this.enabledTools, ...mcpNames]).toSorted((a, b) => a.localeCompare(b)).filter((name) => !(hideGoalMutationTools && (name === "SetGoalBudget" || name === "UpdateGoal")));
263849
+ selectedTools = (allowedTools !== void 0 && allowedTools.length > 0 ? names.filter((name) => allowedTools.includes(name)) : names).map((name) => this.userTools.get(name) ?? this.mcpTools.get(name)?.tool ?? this.builtinTools.get(name)).filter((tool) => !!tool);
263850
+ }
263851
+ const exclusion = applyProfileToolExclusions(selectedTools, this.excludedTools);
263852
+ for (const name of exclusion.unmatched) if (!this.reportedUnmatchedExclusions.has(name)) {
263853
+ this.reportedUnmatchedExclusions.add(name);
263854
+ this.agent.log.warn("profile tool exclusion did not match a loaded tool", { name });
263855
+ this.agent.telemetry.track("profile_tool_exclusion_unmatched", { tool_name: name });
263856
+ }
263857
+ return exclusion.tools;
263830
263858
  }
263831
263859
  };
263832
263860
  }));
@@ -264424,6 +264452,7 @@ var init_agent = __esmMin((() => {
264424
264452
  this.setActiveProfile(profile, brandHome);
264425
264453
  this.updateSystemPromptFromProfile(profile, context);
264426
264454
  this.tools.setActiveTools(profile.tools);
264455
+ this.tools.setExcludedTools(profile.excludedTools);
264427
264456
  }
264428
264457
  setActiveProfile(profile, brandHome) {
264429
264458
  this.activeProfile = profile;
@@ -412820,27 +412849,45 @@ const STREAMING_ARGS_PREVIEW_MAX_CHARS = 64 * 1024;
412820
412849
  registerUiCatalogFragment({
412821
412850
  en: {
412822
412851
  "eventPayload.providerFiltered": "Provider filtered the response before visible output (finishReason={finishReason}{raw}).",
412823
- "eventPayload.modelEmptyResponse": "King ended twice without producing content. Please send the message again."
412852
+ "eventPayload.modelEmptyResponse": "King ended twice without producing content. Please send the message again.",
412853
+ "eventPayload.providerBusy": "King is busy right now. Please try again shortly.",
412854
+ "eventPayload.providerUnavailable": "King could not complete this response. Please try again.",
412855
+ "eventPayload.providerAuthRequired": "Your King connection needs to be renewed. Please sign in again."
412824
412856
  },
412825
412857
  de: {
412826
412858
  "eventPayload.providerFiltered": "Der Anbieter hat die Antwort vor der sichtbaren Ausgabe gefiltert (finishReason={finishReason}{raw}).",
412827
- "eventPayload.modelEmptyResponse": "King hat die Antwort zweimal ohne Inhalt beendet. Bitte sende die Nachricht noch einmal."
412859
+ "eventPayload.modelEmptyResponse": "King hat die Antwort zweimal ohne Inhalt beendet. Bitte sende die Nachricht noch einmal.",
412860
+ "eventPayload.providerBusy": "King ist gerade ausgelastet. Bitte versuche es gleich noch einmal.",
412861
+ "eventPayload.providerUnavailable": "King konnte diese Antwort nicht abschließen. Bitte versuche es noch einmal.",
412862
+ "eventPayload.providerAuthRequired": "Die Verbindung zu King muss erneuert werden. Bitte melde dich erneut an."
412828
412863
  },
412829
412864
  es: {
412830
412865
  "eventPayload.providerFiltered": "El proveedor filtró la respuesta antes de que se mostrara la salida (finishReason={finishReason}{raw}).",
412831
- "eventPayload.modelEmptyResponse": "King terminó dos veces sin generar contenido. Envía el mensaje de nuevo."
412866
+ "eventPayload.modelEmptyResponse": "King terminó dos veces sin generar contenido. Envía el mensaje de nuevo.",
412867
+ "eventPayload.providerBusy": "King está ocupado en este momento. Vuelve a intentarlo en unos instantes.",
412868
+ "eventPayload.providerUnavailable": "King no ha podido completar esta respuesta. Vuelve a intentarlo.",
412869
+ "eventPayload.providerAuthRequired": "Es necesario renovar la conexión con King. Vuelve a iniciar sesión."
412832
412870
  },
412833
412871
  fr: {
412834
412872
  "eventPayload.providerFiltered": "Le fournisseur a filtré la réponse avant l’affichage de la sortie (finishReason={finishReason}{raw}).",
412835
- "eventPayload.modelEmptyResponse": "King a terminé deux fois sans produire de contenu. Envoyez à nouveau le message."
412873
+ "eventPayload.modelEmptyResponse": "King a terminé deux fois sans produire de contenu. Envoyez à nouveau le message.",
412874
+ "eventPayload.providerBusy": "King est occupé pour le moment. Réessayez dans quelques instants.",
412875
+ "eventPayload.providerUnavailable": "King n’a pas pu terminer cette réponse. Réessayez.",
412876
+ "eventPayload.providerAuthRequired": "La connexion à King doit être renouvelée. Reconnectez-vous."
412836
412877
  },
412837
412878
  sv: {
412838
412879
  "eventPayload.providerFiltered": "Leverantören filtrerade svaret innan någon utdata visades (finishReason={finishReason}{raw}).",
412839
- "eventPayload.modelEmptyResponse": "King avslutade två gånger utan att skapa något innehåll. Skicka meddelandet igen."
412880
+ "eventPayload.modelEmptyResponse": "King avslutade två gånger utan att skapa något innehåll. Skicka meddelandet igen.",
412881
+ "eventPayload.providerBusy": "King är upptagen just nu. Försök igen om en liten stund.",
412882
+ "eventPayload.providerUnavailable": "King kunde inte slutföra svaret. Försök igen.",
412883
+ "eventPayload.providerAuthRequired": "Anslutningen till King behöver förnyas. Logga in igen."
412840
412884
  },
412841
412885
  cs: {
412842
412886
  "eventPayload.providerFiltered": "Poskytovatel filtroval odpověď před viditelným výstupem (finishReason={finishReason}{raw}).",
412843
- "eventPayload.modelEmptyResponse": "King dvakrát ukončil odpověď bez obsahu. Odešlete zprávu znovu."
412887
+ "eventPayload.modelEmptyResponse": "King dvakrát ukončil odpověď bez obsahu. Odešlete zprávu znovu.",
412888
+ "eventPayload.providerBusy": "King je právě zaneprázdněný. Zkuste to za chvíli znovu.",
412889
+ "eventPayload.providerUnavailable": "King nemohl tuto odpověď dokončit. Zkuste to znovu.",
412890
+ "eventPayload.providerAuthRequired": "Připojení ke Kingovi je potřeba obnovit. Přihlaste se znovu."
412844
412891
  }
412845
412892
  });
412846
412893
  //#endregion
@@ -412915,10 +412962,24 @@ function formatErrorMessage$2(error) {
412915
412962
  }
412916
412963
  function formatErrorPayload(error) {
412917
412964
  if (error.code === "model.empty_response") return uiText("eventPayload.modelEmptyResponse");
412965
+ if (error.code === "provider.rate_limit") return uiText("eventPayload.providerBusy");
412966
+ if (error.code === "provider.api_error" || error.code === "provider.connection_error") return uiText("eventPayload.providerUnavailable");
412967
+ if (error.code === "provider.auth_error") return uiText("eventPayload.providerAuthRequired");
412918
412968
  const filteredMessage = formatProviderFilteredMessage(error.details);
412919
- if (filteredMessage !== void 0) return projectBlunIdentity(`[${error.code}] ${filteredMessage}`);
412969
+ if (filteredMessage !== void 0) return projectBlunIdentity(filteredMessage);
412920
412970
  return projectBlunIdentity(`[${error.code}] ${error.message}`);
412921
412971
  }
412972
+
412973
+ const CUSTOMER_FACING_ERROR_CODES = /* @__PURE__ */ new Set([
412974
+ "provider.rate_limit",
412975
+ "provider.api_error",
412976
+ "provider.connection_error",
412977
+ "provider.auth_error",
412978
+ "model.empty_response"
412979
+ ]);
412980
+ function shouldShowErrorReportHint(event) {
412981
+ return !CUSTOMER_FACING_ERROR_CODES.has(event.code);
412982
+ }
412922
412983
  function formatProviderFilteredMessage(details) {
412923
412984
  const finishReason = stringDetail(details, "finishReason");
412924
412985
  const rawFinishReason = stringDetail(details, "rawFinishReason");
@@ -497166,29 +497227,41 @@ var HelpPanelComponent = class extends Container {
497166
497227
  focused = false;
497167
497228
  opts;
497168
497229
  scrollTop = 0;
497230
+ selectedCommandIndex = 0;
497231
+ showCommandDetail = false;
497169
497232
  constructor(opts) {
497170
497233
  super();
497171
497234
  this.opts = opts;
497172
497235
  }
497173
497236
  handleInput(data) {
497174
497237
  const printable = decodeKittyPrintable(data) ?? data;
497175
- if (matchesKey(data, Key.escape) || matchesKey(data, Key.enter) || printable === "q" || printable === "Q") {
497238
+ if (matchesKey(data, Key.escape) || printable === "q" || printable === "Q") {
497176
497239
  this.opts.onClose();
497177
497240
  return;
497178
497241
  }
497242
+ const sortedCmds = [...this.opts.commands].toSorted(compareSlashCommandsForDisplay);
497243
+ if (sortedCmds.length === 0) return;
497244
+ if (matchesKey(data, Key.right) || matchesKey(data, Key.enter)) {
497245
+ this.showCommandDetail = true;
497246
+ return;
497247
+ }
497248
+ if (matchesKey(data, Key.left)) {
497249
+ this.showCommandDetail = false;
497250
+ return;
497251
+ }
497179
497252
  if (matchesKey(data, Key.up)) {
497180
- this.scrollTop = Math.max(0, this.scrollTop - 1);
497253
+ this.selectedCommandIndex = Math.max(0, this.selectedCommandIndex - 1);
497181
497254
  return;
497182
497255
  }
497183
497256
  if (matchesKey(data, Key.down)) {
497184
- this.scrollTop += 1;
497257
+ this.selectedCommandIndex = Math.min(sortedCmds.length - 1, this.selectedCommandIndex + 1);
497185
497258
  return;
497186
497259
  }
497187
497260
  if (matchesKey(data, Key.pageUp)) {
497188
- this.scrollTop = Math.max(0, this.scrollTop - 10);
497261
+ this.selectedCommandIndex = Math.max(0, this.selectedCommandIndex - 10);
497189
497262
  return;
497190
497263
  }
497191
- if (matchesKey(data, Key.pageDown)) this.scrollTop += 10;
497264
+ if (matchesKey(data, Key.pageDown)) this.selectedCommandIndex = Math.min(sortedCmds.length - 1, this.selectedCommandIndex + 10);
497192
497265
  }
497193
497266
  render(width) {
497194
497267
  const accent = (text) => currentTheme.fg("primary", text);
@@ -497199,6 +497272,8 @@ var HelpPanelComponent = class extends Container {
497199
497272
  const shortcuts = this.opts.shortcuts ?? DEFAULT_KEYBOARD_SHORTCUTS;
497200
497273
  const kbdWidth = Math.max(8, ...shortcuts.map((s) => s.keys.length));
497201
497274
  const sortedCmds = [...this.opts.commands].toSorted(compareSlashCommandsForDisplay);
497275
+ this.selectedCommandIndex = Math.max(0, Math.min(this.selectedCommandIndex, Math.max(0, sortedCmds.length - 1)));
497276
+ if (this.showCommandDetail && sortedCmds.length > 0) return this.renderCommandDetail(width, sortedCmds);
497202
497277
  const cmdLabels = sortedCmds.map((c) => {
497203
497278
  const aliases = c.aliases.length > 0 ? ` (${c.aliases.map((a) => "/" + a).join(", ")})` : "";
497204
497279
  return `/${c.name}${aliases}`;
@@ -497215,7 +497290,10 @@ var HelpPanelComponent = class extends Container {
497215
497290
  "",
497216
497291
  ` ${currentTheme.bold(uiText("help.slashCommands"))}`,
497217
497292
  ...sortedCmds.map((cmd, i) => {
497218
- return ` ${slashColor((cmdLabels[i] ?? `/${cmd.name}`).padEnd(cmdWidth))} ${dim(cmd.description)}`;
497293
+ const marker = i === this.selectedCommandIndex ? accent("â–¶") : " ";
497294
+ const label = (cmdLabels[i] ?? `/${cmd.name}`).padEnd(cmdWidth);
497295
+ const commandText = i === this.selectedCommandIndex ? currentTheme.boldFg("primary", label) : slashColor(label);
497296
+ return ` ${marker} ${commandText} ${dim(cmd.description)}`;
497219
497297
  }),
497220
497298
  "",
497221
497299
  accent("─".repeat(width))
@@ -497223,6 +497301,9 @@ var HelpPanelComponent = class extends Container {
497223
497301
  const content = lines.slice(1, lines.length - 1);
497224
497302
  const maxVisible = Math.max(5, this.opts.maxVisible ?? 24);
497225
497303
  if (content.length > maxVisible) {
497304
+ const selectedLine = 7 + shortcuts.length + this.selectedCommandIndex;
497305
+ if (selectedLine < this.scrollTop) this.scrollTop = selectedLine;
497306
+ if (selectedLine >= this.scrollTop + maxVisible) this.scrollTop = selectedLine - maxVisible + 1;
497226
497307
  this.scrollTop = Math.max(0, Math.min(this.scrollTop, content.length - maxVisible));
497227
497308
  const slice = content.slice(this.scrollTop, this.scrollTop + maxVisible);
497228
497309
  const scrollInfo = muted(` ${uiText("help.scrollInfo", {
@@ -497240,6 +497321,27 @@ var HelpPanelComponent = class extends Container {
497240
497321
  this.scrollTop = 0;
497241
497322
  return lines.map((line) => truncateToWidth(line, width));
497242
497323
  }
497324
+ renderCommandDetail(width, sortedCmds) {
497325
+ const accent = (text) => currentTheme.fg("primary", text);
497326
+ const dim = (text) => currentTheme.fg("textDim", text);
497327
+ const muted = (text) => currentTheme.fg("textMuted", text);
497328
+ const command = sortedCmds[this.selectedCommandIndex];
497329
+ if (command === void 0) return [];
497330
+ const argumentHint = typeof command.argumentHint === "string" && command.argumentHint.length > 0 ? ` ${command.argumentHint}` : "";
497331
+ const aliases = command.aliases.length > 0 ? command.aliases.map((alias) => `/${alias}`).join(", ") : "—";
497332
+ const descriptionLines = wrapTextWithAnsi(dim(command.description), Math.max(10, width - 4)).map((line) => ` ${line}`);
497333
+ return [
497334
+ accent("─".repeat(width)),
497335
+ currentTheme.boldFg("primary", ` /${command.name}${argumentHint}`),
497336
+ "",
497337
+ ...descriptionLines,
497338
+ "",
497339
+ ` ${muted("=")} ${dim(aliases)}`,
497340
+ "",
497341
+ muted(` ${this.selectedCommandIndex + 1}/${sortedCmds.length} · ↑↓ · ← · Esc / q`),
497342
+ accent("─".repeat(width))
497343
+ ].map((line) => truncateToWidth(line, width));
497344
+ }
497243
497345
  };
497244
497346
  function localizedShortcut(keys, descriptionKey) {
497245
497347
  return {
@@ -506727,6 +506829,7 @@ var SessionEventHandler = class {
506727
506829
  this.showErrorReportHint(event);
506728
506830
  }
506729
506831
  showErrorReportHint(event) {
506832
+ if (!shouldShowErrorReportHint(event)) return;
506730
506833
  const { appState } = this.host.state;
506731
506834
  if (appState.sessionId.length === 0) return;
506732
506835
  this.host.showStatus(errorReportHintLine({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.105",
3
+ "version": "9.1.107",
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": {