blun-king-cli 9.1.22 → 9.1.24
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/blun.js +11 -12
- package/bin/king.js +11 -12
- package/bin/launcher-runtime.js +1 -1
- package/bin/update-notice.js +93 -17
- package/blun.mjs +448 -185
- package/package.json +1 -1
- package/telegram-plugin/dist/bridge.mjs +10 -2
package/bin/blun.js
CHANGED
|
@@ -313,9 +313,9 @@ function connectRuntimeBroker(endpoint) {
|
|
|
313
313
|
});
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
async function connectExistingRuntimeLease() {
|
|
316
|
+
async function connectExistingRuntimeLease(timeoutMs = 3_000) {
|
|
317
317
|
const endpoint = deriveLeaseEndpoint('runtime');
|
|
318
|
-
const deadline = Date.now() +
|
|
318
|
+
const deadline = Date.now() + timeoutMs;
|
|
319
319
|
while (Date.now() < deadline) {
|
|
320
320
|
const connected = await connectRuntimeBroker(endpoint);
|
|
321
321
|
if (connected.acquired) return connected;
|
|
@@ -328,18 +328,17 @@ async function main() {
|
|
|
328
328
|
const explicitUpdateRequest = process.argv.length === 3
|
|
329
329
|
&& /^(?:update|upgrade)$/iu.test(process.argv[2] || '');
|
|
330
330
|
let noticeResult = await acquireNoticeLease();
|
|
331
|
-
if (!noticeResult.acquired && explicitUpdateRequest) {
|
|
332
|
-
process.stderr.write('BLUN laeuft noch. Beende die laufenden Konsolen und starte das Update erneut.\n');
|
|
333
|
-
process.exitCode = 1;
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
331
|
let runtimeResult;
|
|
337
332
|
try {
|
|
338
333
|
if (explicitUpdateRequest) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
334
|
+
runtimeResult = await connectExistingRuntimeLease(750);
|
|
335
|
+
if (!runtimeResult.acquired) {
|
|
336
|
+
runtimeResult = undefined;
|
|
337
|
+
if (!noticeResult.acquired || !await installLeaseIsClear()) {
|
|
338
|
+
process.stderr.write('Der geschuetzte BLUN-Start ist gerade nicht verfuegbar.\n');
|
|
339
|
+
process.exitCode = 1;
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
343
342
|
}
|
|
344
343
|
} else {
|
|
345
344
|
const installClear = await installLeaseIsClear();
|
|
@@ -373,7 +372,7 @@ async function main() {
|
|
|
373
372
|
mode: filename.startsWith('king') ? 'king' : 'blun',
|
|
374
373
|
noticeLease: noticeResult.lease,
|
|
375
374
|
runtimeLease: runtimeResult?.lease,
|
|
376
|
-
skipUpdateNotice: runtimeResult?.acquired === true,
|
|
375
|
+
skipUpdateNotice: runtimeResult?.acquired === true || !noticeResult.acquired,
|
|
377
376
|
});
|
|
378
377
|
} finally {
|
|
379
378
|
await runtimeResult?.lease?.release();
|
package/bin/king.js
CHANGED
|
@@ -313,9 +313,9 @@ function connectRuntimeBroker(endpoint) {
|
|
|
313
313
|
});
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
async function connectExistingRuntimeLease() {
|
|
316
|
+
async function connectExistingRuntimeLease(timeoutMs = 3_000) {
|
|
317
317
|
const endpoint = deriveLeaseEndpoint('runtime');
|
|
318
|
-
const deadline = Date.now() +
|
|
318
|
+
const deadline = Date.now() + timeoutMs;
|
|
319
319
|
while (Date.now() < deadline) {
|
|
320
320
|
const connected = await connectRuntimeBroker(endpoint);
|
|
321
321
|
if (connected.acquired) return connected;
|
|
@@ -328,18 +328,17 @@ async function main() {
|
|
|
328
328
|
const explicitUpdateRequest = process.argv.length === 3
|
|
329
329
|
&& /^(?:update|upgrade)$/iu.test(process.argv[2] || '');
|
|
330
330
|
let noticeResult = await acquireNoticeLease();
|
|
331
|
-
if (!noticeResult.acquired && explicitUpdateRequest) {
|
|
332
|
-
process.stderr.write('BLUN laeuft noch. Beende die laufenden Konsolen und starte das Update erneut.\n');
|
|
333
|
-
process.exitCode = 1;
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
331
|
let runtimeResult;
|
|
337
332
|
try {
|
|
338
333
|
if (explicitUpdateRequest) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
334
|
+
runtimeResult = await connectExistingRuntimeLease(750);
|
|
335
|
+
if (!runtimeResult.acquired) {
|
|
336
|
+
runtimeResult = undefined;
|
|
337
|
+
if (!noticeResult.acquired || !await installLeaseIsClear()) {
|
|
338
|
+
process.stderr.write('Der geschuetzte BLUN-Start ist gerade nicht verfuegbar.\n');
|
|
339
|
+
process.exitCode = 1;
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
343
342
|
}
|
|
344
343
|
} else {
|
|
345
344
|
const installClear = await installLeaseIsClear();
|
|
@@ -373,7 +372,7 @@ async function main() {
|
|
|
373
372
|
mode: filename.startsWith('king') ? 'king' : 'blun',
|
|
374
373
|
noticeLease: noticeResult.lease,
|
|
375
374
|
runtimeLease: runtimeResult?.lease,
|
|
376
|
-
skipUpdateNotice: runtimeResult?.acquired === true,
|
|
375
|
+
skipUpdateNotice: runtimeResult?.acquired === true || !noticeResult.acquired,
|
|
377
376
|
});
|
|
378
377
|
} finally {
|
|
379
378
|
await runtimeResult?.lease?.release();
|
package/bin/launcher-runtime.js
CHANGED
|
@@ -210,7 +210,7 @@ async function runLauncher(options = {}) {
|
|
|
210
210
|
};
|
|
211
211
|
|
|
212
212
|
try {
|
|
213
|
-
if (!runtimeLease) {
|
|
213
|
+
if (!runtimeLease && !explicitUpdateRequest) {
|
|
214
214
|
const installProbe = await tryAcquireUpdateLease({ packageRoot: PKG, role: 'install' });
|
|
215
215
|
if (!installProbe.acquired) {
|
|
216
216
|
process.stderr.write(explicitUpdateRequest
|
package/bin/update-notice.js
CHANGED
|
@@ -24,6 +24,7 @@ const SNOOZE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
|
24
24
|
const REQUEST_TIMEOUT_MS = 2_500;
|
|
25
25
|
const STATE_FILE = 'update-notice.json';
|
|
26
26
|
const UPDATE_SKIP_FILE = 'update-skip-version.json';
|
|
27
|
+
const PENDING_UPDATE_FILE = 'update-pending.json';
|
|
27
28
|
const UPDATE_DIRECTORY = 'updates';
|
|
28
29
|
const UPDATE_KEY_ESCAPE_TIMEOUT_MS = 500;
|
|
29
30
|
const UPDATE_SIGNAL_EXIT_CODES = Object.freeze({
|
|
@@ -441,6 +442,59 @@ function writeSkippedVersion(blunDir, skippedVersion) {
|
|
|
441
442
|
}
|
|
442
443
|
}
|
|
443
444
|
|
|
445
|
+
function pendingUpdatePath(blunDir) {
|
|
446
|
+
return path.join(blunDir, PENDING_UPDATE_FILE);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function readPendingUpdate(blunDir) {
|
|
450
|
+
try {
|
|
451
|
+
const filePath = pendingUpdatePath(blunDir);
|
|
452
|
+
if (!fs.existsSync(filePath)) return undefined;
|
|
453
|
+
securePrivateFile(filePath);
|
|
454
|
+
const stat = fs.lstatSync(filePath);
|
|
455
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1_024) return undefined;
|
|
456
|
+
const record = exactDataRecord(JSON.parse(fs.readFileSync(filePath, 'utf8')), [
|
|
457
|
+
'targetVersion',
|
|
458
|
+
'version',
|
|
459
|
+
]);
|
|
460
|
+
if (!record || record.version !== 1 || !parseSemver(record.targetVersion)) return undefined;
|
|
461
|
+
return record.targetVersion;
|
|
462
|
+
} catch {
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function writePendingUpdate(blunDir, targetVersion) {
|
|
468
|
+
if (!parseSemver(targetVersion)) throw new Error('INVALID_UPDATE_VERSION');
|
|
469
|
+
ensurePrivateDirectory(blunDir);
|
|
470
|
+
const filePath = pendingUpdatePath(blunDir);
|
|
471
|
+
const temporaryPath = path.join(
|
|
472
|
+
blunDir,
|
|
473
|
+
`.${PENDING_UPDATE_FILE}.${process.pid}.${randomUUID()}.tmp`,
|
|
474
|
+
);
|
|
475
|
+
try {
|
|
476
|
+
writePrivateFile(temporaryPath, `${JSON.stringify({
|
|
477
|
+
version: 1,
|
|
478
|
+
targetVersion,
|
|
479
|
+
})}\n`);
|
|
480
|
+
const handle = fs.openSync(temporaryPath, 'r+');
|
|
481
|
+
try {
|
|
482
|
+
fs.fsyncSync(handle);
|
|
483
|
+
} finally {
|
|
484
|
+
fs.closeSync(handle);
|
|
485
|
+
}
|
|
486
|
+
fs.renameSync(temporaryPath, filePath);
|
|
487
|
+
securePrivateFile(filePath);
|
|
488
|
+
} catch (error) {
|
|
489
|
+
fs.rmSync(temporaryPath, { force: true });
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function clearPendingUpdate(blunDir) {
|
|
495
|
+
fs.rmSync(pendingUpdatePath(blunDir), { force: true });
|
|
496
|
+
}
|
|
497
|
+
|
|
444
498
|
function isInteractiveUpdateStart({ argv, env, stdin, stdout }) {
|
|
445
499
|
const isOrdinaryStartup = Array.isArray(argv)
|
|
446
500
|
&& (argv.length === 0
|
|
@@ -1145,6 +1199,19 @@ function explicitFailure(stderr, reason, exitCode) {
|
|
|
1145
1199
|
};
|
|
1146
1200
|
}
|
|
1147
1201
|
|
|
1202
|
+
function queueExplicitUpdate(blunDir, release, stdout, stderr) {
|
|
1203
|
+
try {
|
|
1204
|
+
ensurePrivateDirectory(blunDir);
|
|
1205
|
+
writePendingUpdate(blunDir, release.version);
|
|
1206
|
+
} catch {
|
|
1207
|
+
return explicitFailure(stderr, 'private_home_unavailable');
|
|
1208
|
+
}
|
|
1209
|
+
stdout.write(
|
|
1210
|
+
`Update ${release.version} vorgemerkt. Es wird beim ersten freien Start automatisch installiert.\n`,
|
|
1211
|
+
);
|
|
1212
|
+
return { kind: 'queued', version: release.version };
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1148
1215
|
async function runUpdateFlow(options, explicitUpdate) {
|
|
1149
1216
|
const {
|
|
1150
1217
|
currentVersion,
|
|
@@ -1164,8 +1231,13 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1164
1231
|
: { kind: 'continue', reason: 'invalid_current_version' };
|
|
1165
1232
|
}
|
|
1166
1233
|
|
|
1234
|
+
let pendingVersion = readPendingUpdate(blunDir);
|
|
1235
|
+
if (pendingVersion !== undefined && compareSemver(currentVersion, pendingVersion) >= 0) {
|
|
1236
|
+
clearPendingUpdate(blunDir);
|
|
1237
|
+
pendingVersion = undefined;
|
|
1238
|
+
}
|
|
1167
1239
|
const now = (options.now || Date.now)();
|
|
1168
|
-
if (!explicitUpdate && readSnoozeState(blunDir, now)) {
|
|
1240
|
+
if (!explicitUpdate && pendingVersion === undefined && readSnoozeState(blunDir, now)) {
|
|
1169
1241
|
return { kind: 'continue', reason: 'snoozed' };
|
|
1170
1242
|
}
|
|
1171
1243
|
|
|
@@ -1198,20 +1270,11 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1198
1270
|
let installerSession;
|
|
1199
1271
|
|
|
1200
1272
|
try {
|
|
1201
|
-
if (!explicitUpdate
|
|
1273
|
+
if (!explicitUpdate
|
|
1274
|
+
&& pendingVersion === undefined
|
|
1275
|
+
&& readSnoozeState(blunDir, (options.now || Date.now)())) {
|
|
1202
1276
|
return { kind: 'continue', reason: 'snoozed' };
|
|
1203
1277
|
}
|
|
1204
|
-
const initialInstallLease = await probeInstallLease(options, packageRoot);
|
|
1205
|
-
if (initialInstallLease === 'busy') {
|
|
1206
|
-
return explicitUpdate
|
|
1207
|
-
? explicitFailure(stderr, 'update_in_progress')
|
|
1208
|
-
: { kind: 'update_in_progress' };
|
|
1209
|
-
}
|
|
1210
|
-
if (initialInstallLease !== 'clear') {
|
|
1211
|
-
return explicitUpdate
|
|
1212
|
-
? explicitFailure(stderr, 'lease_unavailable')
|
|
1213
|
-
: { kind: 'continue', reason: 'lease_unavailable' };
|
|
1214
|
-
}
|
|
1215
1278
|
let sources;
|
|
1216
1279
|
try {
|
|
1217
1280
|
sources = await (options.loadReleaseSources || loadReleaseSources)();
|
|
@@ -1229,10 +1292,22 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1229
1292
|
? explicitNoTarget(stdout, reason)
|
|
1230
1293
|
: { kind: 'continue', reason };
|
|
1231
1294
|
}
|
|
1232
|
-
|
|
1295
|
+
const queuedForRelease = pendingVersion === release.version;
|
|
1296
|
+
const initialInstallLease = await probeInstallLease(options, packageRoot);
|
|
1297
|
+
if (initialInstallLease === 'busy') {
|
|
1298
|
+
return explicitUpdate
|
|
1299
|
+
? queueExplicitUpdate(blunDir, release, stdout, stderr)
|
|
1300
|
+
: { kind: 'update_in_progress' };
|
|
1301
|
+
}
|
|
1302
|
+
if (initialInstallLease !== 'clear') {
|
|
1303
|
+
return explicitUpdate
|
|
1304
|
+
? explicitFailure(stderr, 'lease_unavailable')
|
|
1305
|
+
: { kind: 'continue', reason: 'lease_unavailable' };
|
|
1306
|
+
}
|
|
1307
|
+
if (!explicitUpdate && !queuedForRelease && readSkippedVersion(blunDir) === release.version) {
|
|
1233
1308
|
return { kind: 'continue', reason: 'skipped_version' };
|
|
1234
1309
|
}
|
|
1235
|
-
if (explicitUpdate) {
|
|
1310
|
+
if (explicitUpdate || queuedForRelease) {
|
|
1236
1311
|
try {
|
|
1237
1312
|
ensurePrivateDirectory(blunDir);
|
|
1238
1313
|
} catch {
|
|
@@ -1249,7 +1324,7 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1249
1324
|
const prePromptInstallLease = await probeInstallLease(options, packageRoot);
|
|
1250
1325
|
if (prePromptInstallLease === 'busy') {
|
|
1251
1326
|
return explicitUpdate
|
|
1252
|
-
?
|
|
1327
|
+
? queueExplicitUpdate(blunDir, release, stdout, stderr)
|
|
1253
1328
|
: { kind: 'update_in_progress' };
|
|
1254
1329
|
}
|
|
1255
1330
|
if (prePromptInstallLease !== 'clear') {
|
|
@@ -1272,7 +1347,7 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1272
1347
|
}
|
|
1273
1348
|
}
|
|
1274
1349
|
let action;
|
|
1275
|
-
if (explicitUpdate) {
|
|
1350
|
+
if (explicitUpdate || queuedForRelease) {
|
|
1276
1351
|
action = 'install';
|
|
1277
1352
|
} else {
|
|
1278
1353
|
try {
|
|
@@ -1337,6 +1412,7 @@ async function runUpdateFlow(options, explicitUpdate) {
|
|
|
1337
1412
|
}
|
|
1338
1413
|
if (installResult?.code === 0 && installResult?.verified === true) {
|
|
1339
1414
|
updateProgress(4, 'Installation geprüft');
|
|
1415
|
+
clearPendingUpdate(blunDir);
|
|
1340
1416
|
stdout.write('Update erfolgreich installiert. Starte BLUN Code neu, um die neue Version zu verwenden.\n');
|
|
1341
1417
|
return { kind: 'installed', version: release.version };
|
|
1342
1418
|
}
|