blun-king-cli 9.1.445 → 9.1.446

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.
@@ -5,6 +5,11 @@ const DEFAULT_WINDOW_WORDS = 20;
5
5
  const DEFAULT_REQUIRED_OCCURRENCES = 4;
6
6
  const DEFAULT_MAX_CHARS = 24_000;
7
7
  const DEFAULT_CHECK_EVERY_WORDS = 24;
8
+ const DEFAULT_SHORT_BURST_MAX_WORDS = 8;
9
+ const DEFAULT_SHORT_BURST_MIN_OCCURRENCES = 8;
10
+ const DEFAULT_SHORT_BURST_MIN_TOTAL_WORDS = 24;
11
+ const DEFAULT_SHORT_BURST_MIN_WORDS = 2;
12
+ const DEFAULT_SHORT_BURST_SCAN_WORDS = 192;
8
13
 
9
14
  function normalizeWords(text) {
10
15
  return String(text)
@@ -40,16 +45,80 @@ function repeatedWindow(words, options) {
40
45
  return null;
41
46
  }
42
47
 
48
+ function equalWindow(words, left, right, width) {
49
+ for (let offset = 0; offset < width; offset += 1) {
50
+ if (words[left + offset] !== words[right + offset]) return false;
51
+ }
52
+ return true;
53
+ }
54
+
55
+ function canCloseConsecutiveWindow(words, minWords, maxWords) {
56
+ const lastIndex = words.length - 1;
57
+ for (let windowWords = minWords; windowWords <= maxWords; windowWords += 1) {
58
+ const previousIndex = lastIndex - windowWords;
59
+ if (previousIndex >= 0 && words[lastIndex] === words[previousIndex]) return true;
60
+ }
61
+ return false;
62
+ }
63
+
64
+ function repeatedConsecutiveWindow(words, options) {
65
+ const {
66
+ maxWords,
67
+ minOccurrences,
68
+ minTotalWords,
69
+ minWords,
70
+ scanWords,
71
+ firstEnd = 1,
72
+ } = options;
73
+ const sourceStart = Math.max(0, words.length - scanWords);
74
+ const localFirstEnd = Math.max(sourceStart + 1, firstEnd);
75
+
76
+ for (let end = localFirstEnd; end <= words.length; end += 1) {
77
+ for (let windowWords = minWords; windowWords <= maxWords; windowWords += 1) {
78
+ const requiredOccurrences = Math.max(
79
+ minOccurrences,
80
+ Math.ceil(minTotalWords / windowWords),
81
+ );
82
+ const requiredSpan = windowWords * requiredOccurrences;
83
+ const start = end - requiredSpan;
84
+ if (start < sourceStart) continue;
85
+ let count = 1;
86
+ let cursor = start + windowWords;
87
+ while (cursor + windowWords <= end
88
+ && equalWindow(words, start, cursor, windowWords)) {
89
+ count += 1;
90
+ cursor += windowWords;
91
+ }
92
+ if (count < requiredOccurrences) continue;
93
+ return {
94
+ kind: 'short_burst',
95
+ count,
96
+ firstWords: words.slice(start, start + windowWords).join(' '),
97
+ };
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+
43
103
  function createLiveResponseRepetitionGuard(options = {}) {
44
104
  const config = {
45
105
  checkEveryWords: options.checkEveryWords ?? DEFAULT_CHECK_EVERY_WORDS,
46
106
  maxChars: options.maxChars ?? DEFAULT_MAX_CHARS,
47
107
  minWords: options.minWords ?? DEFAULT_MIN_WORDS,
48
108
  requiredOccurrences: options.requiredOccurrences ?? DEFAULT_REQUIRED_OCCURRENCES,
109
+ shortBurstMaxWords: options.shortBurstMaxWords ?? DEFAULT_SHORT_BURST_MAX_WORDS,
110
+ shortBurstMinOccurrences: options.shortBurstMinOccurrences
111
+ ?? DEFAULT_SHORT_BURST_MIN_OCCURRENCES,
112
+ shortBurstMinTotalWords: options.shortBurstMinTotalWords
113
+ ?? DEFAULT_SHORT_BURST_MIN_TOTAL_WORDS,
114
+ shortBurstMinWords: options.shortBurstMinWords ?? DEFAULT_SHORT_BURST_MIN_WORDS,
115
+ shortBurstScanWords: options.shortBurstScanWords ?? DEFAULT_SHORT_BURST_SCAN_WORDS,
49
116
  windowWords: options.windowWords ?? DEFAULT_WINDOW_WORDS,
50
117
  };
51
118
  let text = '';
52
119
  let lastCheckedWords = 0;
120
+ let lastShortBurstLastWord = '';
121
+ let lastShortBurstWordCount = 0;
53
122
  let detection = null;
54
123
 
55
124
  return {
@@ -57,12 +126,46 @@ function createLiveResponseRepetitionGuard(options = {}) {
57
126
  if (detection !== null || typeof delta !== 'string' || delta.length === 0) return detection;
58
127
  text = `${text}${delta}`.slice(-config.maxChars);
59
128
  const words = normalizeWords(text);
129
+ const previousShortBurstWordCount = lastShortBurstWordCount;
130
+ const lastWord = words.at(-1) ?? '';
131
+ const wordCountChanged = words.length !== previousShortBurstWordCount;
132
+ const lastWordChanged = lastWord !== lastShortBurstLastWord;
133
+ const firstChangedEnd = words.length > lastShortBurstWordCount
134
+ ? Math.max(1, lastShortBurstWordCount)
135
+ : words.length;
136
+ const shouldCheckShortBurst = wordCountChanged || (lastWordChanged
137
+ && canCloseConsecutiveWindow(
138
+ words,
139
+ config.shortBurstMinWords,
140
+ config.shortBurstMaxWords,
141
+ ));
142
+ lastShortBurstLastWord = lastWord;
143
+ lastShortBurstWordCount = words.length;
144
+ if (words.length >= config.shortBurstMinTotalWords && shouldCheckShortBurst) {
145
+ const shortBurst = repeatedConsecutiveWindow(words, {
146
+ firstEnd: firstChangedEnd,
147
+ maxWords: config.shortBurstMaxWords,
148
+ minOccurrences: config.shortBurstMinOccurrences,
149
+ minTotalWords: config.shortBurstMinTotalWords,
150
+ minWords: config.shortBurstMinWords,
151
+ scanWords: config.shortBurstScanWords,
152
+ });
153
+ if (shortBurst !== null) {
154
+ detection = {
155
+ ...shortBurst,
156
+ charCount: text.length,
157
+ wordCount: words.length,
158
+ };
159
+ return detection;
160
+ }
161
+ }
60
162
  if (words.length < config.minWords) return null;
61
163
  if (words.length - lastCheckedWords < config.checkEveryWords) return null;
62
164
  lastCheckedWords = words.length;
63
165
  const repeated = repeatedWindow(words, config);
64
166
  if (repeated === null) return null;
65
167
  detection = {
168
+ kind: 'long_window',
66
169
  ...repeated,
67
170
  charCount: text.length,
68
171
  wordCount: words.length,
@@ -80,8 +183,14 @@ module.exports = {
80
183
  DEFAULT_MAX_CHARS,
81
184
  DEFAULT_MIN_WORDS,
82
185
  DEFAULT_REQUIRED_OCCURRENCES,
186
+ DEFAULT_SHORT_BURST_MAX_WORDS,
187
+ DEFAULT_SHORT_BURST_MIN_OCCURRENCES,
188
+ DEFAULT_SHORT_BURST_MIN_TOTAL_WORDS,
189
+ DEFAULT_SHORT_BURST_MIN_WORDS,
190
+ DEFAULT_SHORT_BURST_SCAN_WORDS,
83
191
  DEFAULT_WINDOW_WORDS,
84
192
  createLiveResponseRepetitionGuard,
85
193
  normalizeWords,
194
+ repeatedConsecutiveWindow,
86
195
  repeatedWindow,
87
196
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.445",
3
+ "version": "9.1.446",
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": {