blun-king-cli 9.1.49 → 9.1.51

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.49",
3
+ "version": "9.1.51",
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": {
@@ -73603,8 +73603,9 @@ async function runTool(api, token, name, args) {
73603
73603
  * Idempotency guard: models occasionally call reply multiple times with the
73604
73604
  * same text. A message that
73605
73605
  * innerhalb des Fensters bereits wortgleich an denselben Chat ging, wird nicht
73606
- * erneut gesendet — das Tool meldet dem Modell "bereits zugestellt", damit es
73607
- * nicht weiter retryt. Datei-Anhänge sind nie betroffen.
73606
+ * erneut gesendet — das Tool meldet dem Modell "bereits zugestellt", damit es
73607
+ * nicht weiter retryt. Bereits automatisch gelieferte Dateien werden aus
73608
+ * einem direkt folgenden manuellen Reply entfernt.
73608
73609
  */
73609
73610
  const DUPLICATE_WINDOW_MS = 3e5;
73610
73611
  const OUTBOX_TAIL_BYTES = 32768;
@@ -73629,13 +73630,49 @@ function isRecentDuplicate(chatId, text) {
73629
73630
  } catch {}
73630
73631
  return false;
73631
73632
  }
73633
+ function recentlyDeliveredFiles(chatId, files) {
73634
+ if (files.length === 0) return /* @__PURE__ */ new Set();
73635
+ const wanted = new Map(files.map((file) => [resolve(file).toLowerCase(), file]));
73636
+ const delivered = /* @__PURE__ */ new Set();
73637
+ try {
73638
+ const file = outboxLog();
73639
+ const size = statSync(file).size;
73640
+ const raw = readFileSync(file, "utf8");
73641
+ const tail = size > OUTBOX_TAIL_BYTES ? raw.slice(raw.length - OUTBOX_TAIL_BYTES) : raw;
73642
+ const cutoff = Date.now() - DUPLICATE_WINDOW_MS;
73643
+ for (const line of tail.split("\n")) {
73644
+ if (line.trim().length === 0) continue;
73645
+ try {
73646
+ const entry = JSON.parse(line);
73647
+ if (String(entry.chat_id) !== String(chatId)) continue;
73648
+ if (entry.ts === void 0 || Date.parse(entry.ts) < cutoff || !Array.isArray(entry.files)) continue;
73649
+ for (const priorFile of entry.files) {
73650
+ if (typeof priorFile !== "string") continue;
73651
+ const original = wanted.get(resolve(priorFile).toLowerCase());
73652
+ if (original !== void 0) delivered.add(original);
73653
+ }
73654
+ } catch {}
73655
+ }
73656
+ } catch {}
73657
+ return delivered;
73658
+ }
73632
73659
  async function runReply(api, args) {
73633
73660
  const chatId = args["chat_id"];
73634
73661
  const text = args["text"];
73635
73662
  const replyTo = args["reply_to"] !== null && args["reply_to"] !== void 0 ? Number(args["reply_to"]) : void 0;
73636
- const files = args["files"] ?? [];
73663
+ let files = args["files"] ?? [];
73637
73664
  const parseMode = args["format"] === "markdownv2" ? "MarkdownV2" : void 0;
73638
73665
  assertAllowedChat(chatId);
73666
+ const duplicateFiles = recentlyDeliveredFiles(chatId, files);
73667
+ if (duplicateFiles.size > 0) {
73668
+ files = files.filter((file) => !duplicateFiles.has(file));
73669
+ appendJsonl(outboxLog(), {
73670
+ direction: "out",
73671
+ kind: "reply-file-duplicate-suppressed",
73672
+ chat_id: chatId,
73673
+ files: [...duplicateFiles]
73674
+ });
73675
+ }
73639
73676
  if (files.length === 0 && isGroupChat(chatId) && isGroupNoiseReply(text)) {
73640
73677
  appendJsonl(outboxLog(), {
73641
73678
  direction: "out",