@agent-relay/harness-driver 14.0.0 → 15.0.0-next.0

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.
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Converge an npm install onto the canonical broker location.
3
+ *
4
+ * `npm i -g agent-relay` ships the broker inside node_modules through the
5
+ * platform optional dependency `@agent-relay/broker-<platform>-<arch>`. On the
6
+ * CLI's first run (not in a postinstall script: many users install with
7
+ * `ignore-scripts`), {@link ensureCanonicalBroker} copies that broker into
8
+ * `<install root>/bin/agent-relay-broker[.exe]` so every install method ends
9
+ * with the broker in the same place (see ./install-paths.ts).
10
+ *
11
+ * Guarantees:
12
+ * - Atomic: the copy is written to a temp file in the target directory,
13
+ * verified, chmod 0755, then renamed over the target.
14
+ * - Integrity: when the npm package ships `<binary>.sha256`, the source must
15
+ * match it; the temp copy must always hash identically to the source.
16
+ * - No races: a lock file in the bin directory serialises concurrent CLI
17
+ * processes; a process that finds the lock held skips this run. An
18
+ * abandoned lock is broken by renaming it aside and confirming the renamed
19
+ * file is the one judged abandoned, so a contender can never delete a
20
+ * replacement lock another process just took. The owner re-checks that it
21
+ * still holds the lock immediately before the final rename.
22
+ * - Integrity of the sidecar itself: a present but unparseable `.sha256`
23
+ * rejects the install (only an absent sidecar falls back to copy-hash
24
+ * verification, for older packages).
25
+ * - No downgrades: a canonical broker whose version is equal to or newer than
26
+ * the npm one (for example from install.sh or the desktop app) is left
27
+ * alone. A canonical file that cannot report a version is replaced.
28
+ */
29
+ /** Set to `1` to disable copying the npm broker into the canonical bin directory. */
30
+ export declare const SKIP_BROKER_INSTALL_ENV = "AGENT_RELAY_SKIP_BROKER_INSTALL";
31
+ export type EnsureCanonicalBrokerSkipReason = 'disabled' | 'override' | 'no-source' | 'source-is-canonical' | 'unknown-source-version' | 'up-to-date' | 'newer-installed' | 'locked' | 'checksum-mismatch' | 'error';
32
+ export type EnsureCanonicalBrokerResult = {
33
+ action: 'installed' | 'upgraded';
34
+ path: string;
35
+ version: string;
36
+ /** Version the replaced broker reported; absent when it reported none. */
37
+ previousVersion?: string;
38
+ } | {
39
+ action: 'skipped';
40
+ reason: EnsureCanonicalBrokerSkipReason;
41
+ path: string;
42
+ detail?: string;
43
+ };
44
+ export interface EnsureCanonicalBrokerOptions {
45
+ /** Environment for overrides (default: process.env). */
46
+ env?: Record<string, string | undefined>;
47
+ /** Broker to copy (default: the npm optional-dependency binary). */
48
+ sourcePath?: string | null;
49
+ /** Version of `sourcePath` (default: its package.json version, else `--version`). */
50
+ sourceVersion?: string | null;
51
+ /** Destination (default: the canonical broker path). */
52
+ targetPath?: string;
53
+ /** Version probe for a binary; returns null when it cannot report one. */
54
+ readVersion?: (binaryPath: string) => string | null;
55
+ /** Age after which a lock is considered abandoned (default 120s). */
56
+ lockStaleMs?: number;
57
+ }
58
+ /**
59
+ * Extract the first semantic version from text such as
60
+ * `agent-relay-broker 14.0.0`.
61
+ * @param text - Output to scan
62
+ * @returns The version string, or null if none is present
63
+ */
64
+ export declare function parseVersion(text: string | null | undefined): string | null;
65
+ /**
66
+ * Compare two semantic versions.
67
+ * @returns -1, 0 or 1 like a sort comparator; null if either is unparseable
68
+ */
69
+ export declare function compareVersions(a: string, b: string): number | null;
70
+ /**
71
+ * Run `<binary> --version` and parse the version it prints.
72
+ * @param binaryPath - Executable to probe
73
+ * @returns The version, or null if the binary could not run or printed none
74
+ */
75
+ export declare function readBinaryVersion(binaryPath: string): string | null;
76
+ declare function versionCachePath(targetPath: string): string;
77
+ /** What identifies one particular lock file, so a takeover can tell it apart from a replacement. */
78
+ interface LockIdentity {
79
+ token?: string;
80
+ ino: number;
81
+ size: number;
82
+ mtimeMs: number;
83
+ }
84
+ /** A held lock. */
85
+ export interface LockHandle {
86
+ /** Remove the lock if it is still ours. */
87
+ release: () => void;
88
+ /** True while the lock file on disk is still the one this process created. */
89
+ isHeld: () => boolean;
90
+ }
91
+ /**
92
+ * Inspect an existing lock. Returns null when it vanished (retry), otherwise
93
+ * whether it is abandoned (owner dead, unparseable and old, or older than
94
+ * `staleMs`) together with its identity.
95
+ */
96
+ declare function inspectLock(lockPath: string, staleMs: number): {
97
+ stale: boolean;
98
+ identity: LockIdentity;
99
+ } | null;
100
+ /**
101
+ * Remove the abandoned lock described by `expected` without ever deleting a
102
+ * different (replacement) lock. The lock is atomically renamed aside first;
103
+ * if the renamed file turns out to be a live replacement that another
104
+ * contender created after the abandoned one was removed, it is linked back
105
+ * into place (no-clobber) and the takeover is abandoned.
106
+ *
107
+ * @returns true when the abandoned lock is gone and the caller may race to create one
108
+ */
109
+ declare function breakStaleLock(lockPath: string, expected: LockIdentity): boolean;
110
+ /**
111
+ * Take an exclusive lock file. Returns a handle, or null when a live process
112
+ * holds the lock (or a concurrent takeover won). An abandoned lock is broken
113
+ * with {@link breakStaleLock}.
114
+ */
115
+ declare function acquireLock(lockPath: string, staleMs: number): LockHandle | null;
116
+ type CopyOutcome = {
117
+ ok: true;
118
+ } | {
119
+ ok: false;
120
+ reason: 'checksum-mismatch' | 'locked';
121
+ detail: string;
122
+ };
123
+ /**
124
+ * Copy `sourcePath` over `targetPath` through a verified temp file in the
125
+ * target directory. `canCommit` is consulted immediately before the final
126
+ * rename; when it returns false the copy is discarded.
127
+ */
128
+ declare function copyAtomically(sourcePath: string, targetPath: string, canCommit: () => boolean): CopyOutcome;
129
+ /**
130
+ * Copy the npm-shipped broker into the canonical bin directory when the
131
+ * canonical broker is missing or older. Never throws.
132
+ *
133
+ * @param options - Overrides, mainly for tests
134
+ * @returns What happened, for diagnostics
135
+ */
136
+ export declare function ensureCanonicalBroker(options?: EnsureCanonicalBrokerOptions): EnsureCanonicalBrokerResult;
137
+ /** @internal Exposed for tests. */
138
+ export declare const testInternals: {
139
+ acquireLock: typeof acquireLock;
140
+ breakStaleLock: typeof breakStaleLock;
141
+ copyAtomically: typeof copyAtomically;
142
+ inspectLock: typeof inspectLock;
143
+ versionCachePath: typeof versionCachePath;
144
+ };
145
+ export {};
146
+ //# sourceMappingURL=broker-install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker-install.d.ts","sourceRoot":"","sources":["../src/broker-install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,494 @@
1
+ /**
2
+ * Converge an npm install onto the canonical broker location.
3
+ *
4
+ * `npm i -g agent-relay` ships the broker inside node_modules through the
5
+ * platform optional dependency `@agent-relay/broker-<platform>-<arch>`. On the
6
+ * CLI's first run (not in a postinstall script: many users install with
7
+ * `ignore-scripts`), {@link ensureCanonicalBroker} copies that broker into
8
+ * `<install root>/bin/agent-relay-broker[.exe]` so every install method ends
9
+ * with the broker in the same place (see ./install-paths.ts).
10
+ *
11
+ * Guarantees:
12
+ * - Atomic: the copy is written to a temp file in the target directory,
13
+ * verified, chmod 0755, then renamed over the target.
14
+ * - Integrity: when the npm package ships `<binary>.sha256`, the source must
15
+ * match it; the temp copy must always hash identically to the source.
16
+ * - No races: a lock file in the bin directory serialises concurrent CLI
17
+ * processes; a process that finds the lock held skips this run. An
18
+ * abandoned lock is broken by renaming it aside and confirming the renamed
19
+ * file is the one judged abandoned, so a contender can never delete a
20
+ * replacement lock another process just took. The owner re-checks that it
21
+ * still holds the lock immediately before the final rename.
22
+ * - Integrity of the sidecar itself: a present but unparseable `.sha256`
23
+ * rejects the install (only an absent sidecar falls back to copy-hash
24
+ * verification, for older packages).
25
+ * - No downgrades: a canonical broker whose version is equal to or newer than
26
+ * the npm one (for example from install.sh or the desktop app) is left
27
+ * alone. A canonical file that cannot report a version is replaced.
28
+ */
29
+ import { execFileSync } from 'node:child_process';
30
+ import { createHash } from 'node:crypto';
31
+ import { chmodSync, closeSync, copyFileSync, existsSync, linkSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync, } from 'node:fs';
32
+ import { basename, dirname, join } from 'node:path';
33
+ import { getOptionalDepBrokerPath } from './broker-path.js';
34
+ import { getCanonicalBrokerPath } from './install-paths.js';
35
+ /** Set to `1` to disable copying the npm broker into the canonical bin directory. */
36
+ export const SKIP_BROKER_INSTALL_ENV = 'AGENT_RELAY_SKIP_BROKER_INSTALL';
37
+ const DEFAULT_LOCK_STALE_MS = 120_000;
38
+ const VERSION_PROBE_TIMEOUT_MS = 5_000;
39
+ // Bounded components and the no-digit lookbehind keep the unanchored scan
40
+ // linear: an unbounded `\d+` re-backtracks every suffix of a long digit run.
41
+ const SEMVER_RE = /(?<!\d)(\d{1,10})\.(\d{1,10})\.(\d{1,10})(?:-([0-9A-Za-z.-]{1,128}))?/u;
42
+ /**
43
+ * Extract the first semantic version from text such as
44
+ * `agent-relay-broker 14.0.0`.
45
+ * @param text - Output to scan
46
+ * @returns The version string, or null if none is present
47
+ */
48
+ export function parseVersion(text) {
49
+ if (!text)
50
+ return null;
51
+ const match = SEMVER_RE.exec(text);
52
+ return match ? match[0] : null;
53
+ }
54
+ function comparePrerelease(a, b) {
55
+ if (a === b)
56
+ return 0;
57
+ if (a === undefined)
58
+ return 1; // a release outranks its prereleases
59
+ if (b === undefined)
60
+ return -1;
61
+ const as = a.split('.');
62
+ const bs = b.split('.');
63
+ for (let i = 0; i < Math.max(as.length, bs.length); i += 1) {
64
+ const x = as[i];
65
+ const y = bs[i];
66
+ if (x === undefined)
67
+ return -1;
68
+ if (y === undefined)
69
+ return 1;
70
+ const xn = /^\d+$/u.test(x);
71
+ const yn = /^\d+$/u.test(y);
72
+ if (xn && yn) {
73
+ const d = Number(x) - Number(y);
74
+ if (d !== 0)
75
+ return d < 0 ? -1 : 1;
76
+ }
77
+ else if (xn !== yn) {
78
+ return xn ? -1 : 1;
79
+ }
80
+ else if (x !== y) {
81
+ return x < y ? -1 : 1;
82
+ }
83
+ }
84
+ return 0;
85
+ }
86
+ /**
87
+ * Compare two semantic versions.
88
+ * @returns -1, 0 or 1 like a sort comparator; null if either is unparseable
89
+ */
90
+ export function compareVersions(a, b) {
91
+ const ma = SEMVER_RE.exec(a);
92
+ const mb = SEMVER_RE.exec(b);
93
+ if (!ma || !mb)
94
+ return null;
95
+ for (let i = 1; i <= 3; i += 1) {
96
+ const d = Number(ma[i]) - Number(mb[i]);
97
+ if (d !== 0)
98
+ return d < 0 ? -1 : 1;
99
+ }
100
+ return comparePrerelease(ma[4], mb[4]);
101
+ }
102
+ /**
103
+ * Run `<binary> --version` and parse the version it prints.
104
+ * @param binaryPath - Executable to probe
105
+ * @returns The version, or null if the binary could not run or printed none
106
+ */
107
+ export function readBinaryVersion(binaryPath) {
108
+ try {
109
+ const out = execFileSync(binaryPath, ['--version'], {
110
+ encoding: 'utf-8',
111
+ stdio: ['ignore', 'pipe', 'ignore'],
112
+ timeout: VERSION_PROBE_TIMEOUT_MS,
113
+ windowsHide: true,
114
+ });
115
+ return parseVersion(out);
116
+ }
117
+ catch {
118
+ return null;
119
+ }
120
+ }
121
+ /** Version from the package.json of the npm package that ships `binaryPath` (`<pkg>/bin/<file>`). */
122
+ function readPackageVersion(binaryPath) {
123
+ try {
124
+ const pkgJson = join(dirname(dirname(binaryPath)), 'package.json');
125
+ const parsed = JSON.parse(readFileSync(pkgJson, 'utf-8'));
126
+ return typeof parsed.version === 'string' ? parseVersion(parsed.version) : null;
127
+ }
128
+ catch {
129
+ return null;
130
+ }
131
+ }
132
+ function sha256File(filePath) {
133
+ return createHash('sha256').update(readFileSync(filePath)).digest('hex');
134
+ }
135
+ /**
136
+ * Expected digest from a `<binary>.sha256` sidecar (`<hex>` or `<hex> <name>`).
137
+ * `digest` is null when the sidecar exists but holds no SHA-256 digest
138
+ * (empty, truncated, corrupt), which callers must treat as a failed check.
139
+ */
140
+ function readSidecarSha256(binaryPath) {
141
+ const sidecar = `${binaryPath}.sha256`;
142
+ if (!existsSync(sidecar))
143
+ return { present: false };
144
+ const match = /\b([0-9a-fA-F]{64})\b/u.exec(readFileSync(sidecar, 'utf-8'));
145
+ return { present: true, digest: match ? match[1].toLowerCase() : null };
146
+ }
147
+ function versionCachePath(targetPath) {
148
+ return join(dirname(targetPath), `.${basename(targetPath)}.version.json`);
149
+ }
150
+ /**
151
+ * Version of the canonical broker, served from a stat-keyed cache so a normal
152
+ * CLI run does not execute the broker just to learn its version.
153
+ */
154
+ function readTargetVersion(targetPath, readVersion) {
155
+ let stat;
156
+ try {
157
+ stat = statSync(targetPath);
158
+ }
159
+ catch {
160
+ return null;
161
+ }
162
+ const cachePath = versionCachePath(targetPath);
163
+ try {
164
+ const cached = JSON.parse(readFileSync(cachePath, 'utf-8'));
165
+ if (cached.size === stat.size && cached.mtimeMs === stat.mtimeMs && typeof cached.version === 'string') {
166
+ return cached.version;
167
+ }
168
+ }
169
+ catch {
170
+ // No usable cache.
171
+ }
172
+ const version = readVersion(targetPath);
173
+ if (version)
174
+ writeVersionCache(targetPath, version);
175
+ return version;
176
+ }
177
+ function writeVersionCache(targetPath, version) {
178
+ try {
179
+ const stat = statSync(targetPath);
180
+ const entry = { size: stat.size, mtimeMs: stat.mtimeMs, version };
181
+ writeFileSync(versionCachePath(targetPath), `${JSON.stringify(entry)}\n`);
182
+ }
183
+ catch {
184
+ // The cache is an optimisation only.
185
+ }
186
+ }
187
+ function isProcessAlive(pid) {
188
+ try {
189
+ process.kill(pid, 0);
190
+ return true;
191
+ }
192
+ catch (err) {
193
+ return err.code === 'EPERM';
194
+ }
195
+ }
196
+ function readLockToken(lockPath) {
197
+ try {
198
+ const held = JSON.parse(readFileSync(lockPath, 'utf-8'));
199
+ return typeof held.token === 'string' ? held.token : undefined;
200
+ }
201
+ catch {
202
+ return undefined;
203
+ }
204
+ }
205
+ function lockIdentity(lockPath) {
206
+ const stat = statSync(lockPath);
207
+ return { token: readLockToken(lockPath), ino: stat.ino, size: stat.size, mtimeMs: stat.mtimeMs };
208
+ }
209
+ function sameLock(a, b) {
210
+ if (a.token !== undefined || b.token !== undefined)
211
+ return a.token === b.token;
212
+ return a.ino === b.ino && a.size === b.size && a.mtimeMs === b.mtimeMs;
213
+ }
214
+ /**
215
+ * Inspect an existing lock. Returns null when it vanished (retry), otherwise
216
+ * whether it is abandoned (owner dead, unparseable and old, or older than
217
+ * `staleMs`) together with its identity.
218
+ */
219
+ function inspectLock(lockPath, staleMs) {
220
+ let identity;
221
+ let pid = NaN;
222
+ try {
223
+ identity = lockIdentity(lockPath);
224
+ const held = JSON.parse(readFileSync(lockPath, 'utf-8'));
225
+ if (typeof held.pid === 'number')
226
+ pid = held.pid;
227
+ }
228
+ catch (err) {
229
+ if (err.code === 'ENOENT')
230
+ return null;
231
+ // Unparseable, probably while being written: held unless it is also old.
232
+ try {
233
+ identity = lockIdentity(lockPath);
234
+ }
235
+ catch {
236
+ return null;
237
+ }
238
+ return { stale: Date.now() - identity.mtimeMs > staleMs, identity };
239
+ }
240
+ const old = Date.now() - identity.mtimeMs > staleMs;
241
+ return { stale: old || !Number.isInteger(pid) || !isProcessAlive(pid), identity };
242
+ }
243
+ /**
244
+ * Remove the abandoned lock described by `expected` without ever deleting a
245
+ * different (replacement) lock. The lock is atomically renamed aside first;
246
+ * if the renamed file turns out to be a live replacement that another
247
+ * contender created after the abandoned one was removed, it is linked back
248
+ * into place (no-clobber) and the takeover is abandoned.
249
+ *
250
+ * @returns true when the abandoned lock is gone and the caller may race to create one
251
+ */
252
+ function breakStaleLock(lockPath, expected) {
253
+ const aside = `${lockPath}.${process.pid}.${Math.random().toString(36).slice(2)}.stale`;
254
+ try {
255
+ renameSync(lockPath, aside);
256
+ }
257
+ catch (err) {
258
+ // ENOENT: someone else already removed it; race to create a fresh one.
259
+ return err.code === 'ENOENT';
260
+ }
261
+ let moved = null;
262
+ try {
263
+ moved = lockIdentity(aside);
264
+ }
265
+ catch {
266
+ // Unreadable; treat as not the lock we judged.
267
+ }
268
+ if (moved && sameLock(moved, expected)) {
269
+ try {
270
+ unlinkSync(aside);
271
+ }
272
+ catch {
273
+ // Best effort.
274
+ }
275
+ return true;
276
+ }
277
+ // We moved someone else's fresh lock. Restore it unless a newer lock already
278
+ // exists (link never overwrites). If restoring fails, its owner notices
279
+ // through isHeld() before committing and backs off.
280
+ try {
281
+ linkSync(aside, lockPath);
282
+ }
283
+ catch {
284
+ // A newer lock is in place, or the filesystem has no hard links.
285
+ }
286
+ try {
287
+ unlinkSync(aside);
288
+ }
289
+ catch {
290
+ // Best effort.
291
+ }
292
+ return false;
293
+ }
294
+ /**
295
+ * Take an exclusive lock file. Returns a handle, or null when a live process
296
+ * holds the lock (or a concurrent takeover won). An abandoned lock is broken
297
+ * with {@link breakStaleLock}.
298
+ */
299
+ function acquireLock(lockPath, staleMs) {
300
+ const token = `${process.pid}:${Date.now()}:${Math.random().toString(36).slice(2)}`;
301
+ for (let attempt = 0; attempt < 3; attempt += 1) {
302
+ try {
303
+ const fd = openSync(lockPath, 'wx', 0o644);
304
+ try {
305
+ writeSync(fd, JSON.stringify({ pid: process.pid, token }));
306
+ }
307
+ finally {
308
+ closeSync(fd);
309
+ }
310
+ return {
311
+ isHeld: () => readLockToken(lockPath) === token,
312
+ release: () => {
313
+ try {
314
+ if (readLockToken(lockPath) === token)
315
+ unlinkSync(lockPath);
316
+ }
317
+ catch {
318
+ // Already gone.
319
+ }
320
+ },
321
+ };
322
+ }
323
+ catch (err) {
324
+ if (err.code !== 'EEXIST')
325
+ throw err;
326
+ }
327
+ const existing = inspectLock(lockPath, staleMs);
328
+ if (existing === null)
329
+ continue;
330
+ if (!existing.stale)
331
+ return null;
332
+ if (!breakStaleLock(lockPath, existing.identity))
333
+ return null;
334
+ }
335
+ return null;
336
+ }
337
+ /** Decide whether this run should converge at all; returns a skip reason or the inputs. */
338
+ function resolveInputs(options, env, targetPath, readVersion) {
339
+ const flag = env[SKIP_BROKER_INSTALL_ENV]?.trim().toLowerCase();
340
+ if (flag === '1' || flag === 'true')
341
+ return { skip: 'disabled' };
342
+ // An explicit broker override means the operator chose a binary; do not
343
+ // populate the canonical slot behind their back.
344
+ if (env.BROKER_BINARY_PATH?.trim() || env.AGENT_RELAY_BIN?.trim())
345
+ return { skip: 'override' };
346
+ // Only the broker that ships with this CLI's own package tree may populate
347
+ // the shared slot; never one found through the current project's
348
+ // node_modules (that broker may be a different version).
349
+ const sourcePath = options.sourcePath === undefined ? getOptionalDepBrokerPath({ includeCwd: false }) : options.sourcePath;
350
+ if (!sourcePath || !existsSync(sourcePath))
351
+ return { skip: 'no-source' };
352
+ if (sameFile(sourcePath, targetPath))
353
+ return { skip: 'source-is-canonical' };
354
+ const declared = options.sourceVersion === undefined ? readPackageVersion(sourcePath) : options.sourceVersion;
355
+ const sourceVersion = declared ?? readVersion(sourcePath);
356
+ if (!sourceVersion)
357
+ return { skip: 'unknown-source-version', detail: sourcePath };
358
+ return { sourcePath, sourceVersion };
359
+ }
360
+ /**
361
+ * Copy `sourcePath` over `targetPath` through a verified temp file in the
362
+ * target directory. `canCommit` is consulted immediately before the final
363
+ * rename; when it returns false the copy is discarded.
364
+ */
365
+ function copyAtomically(sourcePath, targetPath, canCommit) {
366
+ const sourceHash = sha256File(sourcePath);
367
+ const sidecar = readSidecarSha256(sourcePath);
368
+ if (sidecar.present && sidecar.digest === null) {
369
+ return {
370
+ ok: false,
371
+ reason: 'checksum-mismatch',
372
+ detail: `${sourcePath}.sha256 is present but holds no SHA-256 digest`,
373
+ };
374
+ }
375
+ if (sidecar.present && sidecar.digest !== sourceHash) {
376
+ return {
377
+ ok: false,
378
+ reason: 'checksum-mismatch',
379
+ detail: `expected ${sidecar.digest}, got ${sourceHash}`,
380
+ };
381
+ }
382
+ const tempPath = join(dirname(targetPath), `.${basename(targetPath)}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`);
383
+ try {
384
+ copyFileSync(sourcePath, tempPath);
385
+ chmodSync(tempPath, 0o755);
386
+ const copiedHash = sha256File(tempPath);
387
+ if (copiedHash !== sourceHash) {
388
+ return {
389
+ ok: false,
390
+ reason: 'checksum-mismatch',
391
+ detail: `copy hashed ${copiedHash}, source ${sourceHash}`,
392
+ };
393
+ }
394
+ if (!canCommit()) {
395
+ return { ok: false, reason: 'locked', detail: 'install lock was taken over before commit' };
396
+ }
397
+ renameSync(tempPath, targetPath);
398
+ return { ok: true };
399
+ }
400
+ finally {
401
+ try {
402
+ unlinkSync(tempPath);
403
+ }
404
+ catch {
405
+ // Renamed into place, or never created.
406
+ }
407
+ }
408
+ }
409
+ /**
410
+ * Copy the npm-shipped broker into the canonical bin directory when the
411
+ * canonical broker is missing or older. Never throws.
412
+ *
413
+ * @param options - Overrides, mainly for tests
414
+ * @returns What happened, for diagnostics
415
+ */
416
+ export function ensureCanonicalBroker(options = {}) {
417
+ const env = options.env ?? process.env;
418
+ const targetPath = options.targetPath ?? getCanonicalBrokerPath(env);
419
+ const readVersion = options.readVersion ?? readBinaryVersion;
420
+ const skip = (reason, detail) => ({
421
+ action: 'skipped',
422
+ reason,
423
+ path: targetPath,
424
+ ...(detail ? { detail } : {}),
425
+ });
426
+ try {
427
+ const inputs = resolveInputs(options, env, targetPath, readVersion);
428
+ if ('skip' in inputs)
429
+ return skip(inputs.skip, inputs.detail);
430
+ const { sourcePath, sourceVersion } = inputs;
431
+ // Fast path without the lock: the common case is "already converged".
432
+ const preCheck = decide(targetPath, sourceVersion, readVersion);
433
+ if (preCheck.kind !== 'install')
434
+ return skip(preCheck.kind, preCheck.version);
435
+ const binDir = dirname(targetPath);
436
+ mkdirSync(binDir, { recursive: true, mode: 0o755 });
437
+ const lock = acquireLock(join(binDir, `.${basename(targetPath)}.lock`), options.lockStaleMs ?? DEFAULT_LOCK_STALE_MS);
438
+ if (!lock)
439
+ return skip('locked');
440
+ try {
441
+ // Re-check under the lock: another process may have just converged.
442
+ const decision = decide(targetPath, sourceVersion, readVersion);
443
+ if (decision.kind !== 'install')
444
+ return skip(decision.kind, decision.version);
445
+ const copied = copyAtomically(sourcePath, targetPath, lock.isHeld);
446
+ if (!copied.ok)
447
+ return skip(copied.reason, copied.detail);
448
+ writeVersionCache(targetPath, sourceVersion);
449
+ if (decision.previous === undefined) {
450
+ return { action: 'installed', path: targetPath, version: sourceVersion };
451
+ }
452
+ return {
453
+ action: 'upgraded',
454
+ path: targetPath,
455
+ version: sourceVersion,
456
+ ...(decision.previous ? { previousVersion: decision.previous } : {}),
457
+ };
458
+ }
459
+ finally {
460
+ lock.release();
461
+ }
462
+ }
463
+ catch (err) {
464
+ return skip('error', err instanceof Error ? err.message : String(err));
465
+ }
466
+ }
467
+ function decide(targetPath, sourceVersion, readVersion) {
468
+ if (!existsSync(targetPath))
469
+ return { kind: 'install', previous: undefined };
470
+ const installed = readTargetVersion(targetPath, readVersion);
471
+ if (!installed)
472
+ return { kind: 'install', previous: null };
473
+ const cmp = compareVersions(installed, sourceVersion);
474
+ if (cmp === null)
475
+ return { kind: 'install', previous: installed };
476
+ if (cmp > 0)
477
+ return { kind: 'newer-installed', version: installed };
478
+ if (cmp === 0)
479
+ return { kind: 'up-to-date', version: installed };
480
+ return { kind: 'install', previous: installed };
481
+ }
482
+ function sameFile(a, b) {
483
+ try {
484
+ const sa = statSync(a);
485
+ const sb = statSync(b);
486
+ return sa.dev === sb.dev && sa.ino === sb.ino;
487
+ }
488
+ catch {
489
+ return false;
490
+ }
491
+ }
492
+ /** @internal Exposed for tests. */
493
+ export const testInternals = { acquireLock, breakStaleLock, copyAtomically, inspectLock, versionCachePath };
494
+ //# sourceMappingURL=broker-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker-install.js","sourceRoot":"","sources":["../src/broker-install.ts"],"names":[],"mappings":"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"}