blun-king-cli 9.1.626 → 9.1.628

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.
@@ -1,92 +1,93 @@
1
- 'use strict';
2
-
3
- const fs = require('node:fs');
4
- const path = require('node:path');
5
- const { pathToFileURL } = require('node:url');
6
-
7
- const { acquireSharedRuntimeLease } = require('./update-lease');
8
- const { installWindowsNodeCrashDump } = require('./windows-node-crash-dump.cjs');
9
- const { recordRuntimeExit } = require('./runtime-exit-ledger.cjs');
10
- const { isStandaloneHelpRequest } = require('./launcher-mode');
11
-
12
- const CORE_LOADED_MESSAGE = 'blun-core-bootstrap-loaded';
13
-
14
- function bindInteractiveTerminalOwner() {
15
- if (process.platform !== 'win32' || process.env.BLUN_TERMINAL_OWNER !== '1' || !process.channel) return;
16
- const stop = () => {
17
- setTimeout(() => process.exit(143), 5000).unref();
18
- if (!process.emit('SIGTERM')) process.exit(143);
19
- };
20
- process.once('disconnect', stop);
21
- if (!process.connected) stop();
22
- }
23
-
24
- async function runCoreBootstrap() {
25
- bindInteractiveTerminalOwner();
26
- const informational = isStandaloneHelpRequest(process.argv.slice(2));
27
- let diagnostics;
28
- if (!informational) {
29
- try { diagnostics = installWindowsNodeCrashDump({ homeDir: process.env.BLUN_HOME }); } catch {}
30
- }
31
- const packageRoot = path.resolve(__dirname, '..');
32
- const mainPath = path.join(packageRoot, 'blun.mjs');
33
- let leaseResult;
34
-
35
- try {
36
- leaseResult = await acquireSharedRuntimeLease({ packageRoot });
37
- if (!leaseResult.acquired) throw new Error('RUNTIME_PROTECTION_UNAVAILABLE');
38
- leaseResult.lease.assertOwned();
39
- process.argv = [process.execPath, mainPath, ...process.argv.slice(2)];
40
- await import(pathToFileURL(mainPath).href);
41
- leaseResult.lease.assertOwned();
42
- } catch (error) {
43
- if (!informational) {
44
- try {
45
- if (diagnostics?.enabled) diagnostics.write(error, 'bootstrap-failure');
46
- else recordRuntimeExit({ homeDir: process.env.BLUN_HOME, source: 'bootstrap',
47
- kind: 'bootstrap-failure', phase: 'startup', error });
48
- } catch {}
49
- }
50
- try { diagnostics?.dispose(); } catch {}
51
- try { await leaseResult?.lease?.release(); }
52
- catch (leaseError) {
53
- if (!informational) {
54
- try {
55
- recordRuntimeExit({ homeDir: process.env.BLUN_HOME, source: 'bootstrap',
56
- kind: 'lease-release-failure', phase: 'cleanup', error: leaseError });
57
- } catch {}
58
- }
59
- }
60
- throw error;
61
- }
62
-
63
- // The bundled CLI loads package assets lazily after module evaluation. Keep
64
- // the install lease for this process's lifetime, without keeping print/help
65
- // commands alive solely because of the owner server.
66
- leaseResult.lease.unref();
67
-
68
- if (process.connected) {
69
- try {
70
- process.send({ type: CORE_LOADED_MESSAGE }, () => {
71
- if (process.env.BLUN_TERMINAL_OWNER === '1') {
72
- process.channel?.unref();
73
- return;
74
- }
75
- try {
76
- process.disconnect();
77
- } catch {}
78
- });
79
- } catch {}
80
- }
81
- }
82
-
83
- if (require.main === module) {
84
- // oxlint-disable-next-line unicorn/prefer-top-level-await -- Worker entry is CommonJS.
85
- void runCoreBootstrap().catch((error) => {
86
- const message = error && error.message ? error.message : String(error);
87
- fs.writeSync(process.stderr.fd, `BLUN Start fehlgeschlagen: ${message}\n`);
88
- process.exit(1);
89
- });
90
- }
91
-
92
- module.exports = { CORE_LOADED_MESSAGE, runCoreBootstrap };
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { pathToFileURL } = require('node:url');
6
+
7
+ const { acquireSharedRuntimeLease } = require('./update-lease');
8
+ const { installWindowsNodeCrashDump } = require('./windows-node-crash-dump.cjs');
9
+ const { recordRuntimeExit } = require('./runtime-exit-ledger.cjs');
10
+ const { isStandaloneHelpRequest, isReadOnlyInspectionRequest } = require('./launcher-mode');
11
+
12
+ const CORE_LOADED_MESSAGE = 'blun-core-bootstrap-loaded';
13
+
14
+ function bindInteractiveTerminalOwner() {
15
+ if (process.platform !== 'win32' || process.env.BLUN_TERMINAL_OWNER !== '1' || !process.channel) return;
16
+ const stop = () => {
17
+ setTimeout(() => process.exit(143), 5000).unref();
18
+ if (!process.emit('SIGTERM')) process.exit(143);
19
+ };
20
+ process.once('disconnect', stop);
21
+ if (!process.connected) stop();
22
+ }
23
+
24
+ async function runCoreBootstrap() {
25
+ bindInteractiveTerminalOwner();
26
+ const args = process.argv.slice(2);
27
+ const informational = isStandaloneHelpRequest(args) || isReadOnlyInspectionRequest(args);
28
+ let diagnostics;
29
+ if (!informational) {
30
+ try { diagnostics = installWindowsNodeCrashDump({ homeDir: process.env.BLUN_HOME }); } catch {}
31
+ }
32
+ const packageRoot = path.resolve(__dirname, '..');
33
+ const mainPath = path.join(packageRoot, 'blun.mjs');
34
+ let leaseResult;
35
+
36
+ try {
37
+ leaseResult = await acquireSharedRuntimeLease({ packageRoot });
38
+ if (!leaseResult.acquired) throw new Error('RUNTIME_PROTECTION_UNAVAILABLE');
39
+ leaseResult.lease.assertOwned();
40
+ process.argv = [process.execPath, mainPath, ...process.argv.slice(2)];
41
+ await import(pathToFileURL(mainPath).href);
42
+ leaseResult.lease.assertOwned();
43
+ } catch (error) {
44
+ if (!informational) {
45
+ try {
46
+ if (diagnostics?.enabled) diagnostics.write(error, 'bootstrap-failure');
47
+ else recordRuntimeExit({ homeDir: process.env.BLUN_HOME, source: 'bootstrap',
48
+ kind: 'bootstrap-failure', phase: 'startup', error });
49
+ } catch {}
50
+ }
51
+ try { diagnostics?.dispose(); } catch {}
52
+ try { await leaseResult?.lease?.release(); }
53
+ catch (leaseError) {
54
+ if (!informational) {
55
+ try {
56
+ recordRuntimeExit({ homeDir: process.env.BLUN_HOME, source: 'bootstrap',
57
+ kind: 'lease-release-failure', phase: 'cleanup', error: leaseError });
58
+ } catch {}
59
+ }
60
+ }
61
+ throw error;
62
+ }
63
+
64
+ // The bundled CLI loads package assets lazily after module evaluation. Keep
65
+ // the install lease for this process's lifetime, without keeping print/help
66
+ // commands alive solely because of the owner server.
67
+ leaseResult.lease.unref();
68
+
69
+ if (process.connected) {
70
+ try {
71
+ process.send({ type: CORE_LOADED_MESSAGE }, () => {
72
+ if (process.env.BLUN_TERMINAL_OWNER === '1') {
73
+ process.channel?.unref();
74
+ return;
75
+ }
76
+ try {
77
+ process.disconnect();
78
+ } catch {}
79
+ });
80
+ } catch {}
81
+ }
82
+ }
83
+
84
+ if (require.main === module) {
85
+ // oxlint-disable-next-line unicorn/prefer-top-level-await -- Worker entry is CommonJS.
86
+ void runCoreBootstrap().catch((error) => {
87
+ const message = error && error.message ? error.message : String(error);
88
+ fs.writeSync(process.stderr.fd, `BLUN Start fehlgeschlagen: ${message}\n`);
89
+ process.exit(1);
90
+ });
91
+ }
92
+
93
+ module.exports = { CORE_LOADED_MESSAGE, runCoreBootstrap };
@@ -1,93 +1,126 @@
1
- 'use strict';
2
-
3
- const fs = require('node:fs');
4
- const path = require('node:path');
5
-
6
- const LAUNCHER_MODES = Object.freeze({
7
- BLUN: 'blun',
8
- KING: 'king',
9
- });
10
-
11
- const LAUNCHER_HELP_TEXT = [
12
- '',
13
- 'Launchers:',
14
- ' blun Starts the CLI without automatically attaching Telegram.',
15
- ' king Starts the same CLI and automatically attaches the configured Telegram channel.',
16
- ' Both use the same version, account, model, and commands.',
17
- ' blun tools list shows optional tools; enable writes only explicit choices.',
18
- '',
19
- ].join('\n');
20
-
21
- function launcherModeFromArgv(argv) {
22
- const entry = argv[1] || '';
23
- const filename = entry.replaceAll('\\', '/').split('/').pop() || '';
24
- const command = filename.replace(/\.(?:c|m)?js$/i, '').toLowerCase();
25
- return command === LAUNCHER_MODES.KING ? LAUNCHER_MODES.KING : LAUNCHER_MODES.BLUN;
26
- }
27
-
28
- function runtimePolicyEnvironment(blunDir) {
29
- if (blunDir === undefined) return {};
30
- let policy;
31
- try {
32
- if (!path.isAbsolute(blunDir)) throw new Error('Invalid home');
33
- const file = path.join(blunDir, 'runtime-policy.json');
34
- const stat = fs.lstatSync(file);
35
- if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 4096) throw new Error('Invalid file');
36
- policy = JSON.parse(fs.readFileSync(file, 'utf8'));
37
- } catch (error) {
38
- if (error.code === 'ENOENT') return {};
39
- throw new Error('Invalid BLUN runtime policy');
40
- }
41
- const review = policy?.responseReview;
42
- if (policy?.schema !== 'blun.runtime-policy/v1'
43
- || Object.keys(policy).sort().join(',') !== 'responseReview,schema'
44
- || !review || Object.keys(review).sort().join(',') !== 'guardVersion,language,required'
45
- || review.required !== true || typeof review.language !== 'string'
46
- || !/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(review.language)
47
- || /^(auto|all)$/i.test(review.language)
48
- || typeof review.guardVersion !== 'string' || !/^\d+\.\d+\.\d+$/.test(review.guardVersion)) {
49
- throw new Error('Invalid BLUN runtime policy');
50
- }
51
- return {
52
- BLUN_LANGUAGE_GUARD_MANDATORY: '1',
53
- BLUN_LANGUAGE_GUARD_LANGUAGE: review.language,
54
- BLUN_LANGUAGE_GUARD_VERSION: review.guardVersion,
55
- BLUN_TELEGRAM_LANGUAGE_GATE: 'required',
56
- BLUN_TELEGRAM_OUTPUT_LOCALE: review.language,
57
- AGENTSPINE_STATE_DIR: path.join(blunDir, 'state', 'agent-spine'),
58
- };
59
- }
60
-
61
- function createLauncherEnvironment(sourceEnv, mode, publicPackageVersion, blunDir) {
62
- return {
63
- ...sourceEnv,
64
- ...runtimePolicyEnvironment(blunDir),
65
- BLUN_NO_AUTO_UPDATE: '1',
66
- BLUN_PUBLIC_PACKAGE_VERSION: publicPackageVersion,
67
- BLUN_TELEGRAM_ATTACH: mode === LAUNCHER_MODES.KING ? 'on' : 'off',
68
- BLUN_TELEGRAM_HEADLESS: 'off',
69
- };
70
- }
71
-
72
- function isNpmPackageUpdateRequest(args) {
73
- if (!Array.isArray(args) || args.length !== 1) return false;
74
- const command = String(args[0] || '').toLowerCase();
75
- return command === 'update' || command === 'upgrade';
76
- }
77
-
78
- function isStandaloneHelpRequest(args) {
79
- return Array.isArray(args) && args.length === 1 && (args[0] === '--help' || args[0] === '-h');
80
- }
81
-
82
- function launcherHelpText() {
83
- return LAUNCHER_HELP_TEXT;
84
- }
85
-
86
- module.exports = {
87
- LAUNCHER_MODES,
88
- createLauncherEnvironment,
89
- isNpmPackageUpdateRequest,
90
- isStandaloneHelpRequest,
91
- launcherHelpText,
92
- launcherModeFromArgv,
93
- };
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { parseArgs } = require('node:util');
6
+
7
+ const LAUNCHER_MODES = Object.freeze({
8
+ BLUN: 'blun',
9
+ KING: 'king',
10
+ });
11
+
12
+ const SETUP_INSPECTION_OPTIONS = new Set([
13
+ '--json', '--reference', '--proposal', '--validate', '--document', '--query', '--target',
14
+ ]);
15
+ const CONFIG_INSPECTION_COMMANDS = new Set(['validate', 'inspect', 'preview']);
16
+
17
+ const LAUNCHER_HELP_TEXT = [
18
+ '',
19
+ 'Launchers:',
20
+ ' blun Starts the CLI without automatically attaching Telegram.',
21
+ ' king Starts the same CLI and automatically attaches the configured Telegram channel.',
22
+ ' Both use the same version, account, model, and commands.',
23
+ ' blun tools list shows optional tools; enable writes only explicit choices.',
24
+ '',
25
+ ].join('\n');
26
+
27
+ function launcherModeFromArgv(argv) {
28
+ const entry = argv[1] || '';
29
+ const filename = entry.replaceAll('\\', '/').split('/').pop() || '';
30
+ const command = filename.replace(/\.(?:c|m)?js$/i, '').toLowerCase();
31
+ return command === LAUNCHER_MODES.KING ? LAUNCHER_MODES.KING : LAUNCHER_MODES.BLUN;
32
+ }
33
+
34
+ function runtimePolicyEnvironment(blunDir) {
35
+ if (blunDir === undefined) return {};
36
+ let policy;
37
+ try {
38
+ if (!path.isAbsolute(blunDir)) throw new Error('Invalid home');
39
+ const file = path.join(blunDir, 'runtime-policy.json');
40
+ const stat = fs.lstatSync(file);
41
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 4096) throw new Error('Invalid file');
42
+ policy = JSON.parse(fs.readFileSync(file, 'utf8'));
43
+ } catch (error) {
44
+ if (error.code === 'ENOENT') return {};
45
+ throw new Error('Invalid BLUN runtime policy');
46
+ }
47
+ const review = policy?.responseReview;
48
+ if (policy?.schema !== 'blun.runtime-policy/v1'
49
+ || Object.keys(policy).sort().join(',') !== 'responseReview,schema'
50
+ || !review || Object.keys(review).sort().join(',') !== 'guardVersion,language,required'
51
+ || review.required !== true || typeof review.language !== 'string'
52
+ || !/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(review.language)
53
+ || /^(auto|all)$/i.test(review.language)
54
+ || typeof review.guardVersion !== 'string' || !/^\d+\.\d+\.\d+$/.test(review.guardVersion)) {
55
+ throw new Error('Invalid BLUN runtime policy');
56
+ }
57
+ return {
58
+ BLUN_LANGUAGE_GUARD_MANDATORY: '1',
59
+ BLUN_LANGUAGE_GUARD_LANGUAGE: review.language,
60
+ BLUN_LANGUAGE_GUARD_VERSION: review.guardVersion,
61
+ BLUN_TELEGRAM_LANGUAGE_GATE: 'required',
62
+ BLUN_TELEGRAM_OUTPUT_LOCALE: review.language,
63
+ AGENTSPINE_STATE_DIR: path.join(blunDir, 'state', 'agent-spine'),
64
+ };
65
+ }
66
+
67
+ function createLauncherEnvironment(sourceEnv, mode, publicPackageVersion, blunDir) {
68
+ return {
69
+ ...sourceEnv,
70
+ ...runtimePolicyEnvironment(blunDir),
71
+ BLUN_NO_AUTO_UPDATE: '1',
72
+ BLUN_PUBLIC_PACKAGE_VERSION: publicPackageVersion,
73
+ BLUN_TELEGRAM_ATTACH: mode === LAUNCHER_MODES.KING ? 'on' : 'off',
74
+ BLUN_TELEGRAM_HEADLESS: 'off',
75
+ };
76
+ }
77
+
78
+ function isNpmPackageUpdateRequest(args) {
79
+ if (!Array.isArray(args) || args.length !== 1) return false;
80
+ const command = String(args[0] || '').toLowerCase();
81
+ return command === 'update' || command === 'upgrade';
82
+ }
83
+
84
+ function isStandaloneHelpRequest(args) {
85
+ return Array.isArray(args) && args.length === 1 && (args[0] === '--help' || args[0] === '-h');
86
+ }
87
+
88
+ function isReadOnlySetupRequest(args) {
89
+ return Array.isArray(args) && args[0] === 'setup'
90
+ && args.slice(1).some(value => typeof value === 'string' && SETUP_INSPECTION_OPTIONS.has(value.split('=', 1)[0]));
91
+ }
92
+
93
+ function isReadOnlyInspectionRequest(args) {
94
+ return isReadOnlySetupRequest(args)
95
+ || (Array.isArray(args) && args[0] === 'config' && CONFIG_INSPECTION_COMMANDS.has(args[1]))
96
+ || (Array.isArray(args) && args[0] === 'docs')
97
+ || isReadOnlyDoctorRequest(args);
98
+ }
99
+
100
+ function isReadOnlyDoctorRequest(args) {
101
+ if (!Array.isArray(args) || args[0] !== 'doctor') return false;
102
+ try {
103
+ const { positionals } = parseArgs({ args: args.slice(1), allowPositionals: true,
104
+ options: { json: { type: 'boolean' }, schema: { type: 'boolean' }, help: { type: 'boolean', short: 'h' } } });
105
+ if (positionals.length === 0) return true;
106
+ if (positionals[0] === 'config' || positionals[0] === 'tui') return positionals.length <= 2;
107
+ return positionals[0] === 'mcp' && positionals.length === 2;
108
+ } catch {
109
+ return false;
110
+ }
111
+ }
112
+
113
+ function launcherHelpText() {
114
+ return LAUNCHER_HELP_TEXT;
115
+ }
116
+
117
+ module.exports = {
118
+ LAUNCHER_MODES,
119
+ createLauncherEnvironment,
120
+ isNpmPackageUpdateRequest,
121
+ isStandaloneHelpRequest,
122
+ isReadOnlySetupRequest,
123
+ isReadOnlyInspectionRequest,
124
+ launcherHelpText,
125
+ launcherModeFromArgv,
126
+ };
@@ -13,6 +13,7 @@ const {
13
13
  createLauncherEnvironment,
14
14
  isNpmPackageUpdateRequest,
15
15
  isStandaloneHelpRequest,
16
+ isReadOnlyInspectionRequest,
16
17
  launcherHelpText,
17
18
  launcherModeFromArgv,
18
19
  } = require('./launcher-mode');
@@ -39,6 +40,7 @@ const {
39
40
  writePrivateFile,
40
41
  } = require('./private-paths');
41
42
 
43
+ const { writeTelegramTemplate } = require('./rename-private-staging.cjs');
42
44
  const PKG = path.resolve(__dirname, '..');
43
45
  const ARGS = process.argv.slice(2);
44
46
 
@@ -50,6 +52,34 @@ function resolveLauncherPrivatePaths(options = {}) {
50
52
  const env = options.env || process.env;
51
53
  const platform = options.platform || process.platform;
52
54
  const configuredHome = String(env.BLUN_HOME || '').trim();
55
+ const stateDir = String(env.BLUN_STATE_DIR || '').trim();
56
+ if (stateDir) {
57
+ const paths = platform === 'win32' ? path.win32 : path.posix;
58
+ if (!paths.isAbsolute(stateDir) || (platform === 'win32' && !/^[A-Za-z]:[\\/]/u.test(stateDir))) {
59
+ throw new Error('BLUN_STATE_DIR must be an absolute local path.');
60
+ }
61
+ const blunHome = paths.resolve(stateDir);
62
+ const fsImpl = options.fsImpl || fs;
63
+ let ancestor = blunHome;
64
+ for (;;) {
65
+ try {
66
+ const stat = fsImpl.lstatSync(ancestor);
67
+ const realpath = fsImpl.realpathSync.native || fsImpl.realpathSync;
68
+ const canonical = realpath(ancestor);
69
+ const normalize = platform === 'win32' ? normalizeWindowsPath : paths.normalize;
70
+ if (!stat.isDirectory() || stat.isSymbolicLink() || normalize(canonical) !== normalize(ancestor)) {
71
+ throw new Error('BLUN_STATE_DIR must not traverse a symbolic link or junction.');
72
+ }
73
+ break;
74
+ } catch (error) {
75
+ if (error.code !== 'ENOENT') throw error;
76
+ const parent = paths.dirname(ancestor);
77
+ if (parent === ancestor) throw error;
78
+ ancestor = parent;
79
+ }
80
+ }
81
+ return { blunHome, userHome: (options.homedir || os.homedir)() };
82
+ }
53
83
  if (platform !== 'win32') {
54
84
  const userHome = (options.homedir || os.homedir)();
55
85
  return {
@@ -224,7 +254,7 @@ function installTelegramForProfile(packageRoot, blunDir) {
224
254
  ensurePrivateDirectory(channelDir);
225
255
  const envFile = path.join(channelDir, '.env');
226
256
  if (!fs.existsSync(envFile)) {
227
- writePrivateFile(envFile, 'BLUN_TELEGRAM_BOT_TOKEN=HIER_DEIN_BOT_TOKEN_EINFUEGEN\n');
257
+ writeTelegramTemplate(envFile, 'BLUN_TELEGRAM_BOT_TOKEN=HIER_DEIN_BOT_TOKEN_EINFUEGEN\n');
228
258
  } else {
229
259
  securePrivateFile(envFile);
230
260
  }
@@ -369,6 +399,22 @@ async function runLauncher(options = {}) {
369
399
  return;
370
400
  }
371
401
 
402
+ if (isReadOnlyInspectionRequest(ARGS)) {
403
+ const compatibilityError = unsupportedNodeMessage(process.versions.node, process.platform);
404
+ if (compatibilityError !== null) {
405
+ process.stderr.write(`${compatibilityError}\n`);
406
+ process.exitCode = 1;
407
+ return;
408
+ }
409
+ const blunDir = resolveLauncherPrivatePaths().blunHome;
410
+ require('./verify-bundled-agent-sources.cjs').verifyBundledAgentSources(PKG);
411
+ const env = createLauncherEnvironment(process.env, LAUNCHER_MODES.BLUN, readPackageVersion(), blunDir);
412
+ env.BLUN_HOME = blunDir;
413
+ if (String(process.env.BLUN_STATE_DIR || '').trim()) env.BLUN_SHARED_HOME = blunDir;
414
+ process.exitCode = await runInformationalCore(ARGS, env, callerCwd, releaseNotice);
415
+ return;
416
+ }
417
+
372
418
  let privatePaths;
373
419
  const getPrivatePaths = () => {
374
420
  privatePaths ||= resolveLauncherPrivatePaths();
@@ -453,13 +499,31 @@ async function runLauncher(options = {}) {
453
499
  installTelegramForProfile(PKG, blunDir);
454
500
  }
455
501
 
456
- const nativeModules = repairConfiguredNativeModules({
457
- blunDir,
458
- callerCwd,
459
- onRepairStart() {
460
- process.stdout.write('BLUN richtet native Node.js-Module fuer die neue Laufzeit ein.\n');
461
- },
462
- });
502
+ const nativeOwner = new AbortController();
503
+ let nativeStopSignal;
504
+ const nativeSignals = new Map();
505
+ for (const signal of ['SIGHUP', 'SIGINT', 'SIGTERM']) {
506
+ const handler = () => { nativeStopSignal = signal; nativeOwner.abort(); };
507
+ nativeSignals.set(signal, handler);
508
+ process.once(signal, handler);
509
+ }
510
+ let nativeModules;
511
+ try {
512
+ nativeModules = await repairConfiguredNativeModules({
513
+ blunDir,
514
+ callerCwd,
515
+ signal: nativeOwner.signal,
516
+ onRepairStart() {
517
+ process.stdout.write('BLUN richtet native Node.js-Module fuer die neue Laufzeit ein.\n');
518
+ },
519
+ });
520
+ } catch (error) {
521
+ if (!nativeOwner.signal.aborted) throw error;
522
+ process.exitCode = nativeStopSignal === 'SIGINT' ? 130 : nativeStopSignal === 'SIGHUP' ? 129 : 143;
523
+ return;
524
+ } finally {
525
+ for (const [signal, handler] of nativeSignals) process.removeListener(signal, handler);
526
+ }
463
527
  if (nativeModules.repaired.length > 0) {
464
528
  process.stdout.write('Native Node.js-Module sind wieder einsatzbereit.\n');
465
529
  }
@@ -467,6 +531,7 @@ async function runLauncher(options = {}) {
467
531
  // --- 6. Start -----------------------------------------------------------
468
532
  const env = createLauncherEnvironment(process.env, mode, readPackageVersion(), blunDir);
469
533
  env.BLUN_HOME = blunDir;
534
+ if (String(process.env.BLUN_STATE_DIR || '').trim()) env.BLUN_SHARED_HOME = blunDir;
470
535
  process.exitCode = await superviseProtectedCore(
471
536
  ARGS,
472
537
  env,