blun-king-cli 9.1.207 → 9.1.208
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 +11 -1
- package/bin/running-update.cjs +96 -3
- package/blun.mjs +19 -1
- package/package.json +1 -1
package/bin/launcher-runtime.js
CHANGED
|
@@ -37,6 +37,7 @@ const {
|
|
|
37
37
|
handoffArgsForMode,
|
|
38
38
|
handoffRuntime,
|
|
39
39
|
prepareRunningUpdate,
|
|
40
|
+
pruneRunningUpdateReleases,
|
|
40
41
|
readActiveRuntime,
|
|
41
42
|
} = require('./running-update.cjs');
|
|
42
43
|
const {
|
|
@@ -418,7 +419,16 @@ async function superviseProtectedCore(args, env, cwd, releaseNotice, options = {
|
|
|
418
419
|
}
|
|
419
420
|
return { ...nextCore, ready };
|
|
420
421
|
},
|
|
421
|
-
activateTarget: (target) =>
|
|
422
|
+
activateTarget: async (target) => {
|
|
423
|
+
await (options.activateRuntime || activateRuntime)(env.BLUN_SHARED_HOME, target);
|
|
424
|
+
try {
|
|
425
|
+
await (options.pruneRunningUpdateReleases || pruneRunningUpdateReleases)(env.BLUN_SHARED_HOME, {
|
|
426
|
+
activePackageRoot: target.packageRoot,
|
|
427
|
+
});
|
|
428
|
+
} catch (error) {
|
|
429
|
+
options.onRunningUpdateError?.(error);
|
|
430
|
+
}
|
|
431
|
+
},
|
|
422
432
|
});
|
|
423
433
|
const resumed = handoff.core;
|
|
424
434
|
if (resumed === undefined || resumed.ready !== true) return 1;
|
package/bin/running-update.cjs
CHANGED
|
@@ -7,6 +7,7 @@ const path = require('node:path');
|
|
|
7
7
|
const { spawn } = require('node:child_process');
|
|
8
8
|
|
|
9
9
|
const { compareSemver, requestTrustedJson } = require('./update-notice');
|
|
10
|
+
const { tryAcquireUpdateLease } = require('./update-lease');
|
|
10
11
|
const { ensurePrivateDirectory, securePrivateFile, writePrivateFile } = require('./private-paths');
|
|
11
12
|
|
|
12
13
|
const PACKAGE_NAME = 'blun-king-cli';
|
|
@@ -19,6 +20,8 @@ const RUNNING_UPDATE_HANDOFF_MESSAGE = 'blun-running-update-handoff';
|
|
|
19
20
|
const RUNNING_UPDATE_MODE_MESSAGE = 'blun-running-update-mode';
|
|
20
21
|
const RUNTIME_READY_MESSAGE = 'blun-runtime-session-ready';
|
|
21
22
|
const MAX_TARBALL_BYTES = 128 * 1024 * 1024;
|
|
23
|
+
const AUTO_UPDATE_SETTLE_MS = 30 * 60 * 1000;
|
|
24
|
+
const DEFAULT_RETAINED_RELEASE_VERSIONS = 3;
|
|
22
25
|
|
|
23
26
|
function ownData(value, key) {
|
|
24
27
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined;
|
|
@@ -37,22 +40,110 @@ function validIntegrity(value) {
|
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
function selectRunningUpdateTarget(currentVersion, manifest) {
|
|
43
|
+
function selectRunningUpdateTarget(currentVersion, manifest, options = {}) {
|
|
41
44
|
const name = ownData(manifest, 'name');
|
|
42
45
|
const version = ownData(manifest, 'latest');
|
|
43
46
|
const integrity = ownData(manifest, 'integrity');
|
|
44
47
|
const releasedAt = ownData(manifest, 'releasedAt');
|
|
48
|
+
const releasedAtMs = Date.parse(releasedAt);
|
|
49
|
+
const now = options.now || Date.now;
|
|
45
50
|
if (name !== PACKAGE_NAME
|
|
46
51
|
|| typeof version !== 'string'
|
|
47
52
|
|| compareSemver(currentVersion, version) !== -1
|
|
48
53
|
|| !validIntegrity(integrity)
|
|
49
54
|
|| typeof releasedAt !== 'string'
|
|
50
|
-
|| !Number.isFinite(
|
|
55
|
+
|| !Number.isFinite(releasedAtMs)
|
|
56
|
+
|| now() - releasedAtMs < AUTO_UPDATE_SETTLE_MS) {
|
|
51
57
|
return null;
|
|
52
58
|
}
|
|
53
59
|
return Object.freeze({ version, integrity });
|
|
54
60
|
}
|
|
55
61
|
|
|
62
|
+
function releaseVersionEntries(sharedHome) {
|
|
63
|
+
const root = releasesRoot(sharedHome);
|
|
64
|
+
let entries;
|
|
65
|
+
try {
|
|
66
|
+
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
67
|
+
} catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const releases = [];
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
73
|
+
const version = entry.name;
|
|
74
|
+
try {
|
|
75
|
+
if (compareSemver('0.0.0', version) !== -1) continue;
|
|
76
|
+
} catch {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const versionRoot = path.join(root, version);
|
|
80
|
+
const digestEntries = fs.readdirSync(versionRoot, { withFileTypes: true });
|
|
81
|
+
const packageRoots = [];
|
|
82
|
+
let valid = digestEntries.length > 0;
|
|
83
|
+
for (const digestEntry of digestEntries) {
|
|
84
|
+
if (!digestEntry.isDirectory() || digestEntry.isSymbolicLink()) {
|
|
85
|
+
valid = false;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
const packageRoot = path.join(versionRoot, digestEntry.name, 'node_modules', PACKAGE_NAME);
|
|
89
|
+
if (!verifyRuntimePackage(packageRoot, version, { allowedRoot: versionRoot })) {
|
|
90
|
+
valid = false;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
packageRoots.push(path.resolve(packageRoot));
|
|
94
|
+
}
|
|
95
|
+
if (valid && packageRoots.length > 0) releases.push({ packageRoots, version, versionRoot });
|
|
96
|
+
}
|
|
97
|
+
releases.sort((left, right) => compareSemver(right.version, left.version));
|
|
98
|
+
return releases;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function pruneRunningUpdateReleases(sharedHome, options = {}) {
|
|
102
|
+
const keepVersions = Number.isInteger(options.keepVersions) && options.keepVersions >= 1
|
|
103
|
+
? options.keepVersions
|
|
104
|
+
: DEFAULT_RETAINED_RELEASE_VERSIONS;
|
|
105
|
+
const activePackageRoot = typeof options.activePackageRoot === 'string'
|
|
106
|
+
? path.resolve(options.activePackageRoot)
|
|
107
|
+
: readActiveRuntime(sharedHome)?.packageRoot;
|
|
108
|
+
const acquire = options.tryAcquireLease
|
|
109
|
+
|| (({ packageRoot }) => tryAcquireUpdateLease({ packageRoot, role: 'install' }));
|
|
110
|
+
const releases = releaseVersionEntries(sharedHome);
|
|
111
|
+
const kept = new Set(releases.slice(0, keepVersions).map((release) => release.version));
|
|
112
|
+
for (const release of releases) {
|
|
113
|
+
if (release.packageRoots.includes(activePackageRoot)) kept.add(release.version);
|
|
114
|
+
}
|
|
115
|
+
const removedVersions = [];
|
|
116
|
+
const busyVersions = [];
|
|
117
|
+
for (const release of releases) {
|
|
118
|
+
if (kept.has(release.version)) continue;
|
|
119
|
+
const leases = [];
|
|
120
|
+
let blocked = false;
|
|
121
|
+
try {
|
|
122
|
+
for (const packageRoot of release.packageRoots) {
|
|
123
|
+
const result = await acquire({ packageRoot });
|
|
124
|
+
if (!result?.acquired || !result.lease) {
|
|
125
|
+
blocked = true;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
leases.push(result.lease);
|
|
129
|
+
}
|
|
130
|
+
if (blocked) {
|
|
131
|
+
busyVersions.push(release.version);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
for (const lease of leases) lease.assertOwned();
|
|
135
|
+
fs.rmSync(release.versionRoot, { recursive: true, force: true });
|
|
136
|
+
removedVersions.push(release.version);
|
|
137
|
+
} finally {
|
|
138
|
+
await Promise.allSettled(leases.map((lease) => lease.release()));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return Object.freeze({
|
|
142
|
+
busyVersions: Object.freeze(busyVersions),
|
|
143
|
+
removedVersions: Object.freeze(removedVersions),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
56
147
|
function isSafeRuntimeBoundary(state) {
|
|
57
148
|
return state?.isShuttingDown === false
|
|
58
149
|
&& state.streamingPhase === 'idle'
|
|
@@ -325,7 +416,7 @@ async function prepareRunningUpdate(options) {
|
|
|
325
416
|
const manifest = await (options.loadManifest
|
|
326
417
|
? options.loadManifest()
|
|
327
418
|
: requestTrustedJson(MANIFEST_URL));
|
|
328
|
-
const target = selectRunningUpdateTarget(options.currentVersion, manifest);
|
|
419
|
+
const target = selectRunningUpdateTarget(options.currentVersion, manifest, { now: options.now });
|
|
329
420
|
if (target === null) return null;
|
|
330
421
|
const registry = await (options.loadRegistry
|
|
331
422
|
? options.loadRegistry()
|
|
@@ -378,6 +469,7 @@ async function prepareRunningUpdate(options) {
|
|
|
378
469
|
|
|
379
470
|
module.exports = {
|
|
380
471
|
ACTIVE_RUNTIME_FILE,
|
|
472
|
+
AUTO_UPDATE_SETTLE_MS,
|
|
381
473
|
RUNNING_UPDATE_HANDOFF_EXIT_CODE,
|
|
382
474
|
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
383
475
|
RUNNING_UPDATE_MODE_MESSAGE,
|
|
@@ -390,6 +482,7 @@ module.exports = {
|
|
|
390
482
|
handoffRuntime,
|
|
391
483
|
isSafeRuntimeBoundary,
|
|
392
484
|
prepareRunningUpdate,
|
|
485
|
+
pruneRunningUpdateReleases,
|
|
393
486
|
readActiveRuntime,
|
|
394
487
|
resumeArgsForHandoff,
|
|
395
488
|
selectRunningUpdateTarget,
|
package/blun.mjs
CHANGED
|
@@ -515036,12 +515036,14 @@ function turnsToTrim(turns, maxTurns, hysteresis) {
|
|
|
515036
515036
|
//#endregion
|
|
515037
515037
|
//#region src/tui/blun-tui.ts
|
|
515038
515038
|
const {
|
|
515039
|
+
AUTO_UPDATE_SETTLE_MS,
|
|
515039
515040
|
RUNNING_UPDATE_HANDOFF_EXIT_CODE,
|
|
515040
515041
|
RUNNING_UPDATE_HANDOFF_MESSAGE,
|
|
515041
515042
|
RUNNING_UPDATE_MODE_MESSAGE,
|
|
515042
515043
|
RUNNING_UPDATE_PREPARED_MESSAGE,
|
|
515043
515044
|
RUNTIME_READY_MESSAGE,
|
|
515044
|
-
isSafeRuntimeBoundary
|
|
515045
|
+
isSafeRuntimeBoundary,
|
|
515046
|
+
pruneRunningUpdateReleases
|
|
515045
515047
|
} = __require("./bin/running-update.cjs");
|
|
515046
515048
|
const {
|
|
515047
515049
|
RUNNING_UPDATE_MODES,
|
|
@@ -515049,6 +515051,9 @@ const {
|
|
|
515049
515051
|
writeRunningUpdateMode
|
|
515050
515052
|
} = __require("./bin/running-update-preference.cjs");
|
|
515051
515053
|
function notifyRunningRuntimeReady(tui) {
|
|
515054
|
+
if (typeof process.env["BLUN_SHARED_HOME"] === "string" && process.env["BLUN_SHARED_HOME"].length > 0) void pruneRunningUpdateReleases(process.env["BLUN_SHARED_HOME"], {
|
|
515055
|
+
activePackageRoot: __dirname
|
|
515056
|
+
}).catch(() => {});
|
|
515052
515057
|
if (!process.connected) return;
|
|
515053
515058
|
const sessionId = tui.getCurrentSessionId();
|
|
515054
515059
|
if (sessionId.length === 0) return;
|
|
@@ -515061,6 +515066,17 @@ function notifyRunningRuntimeReady(tui) {
|
|
|
515061
515066
|
}
|
|
515062
515067
|
function requestRunningUpdateAtSafeBoundary(tui) {
|
|
515063
515068
|
if (tui.runningUpdatePreparedVersion === void 0 || tui.runningUpdatePreparedMode === void 0 || tui.runningUpdateHandoffStarted || !process.connected) return false;
|
|
515069
|
+
const waitMs = tui.runningUpdateNotBeforeMs - Date.now();
|
|
515070
|
+
if (Number.isFinite(waitMs) && waitMs > 0) {
|
|
515071
|
+
if (tui.runningUpdateDelayTimer === void 0) {
|
|
515072
|
+
tui.runningUpdateDelayTimer = setTimeout(() => {
|
|
515073
|
+
tui.runningUpdateDelayTimer = void 0;
|
|
515074
|
+
requestRunningUpdateAtSafeBoundary(tui);
|
|
515075
|
+
}, waitMs);
|
|
515076
|
+
tui.runningUpdateDelayTimer.unref?.();
|
|
515077
|
+
}
|
|
515078
|
+
return false;
|
|
515079
|
+
}
|
|
515064
515080
|
const boundaryState = () => ({
|
|
515065
515081
|
isShuttingDown: tui.isShuttingDown,
|
|
515066
515082
|
streamingPhase: tui.state.appState.streamingPhase,
|
|
@@ -515191,6 +515207,8 @@ var BlunTUI = class {
|
|
|
515191
515207
|
runningUpdatePreparedVersion;
|
|
515192
515208
|
runningUpdatePreparedMode;
|
|
515193
515209
|
runningUpdateHandoffStarted = false;
|
|
515210
|
+
runningUpdateNotBeforeMs = Date.now() + AUTO_UPDATE_SETTLE_MS;
|
|
515211
|
+
runningUpdateDelayTimer;
|
|
515194
515212
|
runningUpdateMessageDispose;
|
|
515195
515213
|
startupPhaseMs = {};
|
|
515196
515214
|
lastActivityMode;
|