@agent-relay/harness-driver 13.4.1 → 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.
- package/dist/broker-install.d.ts +146 -0
- package/dist/broker-install.d.ts.map +1 -0
- package/dist/broker-install.js +494 -0
- package/dist/broker-install.js.map +1 -0
- package/dist/broker-path.d.ts +53 -10
- package/dist/broker-path.d.ts.map +1 -1
- package/dist/broker-path.js +111 -49
- package/dist/broker-path.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/install-paths.d.ts +94 -0
- package/dist/install-paths.d.ts.map +1 -0
- package/dist/install-paths.js +151 -0
- package/dist/install-paths.js.map +1 -0
- package/package.json +17 -7
|
@@ -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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"}
|