blun-king-cli 9.1.208 → 9.1.209
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/launcher-runtime.js +71 -6
- package/bin/running-update.cjs +26 -0
- package/blun.mjs +4 -0
- package/package.json +1 -1
package/bin/launcher-runtime.js
CHANGED
|
@@ -33,12 +33,15 @@ const {
|
|
|
33
33
|
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
34
34
|
RUNNING_UPDATE_MODE_MESSAGE,
|
|
35
35
|
RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
36
|
+
RUNTIME_EXIT_INTENT_MESSAGE,
|
|
36
37
|
activateRuntime,
|
|
37
38
|
handoffArgsForMode,
|
|
38
39
|
handoffRuntime,
|
|
39
40
|
prepareRunningUpdate,
|
|
40
41
|
pruneRunningUpdateReleases,
|
|
42
|
+
recordRunningUpdateEvent,
|
|
41
43
|
readActiveRuntime,
|
|
44
|
+
restoreActiveRuntime,
|
|
42
45
|
} = require('./running-update.cjs');
|
|
43
46
|
const {
|
|
44
47
|
RUNNING_UPDATE_MODES,
|
|
@@ -65,6 +68,7 @@ const RUNTIME_READY_TIMEOUT_MS = 60_000;
|
|
|
65
68
|
const RUNNING_UPDATE_RECHECK_MS = 60_000;
|
|
66
69
|
const RUNNING_UPDATE_RECHECK_JITTER_MS = 30_000;
|
|
67
70
|
const RUNNING_UPDATE_HANDOFF_NOTICE = 'Ein Update wird geladen. Die TUI wird anschließend neu gestartet.';
|
|
71
|
+
const RUNNING_UPDATE_STABILIZATION_MS = 2 * 60 * 1000;
|
|
68
72
|
|
|
69
73
|
function runningUpdateRecheckDelay(randomValue = Math.random()) {
|
|
70
74
|
const normalized = Number.isFinite(randomValue)
|
|
@@ -268,6 +272,14 @@ function resolveHandoffCwd(candidate, fallback) {
|
|
|
268
272
|
}
|
|
269
273
|
}
|
|
270
274
|
|
|
275
|
+
function shouldRecoverActivatedRuntime(result, recovery, options = {}) {
|
|
276
|
+
if (recovery === undefined || options.runtimeExitIntent === true) return false;
|
|
277
|
+
const signal = result?.signal;
|
|
278
|
+
if (signal === 'SIGINT' || signal === 'SIGTERM' || signal === 'SIGHUP') return false;
|
|
279
|
+
const now = options.now ?? Date.now();
|
|
280
|
+
return now - recovery.activatedAt <= RUNNING_UPDATE_STABILIZATION_MS;
|
|
281
|
+
}
|
|
282
|
+
|
|
271
283
|
async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {}) {
|
|
272
284
|
const packageRoot = path.resolve(options.packageRoot || PKG);
|
|
273
285
|
let preparedTarget;
|
|
@@ -276,6 +288,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
276
288
|
let handoffCwd = cwd;
|
|
277
289
|
let updateStarted = false;
|
|
278
290
|
let runtimeReady = false;
|
|
291
|
+
let runtimeExitIntent = false;
|
|
279
292
|
let runningUpdatePollTimer;
|
|
280
293
|
let runningUpdateMode = readRunningUpdateMode(env.BLUN_HOME);
|
|
281
294
|
const automaticMode = () => runningUpdateMode === RUNNING_UPDATE_MODES.RESUME
|
|
@@ -306,11 +319,17 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
306
319
|
};
|
|
307
320
|
const announcePrepared = (child) => {
|
|
308
321
|
if (preparedTarget === undefined || !automaticMode() || child.connected !== true) return;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
322
|
+
try {
|
|
323
|
+
child.send({
|
|
324
|
+
type: RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
325
|
+
version: preparedTarget.version,
|
|
326
|
+
mode: runningUpdateMode,
|
|
327
|
+
}, (error) => {
|
|
328
|
+
if (error) options.onRunningUpdateError?.(error);
|
|
329
|
+
});
|
|
330
|
+
} catch (error) {
|
|
331
|
+
options.onRunningUpdateError?.(error);
|
|
332
|
+
}
|
|
314
333
|
};
|
|
315
334
|
const startPreparation = (child) => {
|
|
316
335
|
if (updateStarted || options.runningUpdate === false || !automaticMode()) return;
|
|
@@ -341,6 +360,7 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
341
360
|
});
|
|
342
361
|
};
|
|
343
362
|
const handleCoreMessage = (message, child) => {
|
|
363
|
+
if (message?.type === RUNTIME_EXIT_INTENT_MESSAGE) runtimeExitIntent = true;
|
|
344
364
|
if (message?.type === RUNTIME_READY_MESSAGE) {
|
|
345
365
|
runtimeReady = true;
|
|
346
366
|
refreshRunningUpdateMode();
|
|
@@ -395,12 +415,13 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
395
415
|
const result = await core.completed;
|
|
396
416
|
clearRunningUpdatePoll();
|
|
397
417
|
if (existingMessageHandler) core.child.off('message', existingMessageHandler);
|
|
398
|
-
if (result.error) throw result.error;
|
|
399
418
|
if (result.code === RUNNING_UPDATE_HANDOFF_EXIT_CODE
|
|
400
419
|
&& preparedTarget !== undefined
|
|
401
420
|
&& handoffSessionId !== undefined
|
|
402
421
|
&& handoffMode !== undefined) {
|
|
403
422
|
writeRunningUpdateHandoffNotice(options.runningUpdateNoticeOutput || process.stdout);
|
|
423
|
+
const previousActiveRuntime = (options.readActiveRuntime || readActiveRuntime)(env.BLUN_SHARED_HOME);
|
|
424
|
+
const activatedAt = (options.nowImpl || Date.now)();
|
|
404
425
|
const handoff = await handoffRuntime({
|
|
405
426
|
target: preparedTarget,
|
|
406
427
|
previous: { packageRoot, version: readPackageVersionAt(packageRoot) },
|
|
@@ -421,6 +442,11 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
421
442
|
},
|
|
422
443
|
activateTarget: async (target) => {
|
|
423
444
|
await (options.activateRuntime || activateRuntime)(env.BLUN_SHARED_HOME, target);
|
|
445
|
+
(options.recordRunningUpdateEvent || recordRunningUpdateEvent)(env.BLUN_SHARED_HOME, {
|
|
446
|
+
event: 'activated',
|
|
447
|
+
fromVersion: readPackageVersionAt(packageRoot),
|
|
448
|
+
toVersion: target.version,
|
|
449
|
+
}, { now: options.nowImpl });
|
|
424
450
|
try {
|
|
425
451
|
await (options.pruneRunningUpdateReleases || pruneRunningUpdateReleases)(env.BLUN_SHARED_HOME, {
|
|
426
452
|
activePackageRoot: target.packageRoot,
|
|
@@ -437,8 +463,45 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
437
463
|
...options,
|
|
438
464
|
existingCore: resumed,
|
|
439
465
|
packageRoot: handoff.runtime.packageRoot,
|
|
466
|
+
recoveryRuntime: handoff.kind === 'activated' ? {
|
|
467
|
+
activatedAt,
|
|
468
|
+
activeRuntime: previousActiveRuntime,
|
|
469
|
+
packageRoot,
|
|
470
|
+
version: readPackageVersionAt(packageRoot),
|
|
471
|
+
} : undefined,
|
|
440
472
|
});
|
|
441
473
|
}
|
|
474
|
+
const recovery = options.recoveryRuntime;
|
|
475
|
+
if (shouldRecoverActivatedRuntime(result, recovery, {
|
|
476
|
+
now: (options.nowImpl || Date.now)(),
|
|
477
|
+
runtimeExitIntent,
|
|
478
|
+
})) {
|
|
479
|
+
(options.recordRunningUpdateEvent || recordRunningUpdateEvent)(env.BLUN_SHARED_HOME, {
|
|
480
|
+
event: 'post-activation-exit',
|
|
481
|
+
activeVersion: readPackageVersionAt(packageRoot),
|
|
482
|
+
code: Number.isInteger(result.code) ? result.code : null,
|
|
483
|
+
error: result.error?.message || null,
|
|
484
|
+
signal: result.signal || null,
|
|
485
|
+
recoveryVersion: recovery.version,
|
|
486
|
+
}, { now: options.nowImpl });
|
|
487
|
+
await (options.restoreActiveRuntime || restoreActiveRuntime)(env.BLUN_SHARED_HOME, recovery.activeRuntime);
|
|
488
|
+
const fallback = spawnCore(args, env, cwd, { packageRoot: recovery.packageRoot });
|
|
489
|
+
const fallbackLoaded = await fallback.loaded;
|
|
490
|
+
const fallbackReady = fallbackLoaded && await waitForRuntimeReady(fallback, options.readyTimeoutMs);
|
|
491
|
+
(options.recordRunningUpdateEvent || recordRunningUpdateEvent)(env.BLUN_SHARED_HOME, {
|
|
492
|
+
event: fallbackReady ? 'recovery-ready' : 'recovery-failed',
|
|
493
|
+
version: recovery.version,
|
|
494
|
+
}, { now: options.nowImpl });
|
|
495
|
+
if (fallbackReady) {
|
|
496
|
+
return superviseProtectedCore(args, env, cwd, async () => {}, {
|
|
497
|
+
...options,
|
|
498
|
+
existingCore: fallback,
|
|
499
|
+
packageRoot: recovery.packageRoot,
|
|
500
|
+
recoveryRuntime: undefined,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (result.error) throw result.error;
|
|
442
505
|
return exitCodeForChild(result, loaded);
|
|
443
506
|
}
|
|
444
507
|
|
|
@@ -768,12 +831,14 @@ async function runLauncher(options = {}) {
|
|
|
768
831
|
module.exports = {
|
|
769
832
|
RUNNING_UPDATE_RECHECK_JITTER_MS,
|
|
770
833
|
RUNNING_UPDATE_RECHECK_MS,
|
|
834
|
+
RUNNING_UPDATE_STABILIZATION_MS,
|
|
771
835
|
createManagedNodeEnvironment,
|
|
772
836
|
resolveLauncherPrivatePaths,
|
|
773
837
|
resolveHandoffCwd,
|
|
774
838
|
runningUpdateRecheckDelay,
|
|
775
839
|
runLauncher,
|
|
776
840
|
scheduleRunningUpdateRecheck,
|
|
841
|
+
shouldRecoverActivatedRuntime,
|
|
777
842
|
shouldDetachProtectedCore,
|
|
778
843
|
spawnManagedLauncher,
|
|
779
844
|
superviseProtectedCore,
|
package/bin/running-update.cjs
CHANGED
|
@@ -19,6 +19,7 @@ const RUNNING_UPDATE_PREPARED_MESSAGE = 'blun-running-update-prepared';
|
|
|
19
19
|
const RUNNING_UPDATE_HANDOFF_MESSAGE = 'blun-running-update-handoff';
|
|
20
20
|
const RUNNING_UPDATE_MODE_MESSAGE = 'blun-running-update-mode';
|
|
21
21
|
const RUNTIME_READY_MESSAGE = 'blun-runtime-session-ready';
|
|
22
|
+
const RUNTIME_EXIT_INTENT_MESSAGE = 'blun-runtime-exit-intent';
|
|
22
23
|
const MAX_TARBALL_BYTES = 128 * 1024 * 1024;
|
|
23
24
|
const AUTO_UPDATE_SETTLE_MS = 30 * 60 * 1000;
|
|
24
25
|
const DEFAULT_RETAINED_RELEASE_VERSIONS = 3;
|
|
@@ -276,6 +277,28 @@ function activateRuntime(sharedHome, target) {
|
|
|
276
277
|
}
|
|
277
278
|
}
|
|
278
279
|
|
|
280
|
+
function restoreActiveRuntime(sharedHome, runtime) {
|
|
281
|
+
if (runtime === null || runtime === undefined) {
|
|
282
|
+
fs.rmSync(activeRuntimePath(sharedHome), { force: true });
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
activateRuntime(sharedHome, runtime);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function recordRunningUpdateEvent(sharedHome, event, options = {}) {
|
|
289
|
+
if (typeof sharedHome !== 'string' || !path.isAbsolute(sharedHome)) return false;
|
|
290
|
+
const updateRoot = path.join(path.resolve(sharedHome), 'updates');
|
|
291
|
+
ensurePrivateDirectory(path.resolve(sharedHome));
|
|
292
|
+
ensurePrivateDirectory(updateRoot);
|
|
293
|
+
const filePath = path.join(updateRoot, 'handoff.jsonl');
|
|
294
|
+
fs.appendFileSync(filePath, `${JSON.stringify({
|
|
295
|
+
at: new Date((options.now || Date.now)()).toISOString(),
|
|
296
|
+
...event,
|
|
297
|
+
})}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
298
|
+
securePrivateFile(filePath);
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
|
|
279
302
|
function registryRelease(registry, version) {
|
|
280
303
|
const versions = ownData(registry, 'versions');
|
|
281
304
|
const entry = ownData(versions, version);
|
|
@@ -474,6 +497,7 @@ module.exports = {
|
|
|
474
497
|
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
475
498
|
RUNNING_UPDATE_MODE_MESSAGE,
|
|
476
499
|
RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
500
|
+
RUNTIME_EXIT_INTENT_MESSAGE,
|
|
477
501
|
RUNTIME_READY_MESSAGE,
|
|
478
502
|
activateRuntime,
|
|
479
503
|
activeRuntimePath,
|
|
@@ -483,7 +507,9 @@ module.exports = {
|
|
|
483
507
|
isSafeRuntimeBoundary,
|
|
484
508
|
prepareRunningUpdate,
|
|
485
509
|
pruneRunningUpdateReleases,
|
|
510
|
+
recordRunningUpdateEvent,
|
|
486
511
|
readActiveRuntime,
|
|
512
|
+
restoreActiveRuntime,
|
|
487
513
|
resumeArgsForHandoff,
|
|
488
514
|
selectRunningUpdateTarget,
|
|
489
515
|
verifyRuntimePackage,
|
package/blun.mjs
CHANGED
|
@@ -515041,6 +515041,7 @@ const {
|
|
|
515041
515041
|
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
515042
515042
|
RUNNING_UPDATE_MODE_MESSAGE,
|
|
515043
515043
|
RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
515044
|
+
RUNTIME_EXIT_INTENT_MESSAGE,
|
|
515044
515045
|
RUNTIME_READY_MESSAGE,
|
|
515045
515046
|
isSafeRuntimeBoundary,
|
|
515046
515047
|
pruneRunningUpdateReleases
|
|
@@ -515734,6 +515735,9 @@ var BlunTUI = class {
|
|
|
515734
515735
|
async stop(exitCode) {
|
|
515735
515736
|
if (this.isShuttingDown) return;
|
|
515736
515737
|
this.isShuttingDown = true;
|
|
515738
|
+
if (exitCode === 0 && process.connected) try {
|
|
515739
|
+
process.send({ type: RUNTIME_EXIT_INTENT_MESSAGE });
|
|
515740
|
+
} catch {}
|
|
515737
515741
|
this.unregisterSignalHandlers();
|
|
515738
515742
|
this.aborted = true;
|
|
515739
515743
|
this.channelQueueDeadline?.dispose();
|