blun-king-cli 9.1.69 → 9.1.71

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
@@ -20,11 +20,14 @@ Start
20
20
  Beide Startbefehle verwenden dieselbe Version, dasselbe Konto, dasselbe Modell
21
21
  und dieselben Befehle.
22
22
 
23
- Standard-MCPs und Eingabesteuerung in 9.1.69
24
- --------------------------------------------
25
- Beim Start richtet BLUN King agent-browser, blun-language-guard, context7 und
26
- unter Windows windows-mcp automatisch ein. Erkannte Standardkonfigurationen
27
- werden aktiviert; eigene, abweichende MCP-Befehle bleiben unverändert.
23
+ Standard-MCPs und Eingabesteuerung
24
+ ---------------------------------
25
+ Beim Start richtet BLUN King `agent-browser`, `blun-language-guard` und unter
26
+ Windows `windows-mcp` automatisch ein und aktiviert erkannte
27
+ Standardkonfigurationen. Context7 wird eingerichtet, bleibt aber standardmäßig
28
+ deaktiviert, weil sein Start hängen bleiben kann. Mit
29
+ `blun tools enable context7` lässt es sich ausdrücklich aktivieren. Eigene,
30
+ abweichende MCP-Befehle bleiben unverändert.
28
31
 
29
32
  /mcp
30
33
  blun tools list
@@ -85,6 +88,16 @@ Ein neuer /loop ersetzt den bisherigen Loop derselben Sitzung. Dabei bleibt
85
88
  genau ein gespeicherter Loop aktiv. /loop stop, /loop pause und /loop status
86
89
  wirken auch dann sofort, wenn der Agent gerade arbeitet.
87
90
 
91
+ Wird ein neuer /loop während eines laufenden Zugs aktiviert, wird sein erster
92
+ Auftrag hinter dem aktuellen Zug eingereiht. Er startet danach automatisch; es
93
+ entsteht weder ein zweiter paralleler Zug noch der Fehler turn.agent_busy.
94
+
95
+ Beispiel:
96
+
97
+ /loop 5min Prüfe den Teststand und arbeite am nächsten offenen Punkt weiter.
98
+
99
+ Der erste Lauf beginnt direkt nach dem aktuellen Zug, danach alle fünf Minuten.
100
+
88
101
  Eine fällige Wiederholung wird als autonomer Aufwecker eingespeist und nicht
89
102
  als neue Nutzernachricht behandelt. Die Statuszeile zeigt den nächsten
90
103
  Aufweckzeitpunkt laufend an. Beim Fortsetzen derselben Sitzung wird der
@@ -154,10 +167,18 @@ Alle Befehle funktionieren identisch mit `king`.
154
167
 
155
168
  Medienerzeugung
156
169
  ---------------
157
- GenerateVideo erzeugt Videos aus einer Textbeschreibung, animiert einen
158
- abgeschlossenen Bildauftrag oder lädt eine lokale PNG- beziehungsweise JPEG-Datei
159
- hoch und animiert genau dieses Bild. Der Auftrag läuft asynchron und wird
160
- anschließend mit GetMedia abgerufen.
170
+ Für Medienaufträge bleiben GenerateImage, GenerateVideo, GenerateSpeech und
171
+ GetMedia auch bei schlanker Werkzeugauswahl unmittelbar verfügbar. Nutzer
172
+ müssen weder Werkzeugnamen noch Modell-Prompts kennen. Eine normale Anweisung
173
+ wie „Erzeuge ein realistisches Produktbild einer schwarzen Armbanduhr auf weißem
174
+ Marmor“ oder „Animiere das letzte Bild als ruhige Kamerafahrt von sechs Sekunden“
175
+ genügt. King wählt den passenden Medienweg und kann das asynchrone Ergebnis mit
176
+ GetMedia abrufen.
177
+
178
+ Angehängte Bilder werden weiterhin mit ReadMediaFile gelesen. Bild-, Video- und
179
+ Spracherzeugung laufen asynchron, sodass die Konsole während der Verarbeitung
180
+ nutzbar bleibt. GenerateVideo kann außerdem einen abgeschlossenen Bildauftrag
181
+ oder eine lokale PNG- beziehungsweise JPEG-Datei animieren.
161
182
 
162
183
  Die Medienleiste erscheint nur bei aktiven Medienaufträgen. Sie zeigt
163
184
  Warteschlangenplatz, Produktionsphase und Laufzeit sowie nur tatsächlich vom
package/README.md CHANGED
@@ -40,13 +40,16 @@ erzeugt `/telegram:access connect` einen einmaligen Code. `/connect CODE` im
40
40
  gewünschten privaten Chat oder in einer Gruppe speichert Chat und Absender
41
41
  intern; der Code verfällt nach zehn Minuten und ist nur einmal verwendbar.
42
42
 
43
- ## Standard-MCPs und Eingabesteuerung in 9.1.69
43
+ ## Standard-MCPs und Eingabesteuerung
44
44
 
45
- Beim Start richtet BLUN King `agent-browser`, `blun-language-guard`, `context7`
46
- und unter Windows `windows-mcp` automatisch ein und aktiviert erkannte
47
- Standardkonfigurationen wieder. Eigene, abweichende MCP-Befehle bleiben
48
- unverändert. `/mcp` zeigt den Betriebszustand ohne internen Konfigurationspfad;
49
- in der Detailansicht bleibt der Pfad für die Fehlersuche verfügbar.
45
+ Beim Start richtet BLUN King `agent-browser`, `blun-language-guard` und unter
46
+ Windows `windows-mcp` automatisch ein und aktiviert erkannte
47
+ Standardkonfigurationen. Context7 wird eingerichtet, bleibt aber standardmäßig
48
+ deaktiviert, weil sein Start hängen bleiben kann. Mit
49
+ `blun tools enable context7` lässt es sich ausdrücklich aktivieren. Eigene,
50
+ abweichende MCP-Befehle bleiben unverändert. `/mcp` zeigt den Betriebszustand
51
+ ohne internen Konfigurationspfad; in der Detailansicht bleibt der Pfad für die
52
+ Fehlersuche verfügbar.
50
53
 
51
54
  Beispiele:
52
55
 
@@ -108,6 +111,14 @@ genau ein gespeicherter Loop aktiv; der neue Auftrag, das neue Intervall und
108
111
  der neue Startzeitpunkt gelten vollständig. `/loop stop`, `/loop pause` und
109
112
  `/loop status` wirken auch dann sofort, wenn der Agent gerade arbeitet.
110
113
 
114
+ Wird ein neuer `/loop` während eines laufenden Zugs aktiviert, wird sein erster
115
+ Auftrag hinter dem aktuellen Zug eingereiht. Er startet danach automatisch; es
116
+ entsteht weder ein zweiter paralleler Zug noch der Fehler `turn.agent_busy`.
117
+
118
+ Beispiel: `/loop 5min Prüfe den Teststand und arbeite am nächsten offenen Punkt
119
+ weiter.` führt den ersten Lauf direkt nach dem aktuellen Zug aus und danach alle
120
+ fünf Minuten.
121
+
111
122
  Eine fällige Wiederholung wird als autonomer Aufwecker eingespeist und nicht
112
123
  als neue Nutzernachricht behandelt. Die Statuszeile zeigt den nächsten
113
124
  Aufweckzeitpunkt laufend an. Beim Fortsetzen derselben Sitzung wird der
@@ -184,10 +195,18 @@ Sie stehen unter `blun` und `king` identisch zur Verfügung.
184
195
 
185
196
  ## Medienerzeugung
186
197
 
187
- `GenerateVideo` erzeugt Videos aus einer Textbeschreibung, animiert einen
188
- abgeschlossenen Bildauftrag oder lädt eine lokale PNG- beziehungsweise JPEG-Datei
189
- hoch und animiert genau dieses Bild. Der Auftrag läuft asynchron und wird
190
- anschließend mit `GetMedia` abgerufen.
198
+ Für Medienaufträge bleiben `GenerateImage`, `GenerateVideo`, `GenerateSpeech`
199
+ und `GetMedia` auch bei schlanker Werkzeugauswahl unmittelbar verfügbar. Nutzer
200
+ müssen weder Werkzeugnamen noch Modell-Prompts kennen. Eine normale Anweisung
201
+ wie „Erzeuge ein realistisches Produktbild einer schwarzen Armbanduhr auf weißem
202
+ Marmor“ oder „Animiere das letzte Bild als ruhige Kamerafahrt von sechs Sekunden“
203
+ genügt. King wählt den passenden Medienweg und kann das asynchrone Ergebnis mit
204
+ `GetMedia` abrufen.
205
+
206
+ Angehängte Bilder werden weiterhin mit `ReadMediaFile` gelesen. Bild-, Video-
207
+ und Spracherzeugung laufen asynchron, sodass die Konsole während der Verarbeitung
208
+ nutzbar bleibt. `GenerateVideo` kann außerdem einen abgeschlossenen Bildauftrag
209
+ oder eine lokale PNG- beziehungsweise JPEG-Datei animieren.
191
210
 
192
211
  Die Medienleiste erscheint nur bei aktiven Medienaufträgen. Sie zeigt
193
212
  Warteschlangenplatz, Produktionsphase und Laufzeit sowie nur tatsächlich vom
@@ -431,6 +431,7 @@ async function runLauncher(options = {}) {
431
431
  packageRoot: PKG,
432
432
  blunDir: privatePaths.profilePaths.home,
433
433
  names: mcpNames,
434
+ forceEnable: true,
434
435
  });
435
436
  }
436
437
  if (selected.includes('telegram')) {
@@ -31,6 +31,9 @@ function readCatalogue(packageRoot) {
31
31
  || !tool.platforms.every((platform) => platform === 'darwin' || platform === 'win32'))) {
32
32
  throw new Error(`Ungueltige Standard-Tool-Plattform: ${name}`);
33
33
  }
34
+ if (tool.autoEnable !== undefined && typeof tool.autoEnable !== 'boolean') {
35
+ throw new Error(`Ungueltiger Standard-Tool-Autostart: ${name}`);
36
+ }
34
37
  if (tool.owner === 'user-mcp'
35
38
  && (!isObject(tool.config) || typeof tool.config.enabled !== 'boolean')) {
36
39
  throw new Error(`Standard-Tool braucht einen Aktivierungszustand: ${name}`);
@@ -98,7 +101,21 @@ function recognizedBundledServer(name, current, expected) {
98
101
  function migrateBundledTimeouts(name, current, expected) {
99
102
  if (!recognizedBundledServer(name, current, expected)) return false;
100
103
  let changed = false;
101
- if (current.enabled === false) {
104
+ if (name === 'context7') {
105
+ if (expected.blunExplicitlyEnabled === true) {
106
+ if (current.enabled !== true) {
107
+ current.enabled = true;
108
+ changed = true;
109
+ }
110
+ if (current.blunExplicitlyEnabled !== true) {
111
+ current.blunExplicitlyEnabled = true;
112
+ changed = true;
113
+ }
114
+ } else if (current.blunExplicitlyEnabled !== true && current.enabled !== false) {
115
+ current.enabled = false;
116
+ changed = true;
117
+ }
118
+ } else if (current.enabled === false) {
102
119
  current.enabled = true;
103
120
  changed = true;
104
121
  }
@@ -134,9 +151,16 @@ function writeMcpDocument(configPath, document) {
134
151
  }
135
152
  }
136
153
 
137
- function bundledToolConfig(name, tool, { packageRoot, blunDir, platform, env }) {
154
+ function bundledToolConfig(name, tool, {
155
+ packageRoot,
156
+ blunDir,
157
+ platform,
158
+ env,
159
+ forceEnable,
160
+ }) {
138
161
  const config = structuredClone(tool.config);
139
- config.enabled = true;
162
+ config.enabled = forceEnable || tool.autoEnable !== false;
163
+ if (forceEnable && tool.autoEnable === false) config.blunExplicitlyEnabled = true;
140
164
  if (name === 'blun-language-guard') {
141
165
  config.command = platform === 'win32' ? 'python' : 'python3';
142
166
  config.args = [
@@ -185,6 +209,7 @@ function seedStandardTools({
185
209
  names,
186
210
  platform = process.platform,
187
211
  env = process.env,
212
+ forceEnable = false,
188
213
  }) {
189
214
  const catalogue = readCatalogue(packageRoot);
190
215
  if (!Array.isArray(names) || names.length === 0) {
@@ -215,6 +240,7 @@ function seedStandardTools({
215
240
  blunDir,
216
241
  platform,
217
242
  env,
243
+ forceEnable,
218
244
  });
219
245
  if (Object.hasOwn(servers, name)) {
220
246
  if (migrateBundledTimeouts(name, servers[name], expected)) updated.push(name);
@@ -18,6 +18,10 @@ const CORE_TOOL_NAMES = Object.freeze([
18
18
  'ReadMediaFile',
19
19
  'TaskOutput',
20
20
  'Skill',
21
+ 'GenerateImage',
22
+ 'GenerateVideo',
23
+ 'GenerateSpeech',
24
+ 'GetMedia',
21
25
  'mcp__plugin-telegram_telegram__reply',
22
26
  'mcp__plugin-telegram_telegram__react',
23
27
  'mcp__plugin-telegram_telegram__edit_message',
package/blun.mjs CHANGED
@@ -421036,7 +421036,8 @@ async function handleLoopCommand(host, args) {
421036
421036
  host.setAppState?.({ loop });
421037
421037
  host.track("loop_start", { interval: loop.interval });
421038
421038
  host.showStatus(`/loop ${loop.status}`);
421039
- host.sendNormalUserInput(loop.prompt);
421039
+ if (isStreaming(host) || host.state.appState.isCompacting) host.enqueueNormalUserInput(loop.prompt);
421040
+ else host.sendNormalUserInput(loop.prompt);
421040
421041
  return;
421041
421042
  }
421042
421043
  case "pause": {
@@ -515014,6 +515015,12 @@ var BlunTUI = class {
515014
515015
  this.updateQueueDisplay();
515015
515016
  this.state.ui.requestRender();
515016
515017
  }
515018
+ enqueueNormalUserInput(text) {
515019
+ this.enqueueMessage(text);
515020
+ this.updateQueueDisplay();
515021
+ this.scheduleQueueDrain();
515022
+ this.state.ui.requestRender();
515023
+ }
515017
515024
  beginSessionRequest() {
515018
515025
  this.streamingUI.setTurnId(void 0);
515019
515026
  this.streamingUI.resetLiveText();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.69",
3
+ "version": "9.1.71",
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": {
@@ -34,6 +34,7 @@
34
34
  "context7": {
35
35
  "owner": "user-mcp",
36
36
  "version": "latest",
37
+ "autoEnable": false,
37
38
  "detectTokens": ["context7", "@upstash/context7-mcp"],
38
39
  "config": {
39
40
  "transport": "stdio",
@@ -4372,21 +4372,36 @@ var KingSession = class {
4372
4372
  * orphan means permanent 409 Conflict), pairing-approval confirmations,
4373
4373
  * and the backoff polling loop.
4374
4374
  */
4375
- /** Kill any stale poller holding the token, then claim the pid file. */
4375
+ /** Atomically claim the token poller without interrupting a live owner. */
4376
4376
  function claimPollerPid() {
4377
4377
  mkdirSync(stateDir(), {
4378
4378
  recursive: true,
4379
4379
  mode: 448
4380
4380
  });
4381
- try {
4382
- const stale = parseInt(readFileSync(pidFile(), "utf8"), 10);
4383
- if (stale > 1 && stale !== process.pid) {
4384
- process.kill(stale, 0);
4385
- process.stderr.write(`telegram channel: replacing stale poller pid=${stale}\n`);
4386
- process.kill(stale, "SIGTERM");
4381
+ for (let attempt = 0; attempt < 3; attempt += 1) {
4382
+ try {
4383
+ writeFileSync(pidFile(), String(process.pid), { flag: "wx" });
4384
+ return true;
4385
+ } catch (error) {
4386
+ if (error?.code !== "EEXIST") throw error;
4387
4387
  }
4388
- } catch {}
4389
- writeFileSync(pidFile(), String(process.pid));
4388
+ let ownerPid;
4389
+ try {
4390
+ ownerPid = parseInt(readFileSync(pidFile(), "utf8"), 10);
4391
+ } catch {}
4392
+ if (ownerPid === process.pid) return true;
4393
+ if (ownerPid !== void 0 && ownerPid > 1) try {
4394
+ process.kill(ownerPid, 0);
4395
+ process.stderr.write(`telegram channel: live poller pid=${ownerPid} already owns the bot token\n`);
4396
+ return false;
4397
+ } catch {}
4398
+ try {
4399
+ rmSync(pidFile());
4400
+ } catch {
4401
+ return false;
4402
+ }
4403
+ }
4404
+ return false;
4390
4405
  }
4391
4406
  function releasePollerPid() {
4392
4407
  try {
@@ -4546,7 +4561,10 @@ process.on("uncaughtException", (err) => {
4546
4561
  });
4547
4562
  ensureStateDir();
4548
4563
  rotateStaleTuiQueue();
4549
- claimPollerPid();
4564
+ if (!claimPollerPid()) {
4565
+ process.stderr.write("telegram channel: another live poller owns the bot token; exiting\n");
4566
+ process.exit(0);
4567
+ }
4550
4568
  const bot = new import_out.Bot(TOKEN);
4551
4569
  let botUsername = "";
4552
4570
  const session = new KingSession(KING_ENTRY, (msg) => {