blun-king-cli 9.1.20 → 9.1.22
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/bin/update-notice.js +58 -24
- package/blun.mjs +222 -197
- package/package.json +1 -1
- package/standard-tools/language-guard/blun_language_guard.py +22 -15
package/bin/update-notice.js
CHANGED
|
@@ -31,6 +31,13 @@ const UPDATE_SIGNAL_EXIT_CODES = Object.freeze({
|
|
|
31
31
|
SIGINT: 130,
|
|
32
32
|
SIGTERM: 143,
|
|
33
33
|
});
|
|
34
|
+
const INTERACTIVE_START_MODE_FLAGS = new Set([
|
|
35
|
+
'-y',
|
|
36
|
+
'--auto',
|
|
37
|
+
'--auto-approve',
|
|
38
|
+
'--plan',
|
|
39
|
+
'--yolo',
|
|
40
|
+
]);
|
|
34
41
|
const SEMVER_IDENTIFIER = '(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)';
|
|
35
42
|
const SEMVER_PATTERN = new RegExp(
|
|
36
43
|
`^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)`
|
|
@@ -435,8 +442,10 @@ function writeSkippedVersion(blunDir, skippedVersion) {
|
|
|
435
442
|
}
|
|
436
443
|
|
|
437
444
|
function isInteractiveUpdateStart({ argv, env, stdin, stdout }) {
|
|
438
|
-
|
|
439
|
-
&& argv.length === 0
|
|
445
|
+
const isOrdinaryStartup = Array.isArray(argv)
|
|
446
|
+
&& (argv.length === 0
|
|
447
|
+
|| (argv.length === 1 && INTERACTIVE_START_MODE_FLAGS.has(argv[0])));
|
|
448
|
+
return isOrdinaryStartup
|
|
440
449
|
&& (!env || env.BLUN_NO_AUTO_UPDATE !== '1')
|
|
441
450
|
&& stdin?.isTTY === true
|
|
442
451
|
&& stdout?.isTTY === true;
|
|
@@ -449,48 +458,65 @@ function installCommandText(version) {
|
|
|
449
458
|
function createUpdateProgress(output) {
|
|
450
459
|
const enabled = output?.isTTY === true;
|
|
451
460
|
const phaseCount = 4;
|
|
452
|
-
const width =
|
|
453
|
-
|
|
461
|
+
const width = 24;
|
|
462
|
+
const cyan = '\u001B[36m';
|
|
463
|
+
const dim = '\u001B[2m';
|
|
464
|
+
const reset = '\u001B[0m';
|
|
465
|
+
let active = false;
|
|
466
|
+
const update = (phase, label) => {
|
|
454
467
|
if (!enabled) return;
|
|
455
468
|
const completed = Math.max(0, Math.min(phaseCount, phase));
|
|
456
469
|
const filled = Math.round((completed / phaseCount) * width);
|
|
457
|
-
const bar = `${'
|
|
458
|
-
output.write(
|
|
470
|
+
const bar = `${'━'.repeat(filled)}${'─'.repeat(width - filled)}`;
|
|
471
|
+
output.write(`\r\u001B[2K${cyan}${bar}${reset} ${dim}${completed}/${phaseCount}${reset} ${label}`);
|
|
472
|
+
active = completed < phaseCount;
|
|
473
|
+
if (!active) output.write('\n');
|
|
474
|
+
};
|
|
475
|
+
update.finish = () => {
|
|
476
|
+
if (!enabled || !active) return;
|
|
477
|
+
active = false;
|
|
478
|
+
output.write('\n');
|
|
459
479
|
};
|
|
480
|
+
return update;
|
|
460
481
|
}
|
|
461
482
|
|
|
462
483
|
function promptUpdateAction({ currentVersion, release, input, output, processRef = process }) {
|
|
463
484
|
return new Promise((resolve, reject) => {
|
|
464
|
-
let selected =
|
|
485
|
+
let selected = 0;
|
|
465
486
|
let settled = false;
|
|
466
487
|
let cursorHidden = false;
|
|
467
488
|
let escapeTimer;
|
|
468
489
|
let pendingInput = '';
|
|
469
490
|
const decoder = new StringDecoder('utf8');
|
|
470
491
|
const wasRaw = input.isRaw === true;
|
|
492
|
+
const cyan = '\u001B[36m';
|
|
493
|
+
const dim = '\u001B[2m';
|
|
494
|
+
const underline = '\u001B[4m';
|
|
495
|
+
const reset = '\u001B[0m';
|
|
471
496
|
const actions = [
|
|
472
497
|
{
|
|
473
498
|
choice: 'install',
|
|
474
499
|
label: `Jetzt aktualisieren (führt \`${installCommandText(release.version)}\` aus)`,
|
|
475
500
|
},
|
|
476
|
-
{ choice: '
|
|
477
|
-
{ choice: 'skip-version', label: '
|
|
501
|
+
{ choice: 'skip-once', label: 'Überspringen' },
|
|
502
|
+
{ choice: 'skip-version', label: 'Auf den nächsten Release warten' },
|
|
478
503
|
];
|
|
479
504
|
const signalHandlers = new Map();
|
|
480
505
|
|
|
481
506
|
const renderActions = (refresh) => {
|
|
482
507
|
if (refresh) output.write(`\u001B[${actions.length + 1}F`);
|
|
483
508
|
for (let index = 0; index < actions.length; index += 1) {
|
|
484
|
-
|
|
509
|
+
const line = `${selected === index ? '›' : ' '} ${index + 1}. ${actions[index].label}`;
|
|
510
|
+
output.write(`\r\u001B[2K${selected === index ? cyan : ''}${line}${selected === index ? reset : ''}\n`);
|
|
485
511
|
}
|
|
486
|
-
output.write(
|
|
512
|
+
output.write(`\r\u001B[2K${dim}Enter drücken, um fortzufahren${reset}\n`);
|
|
487
513
|
};
|
|
488
514
|
const cleanup = () => {
|
|
489
515
|
if (escapeTimer !== undefined) clearTimeout(escapeTimer);
|
|
490
516
|
input.removeListener('data', onData);
|
|
491
|
-
input.removeListener('end',
|
|
492
|
-
input.removeListener('close',
|
|
493
|
-
input.removeListener('error',
|
|
517
|
+
input.removeListener('end', skipOnce);
|
|
518
|
+
input.removeListener('close', skipOnce);
|
|
519
|
+
input.removeListener('error', skipOnce);
|
|
494
520
|
for (const [signal, handler] of signalHandlers) {
|
|
495
521
|
processRef.removeListener(signal, handler);
|
|
496
522
|
}
|
|
@@ -537,14 +563,14 @@ function promptUpdateAction({ currentVersion, release, input, output, processRef
|
|
|
537
563
|
if (typeof processRef.exit === 'function') processRef.exit(exitCode);
|
|
538
564
|
reject(error);
|
|
539
565
|
};
|
|
540
|
-
function
|
|
541
|
-
finish('
|
|
566
|
+
function skipOnce() {
|
|
567
|
+
finish('skip-once');
|
|
542
568
|
}
|
|
543
569
|
const waitForEscapeSuffix = () => {
|
|
544
570
|
if (escapeTimer !== undefined) return;
|
|
545
571
|
escapeTimer = setTimeout(() => {
|
|
546
572
|
escapeTimer = undefined;
|
|
547
|
-
|
|
573
|
+
skipOnce();
|
|
548
574
|
}, UPDATE_KEY_ESCAPE_TIMEOUT_MS);
|
|
549
575
|
};
|
|
550
576
|
const clearEscapeTimer = () => {
|
|
@@ -573,7 +599,7 @@ function promptUpdateAction({ currentVersion, release, input, output, processRef
|
|
|
573
599
|
while (pendingInput.length > 0) {
|
|
574
600
|
const first = pendingInput[0];
|
|
575
601
|
if (first === '\u0003') {
|
|
576
|
-
|
|
602
|
+
skipOnce();
|
|
577
603
|
return;
|
|
578
604
|
}
|
|
579
605
|
if (first === '\r' || first === '\n') {
|
|
@@ -596,7 +622,7 @@ function promptUpdateAction({ currentVersion, release, input, output, processRef
|
|
|
596
622
|
&& (pendingInput[1] === '\r'
|
|
597
623
|
|| pendingInput[1] === '\n'
|
|
598
624
|
|| pendingInput[1] === '\u0003')) {
|
|
599
|
-
|
|
625
|
+
skipOnce();
|
|
600
626
|
return;
|
|
601
627
|
}
|
|
602
628
|
const sequence = readEscapeSequence();
|
|
@@ -638,16 +664,18 @@ function promptUpdateAction({ currentVersion, release, input, output, processRef
|
|
|
638
664
|
signalHandlers.set(signal, handler);
|
|
639
665
|
processRef.once(signal, handler);
|
|
640
666
|
}
|
|
641
|
-
output.write(`\
|
|
642
|
-
if (release.notesUrl)
|
|
667
|
+
output.write(`\nBLUN Code-Update verfügbar: ${currentVersion} -> ${release.version}\n`);
|
|
668
|
+
if (release.notesUrl) {
|
|
669
|
+
output.write(`${dim}Versionshinweise:${reset} ${underline}${release.notesUrl}${reset}\n`);
|
|
670
|
+
}
|
|
643
671
|
output.write('\n');
|
|
644
672
|
cursorHidden = true;
|
|
645
673
|
output.write('\u001B[?25l');
|
|
646
674
|
renderActions(false);
|
|
647
675
|
input.on('data', onData);
|
|
648
|
-
input.once('end',
|
|
649
|
-
input.once('close',
|
|
650
|
-
input.once('error',
|
|
676
|
+
input.once('end', skipOnce);
|
|
677
|
+
input.once('close', skipOnce);
|
|
678
|
+
input.once('error', skipOnce);
|
|
651
679
|
if (typeof input.setRawMode === 'function') input.setRawMode(true);
|
|
652
680
|
if (typeof input.resume === 'function') input.resume();
|
|
653
681
|
} catch (error) {
|
|
@@ -1260,6 +1288,9 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1260
1288
|
}
|
|
1261
1289
|
if (action !== 'install') {
|
|
1262
1290
|
if (installerSession?.ready) await installerSession.cancel();
|
|
1291
|
+
if (action === 'skip-once') {
|
|
1292
|
+
return { kind: 'continue', reason: 'skipped_once' };
|
|
1293
|
+
}
|
|
1263
1294
|
if (action === 'skip-version') {
|
|
1264
1295
|
try {
|
|
1265
1296
|
writeSkippedVersion(blunDir, release.version);
|
|
@@ -1299,6 +1330,7 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1299
1330
|
if (installResult?.leaseBusy === true
|
|
1300
1331
|
|| installResult?.leaseUnavailable === true
|
|
1301
1332
|
|| installResult?.unknownState === true) {
|
|
1333
|
+
updateProgress.finish();
|
|
1302
1334
|
return explicitUpdate
|
|
1303
1335
|
? explicitFailure(stderr, 'update_in_progress')
|
|
1304
1336
|
: { kind: 'update_in_progress' };
|
|
@@ -1310,12 +1342,14 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1310
1342
|
}
|
|
1311
1343
|
|
|
1312
1344
|
if (Number.isInteger(installResult?.code) && installResult.code !== 0) {
|
|
1345
|
+
updateProgress.finish();
|
|
1313
1346
|
if (explicitUpdate) {
|
|
1314
1347
|
return explicitFailure(stderr, 'install_failed', installResult.code);
|
|
1315
1348
|
}
|
|
1316
1349
|
stderr.write(`Update fehlgeschlagen (Code ${installResult.code}). Die vorhandene Version wird gestartet.\n`);
|
|
1317
1350
|
return { kind: 'continue', reason: 'install_failed', exitCode: installResult.code };
|
|
1318
1351
|
}
|
|
1352
|
+
updateProgress.finish();
|
|
1319
1353
|
if (explicitUpdate) return explicitFailure(stderr, 'verification_failed');
|
|
1320
1354
|
stderr.write('Update konnte nicht verifiziert werden. Starte BLUN Code neu.\n');
|
|
1321
1355
|
return { kind: 'update_in_progress' };
|