blun-king-cli 9.1.337 → 9.1.338

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.
@@ -1,6 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const PRIVATE_CHAT_ID = /^[1-9]\d*$/u;
4
+ const WORK_PERMISSION_QUESTION = /^(?:kann|darf|soll) ich\b.{0,100}\b(?:arbeit(?:en)?|weiterarbeiten|weitermachen|fortfahren|weiterbauen|umbau|bau)\b/u;
5
+ const TRAILING_WORK_PERMISSION_QUESTION = /(?:^|\r?\n\s*\r?\n)(?:kann|darf|soll)\s+ich\b[^\r\n]{0,160}\b(?:arbeit(?:en)?|weiterarbeiten|weitermachen|fortfahren|weiterbauen|umbau|bau)\b[^\r\n]*$/iu;
6
+ const INTERNAL_CONTROL_MARKER = /\b(?:cron|loop|checkpoint|handoff|resume|session|sha|tool|werkzeug|hook|queue|lane|inbound|outbound|arbeitsstand|arbeitsauftrag|bau freigabe|freigabe dieser lane|turn|zug|status|private nachricht|telegram nachricht|reply|verlauf|basis|qa gate|wartezustand|f\d+|m\d+|w\d+)\b/gu;
7
+ const NO_USER_VALUE = /\b(?:keine neue aktion|keine neue information|keine neue nachricht|kein neuer auftrag|kein neuer zweck|kein neuer inbound bedarf|kein offener handlungsbedarf|nichts neues zu melden|nichts zu melden|nichts weiteres|bleibt pausiert|warte auf (?:dein|sein|ihr|papas) (?:zeichen|go|freigabe|antwort)|ich warte|ich sende nichts|wiederholen wäre spam|keine weitere nachricht|bereits geantwortet|bereits gesendet|kein werkzeugaufruf nötig|stand unverändert|zug läuft seit|kein bau ohne|qa gate steht noch aus|wartezustand)\b/u;
4
8
 
5
9
  function normalize(text) {
6
10
  return String(text ?? '')
@@ -11,16 +15,24 @@ function normalize(text) {
11
15
  .trim();
12
16
  }
13
17
 
18
+ function sanitizePrivateConversationReply(chatId, text) {
19
+ const value = String(text ?? '');
20
+ if (!PRIVATE_CHAT_ID.test(String(chatId ?? '').trim())) return value;
21
+ return value.replace(TRAILING_WORK_PERMISSION_QUESTION, '').trim();
22
+ }
23
+
14
24
  function isPrivateInternalStatusReply(chatId, text) {
15
25
  if (!PRIVATE_CHAT_ID.test(String(chatId ?? '').trim())) return false;
16
- const value = normalize(text);
26
+ const sanitized = sanitizePrivateConversationReply(chatId, text);
27
+ const value = normalize(sanitized.length === 0 ? text : sanitized);
17
28
  if (value.length === 0) return false;
29
+ if (sanitized.length === 0 && WORK_PERMISSION_QUESTION.test(value)) return true;
18
30
 
19
- const exposesRuntimeControl = /\b(?:cron|loop|checkpoint|sha|tool|werkzeug|hook|queue|lane|inbound|outbound|arbeitsstand|arbeitsauftrag|bau freigabe|freigabe dieser lane|turn|zug|status|private nachricht|telegram nachricht|reply|verlauf|basis|f\d+|m\d+|w\d+)\b/u.test(value);
20
- const announcesNoUserValue = /\b(?:keine neue aktion|keine neue information|keine neue nachricht|kein neuer auftrag|kein neuer zweck|kein neuer inbound bedarf|kein offener handlungsbedarf|nichts zu melden|nichts weiteres|bleibt pausiert|warte auf (?:dein|sein|ihr|papas) (?:zeichen|go|freigabe|antwort)|ich warte|ich sende nichts|wiederholen wäre spam|keine weitere nachricht|bereits geantwortet|bereits gesendet|kein werkzeugaufruf nötig|stand unverändert|zug läuft seit)\b/u.test(value);
21
- return exposesRuntimeControl && announcesNoUserValue;
31
+ const internalMarkers = value.match(INTERNAL_CONTROL_MARKER) ?? [];
32
+ return internalMarkers.length > 0 && NO_USER_VALUE.test(value);
22
33
  }
23
34
 
24
35
  module.exports = {
25
36
  isPrivateInternalStatusReply,
37
+ sanitizePrivateConversationReply,
26
38
  };
package/blun.mjs CHANGED
@@ -514699,7 +514699,7 @@ function outboxDeliveredFile(marker, chatId, filePath) {
514699
514699
  }
514700
514700
  var retryTelegramMediaDelivery, retryableTelegramMediaFailure;
514701
514701
  ({ retryTelegramMediaDelivery, retryableTelegramMediaFailure } = createRequire(import.meta.url)("./bin/telegram-media-delivery-policy.cjs"));
514702
- var { isPrivateInternalStatusReply } = createRequire(import.meta.url)("./bin/telegram-private-conversation-policy.cjs");
514702
+ var { isPrivateInternalStatusReply, sanitizePrivateConversationReply } = createRequire(import.meta.url)("./bin/telegram-private-conversation-policy.cjs");
514703
514703
  const TELEGRAM_TEXT_LIMIT = 4096;
514704
514704
  const TELEGRAM_ATTACHMENT_LIMIT = 50 * 1024 * 1024;
514705
514705
  function mediaTelegramTarget(filePath) {
@@ -514788,6 +514788,7 @@ async function sendReplyFallback(chatId, text, contextOnly = false) {
514788
514788
  } catch {}
514789
514789
  return true;
514790
514790
  }
514791
+ const privateSafeText = sanitizePrivateConversationReply(chatId, text);
514791
514792
  if (isGroupChat(chatId) && isGroupSuppressed(text, contextOnly)) {
514792
514793
  try {
514793
514794
  appendFileSync(outboxPath(), `${JSON.stringify({
@@ -514802,7 +514803,7 @@ async function sendReplyFallback(chatId, text, contextOnly = false) {
514802
514803
  }
514803
514804
  const token = botToken();
514804
514805
  if (token === void 0) return false;
514805
- const body = text.length > TELEGRAM_TEXT_LIMIT ? `${text.slice(0, TELEGRAM_TEXT_LIMIT - 1)}…` : text;
514806
+ const body = privateSafeText.length > TELEGRAM_TEXT_LIMIT ? `${privateSafeText.slice(0, TELEGRAM_TEXT_LIMIT - 1)}…` : privateSafeText;
514806
514807
  try {
514807
514808
  const payload = await (await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
514808
514809
  method: "POST",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.337",
3
+ "version": "9.1.338",
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": {
@@ -1,6 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const PRIVATE_CHAT_ID = /^[1-9]\d*$/u;
4
+ const WORK_PERMISSION_QUESTION = /^(?:kann|darf|soll) ich\b.{0,100}\b(?:arbeit(?:en)?|weiterarbeiten|weitermachen|fortfahren|weiterbauen|umbau|bau)\b/u;
5
+ const TRAILING_WORK_PERMISSION_QUESTION = /(?:^|\r?\n\s*\r?\n)(?:kann|darf|soll)\s+ich\b[^\r\n]{0,160}\b(?:arbeit(?:en)?|weiterarbeiten|weitermachen|fortfahren|weiterbauen|umbau|bau)\b[^\r\n]*$/iu;
6
+ const INTERNAL_CONTROL_MARKER = /\b(?:cron|loop|checkpoint|handoff|resume|session|sha|tool|werkzeug|hook|queue|lane|inbound|outbound|arbeitsstand|arbeitsauftrag|bau freigabe|freigabe dieser lane|turn|zug|status|private nachricht|telegram nachricht|reply|verlauf|basis|qa gate|wartezustand|f\d+|m\d+|w\d+)\b/gu;
7
+ const NO_USER_VALUE = /\b(?:keine neue aktion|keine neue information|keine neue nachricht|kein neuer auftrag|kein neuer zweck|kein neuer inbound bedarf|kein offener handlungsbedarf|nichts neues zu melden|nichts zu melden|nichts weiteres|bleibt pausiert|warte auf (?:dein|sein|ihr|papas) (?:zeichen|go|freigabe|antwort)|ich warte|ich sende nichts|wiederholen wäre spam|keine weitere nachricht|bereits geantwortet|bereits gesendet|kein werkzeugaufruf nötig|stand unverändert|zug läuft seit|kein bau ohne|qa gate steht noch aus|wartezustand)\b/u;
4
8
 
5
9
  function normalize(text) {
6
10
  return String(text ?? '')
@@ -11,16 +15,24 @@ function normalize(text) {
11
15
  .trim();
12
16
  }
13
17
 
18
+ function sanitizePrivateConversationReply(chatId, text) {
19
+ const value = String(text ?? '');
20
+ if (!PRIVATE_CHAT_ID.test(String(chatId ?? '').trim())) return value;
21
+ return value.replace(TRAILING_WORK_PERMISSION_QUESTION, '').trim();
22
+ }
23
+
14
24
  function isPrivateInternalStatusReply(chatId, text) {
15
25
  if (!PRIVATE_CHAT_ID.test(String(chatId ?? '').trim())) return false;
16
- const value = normalize(text);
26
+ const sanitized = sanitizePrivateConversationReply(chatId, text);
27
+ const value = normalize(sanitized.length === 0 ? text : sanitized);
17
28
  if (value.length === 0) return false;
29
+ if (sanitized.length === 0 && WORK_PERMISSION_QUESTION.test(value)) return true;
18
30
 
19
- const exposesRuntimeControl = /\b(?:cron|loop|checkpoint|sha|tool|werkzeug|hook|queue|lane|inbound|outbound|arbeitsstand|arbeitsauftrag|bau freigabe|freigabe dieser lane|turn|zug|status|private nachricht|telegram nachricht|reply|verlauf|basis|f\d+|m\d+|w\d+)\b/u.test(value);
20
- const announcesNoUserValue = /\b(?:keine neue aktion|keine neue information|keine neue nachricht|kein neuer auftrag|kein neuer zweck|kein neuer inbound bedarf|kein offener handlungsbedarf|nichts zu melden|nichts weiteres|bleibt pausiert|warte auf (?:dein|sein|ihr|papas) (?:zeichen|go|freigabe|antwort)|ich warte|ich sende nichts|wiederholen wäre spam|keine weitere nachricht|bereits geantwortet|bereits gesendet|kein werkzeugaufruf nötig|stand unverändert|zug läuft seit)\b/u.test(value);
21
- return exposesRuntimeControl && announcesNoUserValue;
31
+ const internalMarkers = value.match(INTERNAL_CONTROL_MARKER) ?? [];
32
+ return internalMarkers.length > 0 && NO_USER_VALUE.test(value);
22
33
  }
23
34
 
24
35
  module.exports = {
25
36
  isPrivateInternalStatusReply,
37
+ sanitizePrivateConversationReply,
26
38
  };
@@ -8,8 +8,10 @@ import { fileURLToPath } from "node:url";
8
8
  import { hostname } from "node:os";
9
9
  import remoteStatusPolicy from "../../bin/telegram-remote-status-policy.cjs";
10
10
  import telegramApprovalRelay from "../../bin/telegram-approval-relay.cjs";
11
+ import privateConversationPolicy from "../bin/telegram-private-conversation-policy.cjs";
11
12
  const { buildTelegramRemoteStatus, resolveTelegramRemoteVersion } = remoteStatusPolicy;
12
13
  const { buildTelegramApprovalCard, isAuthorizedTelegramApprovalCallback, listPendingTelegramApprovals, markTelegramApprovalSent, parseTelegramApprovalCallback, resolveTelegramApprovalTarget, wasTelegramApprovalSent, writeTelegramApprovalResponse } = telegramApprovalRelay;
14
+ const { isPrivateInternalStatusReply, sanitizePrivateConversationReply } = privateConversationPolicy;
13
15
  //#region ../../node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs
14
16
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
15
17
  function normalizeWindowsPath(input = "") {
@@ -4186,11 +4188,23 @@ function scrubSecrets(text) {
4186
4188
  async function sendReplyFallback(chatId, rawText) {
4187
4189
  const token = botToken();
4188
4190
  if (token === void 0) return false;
4191
+ if (isPrivateInternalStatusReply(chatId, rawText)) {
4192
+ appendFileSync(outboxLog(), `${JSON.stringify({
4193
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4194
+ direction: "out",
4195
+ kind: "reply-fallback-suppressed-private-internal",
4196
+ chat_id: String(chatId),
4197
+ text: rawText
4198
+ })}\n`);
4199
+ logLine(`reply-fallback suppressed (private internal): ${rawText.slice(0, 60)}`);
4200
+ return true;
4201
+ }
4202
+ const privateSafeText = sanitizePrivateConversationReply(chatId, rawText);
4189
4203
  if (isGroupChat(chatId) && isGroupNoiseReply(rawText)) {
4190
4204
  logLine(`reply-fallback suppressed (group meta-noise): ${rawText.slice(0, 60)}`);
4191
4205
  return true;
4192
4206
  }
4193
- const text = scrubSecrets(rawText);
4207
+ const text = scrubSecrets(privateSafeText);
4194
4208
  const body = text.length > TELEGRAM_TEXT_LIMIT ? `${text.slice(0, TELEGRAM_TEXT_LIMIT - 1)}…` : text;
4195
4209
  try {
4196
4210
  const payload = await (await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
@@ -9667,7 +9667,7 @@ var StdioServerTransport = class {
9667
9667
  * chats the inbound gate would deliver from.
9668
9668
  */
9669
9669
  var import_out = require_out();
9670
- const { isPrivateInternalStatusReply } = privateConversationPolicy;
9670
+ const { isPrivateInternalStatusReply, sanitizePrivateConversationReply } = privateConversationPolicy;
9671
9671
  const TOOL_DEFINITIONS = [
9672
9672
  {
9673
9673
  name: "reply",
@@ -9841,11 +9841,12 @@ async function sendTelegramTextChunk(api, chatId, text, options, parseMode) {
9841
9841
  }
9842
9842
  async function runReply(api, args) {
9843
9843
  const chatId = resolveAllowedChatId(args.chat_id);
9844
- const text = args.text;
9844
+ const rawText = args.text;
9845
9845
  const replyTo = args.reply_to != null ? Number(args.reply_to) : void 0;
9846
9846
  const files = args.files ?? [];
9847
+ const text = files.length === 0 ? sanitizePrivateConversationReply(chatId, rawText) : rawText;
9847
9848
  const parseMode = args.format === "markdownv2" ? "MarkdownV2" : void 0;
9848
- if (files.length === 0 && isPrivateInternalStatusReply(chatId, text)) {
9849
+ if (files.length === 0 && isPrivateInternalStatusReply(chatId, rawText)) {
9849
9850
  appendJsonl(outboxLog(), {
9850
9851
  direction: "out",
9851
9852
  kind: "reply-suppressed-private-internal",