blun-king-cli 9.1.624 → 9.1.625

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.
Files changed (142) hide show
  1. package/CHANGELOG.md +62 -213
  2. package/LIESMICH.txt +57 -74
  3. package/README.md +76 -119
  4. package/agent-spine-plugin/scripts/check-install.js +4 -4
  5. package/agent-spine-plugin/src/hook.js +0 -4
  6. package/agent-spine-plugin/src/lib/documents.js +1 -1
  7. package/agent-spine-plugin/src/lib/hook-context.js +0 -1
  8. package/agent-spine-plugin/src/lib/host-instruction-budget.js +2 -1
  9. package/agent-spine-plugin/src/lib/preflight.js +9 -38
  10. package/agent-spine-plugin/src/lib/source-roots.js +1 -1
  11. package/bin/agentspine-king-goal-inbox.mjs +127 -127
  12. package/bin/agentspine-king-goal-intake.mjs +106 -106
  13. package/bin/agentspine-king-host-runner.mjs +109 -109
  14. package/bin/agentspine-king-snapshot-policy.cjs +80 -80
  15. package/bin/agentspine-king-status-policy.mjs +226 -226
  16. package/bin/agentspine-king-worker-host.mjs +160 -160
  17. package/bin/core-bootstrap.js +71 -100
  18. package/bin/launcher-mode.js +93 -93
  19. package/bin/launcher-restart-policy.cjs +131 -131
  20. package/bin/launcher-runtime.js +89 -254
  21. package/bin/managed-node.js +186 -186
  22. package/bin/managed-plugin-selection.cjs +109 -116
  23. package/bin/native-module-repair.js +201 -201
  24. package/bin/node-runtime.js +34 -34
  25. package/bin/node-version.js +49 -49
  26. package/bin/plugin-bootstrap.js +149 -172
  27. package/bin/private-paths.js +1578 -1624
  28. package/bin/runtime-exit-ledger.cjs +144 -144
  29. package/bin/runtime-exit-ledger.d.cts +23 -23
  30. package/bin/standard-tools-bootstrap.js +277 -272
  31. package/bin/turn-thinking-policy.cjs +82 -82
  32. package/bin/update-copy.js +200 -200
  33. package/bin/update-lease.js +597 -599
  34. package/bin/update-notice.js +1568 -1568
  35. package/bin/verify-agent-behavior.cjs +122 -122
  36. package/bin/verify-agent-components.cjs +104 -104
  37. package/bin/verify-bundled-agent-sources.cjs +91 -96
  38. package/bin/windows-node-crash-dump.cjs +289 -289
  39. package/blun.mjs +187640 -180475
  40. package/bundled-agent-sources.json +26 -30
  41. package/codebase-index/codebase_index.py +462 -470
  42. package/dist-web/assets/{CodeBlockNode-TKKkJX8L.js → CodeBlockNode-BMbuG85x.js} +1 -1
  43. package/dist-web/assets/{CodeBlockShell.vue_vue_type_style_index_0_lang-CUj2Ds5x.js → CodeBlockShell.vue_vue_type_style_index_0_lang-C1fv7l_Z.js} +1 -1
  44. package/dist-web/assets/DesignSystemView-6HgAUEmC.css +1 -0
  45. package/dist-web/assets/DesignSystemView-CEEBqXSX.js +12 -0
  46. package/dist-web/assets/{Tooltip-CTWv7WCU.js → Tooltip--YoauJ24.js} +1 -1
  47. package/dist-web/assets/{abnfDiagram-N423BO3Z-DA8V8Zjh.js → abnfDiagram-N423BO3Z-DZvBWkRg.js} +1 -1
  48. package/dist-web/assets/{arc-YtddKbdY.js → arc-B04JATeX.js} +1 -1
  49. package/dist-web/assets/{architectureDiagram-T3A2C74G-CGEiObmo.js → architectureDiagram-T3A2C74G-DmYnMep2.js} +1 -1
  50. package/dist-web/assets/{blockDiagram-VBNYF7ZC-Bd5Vt50e.js → blockDiagram-VBNYF7ZC-DJ1gPS1C.js} +1 -1
  51. package/dist-web/assets/{c4Diagram-5PPSVZJV-D2ApPM54.js → c4Diagram-5PPSVZJV-DmjxvUbd.js} +1 -1
  52. package/dist-web/assets/channel-472fcEvw.js +1 -0
  53. package/dist-web/assets/{chunk-2GRJ4B5K-BDcIEZSl.js → chunk-2GRJ4B5K-AB0raj3I.js} +1 -1
  54. package/dist-web/assets/{chunk-2Q5K7J3B-6aSabCX7.js → chunk-2Q5K7J3B-Drf039vM.js} +1 -1
  55. package/dist-web/assets/{chunk-5RXB4S5H-BFRQvIJS.js → chunk-5RXB4S5H-D5ILttmz.js} +1 -1
  56. package/dist-web/assets/{chunk-5VM5RSS4-ChAa-DNY.js → chunk-5VM5RSS4-DrLSdi8y.js} +1 -1
  57. package/dist-web/assets/{chunk-6Q2QTUOP-BIfrb2Jc.js → chunk-6Q2QTUOP-LiaqdEOQ.js} +1 -1
  58. package/dist-web/assets/{chunk-GF5L2VYU-BR0gvtWI.js → chunk-GF5L2VYU-AIYkb--o.js} +1 -1
  59. package/dist-web/assets/{chunk-JWPE2WC7-BgXKsx5E.js → chunk-JWPE2WC7-CogdNl0i.js} +1 -1
  60. package/dist-web/assets/{chunk-KBJHAD2P-I8mrZhpz.js → chunk-KBJHAD2P-DHjpNtZv.js} +1 -1
  61. package/dist-web/assets/{chunk-RYQCIY6F-BMPaem92.js → chunk-RYQCIY6F-BUSOqH2X.js} +1 -1
  62. package/dist-web/assets/{chunk-XXDRQBXY-COy0J-0j.js → chunk-XXDRQBXY-BpoMV0bh.js} +1 -1
  63. package/dist-web/assets/classDiagram-JCYQIIEL-BTZeLngj.js +1 -0
  64. package/dist-web/assets/classDiagram-v2-OCEON4UE-BTZeLngj.js +1 -0
  65. package/dist-web/assets/{cose-bilkent-JH36ORCC-MosTTRdo.js → cose-bilkent-JH36ORCC-BJr2I61o.js} +1 -1
  66. package/dist-web/assets/{cynefin-VYW2F7L2-5tjPgrkP.js → cynefin-VYW2F7L2-HtysQZ4A.js} +1 -1
  67. package/dist-web/assets/{cynefinDiagram-MW4NZA55-CbDcdInR.js → cynefinDiagram-MW4NZA55-CcpC_2uv.js} +1 -1
  68. package/dist-web/assets/{dagre-VZM6K2ZE-YaBom1ZH.js → dagre-VZM6K2ZE-D8Ao0LUg.js} +1 -1
  69. package/dist-web/assets/{diagram-7IWD3JNH-Da4m-Hgz.js → diagram-7IWD3JNH-BITiLhjX.js} +1 -1
  70. package/dist-web/assets/{diagram-B4RE2ZJO-CAUUegxg.js → diagram-B4RE2ZJO-CJtwfy9f.js} +1 -1
  71. package/dist-web/assets/{diagram-LBJQPF4R-o21mWKG4.js → diagram-LBJQPF4R-BsVTh6w8.js} +1 -1
  72. package/dist-web/assets/{diagram-Q27KOJAE-BA3z3sXf.js → diagram-Q27KOJAE-pA_MUCUf.js} +1 -1
  73. package/dist-web/assets/{diagram-UB23O5K3-CGRdSSDK.js → diagram-UB23O5K3-CIY8z7vu.js} +1 -1
  74. package/dist-web/assets/{ebnfDiagram-BXEA7PRR-Bw-iU9FP.js → ebnfDiagram-BXEA7PRR-C3FMioqp.js} +1 -1
  75. package/dist-web/assets/{erDiagram-JOGREHBK-BwM1yiR0.js → erDiagram-JOGREHBK-CzoyKmKc.js} +1 -1
  76. package/dist-web/assets/{flowDiagram-UKHOOZJN-z05eOR1Q.js → flowDiagram-UKHOOZJN-DOqfushy.js} +1 -1
  77. package/dist-web/assets/{ganttDiagram-PKOTCBZU-BMUubNTl.js → ganttDiagram-PKOTCBZU-Cf9XQSWl.js} +1 -1
  78. package/dist-web/assets/{gitGraphDiagram-DS77QQ5N-Dccbi1wU.js → gitGraphDiagram-DS77QQ5N-DHUDofE5.js} +1 -1
  79. package/dist-web/assets/{index-h0KEOmkU.js → index-B6qEMQMx.js} +14 -14
  80. package/dist-web/assets/{index-C9eDH3u-.css → index-BmKj7CB1.css} +1 -1
  81. package/dist-web/assets/{index-BBbC5LRF.js → index-DokxDX1w.js} +1 -1
  82. package/dist-web/assets/{index-D48p0M2S.js → index-auojtiAA.js} +2 -2
  83. package/dist-web/assets/{index10-Qbuw1N6u.js → index10-Drb2n5e5.js} +1 -1
  84. package/dist-web/assets/{index11-g8v025wN.js → index11-Cx-aV4G2.js} +1 -1
  85. package/dist-web/assets/{index5-BYNcV8BY.js → index5-Dg3qGTyH.js} +1 -1
  86. package/dist-web/assets/{index6-BetANtnV.js → index6-BgvtIICP.js} +1 -1
  87. package/dist-web/assets/{index7-BcPbgCKN.js → index7-uEnniPQG.js} +1 -1
  88. package/dist-web/assets/{index8-B1lp-RvF.js → index8-h4IKc0ek.js} +2 -2
  89. package/dist-web/assets/{infoDiagram-6WML65LV-BF_pbUnN.js → infoDiagram-6WML65LV-D-3tvEiJ.js} +1 -1
  90. package/dist-web/assets/{ishikawaDiagram-WSZJBQD7-Dedv4urS.js → ishikawaDiagram-WSZJBQD7-DIIBNv7a.js} +1 -1
  91. package/dist-web/assets/{journeyDiagram-NVQOT4AX-B1Ex3b6o.js → journeyDiagram-NVQOT4AX-DP4r1Vlx.js} +1 -1
  92. package/dist-web/assets/{kanban-definition-27J2QSJJ-BtCGliBH.js → kanban-definition-27J2QSJJ-C3_Ztgxv.js} +1 -1
  93. package/dist-web/assets/{linear-ByItc8Qr.js → linear-DnqhIw-y.js} +1 -1
  94. package/dist-web/assets/{mermaid.core-B1M2O7nN.js → mermaid.core-xYUgBa3T.js} +4 -4
  95. package/dist-web/assets/{mindmap-definition-FAOFIHXS-D0UHKUyj.js → mindmap-definition-FAOFIHXS-l-dq-zfr.js} +1 -1
  96. package/dist-web/assets/{pegDiagram-VL7TDLO6-D7zYCVmG.js → pegDiagram-VL7TDLO6-C8vXQiaJ.js} +1 -1
  97. package/dist-web/assets/{pieDiagram-7S7Q4E2Y-Bd0i9CHa.js → pieDiagram-7S7Q4E2Y-CyNRSsI6.js} +1 -1
  98. package/dist-web/assets/{quadrantDiagram-CIZ2JOQS-MG-Ug47d.js → quadrantDiagram-CIZ2JOQS-D-w8AD_g.js} +1 -1
  99. package/dist-web/assets/{railroadDiagram-AXF67PYL-AZdl90Gj.js → railroadDiagram-AXF67PYL-BLkyQCWy.js} +1 -1
  100. package/dist-web/assets/{requirementDiagram-LRYGKXZP-DjplF9kt.js → requirementDiagram-LRYGKXZP-CEWO7XfT.js} +1 -1
  101. package/dist-web/assets/{sankeyDiagram-W5VNT64P-Bi9Zgfjs.js → sankeyDiagram-W5VNT64P-ByGoAaGj.js} +1 -1
  102. package/dist-web/assets/{sequenceDiagram-SI44F4Z6-ChEpdCvb.js → sequenceDiagram-SI44F4Z6-Bhn9GQtd.js} +1 -1
  103. package/dist-web/assets/{sizeCapture-X5ZJPWSS-B5RFUdaa.js → sizeCapture-X5ZJPWSS-jVKR9CTu.js} +1 -1
  104. package/dist-web/assets/{stateDiagram-OKZ733FA-BkRblSKp.js → stateDiagram-OKZ733FA-wW3XbegA.js} +1 -1
  105. package/dist-web/assets/stateDiagram-v2-UEYNNEHI-B8aids-Z.js +1 -0
  106. package/dist-web/assets/{swimlanes-SLNWSIFB-DLXH6Zhc.js → swimlanes-SLNWSIFB-B8QyFS7G.js} +2 -2
  107. package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-B8XAkdSm.js +8 -0
  108. package/dist-web/assets/{timeline-definition-Z64GVDOM-C_N88siO.js → timeline-definition-Z64GVDOM-DpvxS-1A.js} +1 -1
  109. package/dist-web/assets/{vennDiagram-T6HMQDX7-DMsnvDt0.js → vennDiagram-T6HMQDX7-BzGM0ihY.js} +1 -1
  110. package/dist-web/assets/{vue.runtime.esm-bundler-B-3uIy85.js → vue.runtime.esm-bundler-BOcpwIX1.js} +1 -1
  111. package/dist-web/assets/{wardleyDiagram-T6FBY63Y-C9SJIPzq.js → wardleyDiagram-T6FBY63Y-2DKAOs5e.js} +1 -1
  112. package/dist-web/assets/{xychartDiagram-ELKLHX3M-DZLWA6Go.js → xychartDiagram-ELKLHX3M-B0SP0TXd.js} +1 -1
  113. package/dist-web/index.html +32 -32
  114. package/dist-web/vis/index.html.gz +0 -0
  115. package/package.json +1 -1
  116. package/scripts/fix-node-pty-perms.js +53 -53
  117. package/standard-skills/blun-app-design-system/SKILL.md +30 -30
  118. package/standard-skills/blun-app-design-system/provenance.json +17 -17
  119. package/standard-skills/blun-app-design-system/references/tokens.md +48 -48
  120. package/standard-skills/blun-app-design-system/scripts/check-blun-design.mjs +49 -49
  121. package/standard-skills/translate-native/README.md +1 -1
  122. package/standard-skills/translate-native/scripts/blun_language_guard.py +2 -0
  123. package/standard-skills/translate-native/scripts/language_gateway.py +2 -0
  124. package/standard-skills/translate-native/scripts/pre_output_guard.py +2 -0
  125. package/standard-tools/language-guard/blun_language_guard.py +2 -0
  126. package/standard-tools/language-guard/language_gateway.py +2 -0
  127. package/standard-tools/language-guard/pre_output_guard.py +2 -0
  128. package/telegram-plugin/blun.plugin.json +20 -20
  129. package/telegram-plugin/commands/access.md +37 -37
  130. package/telegram-plugin/dist/bridge.mjs +310 -187
  131. package/telegram-plugin/dist/mcp-server.mjs +174 -261
  132. package/telegram-plugin/dist/noise.mjs +1 -19
  133. package/worker-host.mjs +13747 -16824
  134. package/bin/profile-handoff.cjs +0 -152
  135. package/bin/profile-launch.cjs +0 -120
  136. package/dist-web/assets/DesignSystemView-DwK1aQMo.js +0 -12
  137. package/dist-web/assets/DesignSystemView-szjTj7ns.css +0 -1
  138. package/dist-web/assets/channel-BnluexuN.js +0 -1
  139. package/dist-web/assets/classDiagram-JCYQIIEL-BliFdSD9.js +0 -1
  140. package/dist-web/assets/classDiagram-v2-OCEON4UE-BliFdSD9.js +0 -1
  141. package/dist-web/assets/stateDiagram-v2-UEYNNEHI-fVkQcACW.js +0 -1
  142. package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-Bg-BiZJQ.js +0 -8
@@ -1,599 +1,597 @@
1
- 'use strict';
2
-
3
- const { createHash } = require('node:crypto');
4
- const fs = require('node:fs');
5
- const net = require('node:net');
6
- const os = require('node:os');
7
- const path = require('node:path');
8
- const { spawn } = require('node:child_process');
9
-
10
- const LEASE_ADOPT_MESSAGE = 'blun-update-lease-adopted';
11
- const LEASE_CANCEL_MESSAGE = 'blun-update-lease-cancel';
12
- const LEASE_COMMIT_MESSAGE = 'blun-update-lease-commit';
13
- const LEASE_HANDOFF_MESSAGE = 'blun-update-lease-handoff';
14
- const LEASE_BUSY_MESSAGE = 'blun-update-lease-busy';
15
- const LEASE_UNAVAILABLE_MESSAGE = 'blun-update-lease-unavailable';
16
- const LEASE_PROTOCOL_VERSION = 'BLUN_UPDATE_LEASE_V3';
17
- const LEASE_PROBE_TIMEOUT_MS = 500;
18
- const MAX_POSIX_SOCKET_PATH_BYTES = 96;
19
- const LEASE_CONNECTIONS = Symbol('blunLeaseConnections');
20
-
21
- function canonicalPackageIdentity(packageRoot, options = {}) {
22
- if (typeof packageRoot !== 'string' || packageRoot.trim().length === 0) {
23
- throw new Error('UPDATE_PACKAGE_ROOT_REQUIRED');
24
- }
25
- const fsImpl = options.fsImpl || fs;
26
- const platform = options.platform || process.platform;
27
- const realpath = fsImpl.realpathSync.native || fsImpl.realpathSync;
28
- let canonical = realpath(path.resolve(packageRoot));
29
- if (!fsImpl.statSync(canonical).isDirectory()) throw new Error('INVALID_UPDATE_PACKAGE_ROOT');
30
- canonical = canonical.replaceAll('\\', '/');
31
- if (platform === 'win32') canonical = canonical.toLowerCase();
32
- return canonical;
33
- }
34
-
35
- function deriveUpdateLeaseEndpoint(packageRoot, options = {}) {
36
- const platform = options.platform || process.platform;
37
- const role = options.role === 'profile'
38
- ? 'profile'
39
- : options.role === 'install'
40
- ? 'install'
41
- : options.role === 'runtime'
42
- ? 'runtime'
43
- : 'notice';
44
- const identity = canonicalPackageIdentity(packageRoot, options);
45
- const digest = createHash('sha256')
46
- .update(`blun-update-v3\0${role}\0${identity}`)
47
- .digest('hex');
48
- const magic = `${LEASE_PROTOCOL_VERSION} ${digest}\n`;
49
- if (platform === 'win32') {
50
- return Object.freeze({
51
- magic,
52
- path: `\\\\.\\pipe\\blun-update-v3-${digest.slice(0, 32)}`,
53
- platform,
54
- });
55
- }
56
-
57
- const uid = options.uid ?? (typeof process.getuid === 'function' ? process.getuid() : undefined);
58
- const directoryName = `blun-update-${uid ?? digest.slice(0, 12)}`;
59
- const requestedRoot = String(options.socketDirectory || options.tempDir || os.tmpdir())
60
- .replaceAll('\\', '/');
61
- let directory = options.socketDirectory
62
- ? requestedRoot
63
- : path.posix.join(requestedRoot, directoryName);
64
- let socketPath = path.posix.join(directory, `lease-${digest.slice(0, 24)}.sock`);
65
- if (Buffer.byteLength(socketPath, 'utf8') > MAX_POSIX_SOCKET_PATH_BYTES) {
66
- directory = path.posix.join('/tmp', directoryName);
67
- socketPath = path.posix.join(directory, `lease-${digest.slice(0, 24)}.sock`);
68
- }
69
- if (Buffer.byteLength(socketPath, 'utf8') > MAX_POSIX_SOCKET_PATH_BYTES) {
70
- throw new Error('UPDATE_LEASE_SOCKET_PATH_TOO_LONG');
71
- }
72
- return Object.freeze({ directory, magic, path: socketPath, platform });
73
- }
74
-
75
- function connectRuntimeBroker(endpoint, options = {}) {
76
- const netImpl = options.netImpl || net;
77
- const timeoutMs = options.probeTimeoutMs || LEASE_PROBE_TIMEOUT_MS;
78
- return new Promise((resolve) => {
79
- let settled = false;
80
- let received = '';
81
- let socket;
82
- const finish = (result) => {
83
- if (settled) return;
84
- settled = true;
85
- clearTimeout(timer);
86
- if (!result.acquired) {
87
- try {
88
- socket?.destroy();
89
- } catch {}
90
- }
91
- resolve(result);
92
- };
93
- const timer = setTimeout(() => finish({ acquired: false, reason: 'unavailable' }), timeoutMs);
94
- timer.unref?.();
95
- try {
96
- socket = netImpl.createConnection({ path: endpoint.path });
97
- socket.setEncoding?.('utf8');
98
- socket.once('connect', () => socket.write(endpoint.magic));
99
- socket.on('data', (chunk) => {
100
- received += String(chunk);
101
- if (!received.includes('\n')) return;
102
- if (received !== endpoint.magic) {
103
- finish({ acquired: false, reason: 'unavailable' });
104
- return;
105
- }
106
- let owned = true;
107
- let released = false;
108
- socket.once('close', () => { owned = false; });
109
- socket.once('error', () => { owned = false; });
110
- const lease = Object.freeze({
111
- assertOwned() {
112
- if (!owned || socket.destroyed) throw new Error('RUNTIME_LEASE_LOST');
113
- },
114
- async release() {
115
- if (released) return;
116
- released = true;
117
- owned = false;
118
- if (socket.destroyed) return;
119
- socket.destroy();
120
- },
121
- unref() {
122
- socket.unref?.();
123
- },
124
- });
125
- finish({ acquired: true, lease });
126
- });
127
- socket.once('error', () => finish({ acquired: false, reason: 'unavailable' }));
128
- socket.once('close', () => finish({ acquired: false, reason: 'unavailable' }));
129
- } catch {
130
- finish({ acquired: false, reason: 'unavailable' });
131
- }
132
- });
133
- }
134
-
135
- function spawnRuntimeBroker(packageRoot, options = {}) {
136
- const spawnImpl = options.spawnImpl || spawn;
137
- const child = spawnImpl(
138
- options.execPath || process.execPath,
139
- [__filename, '--runtime-broker'],
140
- {
141
- cwd: os.tmpdir(),
142
- detached: true,
143
- env: {
144
- ...process.env,
145
- BLUN_RUNTIME_BROKER_PACKAGE_ROOT: packageRoot,
146
- },
147
- stdio: 'ignore',
148
- windowsHide: true,
149
- },
150
- );
151
- child.unref?.();
152
- }
153
-
154
- async function acquireSharedRuntimeLease(options = {}) {
155
- const packageRoot = canonicalPackageIdentity(options.packageRoot, options);
156
- const endpoint = deriveUpdateLeaseEndpoint(packageRoot, { ...options, role: 'runtime' });
157
- const deadline = Date.now() + (options.startTimeoutMs || 3_000);
158
- let spawned = false;
159
- while (Date.now() < deadline) {
160
- const connected = await connectRuntimeBroker(endpoint, options);
161
- if (connected.acquired) return connected;
162
- if (!spawned) {
163
- spawned = true;
164
- spawnRuntimeBroker(packageRoot, options);
165
- }
166
- await new Promise((resolve) => setTimeout(resolve, 25));
167
- }
168
- const install = await tryAcquireUpdateLease({ ...options, packageRoot, role: 'install' });
169
- if (install.acquired) {
170
- await install.lease.release();
171
- return { acquired: false, reason: 'unavailable' };
172
- }
173
- return { acquired: false, reason: install.reason };
174
- }
175
-
176
- async function runRuntimeBroker(options = {}) {
177
- const packageRoot = options.packageRoot
178
- || String(process.env.BLUN_RUNTIME_BROKER_PACKAGE_ROOT || '');
179
- if (!path.isAbsolute(packageRoot)) throw new Error('RUNTIME_BROKER_PACKAGE_ROOT_REQUIRED');
180
- const install = await tryAcquireUpdateLease({ packageRoot, role: 'install' });
181
- if (!install.acquired) return false;
182
-
183
- const endpoint = deriveUpdateLeaseEndpoint(packageRoot, { role: 'runtime' });
184
- ensurePrivateSocketDirectory(endpoint);
185
- const holders = new Set();
186
- let idleTimer;
187
- let closing = false;
188
- let identity;
189
- const closeBroker = async (server) => {
190
- if (closing) return;
191
- closing = true;
192
- clearTimeout(idleTimer);
193
- await closeServer(server);
194
- removeOwnedSocket(endpoint, identity);
195
- await install.lease.release();
196
- };
197
- const server = net.createServer((socket) => {
198
- socket.setEncoding('utf8');
199
- let received = '';
200
- let admitted = false;
201
- const reject = () => {
202
- try {
203
- socket.destroy();
204
- } catch {}
205
- };
206
- const onData = (chunk) => {
207
- if (admitted) return;
208
- received += String(chunk);
209
- if (Buffer.byteLength(received, 'utf8') > Buffer.byteLength(endpoint.magic, 'utf8')) {
210
- reject();
211
- return;
212
- }
213
- if (!received.includes('\n')) return;
214
- if (received !== endpoint.magic) {
215
- reject();
216
- return;
217
- }
218
- admitted = true;
219
- clearTimeout(idleTimer);
220
- holders.add(socket);
221
- socket.write(endpoint.magic);
222
- };
223
- socket.on('data', onData);
224
- socket.on('error', () => {});
225
- socket.once('close', () => {
226
- holders.delete(socket);
227
- if (holders.size === 0 && !closing) {
228
- idleTimer = setTimeout(() => { void closeBroker(server); }, 0);
229
- }
230
- });
231
- });
232
- try {
233
- await new Promise((resolve, reject) => {
234
- const onError = (error) => {
235
- server.removeListener('error', onError);
236
- reject(error);
237
- };
238
- server.once('error', onError);
239
- server.listen({ path: endpoint.path, exclusive: true }, () => {
240
- server.removeListener('error', onError);
241
- resolve();
242
- });
243
- });
244
- identity = recordSocketIdentity(endpoint);
245
- } catch {
246
- await closeServer(server);
247
- await install.lease.release();
248
- return false;
249
- }
250
- install.lease.unref();
251
- server.unref?.();
252
- idleTimer = setTimeout(() => { void closeBroker(server); }, 5_000);
253
- return true;
254
- }
255
-
256
- function closeServer(server) {
257
- for (const socket of server[LEASE_CONNECTIONS] || []) {
258
- try {
259
- socket.destroy();
260
- } catch {}
261
- }
262
- if (!server.listening) return Promise.resolve();
263
- try {
264
- server.close();
265
- server.unref?.();
266
- } catch {}
267
- return Promise.resolve();
268
- }
269
-
270
- function ensurePrivateSocketDirectory(endpoint, options = {}) {
271
- if (endpoint.platform === 'win32') return;
272
- const fsImpl = options.fsImpl || fs;
273
- fsImpl.mkdirSync(endpoint.directory, { recursive: true, mode: 0o700 });
274
- const stat = fsImpl.lstatSync(endpoint.directory);
275
- if (!stat.isDirectory() || stat.isSymbolicLink()) {
276
- throw new Error('INVALID_UPDATE_LEASE_DIRECTORY');
277
- }
278
- if (typeof process.getuid === 'function'
279
- && Number.isInteger(stat.uid)
280
- && stat.uid !== process.getuid()) {
281
- throw new Error('INVALID_UPDATE_LEASE_DIRECTORY_OWNER');
282
- }
283
- fsImpl.chmodSync(endpoint.directory, 0o700);
284
- }
285
-
286
- function listenForLease(endpoint, options = {}) {
287
- const netImpl = options.netImpl || net;
288
- return new Promise((resolve, reject) => {
289
- const server = netImpl.createServer((socket) => {
290
- server[LEASE_CONNECTIONS].add(socket);
291
- socket.once('close', () => server[LEASE_CONNECTIONS].delete(socket));
292
- socket.on('error', () => {});
293
- socket.end(endpoint.magic);
294
- });
295
- server[LEASE_CONNECTIONS] = new Set();
296
- const onError = (error) => {
297
- server.removeListener('error', onError);
298
- reject(error);
299
- };
300
- server.once('error', onError);
301
- server.listen({ path: endpoint.path, exclusive: true }, () => {
302
- server.removeListener('error', onError);
303
- resolve(server);
304
- });
305
- });
306
- }
307
-
308
- function probeExistingLease(endpoint, options = {}) {
309
- const netImpl = options.netImpl || net;
310
- const timeoutMs = options.probeTimeoutMs || LEASE_PROBE_TIMEOUT_MS;
311
- return new Promise((resolve) => {
312
- let settled = false;
313
- let received = '';
314
- let socket;
315
- const finish = (state, error) => {
316
- if (settled) return;
317
- settled = true;
318
- clearTimeout(timer);
319
- try {
320
- socket?.destroy();
321
- } catch {}
322
- // oxlint-disable-next-line promise/no-multiple-resolved -- settled is the idempotence guard.
323
- resolve({ error, state });
324
- };
325
- const timer = setTimeout(() => finish('foreign'), timeoutMs);
326
- timer.unref?.();
327
- try {
328
- socket = netImpl.createConnection({ path: endpoint.path });
329
- socket.setEncoding?.('utf8');
330
- socket.on('data', (chunk) => {
331
- received += String(chunk);
332
- if (Buffer.byteLength(received, 'utf8') > Buffer.byteLength(endpoint.magic, 'utf8')) {
333
- finish('foreign');
334
- }
335
- });
336
- socket.once('end', () => finish(received === endpoint.magic ? 'owner' : 'foreign'));
337
- socket.once('error', (error) => {
338
- const stale = error?.code === 'ECONNREFUSED' || error?.code === 'ENOENT';
339
- finish(stale ? 'stale' : 'foreign', error);
340
- });
341
- socket.once('close', () => {
342
- if (!settled) finish(received === endpoint.magic ? 'owner' : 'foreign');
343
- });
344
- } catch (error) {
345
- const stale = error?.code === 'ECONNREFUSED' || error?.code === 'ENOENT';
346
- finish(stale ? 'stale' : 'foreign', error);
347
- }
348
- });
349
- }
350
-
351
- function observeSocketPath(endpoint, options = {}) {
352
- if (endpoint.platform === 'win32') return { state: 'not_applicable' };
353
- const fsImpl = options.fsImpl || fs;
354
- try {
355
- const stat = fsImpl.lstatSync(endpoint.path);
356
- if (!stat.isSocket() || stat.isSymbolicLink()) return { state: 'unsafe' };
357
- return { dev: stat.dev, ino: stat.ino, state: 'socket' };
358
- } catch (error) {
359
- return error?.code === 'ENOENT' ? { state: 'missing' } : { state: 'unsafe' };
360
- }
361
- }
362
-
363
- function removeObservedStaleSocket(endpoint, observed, options = {}) {
364
- if (endpoint.platform === 'win32') return false;
365
- const fsImpl = options.fsImpl || fs;
366
- try {
367
- const stat = fsImpl.lstatSync(endpoint.path);
368
- if (observed.state !== 'socket'
369
- || !stat.isSocket()
370
- || stat.isSymbolicLink()
371
- || stat.dev !== observed.dev
372
- || stat.ino !== observed.ino) {
373
- return false;
374
- }
375
- fsImpl.unlinkSync(endpoint.path);
376
- return true;
377
- } catch (error) {
378
- return error?.code === 'ENOENT' && observed.state === 'missing';
379
- }
380
- }
381
-
382
- function recordSocketIdentity(endpoint, options = {}) {
383
- if (endpoint.platform === 'win32') return undefined;
384
- const fsImpl = options.fsImpl || fs;
385
- const stat = fsImpl.lstatSync(endpoint.path);
386
- if (!stat.isSocket() || stat.isSymbolicLink()) throw new Error('INVALID_UPDATE_LEASE_SOCKET');
387
- fsImpl.chmodSync(endpoint.path, 0o600);
388
- return { dev: stat.dev, ino: stat.ino };
389
- }
390
-
391
- function removeOwnedSocket(endpoint, identity, options = {}) {
392
- if (endpoint.platform === 'win32' || !identity) return;
393
- const fsImpl = options.fsImpl || fs;
394
- try {
395
- const stat = fsImpl.lstatSync(endpoint.path);
396
- if (stat.isSocket()
397
- && !stat.isSymbolicLink()
398
- && stat.dev === identity.dev
399
- && stat.ino === identity.ino) {
400
- fsImpl.unlinkSync(endpoint.path);
401
- }
402
- } catch {}
403
- }
404
-
405
- async function tryAcquireUpdateLease(options = {}) {
406
- let endpoint;
407
- try {
408
- endpoint = deriveUpdateLeaseEndpoint(options.packageRoot, options);
409
- ensurePrivateSocketDirectory(endpoint, options);
410
- } catch {
411
- return { acquired: false, reason: 'unavailable' };
412
- }
413
-
414
- let server;
415
- for (let attempt = 0; attempt < 2; attempt += 1) {
416
- try {
417
- server = await listenForLease(endpoint, options);
418
- break;
419
- } catch (error) {
420
- if (error?.code !== 'EADDRINUSE') {
421
- return { acquired: false, reason: 'unavailable' };
422
- }
423
- const observed = observeSocketPath(endpoint, options);
424
- const probe = await probeExistingLease(endpoint, options);
425
- if (probe.state === 'owner') return { acquired: false, reason: 'busy' };
426
- if (probe.state !== 'stale' || attempt > 0) {
427
- return { acquired: false, reason: 'unavailable' };
428
- }
429
- if (endpoint.platform === 'win32') continue;
430
- if (!removeObservedStaleSocket(endpoint, observed, options)) {
431
- return { acquired: false, reason: 'unavailable' };
432
- }
433
- }
434
- }
435
- if (!server) return { acquired: false, reason: 'unavailable' };
436
-
437
- let identity;
438
- try {
439
- identity = recordSocketIdentity(endpoint, options);
440
- } catch {
441
- await closeServer(server);
442
- removeOwnedSocket(endpoint, identity, options);
443
- return { acquired: false, reason: 'unavailable' };
444
- }
445
-
446
- let owned = true;
447
- let released = false;
448
- server.on('error', () => {
449
- owned = false;
450
- });
451
- server.on('close', () => {
452
- owned = false;
453
- });
454
- const lease = Object.freeze({
455
- assertOwned() {
456
- if (!owned || !server.listening) throw new Error('UPDATE_LEASE_LOST');
457
- },
458
- async release() {
459
- if (released) return;
460
- released = true;
461
- owned = false;
462
- await closeServer(server);
463
- removeOwnedSocket(endpoint, identity, options);
464
- },
465
- unref() {
466
- server.unref?.();
467
- },
468
- });
469
- return { acquired: true, lease };
470
- }
471
-
472
- function isInstallerMessage(message) {
473
- if (!message || message.type !== LEASE_HANDOFF_MESSAGE) return false;
474
- const installer = message.installer;
475
- return installer
476
- && typeof installer === 'object'
477
- && typeof message.packageRoot === 'string'
478
- && path.isAbsolute(message.packageRoot)
479
- && typeof installer.npmCliPath === 'string'
480
- && path.isAbsolute(installer.npmCliPath)
481
- && Array.isArray(installer.npmArgs)
482
- && installer.npmArgs.every((entry) => typeof entry === 'string')
483
- && typeof installer.installCwd === 'string'
484
- && path.isAbsolute(installer.installCwd);
485
- }
486
-
487
- function runInstallerWorker() {
488
- let state = 'BOOT';
489
- let started = false;
490
- let installLease;
491
- let installCwd;
492
- const isControlMessage = (message, type) => message
493
- && typeof message === 'object'
494
- && Object.getPrototypeOf(message) === Object.prototype
495
- && Reflect.ownKeys(message).length === 1
496
- && message.type === type;
497
- const exitWithoutInstall = async (code = 0) => {
498
- if (state === 'DONE') return;
499
- state = 'DONE';
500
- try {
501
- await installLease?.release();
502
- } catch {}
503
- process.exit(code);
504
- };
505
- const startInstaller = (installer) => {
506
- if (started || state !== 'COMMITTED') return;
507
- started = true;
508
- try {
509
- installLease.assertOwned();
510
- process.chdir(installer.installCwd);
511
- process.argv = [process.execPath, installer.npmCliPath, ...installer.npmArgs];
512
- require(installer.npmCliPath);
513
- } catch {
514
- process.exit(1);
515
- }
516
- };
517
-
518
- process.once('message', async (message) => {
519
- if (state !== 'BOOT' || !isInstallerMessage(message)) {
520
- process.exit(1);
521
- return;
522
- }
523
- state = 'PREPARED';
524
- installCwd = message.installer.installCwd;
525
- process.once('exit', () => {
526
- if (!installCwd) return;
527
- try {
528
- process.chdir(path.dirname(installCwd));
529
- fs.rmSync(installCwd, { recursive: true, force: true });
530
- } catch {}
531
- });
532
- const leaseResult = await tryAcquireUpdateLease({
533
- packageRoot: message.packageRoot,
534
- role: 'install',
535
- });
536
- if (!leaseResult.acquired) {
537
- const type = leaseResult.reason === 'busy'
538
- ? LEASE_BUSY_MESSAGE
539
- : LEASE_UNAVAILABLE_MESSAGE;
540
- if (process.connected) {
541
- try {
542
- process.send({ type }, () => process.exit(75));
543
- return;
544
- } catch {}
545
- }
546
- process.exit(75);
547
- return;
548
- }
549
- installLease = leaseResult.lease;
550
- state = 'LEASED';
551
- if (!process.connected) {
552
- await exitWithoutInstall();
553
- return;
554
- }
555
- const onControl = (control) => {
556
- if (state !== 'LEASED') {
557
- void exitWithoutInstall(1);
558
- return;
559
- }
560
- if (isControlMessage(control, LEASE_CANCEL_MESSAGE)) {
561
- void exitWithoutInstall();
562
- return;
563
- }
564
- if (!isControlMessage(control, LEASE_COMMIT_MESSAGE)) {
565
- void exitWithoutInstall(1);
566
- return;
567
- }
568
- state = 'COMMITTED';
569
- setImmediate(() => startInstaller(message.installer));
570
- };
571
- process.once('message', onControl);
572
- try {
573
- process.send({ type: LEASE_ADOPT_MESSAGE });
574
- } catch {
575
- process.removeListener('message', onControl);
576
- await exitWithoutInstall();
577
- }
578
- });
579
- process.once('disconnect', () => {
580
- if (state !== 'COMMITTED' && state !== 'DONE') void exitWithoutInstall();
581
- });
582
- }
583
-
584
- if (require.main === module && process.argv[2] === '--installer-worker') {
585
- runInstallerWorker();
586
- } else if (require.main === module && process.argv[2] === '--runtime-broker') {
587
- void runRuntimeBroker().then((started) => {
588
- if (!started) process.exitCode = 75;
589
- }).catch(() => {
590
- process.exitCode = 1;
591
- });
592
- }
593
-
594
- module.exports = {
595
- acquireSharedRuntimeLease,
596
- deriveUpdateLeaseEndpoint,
597
- runRuntimeBroker,
598
- tryAcquireUpdateLease,
599
- };
1
+ 'use strict';
2
+
3
+ const { createHash } = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const net = require('node:net');
6
+ const os = require('node:os');
7
+ const path = require('node:path');
8
+ const { spawn } = require('node:child_process');
9
+
10
+ const LEASE_ADOPT_MESSAGE = 'blun-update-lease-adopted';
11
+ const LEASE_CANCEL_MESSAGE = 'blun-update-lease-cancel';
12
+ const LEASE_COMMIT_MESSAGE = 'blun-update-lease-commit';
13
+ const LEASE_HANDOFF_MESSAGE = 'blun-update-lease-handoff';
14
+ const LEASE_BUSY_MESSAGE = 'blun-update-lease-busy';
15
+ const LEASE_UNAVAILABLE_MESSAGE = 'blun-update-lease-unavailable';
16
+ const LEASE_PROTOCOL_VERSION = 'BLUN_UPDATE_LEASE_V3';
17
+ const LEASE_PROBE_TIMEOUT_MS = 500;
18
+ const MAX_POSIX_SOCKET_PATH_BYTES = 96;
19
+ const LEASE_CONNECTIONS = Symbol('blunLeaseConnections');
20
+
21
+ function canonicalPackageIdentity(packageRoot, options = {}) {
22
+ if (typeof packageRoot !== 'string' || packageRoot.trim().length === 0) {
23
+ throw new Error('UPDATE_PACKAGE_ROOT_REQUIRED');
24
+ }
25
+ const fsImpl = options.fsImpl || fs;
26
+ const platform = options.platform || process.platform;
27
+ const realpath = fsImpl.realpathSync.native || fsImpl.realpathSync;
28
+ let canonical = realpath(path.resolve(packageRoot));
29
+ if (!fsImpl.statSync(canonical).isDirectory()) throw new Error('INVALID_UPDATE_PACKAGE_ROOT');
30
+ canonical = canonical.replaceAll('\\', '/');
31
+ if (platform === 'win32') canonical = canonical.toLowerCase();
32
+ return canonical;
33
+ }
34
+
35
+ function deriveUpdateLeaseEndpoint(packageRoot, options = {}) {
36
+ const platform = options.platform || process.platform;
37
+ const role = options.role === 'install'
38
+ ? 'install'
39
+ : options.role === 'runtime'
40
+ ? 'runtime'
41
+ : 'notice';
42
+ const identity = canonicalPackageIdentity(packageRoot, options);
43
+ const digest = createHash('sha256')
44
+ .update(`blun-update-v3\0${role}\0${identity}`)
45
+ .digest('hex');
46
+ const magic = `${LEASE_PROTOCOL_VERSION} ${digest}\n`;
47
+ if (platform === 'win32') {
48
+ return Object.freeze({
49
+ magic,
50
+ path: `\\\\.\\pipe\\blun-update-v3-${digest.slice(0, 32)}`,
51
+ platform,
52
+ });
53
+ }
54
+
55
+ const uid = options.uid ?? (typeof process.getuid === 'function' ? process.getuid() : undefined);
56
+ const directoryName = `blun-update-${uid ?? digest.slice(0, 12)}`;
57
+ const requestedRoot = String(options.socketDirectory || options.tempDir || os.tmpdir())
58
+ .replaceAll('\\', '/');
59
+ let directory = options.socketDirectory
60
+ ? requestedRoot
61
+ : path.posix.join(requestedRoot, directoryName);
62
+ let socketPath = path.posix.join(directory, `lease-${digest.slice(0, 24)}.sock`);
63
+ if (Buffer.byteLength(socketPath, 'utf8') > MAX_POSIX_SOCKET_PATH_BYTES) {
64
+ directory = path.posix.join('/tmp', directoryName);
65
+ socketPath = path.posix.join(directory, `lease-${digest.slice(0, 24)}.sock`);
66
+ }
67
+ if (Buffer.byteLength(socketPath, 'utf8') > MAX_POSIX_SOCKET_PATH_BYTES) {
68
+ throw new Error('UPDATE_LEASE_SOCKET_PATH_TOO_LONG');
69
+ }
70
+ return Object.freeze({ directory, magic, path: socketPath, platform });
71
+ }
72
+
73
+ function connectRuntimeBroker(endpoint, options = {}) {
74
+ const netImpl = options.netImpl || net;
75
+ const timeoutMs = options.probeTimeoutMs || LEASE_PROBE_TIMEOUT_MS;
76
+ return new Promise((resolve) => {
77
+ let settled = false;
78
+ let received = '';
79
+ let socket;
80
+ const finish = (result) => {
81
+ if (settled) return;
82
+ settled = true;
83
+ clearTimeout(timer);
84
+ if (!result.acquired) {
85
+ try {
86
+ socket?.destroy();
87
+ } catch {}
88
+ }
89
+ resolve(result);
90
+ };
91
+ const timer = setTimeout(() => finish({ acquired: false, reason: 'unavailable' }), timeoutMs);
92
+ timer.unref?.();
93
+ try {
94
+ socket = netImpl.createConnection({ path: endpoint.path });
95
+ socket.setEncoding?.('utf8');
96
+ socket.once('connect', () => socket.write(endpoint.magic));
97
+ socket.on('data', (chunk) => {
98
+ received += String(chunk);
99
+ if (!received.includes('\n')) return;
100
+ if (received !== endpoint.magic) {
101
+ finish({ acquired: false, reason: 'unavailable' });
102
+ return;
103
+ }
104
+ let owned = true;
105
+ let released = false;
106
+ socket.once('close', () => { owned = false; });
107
+ socket.once('error', () => { owned = false; });
108
+ const lease = Object.freeze({
109
+ assertOwned() {
110
+ if (!owned || socket.destroyed) throw new Error('RUNTIME_LEASE_LOST');
111
+ },
112
+ async release() {
113
+ if (released) return;
114
+ released = true;
115
+ owned = false;
116
+ if (socket.destroyed) return;
117
+ socket.destroy();
118
+ },
119
+ unref() {
120
+ socket.unref?.();
121
+ },
122
+ });
123
+ finish({ acquired: true, lease });
124
+ });
125
+ socket.once('error', () => finish({ acquired: false, reason: 'unavailable' }));
126
+ socket.once('close', () => finish({ acquired: false, reason: 'unavailable' }));
127
+ } catch {
128
+ finish({ acquired: false, reason: 'unavailable' });
129
+ }
130
+ });
131
+ }
132
+
133
+ function spawnRuntimeBroker(packageRoot, options = {}) {
134
+ const spawnImpl = options.spawnImpl || spawn;
135
+ const child = spawnImpl(
136
+ options.execPath || process.execPath,
137
+ [__filename, '--runtime-broker'],
138
+ {
139
+ cwd: os.tmpdir(),
140
+ detached: true,
141
+ env: {
142
+ ...process.env,
143
+ BLUN_RUNTIME_BROKER_PACKAGE_ROOT: packageRoot,
144
+ },
145
+ stdio: 'ignore',
146
+ windowsHide: true,
147
+ },
148
+ );
149
+ child.unref?.();
150
+ }
151
+
152
+ async function acquireSharedRuntimeLease(options = {}) {
153
+ const packageRoot = canonicalPackageIdentity(options.packageRoot, options);
154
+ const endpoint = deriveUpdateLeaseEndpoint(packageRoot, { ...options, role: 'runtime' });
155
+ const deadline = Date.now() + (options.startTimeoutMs || 3_000);
156
+ let spawned = false;
157
+ while (Date.now() < deadline) {
158
+ const connected = await connectRuntimeBroker(endpoint, options);
159
+ if (connected.acquired) return connected;
160
+ if (!spawned) {
161
+ spawned = true;
162
+ spawnRuntimeBroker(packageRoot, options);
163
+ }
164
+ await new Promise((resolve) => setTimeout(resolve, 25));
165
+ }
166
+ const install = await tryAcquireUpdateLease({ ...options, packageRoot, role: 'install' });
167
+ if (install.acquired) {
168
+ await install.lease.release();
169
+ return { acquired: false, reason: 'unavailable' };
170
+ }
171
+ return { acquired: false, reason: install.reason };
172
+ }
173
+
174
+ async function runRuntimeBroker(options = {}) {
175
+ const packageRoot = options.packageRoot
176
+ || String(process.env.BLUN_RUNTIME_BROKER_PACKAGE_ROOT || '');
177
+ if (!path.isAbsolute(packageRoot)) throw new Error('RUNTIME_BROKER_PACKAGE_ROOT_REQUIRED');
178
+ const install = await tryAcquireUpdateLease({ packageRoot, role: 'install' });
179
+ if (!install.acquired) return false;
180
+
181
+ const endpoint = deriveUpdateLeaseEndpoint(packageRoot, { role: 'runtime' });
182
+ ensurePrivateSocketDirectory(endpoint);
183
+ const holders = new Set();
184
+ let idleTimer;
185
+ let closing = false;
186
+ let identity;
187
+ const closeBroker = async (server) => {
188
+ if (closing) return;
189
+ closing = true;
190
+ clearTimeout(idleTimer);
191
+ await closeServer(server);
192
+ removeOwnedSocket(endpoint, identity);
193
+ await install.lease.release();
194
+ };
195
+ const server = net.createServer((socket) => {
196
+ socket.setEncoding('utf8');
197
+ let received = '';
198
+ let admitted = false;
199
+ const reject = () => {
200
+ try {
201
+ socket.destroy();
202
+ } catch {}
203
+ };
204
+ const onData = (chunk) => {
205
+ if (admitted) return;
206
+ received += String(chunk);
207
+ if (Buffer.byteLength(received, 'utf8') > Buffer.byteLength(endpoint.magic, 'utf8')) {
208
+ reject();
209
+ return;
210
+ }
211
+ if (!received.includes('\n')) return;
212
+ if (received !== endpoint.magic) {
213
+ reject();
214
+ return;
215
+ }
216
+ admitted = true;
217
+ clearTimeout(idleTimer);
218
+ holders.add(socket);
219
+ socket.write(endpoint.magic);
220
+ };
221
+ socket.on('data', onData);
222
+ socket.on('error', () => {});
223
+ socket.once('close', () => {
224
+ holders.delete(socket);
225
+ if (holders.size === 0 && !closing) {
226
+ idleTimer = setTimeout(() => { void closeBroker(server); }, 0);
227
+ }
228
+ });
229
+ });
230
+ try {
231
+ await new Promise((resolve, reject) => {
232
+ const onError = (error) => {
233
+ server.removeListener('error', onError);
234
+ reject(error);
235
+ };
236
+ server.once('error', onError);
237
+ server.listen({ path: endpoint.path, exclusive: true }, () => {
238
+ server.removeListener('error', onError);
239
+ resolve();
240
+ });
241
+ });
242
+ identity = recordSocketIdentity(endpoint);
243
+ } catch {
244
+ await closeServer(server);
245
+ await install.lease.release();
246
+ return false;
247
+ }
248
+ install.lease.unref();
249
+ server.unref?.();
250
+ idleTimer = setTimeout(() => { void closeBroker(server); }, 5_000);
251
+ return true;
252
+ }
253
+
254
+ function closeServer(server) {
255
+ for (const socket of server[LEASE_CONNECTIONS] || []) {
256
+ try {
257
+ socket.destroy();
258
+ } catch {}
259
+ }
260
+ if (!server.listening) return Promise.resolve();
261
+ try {
262
+ server.close();
263
+ server.unref?.();
264
+ } catch {}
265
+ return Promise.resolve();
266
+ }
267
+
268
+ function ensurePrivateSocketDirectory(endpoint, options = {}) {
269
+ if (endpoint.platform === 'win32') return;
270
+ const fsImpl = options.fsImpl || fs;
271
+ fsImpl.mkdirSync(endpoint.directory, { recursive: true, mode: 0o700 });
272
+ const stat = fsImpl.lstatSync(endpoint.directory);
273
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
274
+ throw new Error('INVALID_UPDATE_LEASE_DIRECTORY');
275
+ }
276
+ if (typeof process.getuid === 'function'
277
+ && Number.isInteger(stat.uid)
278
+ && stat.uid !== process.getuid()) {
279
+ throw new Error('INVALID_UPDATE_LEASE_DIRECTORY_OWNER');
280
+ }
281
+ fsImpl.chmodSync(endpoint.directory, 0o700);
282
+ }
283
+
284
+ function listenForLease(endpoint, options = {}) {
285
+ const netImpl = options.netImpl || net;
286
+ return new Promise((resolve, reject) => {
287
+ const server = netImpl.createServer((socket) => {
288
+ server[LEASE_CONNECTIONS].add(socket);
289
+ socket.once('close', () => server[LEASE_CONNECTIONS].delete(socket));
290
+ socket.on('error', () => {});
291
+ socket.end(endpoint.magic);
292
+ });
293
+ server[LEASE_CONNECTIONS] = new Set();
294
+ const onError = (error) => {
295
+ server.removeListener('error', onError);
296
+ reject(error);
297
+ };
298
+ server.once('error', onError);
299
+ server.listen({ path: endpoint.path, exclusive: true }, () => {
300
+ server.removeListener('error', onError);
301
+ resolve(server);
302
+ });
303
+ });
304
+ }
305
+
306
+ function probeExistingLease(endpoint, options = {}) {
307
+ const netImpl = options.netImpl || net;
308
+ const timeoutMs = options.probeTimeoutMs || LEASE_PROBE_TIMEOUT_MS;
309
+ return new Promise((resolve) => {
310
+ let settled = false;
311
+ let received = '';
312
+ let socket;
313
+ const finish = (state, error) => {
314
+ if (settled) return;
315
+ settled = true;
316
+ clearTimeout(timer);
317
+ try {
318
+ socket?.destroy();
319
+ } catch {}
320
+ // oxlint-disable-next-line promise/no-multiple-resolved -- settled is the idempotence guard.
321
+ resolve({ error, state });
322
+ };
323
+ const timer = setTimeout(() => finish('foreign'), timeoutMs);
324
+ timer.unref?.();
325
+ try {
326
+ socket = netImpl.createConnection({ path: endpoint.path });
327
+ socket.setEncoding?.('utf8');
328
+ socket.on('data', (chunk) => {
329
+ received += String(chunk);
330
+ if (Buffer.byteLength(received, 'utf8') > Buffer.byteLength(endpoint.magic, 'utf8')) {
331
+ finish('foreign');
332
+ }
333
+ });
334
+ socket.once('end', () => finish(received === endpoint.magic ? 'owner' : 'foreign'));
335
+ socket.once('error', (error) => {
336
+ const stale = error?.code === 'ECONNREFUSED' || error?.code === 'ENOENT';
337
+ finish(stale ? 'stale' : 'foreign', error);
338
+ });
339
+ socket.once('close', () => {
340
+ if (!settled) finish(received === endpoint.magic ? 'owner' : 'foreign');
341
+ });
342
+ } catch (error) {
343
+ const stale = error?.code === 'ECONNREFUSED' || error?.code === 'ENOENT';
344
+ finish(stale ? 'stale' : 'foreign', error);
345
+ }
346
+ });
347
+ }
348
+
349
+ function observeSocketPath(endpoint, options = {}) {
350
+ if (endpoint.platform === 'win32') return { state: 'not_applicable' };
351
+ const fsImpl = options.fsImpl || fs;
352
+ try {
353
+ const stat = fsImpl.lstatSync(endpoint.path);
354
+ if (!stat.isSocket() || stat.isSymbolicLink()) return { state: 'unsafe' };
355
+ return { dev: stat.dev, ino: stat.ino, state: 'socket' };
356
+ } catch (error) {
357
+ return error?.code === 'ENOENT' ? { state: 'missing' } : { state: 'unsafe' };
358
+ }
359
+ }
360
+
361
+ function removeObservedStaleSocket(endpoint, observed, options = {}) {
362
+ if (endpoint.platform === 'win32') return false;
363
+ const fsImpl = options.fsImpl || fs;
364
+ try {
365
+ const stat = fsImpl.lstatSync(endpoint.path);
366
+ if (observed.state !== 'socket'
367
+ || !stat.isSocket()
368
+ || stat.isSymbolicLink()
369
+ || stat.dev !== observed.dev
370
+ || stat.ino !== observed.ino) {
371
+ return false;
372
+ }
373
+ fsImpl.unlinkSync(endpoint.path);
374
+ return true;
375
+ } catch (error) {
376
+ return error?.code === 'ENOENT' && observed.state === 'missing';
377
+ }
378
+ }
379
+
380
+ function recordSocketIdentity(endpoint, options = {}) {
381
+ if (endpoint.platform === 'win32') return undefined;
382
+ const fsImpl = options.fsImpl || fs;
383
+ const stat = fsImpl.lstatSync(endpoint.path);
384
+ if (!stat.isSocket() || stat.isSymbolicLink()) throw new Error('INVALID_UPDATE_LEASE_SOCKET');
385
+ fsImpl.chmodSync(endpoint.path, 0o600);
386
+ return { dev: stat.dev, ino: stat.ino };
387
+ }
388
+
389
+ function removeOwnedSocket(endpoint, identity, options = {}) {
390
+ if (endpoint.platform === 'win32' || !identity) return;
391
+ const fsImpl = options.fsImpl || fs;
392
+ try {
393
+ const stat = fsImpl.lstatSync(endpoint.path);
394
+ if (stat.isSocket()
395
+ && !stat.isSymbolicLink()
396
+ && stat.dev === identity.dev
397
+ && stat.ino === identity.ino) {
398
+ fsImpl.unlinkSync(endpoint.path);
399
+ }
400
+ } catch {}
401
+ }
402
+
403
+ async function tryAcquireUpdateLease(options = {}) {
404
+ let endpoint;
405
+ try {
406
+ endpoint = deriveUpdateLeaseEndpoint(options.packageRoot, options);
407
+ ensurePrivateSocketDirectory(endpoint, options);
408
+ } catch {
409
+ return { acquired: false, reason: 'unavailable' };
410
+ }
411
+
412
+ let server;
413
+ for (let attempt = 0; attempt < 2; attempt += 1) {
414
+ try {
415
+ server = await listenForLease(endpoint, options);
416
+ break;
417
+ } catch (error) {
418
+ if (error?.code !== 'EADDRINUSE') {
419
+ return { acquired: false, reason: 'unavailable' };
420
+ }
421
+ const observed = observeSocketPath(endpoint, options);
422
+ const probe = await probeExistingLease(endpoint, options);
423
+ if (probe.state === 'owner') return { acquired: false, reason: 'busy' };
424
+ if (probe.state !== 'stale' || attempt > 0) {
425
+ return { acquired: false, reason: 'unavailable' };
426
+ }
427
+ if (endpoint.platform === 'win32') continue;
428
+ if (!removeObservedStaleSocket(endpoint, observed, options)) {
429
+ return { acquired: false, reason: 'unavailable' };
430
+ }
431
+ }
432
+ }
433
+ if (!server) return { acquired: false, reason: 'unavailable' };
434
+
435
+ let identity;
436
+ try {
437
+ identity = recordSocketIdentity(endpoint, options);
438
+ } catch {
439
+ await closeServer(server);
440
+ removeOwnedSocket(endpoint, identity, options);
441
+ return { acquired: false, reason: 'unavailable' };
442
+ }
443
+
444
+ let owned = true;
445
+ let released = false;
446
+ server.on('error', () => {
447
+ owned = false;
448
+ });
449
+ server.on('close', () => {
450
+ owned = false;
451
+ });
452
+ const lease = Object.freeze({
453
+ assertOwned() {
454
+ if (!owned || !server.listening) throw new Error('UPDATE_LEASE_LOST');
455
+ },
456
+ async release() {
457
+ if (released) return;
458
+ released = true;
459
+ owned = false;
460
+ await closeServer(server);
461
+ removeOwnedSocket(endpoint, identity, options);
462
+ },
463
+ unref() {
464
+ server.unref?.();
465
+ },
466
+ });
467
+ return { acquired: true, lease };
468
+ }
469
+
470
+ function isInstallerMessage(message) {
471
+ if (!message || message.type !== LEASE_HANDOFF_MESSAGE) return false;
472
+ const installer = message.installer;
473
+ return installer
474
+ && typeof installer === 'object'
475
+ && typeof message.packageRoot === 'string'
476
+ && path.isAbsolute(message.packageRoot)
477
+ && typeof installer.npmCliPath === 'string'
478
+ && path.isAbsolute(installer.npmCliPath)
479
+ && Array.isArray(installer.npmArgs)
480
+ && installer.npmArgs.every((entry) => typeof entry === 'string')
481
+ && typeof installer.installCwd === 'string'
482
+ && path.isAbsolute(installer.installCwd);
483
+ }
484
+
485
+ function runInstallerWorker() {
486
+ let state = 'BOOT';
487
+ let started = false;
488
+ let installLease;
489
+ let installCwd;
490
+ const isControlMessage = (message, type) => message
491
+ && typeof message === 'object'
492
+ && Object.getPrototypeOf(message) === Object.prototype
493
+ && Reflect.ownKeys(message).length === 1
494
+ && message.type === type;
495
+ const exitWithoutInstall = async (code = 0) => {
496
+ if (state === 'DONE') return;
497
+ state = 'DONE';
498
+ try {
499
+ await installLease?.release();
500
+ } catch {}
501
+ process.exit(code);
502
+ };
503
+ const startInstaller = (installer) => {
504
+ if (started || state !== 'COMMITTED') return;
505
+ started = true;
506
+ try {
507
+ installLease.assertOwned();
508
+ process.chdir(installer.installCwd);
509
+ process.argv = [process.execPath, installer.npmCliPath, ...installer.npmArgs];
510
+ require(installer.npmCliPath);
511
+ } catch {
512
+ process.exit(1);
513
+ }
514
+ };
515
+
516
+ process.once('message', async (message) => {
517
+ if (state !== 'BOOT' || !isInstallerMessage(message)) {
518
+ process.exit(1);
519
+ return;
520
+ }
521
+ state = 'PREPARED';
522
+ installCwd = message.installer.installCwd;
523
+ process.once('exit', () => {
524
+ if (!installCwd) return;
525
+ try {
526
+ process.chdir(path.dirname(installCwd));
527
+ fs.rmSync(installCwd, { recursive: true, force: true });
528
+ } catch {}
529
+ });
530
+ const leaseResult = await tryAcquireUpdateLease({
531
+ packageRoot: message.packageRoot,
532
+ role: 'install',
533
+ });
534
+ if (!leaseResult.acquired) {
535
+ const type = leaseResult.reason === 'busy'
536
+ ? LEASE_BUSY_MESSAGE
537
+ : LEASE_UNAVAILABLE_MESSAGE;
538
+ if (process.connected) {
539
+ try {
540
+ process.send({ type }, () => process.exit(75));
541
+ return;
542
+ } catch {}
543
+ }
544
+ process.exit(75);
545
+ return;
546
+ }
547
+ installLease = leaseResult.lease;
548
+ state = 'LEASED';
549
+ if (!process.connected) {
550
+ await exitWithoutInstall();
551
+ return;
552
+ }
553
+ const onControl = (control) => {
554
+ if (state !== 'LEASED') {
555
+ void exitWithoutInstall(1);
556
+ return;
557
+ }
558
+ if (isControlMessage(control, LEASE_CANCEL_MESSAGE)) {
559
+ void exitWithoutInstall();
560
+ return;
561
+ }
562
+ if (!isControlMessage(control, LEASE_COMMIT_MESSAGE)) {
563
+ void exitWithoutInstall(1);
564
+ return;
565
+ }
566
+ state = 'COMMITTED';
567
+ setImmediate(() => startInstaller(message.installer));
568
+ };
569
+ process.once('message', onControl);
570
+ try {
571
+ process.send({ type: LEASE_ADOPT_MESSAGE });
572
+ } catch {
573
+ process.removeListener('message', onControl);
574
+ await exitWithoutInstall();
575
+ }
576
+ });
577
+ process.once('disconnect', () => {
578
+ if (state !== 'COMMITTED' && state !== 'DONE') void exitWithoutInstall();
579
+ });
580
+ }
581
+
582
+ if (require.main === module && process.argv[2] === '--installer-worker') {
583
+ runInstallerWorker();
584
+ } else if (require.main === module && process.argv[2] === '--runtime-broker') {
585
+ void runRuntimeBroker().then((started) => {
586
+ if (!started) process.exitCode = 75;
587
+ }).catch(() => {
588
+ process.exitCode = 1;
589
+ });
590
+ }
591
+
592
+ module.exports = {
593
+ acquireSharedRuntimeLease,
594
+ deriveUpdateLeaseEndpoint,
595
+ runRuntimeBroker,
596
+ tryAcquireUpdateLease,
597
+ };