blun-king-cli 9.1.485 → 9.1.486

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,16 +20,13 @@ Start
20
20
  Beide Startbefehle verwenden dieselbe Version, dasselbe Konto, dasselbe Modell
21
21
  und dieselben Befehle.
22
22
 
23
- king und king -c prüfen beim interaktiven Start auf eine neuere Version. Ist
24
- eine vorhanden, erscheint der sichtbare Dialog:
25
-
26
- 1. Jetzt aktualisieren
27
- 2. Überspringen
28
- 3. Auf den nächsten Release warten
29
-
30
- Es gibt keinen Download und keine Installation im Hintergrund. Nach einer
31
- gewählten Installation endet king; king -c setzt die letzte Sitzung mit der
32
- neuen Version fort.
23
+ king und king -c prüfen beim interaktiven Start auf eine neuere Version.
24
+ Automatische Updates sind standardmäßig aktiv und installieren den geprüften
25
+ Zielstand ohne zusätzliche Bestätigung. Danach endet king; king -c setzt die
26
+ letzte Sitzung mit der neuen Version fort. Mit
27
+ [upgrade].auto_install = false in tui.toml erscheint stattdessen der sichtbare
28
+ Auswahldialog. Start- und Update-Meldungen sind bei einer neuen Installation
29
+ standardmäßig Englisch; eine ausdrücklich gewählte Sprache bleibt erhalten.
33
30
 
34
31
  Standard-MCPs und Eingabesteuerung
35
32
  ---------------------------------
package/README.md CHANGED
@@ -36,11 +36,12 @@ gilt nur für den laufenden Prozess; die gespeicherte
36
36
  Plugin-Konfiguration wird nicht umgeschrieben.
37
37
 
38
38
  `king` und `king -c` prüfen beim interaktiven Start, ob eine neuere Version
39
- vorliegt. Dann erscheint der sichtbare Dialog mit den Optionen jetzt
40
- aktualisieren, überspringen oder auf den nächsten Release warten. Im Hintergrund
41
- wird nichts heruntergeladen oder installiert. Nach einer gewählten Installation
42
- endet `king`; `king -c` setzt dagegen die letzte Sitzung mit der neuen Version
43
- fort.
39
+ vorliegt. Automatische Updates sind standardmäßig aktiv und installieren den
40
+ geprüften Zielstand ohne zusätzliche Bestätigung. Danach endet `king`; `king -c`
41
+ setzt die letzte Sitzung mit der neuen Version fort. Mit
42
+ `[upgrade].auto_install = false` in `tui.toml` erscheint stattdessen der sichtbare
43
+ Auswahldialog. Start- und Update-Meldungen sind bei einer neuen Installation
44
+ standardmäßig Englisch; eine ausdrücklich gewählte Sprache bleibt erhalten.
44
45
 
45
46
  Telegram-Chats werden ohne manuell eingegebene IDs verbunden. In der Konsole
46
47
  erzeugt `/telegram:access connect` einen einmaligen Code. `/connect CODE` im
@@ -42,6 +42,11 @@ const {
42
42
  resolveProfilePaths,
43
43
  seedDefaultProfileFromLegacy,
44
44
  } = require('./profile-runtime.cjs');
45
+ const {
46
+ migrateLegacyStartupPreferences,
47
+ readStartupPreferences,
48
+ resolveStartupUiLocale,
49
+ } = require('./startup-preferences.cjs');
45
50
 
46
51
  const PKG = path.resolve(__dirname, '..');
47
52
  const RAW_ARGS = process.argv.slice(2);
@@ -398,6 +403,9 @@ async function runLauncher(options = {}) {
398
403
  if (explicitUpdateRequest) {
399
404
  const privatePaths = getPrivatePaths();
400
405
  ensurePrivateDirectory(privatePaths.sharedHome);
406
+ ensurePrivateDirectory(privatePaths.profilePaths.home);
407
+ migrateLegacyStartupPreferences(privatePaths.profilePaths.home);
408
+ const startupPreferences = readStartupPreferences(privatePaths.profilePaths.home);
401
409
  const result = await runExplicitUpdate({
402
410
  currentVersion: readPackageVersion(),
403
411
  env: process.env,
@@ -405,6 +413,7 @@ async function runLauncher(options = {}) {
405
413
  stdout: process.stdout,
406
414
  stderr: process.stderr,
407
415
  blunDir: privatePaths.sharedHome,
416
+ uiLocale: resolveStartupUiLocale(startupPreferences.uiLocale, process.env),
408
417
  packageRoot: PKG,
409
418
  noticeLease: launcherLease,
410
419
  });
@@ -449,6 +458,8 @@ async function runLauncher(options = {}) {
449
458
  }
450
459
  const blunDir = profilePaths.home;
451
460
  ensurePrivateDirectory(blunDir);
461
+ migrateLegacyStartupPreferences(blunDir);
462
+ const startupPreferences = readStartupPreferences(blunDir);
452
463
 
453
464
  const updateResult = await runUpdateNotice({
454
465
  currentVersion: readPackageVersion(),
@@ -458,6 +469,8 @@ async function runLauncher(options = {}) {
458
469
  stdout: process.stdout,
459
470
  stderr: process.stderr,
460
471
  blunDir: privatePaths.sharedHome,
472
+ autoInstall: startupPreferences.autoInstall,
473
+ uiLocale: resolveStartupUiLocale(startupPreferences.uiLocale, process.env),
461
474
  packageRoot: PKG,
462
475
  noticeLease: launcherLease,
463
476
  });
@@ -0,0 +1,130 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ const CONFIG_FILE = 'tui.toml';
7
+ const MIGRATION_MARKER = '.legacy-auto-ui-locale-v1';
8
+ const MIGRATION_BACKUP = 'tui.toml.vor-english-default-v1';
9
+ const MAX_CONFIG_BYTES = 256 * 1024;
10
+
11
+ function safeConfigPath(profileHome, fsImpl = fs) {
12
+ const configPath = path.join(path.resolve(profileHome), CONFIG_FILE);
13
+ if (!fsImpl.existsSync(configPath)) return undefined;
14
+ const stat = fsImpl.lstatSync(configPath);
15
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_CONFIG_BYTES) {
16
+ return undefined;
17
+ }
18
+ return configPath;
19
+ }
20
+
21
+ function parseStartupPreferences(text) {
22
+ let section = '';
23
+ let autoInstall = true;
24
+ let uiLocale = 'en';
25
+
26
+ for (const line of String(text).replace(/^\uFEFF/u, '').split(/\r?\n/u)) {
27
+ const sectionMatch = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/u.exec(line);
28
+ if (sectionMatch) {
29
+ section = sectionMatch[1].trim().toLowerCase();
30
+ continue;
31
+ }
32
+ if (section === '') {
33
+ const localeMatch = /^\s*ui_locale\s*=\s*"([^"]+)"\s*(?:#.*)?$/u.exec(line);
34
+ if (localeMatch && /^(?:auto|[a-z]{2}(?:-[a-z0-9]+)*)$/iu.test(localeMatch[1])) {
35
+ uiLocale = localeMatch[1].toLowerCase();
36
+ }
37
+ continue;
38
+ }
39
+ if (section === 'upgrade') {
40
+ const automaticMatch = /^\s*auto_install\s*=\s*(true|false)\s*(?:#.*)?$/iu.exec(line);
41
+ if (automaticMatch) autoInstall = automaticMatch[1].toLowerCase() === 'true';
42
+ }
43
+ }
44
+
45
+ return { autoInstall, uiLocale };
46
+ }
47
+
48
+ function readStartupPreferences(profileHome, fsImpl = fs) {
49
+ const configPath = safeConfigPath(profileHome, fsImpl);
50
+ if (!configPath) return { autoInstall: true, uiLocale: 'en' };
51
+ try {
52
+ return parseStartupPreferences(fsImpl.readFileSync(configPath, 'utf8'));
53
+ } catch {
54
+ return { autoInstall: true, uiLocale: 'en' };
55
+ }
56
+ }
57
+
58
+ function resolveStartupUiLocale(uiLocale, env = process.env) {
59
+ const normalized = String(uiLocale || 'en').trim().toLowerCase();
60
+ if (normalized !== 'auto') return normalized;
61
+ const operatingSystemLocale = String(env.LC_ALL || env.LC_MESSAGES || env.LANG || '')
62
+ .trim()
63
+ .toLowerCase();
64
+ return operatingSystemLocale === 'de'
65
+ || operatingSystemLocale.startsWith('de-')
66
+ || operatingSystemLocale.startsWith('de_')
67
+ || operatingSystemLocale.startsWith('de.')
68
+ ? 'de'
69
+ : 'en';
70
+ }
71
+
72
+ function writeMarkerOnce(markerPath, fsImpl) {
73
+ try {
74
+ fsImpl.writeFileSync(markerPath, 'legacy automatic UI locale reviewed once\n', {
75
+ encoding: 'utf8',
76
+ flag: 'wx',
77
+ });
78
+ } catch (error) {
79
+ if (error?.code !== 'EEXIST') throw error;
80
+ }
81
+ }
82
+
83
+ function replaceIfUnchanged(target, original, replacement, fsImpl) {
84
+ if (fsImpl.readFileSync(target, 'utf8') !== original) {
85
+ throw new Error(`Startup preferences changed during migration: ${target}`);
86
+ }
87
+ const temporary = `${target}.migration-${process.pid}-${Date.now()}.tmp`;
88
+ fsImpl.writeFileSync(temporary, replacement, 'utf8');
89
+ try {
90
+ fsImpl.renameSync(temporary, target);
91
+ } catch (error) {
92
+ try {
93
+ fsImpl.rmSync(temporary, { force: true });
94
+ } catch {}
95
+ throw error;
96
+ }
97
+ }
98
+
99
+ function migrateLegacyStartupPreferences(profileHome, fsImpl = fs) {
100
+ const resolvedHome = path.resolve(profileHome);
101
+ fsImpl.mkdirSync(resolvedHome, { recursive: true });
102
+ const markerPath = path.join(resolvedHome, MIGRATION_MARKER);
103
+ const backupPath = path.join(resolvedHome, MIGRATION_BACKUP);
104
+ if (fsImpl.existsSync(markerPath)) return { changed: false };
105
+
106
+ const configPath = safeConfigPath(resolvedHome, fsImpl);
107
+ if (!configPath) {
108
+ writeMarkerOnce(markerPath, fsImpl);
109
+ return { changed: false };
110
+ }
111
+
112
+ const original = fsImpl.readFileSync(configPath, 'utf8');
113
+ const legacyLocale = /^(\s*ui_locale\s*=\s*)"auto"(\s*(?:#.*)?)$/mu;
114
+ if (!legacyLocale.test(original)) {
115
+ writeMarkerOnce(markerPath, fsImpl);
116
+ return { changed: false };
117
+ }
118
+
119
+ if (!fsImpl.existsSync(backupPath)) fsImpl.copyFileSync(configPath, backupPath);
120
+ const replacement = original.replace(legacyLocale, '$1"en"$2');
121
+ replaceIfUnchanged(configPath, original, replacement, fsImpl);
122
+ writeMarkerOnce(markerPath, fsImpl);
123
+ return { backupPath, changed: true };
124
+ }
125
+
126
+ module.exports = {
127
+ migrateLegacyStartupPreferences,
128
+ readStartupPreferences,
129
+ resolveStartupUiLocale,
130
+ };
@@ -621,6 +621,54 @@ function installCommandText(version) {
621
621
  return `npm i -g ${PACKAGE_NAME}@${version}`;
622
622
  }
623
623
 
624
+ function updateCopy(uiLocale) {
625
+ const german = String(uiLocale || '').toLowerCase().startsWith('de');
626
+ if (german) {
627
+ return {
628
+ available: (current, next) => `BLUN Code-Update verfügbar: ${current} -> ${next}`,
629
+ current: (version) => `Kein Update verfügbar. Installiert: ${version} · Aktuell: ${version}.`,
630
+ enter: 'Enter drücken, um fortzufahren',
631
+ failed: (code) => `Update fehlgeschlagen (Code ${code}).`,
632
+ install: (version) => `Jetzt aktualisieren (führt \`${installCommandText(version)}\` aus)`,
633
+ installFailed: (code) => `Update fehlgeschlagen (Code ${code}). Die vorhandene Version wird gestartet.`,
634
+ installed: 'Installation geprüft',
635
+ installedContinue: (current, next) => `Update ${current} -> ${next} erfolgreich installiert. Die letzte Sitzung wird mit der neuen Version fortgesetzt.`,
636
+ installedRestart: (current, next) => `Update ${current} -> ${next} erfolgreich installiert. Starte BLUN Code neu, um die neue Version zu verwenden.`,
637
+ installerReady: 'Installer bereit',
638
+ installing: 'Paket wird installiert',
639
+ invalidTarget: (version) => `Kein sicherer Update-Zielstand verfügbar. Installiert: ${version}.`,
640
+ nextRelease: 'Auf den nächsten Release warten',
641
+ notes: 'Versionshinweise',
642
+ skip: 'Überspringen',
643
+ startupNoticeFailed: (version) => `Update ${version} wurde installiert, aber die Startmeldung konnte nicht gespeichert werden.`,
644
+ updateChecked: 'Update geprüft',
645
+ verificationFailed: 'Das Update konnte nicht verifiziert werden.',
646
+ verificationRestart: 'Update konnte nicht verifiziert werden. Starte BLUN Code neu.',
647
+ };
648
+ }
649
+ return {
650
+ available: (current, next) => `BLUN Code update available: ${current} -> ${next}`,
651
+ current: (version) => `No update available. Installed: ${version} · Current: ${version}.`,
652
+ enter: 'Press Enter to continue',
653
+ failed: (code) => `Update failed (code ${code}).`,
654
+ install: (version) => `Update now (runs \`${installCommandText(version)}\`)`,
655
+ installFailed: (code) => `Update failed (code ${code}). The installed version will start.`,
656
+ installed: 'Installation verified',
657
+ installedContinue: (current, next) => `Update ${current} -> ${next} installed successfully. The last session will continue with the new version.`,
658
+ installedRestart: (current, next) => `Update ${current} -> ${next} installed successfully. Restart BLUN Code to use the new version.`,
659
+ installerReady: 'Installer ready',
660
+ installing: 'Installing package',
661
+ invalidTarget: (version) => `No safe update target is available. Installed: ${version}.`,
662
+ nextRelease: 'Wait for the next release',
663
+ notes: 'Release notes',
664
+ skip: 'Skip',
665
+ startupNoticeFailed: (version) => `Update ${version} was installed, but the startup notice could not be saved.`,
666
+ updateChecked: 'Update checked',
667
+ verificationFailed: 'The update could not be verified.',
668
+ verificationRestart: 'The update could not be verified. Restart BLUN Code.',
669
+ };
670
+ }
671
+
624
672
  function createUpdateProgress(output) {
625
673
  const enabled = output?.isTTY === true;
626
674
  const phaseCount = 4;
@@ -646,7 +694,14 @@ function createUpdateProgress(output) {
646
694
  return update;
647
695
  }
648
696
 
649
- function promptUpdateAction({ currentVersion, release, input, output, processRef = process }) {
697
+ function promptUpdateAction({
698
+ currentVersion,
699
+ release,
700
+ input,
701
+ output,
702
+ processRef = process,
703
+ uiLocale = 'en',
704
+ }) {
650
705
  return new Promise((resolve, reject) => {
651
706
  let selected = 0;
652
707
  let settled = false;
@@ -659,13 +714,14 @@ function promptUpdateAction({ currentVersion, release, input, output, processRef
659
714
  const dim = '\u001B[2m';
660
715
  const underline = '\u001B[4m';
661
716
  const reset = '\u001B[0m';
717
+ const copy = updateCopy(uiLocale);
662
718
  const actions = [
663
719
  {
664
720
  choice: 'install',
665
- label: `Jetzt aktualisieren (führt \`${installCommandText(release.version)}\` aus)`,
721
+ label: copy.install(release.version),
666
722
  },
667
- { choice: 'skip-once', label: 'Überspringen' },
668
- { choice: 'skip-version', label: 'Auf den nächsten Release warten' },
723
+ { choice: 'skip-once', label: copy.skip },
724
+ { choice: 'skip-version', label: copy.nextRelease },
669
725
  ];
670
726
  const signalHandlers = new Map();
671
727
 
@@ -675,7 +731,7 @@ function promptUpdateAction({ currentVersion, release, input, output, processRef
675
731
  const line = `${selected === index ? '›' : ' '} ${index + 1}. ${actions[index].label}`;
676
732
  output.write(`\r\u001B[2K${selected === index ? cyan : ''}${line}${selected === index ? reset : ''}\n`);
677
733
  }
678
- output.write(`\r\u001B[2K${dim}Enter drücken, um fortzufahren${reset}\n`);
734
+ output.write(`\r\u001B[2K${dim}${copy.enter}${reset}\n`);
679
735
  };
680
736
  const cleanup = () => {
681
737
  if (escapeTimer !== undefined) clearTimeout(escapeTimer);
@@ -830,9 +886,9 @@ function promptUpdateAction({ currentVersion, release, input, output, processRef
830
886
  signalHandlers.set(signal, handler);
831
887
  processRef.once(signal, handler);
832
888
  }
833
- output.write(`\nBLUN Code-Update verfügbar: ${currentVersion} -> ${release.version}\n`);
889
+ output.write(`\n${copy.available(currentVersion, release.version)}\n`);
834
890
  if (release.notesUrl) {
835
- output.write(`${dim}Versionshinweise:${reset} ${underline}${release.notesUrl}${reset}\n`);
891
+ output.write(`${dim}${copy.notes}:${reset} ${underline}${release.notesUrl}${reset}\n`);
836
892
  }
837
893
  output.write('\n');
838
894
  cursorHidden = true;
@@ -1290,19 +1346,21 @@ function noReleaseReason(currentVersion, registryTags, fallbackManifest) {
1290
1346
  return parseSemver(latest) || fallbackManifest ? 'current' : 'unavailable';
1291
1347
  }
1292
1348
 
1293
- function explicitNoTarget(stdout, reason, currentVersion) {
1349
+ function explicitNoTarget(stdout, reason, currentVersion, uiLocale) {
1350
+ const copy = updateCopy(uiLocale);
1294
1351
  stdout.write(reason === 'current'
1295
- ? `Kein Update verfügbar. Installiert: ${currentVersion} · Aktuell: ${currentVersion}.\n`
1296
- : `Kein sicherer Update-Zielstand verfügbar. Installiert: ${currentVersion}.\n`);
1352
+ ? `${copy.current(currentVersion)}\n`
1353
+ : `${copy.invalidTarget(currentVersion)}\n`);
1297
1354
  return { kind: 'current', reason };
1298
1355
  }
1299
1356
 
1300
- function explicitFailure(stderr, reason, exitCode) {
1357
+ function explicitFailure(stderr, reason, exitCode, uiLocale) {
1358
+ const copy = updateCopy(uiLocale);
1301
1359
  const hasExitCode = Number.isInteger(exitCode) && exitCode !== 0;
1302
1360
  if (hasExitCode) {
1303
- stderr.write(`Update fehlgeschlagen (Code ${exitCode}).\n`);
1361
+ stderr.write(`${copy.failed(exitCode)}\n`);
1304
1362
  } else {
1305
- stderr.write('Das Update konnte nicht verifiziert werden.\n');
1363
+ stderr.write(`${copy.verificationFailed}\n`);
1306
1364
  }
1307
1365
  return {
1308
1366
  kind: 'failed',
@@ -1321,12 +1379,14 @@ async function runUpdateFlow(options, explicitUpdate) {
1321
1379
  stderr,
1322
1380
  blunDir,
1323
1381
  } = options;
1382
+ const uiLocale = options.uiLocale || 'en';
1383
+ const copy = updateCopy(uiLocale);
1324
1384
  if (!explicitUpdate && !isInteractiveUpdateStart({ argv, env, stdin, stdout })) {
1325
1385
  return { kind: 'continue', reason: 'not_interactive' };
1326
1386
  }
1327
1387
  if (!parseSemver(currentVersion)) {
1328
1388
  return explicitUpdate
1329
- ? explicitFailure(stderr, 'invalid_current_version')
1389
+ ? explicitFailure(stderr, 'invalid_current_version', undefined, uiLocale)
1330
1390
  : { kind: 'continue', reason: 'invalid_current_version' };
1331
1391
  }
1332
1392
 
@@ -1340,7 +1400,7 @@ async function runUpdateFlow(options, explicitUpdate) {
1340
1400
  leaseResult = await (options.acquireLease || tryAcquireUpdateLease)({ packageRoot });
1341
1401
  } catch {
1342
1402
  return explicitUpdate
1343
- ? explicitFailure(stderr, 'lease_unavailable')
1403
+ ? explicitFailure(stderr, 'lease_unavailable', undefined, uiLocale)
1344
1404
  : { kind: 'continue', reason: 'lease_unavailable' };
1345
1405
  }
1346
1406
  } else {
@@ -1351,6 +1411,8 @@ async function runUpdateFlow(options, explicitUpdate) {
1351
1411
  return explicitFailure(
1352
1412
  stderr,
1353
1413
  leaseResult?.reason === 'busy' ? 'update_in_progress' : 'lease_unavailable',
1414
+ undefined,
1415
+ uiLocale,
1354
1416
  );
1355
1417
  }
1356
1418
  return leaseResult?.reason === 'busy'
@@ -1366,7 +1428,7 @@ async function runUpdateFlow(options, explicitUpdate) {
1366
1428
  sources = await (options.loadReleaseSources || loadReleaseSources)();
1367
1429
  } catch {
1368
1430
  return explicitUpdate
1369
- ? explicitNoTarget(stdout, 'unavailable', currentVersion)
1431
+ ? explicitNoTarget(stdout, 'unavailable', currentVersion, uiLocale)
1370
1432
  : { kind: 'continue', reason: 'unavailable' };
1371
1433
  }
1372
1434
  const registryTags = parseRegistryDocument(sources?.registryDocument);
@@ -1375,7 +1437,7 @@ async function runUpdateFlow(options, explicitUpdate) {
1375
1437
  if (!release) {
1376
1438
  const reason = noReleaseReason(currentVersion, registryTags, fallbackManifest);
1377
1439
  return explicitUpdate
1378
- ? explicitNoTarget(stdout, reason, currentVersion)
1440
+ ? explicitNoTarget(stdout, reason, currentVersion, uiLocale)
1379
1441
  : { kind: 'continue', reason };
1380
1442
  }
1381
1443
  if (!explicitUpdate
@@ -1385,12 +1447,12 @@ async function runUpdateFlow(options, explicitUpdate) {
1385
1447
  const initialInstallLease = await probeInstallLease(options, packageRoot);
1386
1448
  if (initialInstallLease === 'busy') {
1387
1449
  return explicitUpdate
1388
- ? explicitFailure(stderr, 'update_in_progress')
1450
+ ? explicitFailure(stderr, 'update_in_progress', undefined, uiLocale)
1389
1451
  : { kind: 'update_in_progress' };
1390
1452
  }
1391
1453
  if (initialInstallLease !== 'clear') {
1392
1454
  return explicitUpdate
1393
- ? explicitFailure(stderr, 'lease_unavailable')
1455
+ ? explicitFailure(stderr, 'lease_unavailable', undefined, uiLocale)
1394
1456
  : { kind: 'continue', reason: 'lease_unavailable' };
1395
1457
  }
1396
1458
  if (!explicitUpdate
@@ -1401,25 +1463,25 @@ async function runUpdateFlow(options, explicitUpdate) {
1401
1463
  try {
1402
1464
  ensurePrivateDirectory(blunDir);
1403
1465
  } catch {
1404
- return explicitFailure(stderr, 'private_home_unavailable');
1466
+ return explicitFailure(stderr, 'private_home_unavailable', undefined, uiLocale);
1405
1467
  }
1406
1468
  }
1407
1469
  try {
1408
1470
  lease.assertOwned();
1409
1471
  } catch {
1410
1472
  return explicitUpdate
1411
- ? explicitFailure(stderr, 'update_in_progress')
1473
+ ? explicitFailure(stderr, 'update_in_progress', undefined, uiLocale)
1412
1474
  : { kind: 'update_in_progress' };
1413
1475
  }
1414
1476
  const prePromptInstallLease = await probeInstallLease(options, packageRoot);
1415
1477
  if (prePromptInstallLease === 'busy') {
1416
1478
  return explicitUpdate
1417
- ? explicitFailure(stderr, 'update_in_progress')
1479
+ ? explicitFailure(stderr, 'update_in_progress', undefined, uiLocale)
1418
1480
  : { kind: 'update_in_progress' };
1419
1481
  }
1420
1482
  if (prePromptInstallLease !== 'clear') {
1421
1483
  return explicitUpdate
1422
- ? explicitFailure(stderr, 'lease_unavailable')
1484
+ ? explicitFailure(stderr, 'lease_unavailable', undefined, uiLocale)
1423
1485
  : { kind: 'continue', reason: 'lease_unavailable' };
1424
1486
  }
1425
1487
  if (!options.installVersion) {
@@ -1429,7 +1491,7 @@ async function runUpdateFlow(options, explicitUpdate) {
1429
1491
  );
1430
1492
  if (!installerSession?.ready) {
1431
1493
  if (explicitUpdate) {
1432
- return explicitFailure(stderr, 'installer_unavailable');
1494
+ return explicitFailure(stderr, 'installer_unavailable', undefined, uiLocale);
1433
1495
  }
1434
1496
  return installerSession?.reason === 'failed'
1435
1497
  ? { kind: 'continue', reason: 'installer_unavailable' }
@@ -1437,7 +1499,7 @@ async function runUpdateFlow(options, explicitUpdate) {
1437
1499
  }
1438
1500
  }
1439
1501
  let action;
1440
- if (explicitUpdate) {
1502
+ if (explicitUpdate || options.autoInstall === true) {
1441
1503
  action = 'install';
1442
1504
  } else {
1443
1505
  try {
@@ -1446,6 +1508,7 @@ async function runUpdateFlow(options, explicitUpdate) {
1446
1508
  release,
1447
1509
  input: stdin,
1448
1510
  output: stdout,
1511
+ uiLocale,
1449
1512
  });
1450
1513
  } catch {
1451
1514
  return { kind: 'continue', reason: 'prompt_failed' };
@@ -1476,18 +1539,18 @@ async function runUpdateFlow(options, explicitUpdate) {
1476
1539
  }
1477
1540
 
1478
1541
  const updateProgress = createUpdateProgress(stdout);
1479
- updateProgress(1, 'Update geprüft');
1480
- updateProgress(2, 'Installer bereit');
1542
+ updateProgress(1, copy.updateChecked);
1543
+ updateProgress(2, copy.installerReady);
1481
1544
 
1482
1545
  try {
1483
1546
  lease.assertOwned();
1484
1547
  } catch {
1485
1548
  return explicitUpdate
1486
- ? explicitFailure(stderr, 'update_in_progress')
1549
+ ? explicitFailure(stderr, 'update_in_progress', undefined, uiLocale)
1487
1550
  : { kind: 'update_in_progress' };
1488
1551
  }
1489
1552
  let installResult;
1490
- updateProgress(3, 'Paket wird installiert');
1553
+ updateProgress(3, copy.installing);
1491
1554
  try {
1492
1555
  installResult = options.installVersion
1493
1556
  ? await options.installVersion(release.version)
@@ -1500,11 +1563,11 @@ async function runUpdateFlow(options, explicitUpdate) {
1500
1563
  || installResult?.unknownState === true) {
1501
1564
  updateProgress.finish();
1502
1565
  return explicitUpdate
1503
- ? explicitFailure(stderr, 'update_in_progress')
1566
+ ? explicitFailure(stderr, 'update_in_progress', undefined, uiLocale)
1504
1567
  : { kind: 'update_in_progress' };
1505
1568
  }
1506
1569
  if (installResult?.code === 0 && installResult?.verified === true) {
1507
- updateProgress(4, 'Installation geprüft');
1570
+ updateProgress(4, copy.installed);
1508
1571
  clearPendingUpdate(blunDir);
1509
1572
  try {
1510
1573
  writeCoreInstallSuccess(
@@ -1512,21 +1575,19 @@ async function runUpdateFlow(options, explicitUpdate) {
1512
1575
  currentVersion,
1513
1576
  release.version,
1514
1577
  release.releaseNotes,
1515
- explicitUpdate ? 'manual' : 'startup_prompt',
1578
+ explicitUpdate ? 'manual' : options.autoInstall === true ? 'startup_auto' : 'startup_prompt',
1516
1579
  (options.now || Date.now)(),
1517
1580
  );
1518
1581
  } catch {
1519
- stderr.write(
1520
- `Update ${release.version} wurde installiert, aber die Startmeldung konnte nicht gespeichert werden.\n`,
1521
- );
1582
+ stderr.write(`${copy.startupNoticeFailed(release.version)}\n`);
1522
1583
  }
1523
1584
  const continuesLastSession = Array.isArray(options.argv)
1524
1585
  && options.argv.length === 1
1525
1586
  && options.argv[0] === '-c';
1526
- stdout.write(continuesLastSession
1527
- ? `Update ${currentVersion} -> ${release.version} erfolgreich installiert. Die letzte Sitzung wird mit der neuen Version fortgesetzt.\n`
1528
- : `Update ${currentVersion} -> ${release.version} erfolgreich installiert. Starte BLUN Code neu, um die neue Version zu verwenden.\n`);
1529
- if (release.notesUrl) stdout.write(`Versionshinweise: ${release.notesUrl}\n`);
1587
+ stdout.write(`${continuesLastSession
1588
+ ? copy.installedContinue(currentVersion, release.version)
1589
+ : copy.installedRestart(currentVersion, release.version)}\n`);
1590
+ if (release.notesUrl) stdout.write(`${copy.notes}: ${release.notesUrl}\n`);
1530
1591
  return {
1531
1592
  kind: 'installed',
1532
1593
  version: release.version,
@@ -1536,14 +1597,14 @@ async function runUpdateFlow(options, explicitUpdate) {
1536
1597
  if (Number.isInteger(installResult?.code) && installResult.code !== 0) {
1537
1598
  updateProgress.finish();
1538
1599
  if (explicitUpdate) {
1539
- return explicitFailure(stderr, 'install_failed', installResult.code);
1600
+ return explicitFailure(stderr, 'install_failed', installResult.code, uiLocale);
1540
1601
  }
1541
- stderr.write(`Update fehlgeschlagen (Code ${installResult.code}). Die vorhandene Version wird gestartet.\n`);
1602
+ stderr.write(`${copy.installFailed(installResult.code)}\n`);
1542
1603
  return { kind: 'continue', reason: 'install_failed', exitCode: installResult.code };
1543
1604
  }
1544
1605
  updateProgress.finish();
1545
- if (explicitUpdate) return explicitFailure(stderr, 'verification_failed');
1546
- stderr.write('Update konnte nicht verifiziert werden. Starte BLUN Code neu.\n');
1606
+ if (explicitUpdate) return explicitFailure(stderr, 'verification_failed', undefined, uiLocale);
1607
+ stderr.write(`${copy.verificationRestart}\n`);
1547
1608
  return { kind: 'update_in_progress' };
1548
1609
  } finally {
1549
1610
  if (installerSession?.ready) {
package/blun.mjs CHANGED
@@ -342525,6 +342525,7 @@ const NotificationsConfigSchema = object({
342525
342525
  enabled: boolean$1(),
342526
342526
  condition: NotificationConditionSchema
342527
342527
  });
342528
+ const UpgradePreferencesSchema = object({ autoInstall: boolean$1() });
342528
342529
  const InlineSuggestConfigSchema = object({ languages: record(string(), boolean$1()) });
342529
342530
  const HexColorSchema = string().regex(/^#[0-9A-Fa-f]{6}$/u);
342530
342531
  const AppearanceConfigSchema = object({
@@ -342541,7 +342542,8 @@ const TuiConfigFileSchema = object({
342541
342542
  notifications: object({
342542
342543
  enabled: boolean$1().optional(),
342543
342544
  notification_condition: NotificationConditionSchema.optional()
342544
- }).optional()
342545
+ }).optional(),
342546
+ upgrade: object({ auto_install: boolean$1().optional() }).optional()
342545
342547
  });
342546
342548
  const TuiConfigSchema = object({
342547
342549
  theme: TuiThemeSchema,
@@ -342550,12 +342552,14 @@ const TuiConfigSchema = object({
342550
342552
  disablePasteBurst: boolean$1(),
342551
342553
  editorCommand: string().nullable(),
342552
342554
  notifications: NotificationsConfigSchema,
342555
+ upgrade: UpgradePreferencesSchema,
342553
342556
  inlineSuggest: InlineSuggestConfigSchema
342554
342557
  });
342555
342558
  const DEFAULT_NOTIFICATIONS_CONFIG = {
342556
342559
  enabled: true,
342557
342560
  condition: "unfocused"
342558
342561
  };
342562
+ const DEFAULT_UPGRADE_PREFERENCES = { autoInstall: true };
342559
342563
  /**
342560
342564
  * F2 Tippen-mit-Vorschlag: Code-Sprachen standardmäßig an, md/plain aus.
342561
342565
  * Unbekannte Sprachen fallen auf "an" zurück (Opt-out über tui.toml).
@@ -342573,6 +342577,7 @@ const DEFAULT_TUI_CONFIG = TuiConfigSchema.parse({
342573
342577
  disablePasteBurst: false,
342574
342578
  editorCommand: null,
342575
342579
  notifications: DEFAULT_NOTIFICATIONS_CONFIG,
342580
+ upgrade: DEFAULT_UPGRADE_PREFERENCES,
342576
342581
  inlineSuggest: { languages: DEFAULT_INLINE_SUGGEST_LANGUAGES }
342577
342582
  });
342578
342583
  /**
@@ -342649,6 +342654,7 @@ function normalizeTuiConfig(config) {
342649
342654
  enabled: config.notifications?.enabled ?? DEFAULT_NOTIFICATIONS_CONFIG.enabled,
342650
342655
  condition: config.notifications?.notification_condition ?? DEFAULT_NOTIFICATIONS_CONFIG.condition
342651
342656
  },
342657
+ upgrade: { autoInstall: config.upgrade?.auto_install ?? DEFAULT_UPGRADE_PREFERENCES.autoInstall },
342652
342658
  inlineSuggest: { languages: {
342653
342659
  ...DEFAULT_INLINE_SUGGEST_LANGUAGES,
342654
342660
  ...config.inline_suggest?.languages
@@ -342673,6 +342679,9 @@ command = "${escapeTomlBasicString(config.editorCommand ?? "")}" # Empty uses $V
342673
342679
  enabled = ${String(config.notifications.enabled)} # true | false
342674
342680
  notification_condition = "${config.notifications.condition}" # "unfocused" | "always"
342675
342681
 
342682
+ [upgrade]
342683
+ auto_install = ${String(config.upgrade.autoInstall)} # true | false
342684
+
342676
342685
  # F2 Tippen-mit-Vorschlag: Inline-Suggest je Sprache an/aus (wirkt ohne Neustart)
342677
342686
  [inline_suggest.languages]
342678
342687
  ${renderInlineSuggestLanguages(config.inlineSuggest.languages)}
@@ -420717,6 +420726,7 @@ async function currentTuiConfig(host) {
420717
420726
  editorCommand: host.state.appState.editorCommand,
420718
420727
  disablePasteBurst: host.state.appState.disablePasteBurst ?? DEFAULT_TUI_CONFIG.disablePasteBurst,
420719
420728
  notifications: host.state.appState.notifications,
420729
+ upgrade: host.state.appState.upgrade ?? DEFAULT_UPGRADE_PREFERENCES,
420720
420730
  inlineSuggest
420721
420731
  };
420722
420732
  }
@@ -516915,6 +516925,7 @@ function createInitialAppState(input) {
516915
516925
  editorCommand: input.tuiConfig.editorCommand,
516916
516926
  disablePasteBurst: input.tuiConfig.disablePasteBurst,
516917
516927
  notifications: input.tuiConfig.notifications,
516928
+ upgrade: input.tuiConfig.upgrade,
516918
516929
  availableModels: {},
516919
516930
  availableProviders: {},
516920
516931
  sessionTitle: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.485",
3
+ "version": "9.1.486",
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": {